From 4df73100cf842f4f52206eabe49f250809742087 Mon Sep 17 00:00:00 2001 From: Murat Cakir Date: Wed, 4 Nov 2015 17:12:17 +0100 Subject: [PATCH 001/707] Export profiles: Minor UI fixes (further changes & fixes follow in a separate branch) --- .../Administration/Content/admin.less | 9 +++++--- .../Administration/Views/Export/Edit.cshtml | 21 ++++++++++--------- .../Views/Export/Preview.cshtml | 4 ++-- src/Presentation/SmartStore.Web/Web.config | 2 +- 4 files changed, 20 insertions(+), 16 deletions(-) diff --git a/src/Presentation/SmartStore.Web/Administration/Content/admin.less b/src/Presentation/SmartStore.Web/Administration/Content/admin.less index 947ca2b377..620ce8206f 100644 --- a/src/Presentation/SmartStore.Web/Administration/Content/admin.less +++ b/src/Presentation/SmartStore.Web/Administration/Content/admin.less @@ -430,12 +430,12 @@ td.adminData > input[type="checkbox"] { -------------------------------------------------------------- */ .large-select2 { .select2-choice { - height: 52px; - min-height: 52px; + height: 42px; + min-height: 42px; padding-top: 4px; > div > b { - padding-top: 14px; + padding-top: 10px; } } } @@ -444,10 +444,13 @@ td.adminData > input[type="checkbox"] { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; + height: 38px; img { margin-right: 12px; vertical-align: middle; + text-align: center; + max-height: 100%; } > div { margin-right: 0px !important; diff --git a/src/Presentation/SmartStore.Web/Administration/Views/Export/Edit.cshtml b/src/Presentation/SmartStore.Web/Administration/Views/Export/Edit.cshtml index f9174a7b29..55bac26fec 100644 --- a/src/Presentation/SmartStore.Web/Administration/Views/Export/Edit.cshtml +++ b/src/Presentation/SmartStore.Web/Administration/Views/Export/Edit.cshtml @@ -82,16 +82,17 @@ @Html.ValidationMessageFor(x => x.Enabled) - - - @Html.SmartLabelFor(x => x.ScheduleTaskId) - - - @(Model.IsTaskEnabled ? T("Common.Scheduled") : T("Common.Unscheduled")) - - @Model.ScheduleTaskName - - + @if (Model.ScheduleTaskId > 0) + { + + + @Html.SmartLabelFor(x => x.ScheduleTaskId) + + + @Html.Action("MinimalTask", "ScheduleTask", new { taskId = Model.ScheduleTaskId, returnUrl = Request.RawUrl, cancellable = true, area = "admin" }) + + + }

 

diff --git a/src/Presentation/SmartStore.Web/Administration/Views/Export/Preview.cshtml b/src/Presentation/SmartStore.Web/Administration/Views/Export/Preview.cshtml index 1c0af5cf0a..b5e527976d 100644 --- a/src/Presentation/SmartStore.Web/Administration/Views/Export/Preview.cshtml +++ b/src/Presentation/SmartStore.Web/Administration/Views/Export/Preview.cshtml @@ -22,10 +22,10 @@ {  @T("Admin.Configuration.ActivityLog") } - - diff --git a/src/Presentation/SmartStore.Web/Web.config b/src/Presentation/SmartStore.Web/Web.config index f45ffa195f..4a073d85ad 100644 --- a/src/Presentation/SmartStore.Web/Web.config +++ b/src/Presentation/SmartStore.Web/Web.config @@ -92,7 +92,7 @@ - + From 6b81ecadafd972363bc1d3b200968c9c86eb5520 Mon Sep 17 00:00:00 2001 From: Marcus Gesing Date: Wed, 4 Nov 2015 18:03:03 +0100 Subject: [PATCH 002/707] SEO Names: Input validation --- .../Controllers/UrlRecordController.cs | 2 +- .../Models/UrlRecord/UrlRecordModel.cs | 8 ++-- .../Views/UrlRecord/_CreateOrUpdate.cshtml | 4 +- .../MvcLocalization.Designer.cs | 41 +++++++++++-------- .../MvcLocalization.de.resx | 9 ++-- .../App_GlobalResources/MvcLocalization.resx | 9 ++-- 6 files changed, 44 insertions(+), 29 deletions(-) diff --git a/src/Presentation/SmartStore.Web/Administration/Controllers/UrlRecordController.cs b/src/Presentation/SmartStore.Web/Administration/Controllers/UrlRecordController.cs index 3d82fa456d..1eb07d10a5 100644 --- a/src/Presentation/SmartStore.Web/Administration/Controllers/UrlRecordController.cs +++ b/src/Presentation/SmartStore.Web/Administration/Controllers/UrlRecordController.cs @@ -180,7 +180,7 @@ public ActionResult Edit(UrlRecordModel model, bool continueEditing) var urlRecords = _urlRecordService.GetAllUrlRecords(0, int.MaxValue, null, model.EntityName, model.EntityId, model.LanguageId, true); if (urlRecords.Count > 0) { - ModelState.AddModelError("", T("Admin.System.SeNames.ActiveSlugAlreadyExist")); + ModelState.AddModelError("IsActive", T("Admin.System.SeNames.ActiveSlugAlreadyExist")); } } diff --git a/src/Presentation/SmartStore.Web/Administration/Models/UrlRecord/UrlRecordModel.cs b/src/Presentation/SmartStore.Web/Administration/Models/UrlRecord/UrlRecordModel.cs index a5996c6bbc..589c616eac 100644 --- a/src/Presentation/SmartStore.Web/Administration/Models/UrlRecord/UrlRecordModel.cs +++ b/src/Presentation/SmartStore.Web/Administration/Models/UrlRecord/UrlRecordModel.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; using System.Web.Mvc; using SmartStore.Web.Framework; using SmartStore.Web.Framework.Mvc; @@ -7,14 +8,13 @@ namespace SmartStore.Admin.Models.UrlRecord { public partial class UrlRecordModel : EntityModelBase { - [SmartResourceDisplayName("Admin.System.SeNames.Name")] - [AllowHtml] + [Required, AllowHtml, SmartResourceDisplayName("Admin.System.SeNames.Name")] public string Slug { get; set; } - [SmartResourceDisplayName("Admin.System.SeNames.EntityName")] + [Required, SmartResourceDisplayName("Admin.System.SeNames.EntityName")] public string EntityName { get; set; } - [SmartResourceDisplayName("Admin.System.SeNames.EntityId")] + [Required, SmartResourceDisplayName("Admin.System.SeNames.EntityId")] public int EntityId { get; set; } [SmartResourceDisplayName("Admin.Common.Entity")] diff --git a/src/Presentation/SmartStore.Web/Administration/Views/UrlRecord/_CreateOrUpdate.cshtml b/src/Presentation/SmartStore.Web/Administration/Views/UrlRecord/_CreateOrUpdate.cshtml index 95ad8832ce..ba361be39e 100644 --- a/src/Presentation/SmartStore.Web/Administration/Views/UrlRecord/_CreateOrUpdate.cshtml +++ b/src/Presentation/SmartStore.Web/Administration/Views/UrlRecord/_CreateOrUpdate.cshtml @@ -2,7 +2,7 @@ @using SmartStore.Admin.Models.UrlRecord; @using Telerik.Web.Mvc.UI; -@Html.ValidationSummary(true) +@Html.ValidationSummary() @Html.HiddenFor(model => model.Id) @@ -29,8 +29,8 @@ diff --git a/src/Presentation/SmartStore.Web/App_GlobalResources/MvcLocalization.Designer.cs b/src/Presentation/SmartStore.Web/App_GlobalResources/MvcLocalization.Designer.cs index 07cb03a819..1eda45cf26 100644 --- a/src/Presentation/SmartStore.Web/App_GlobalResources/MvcLocalization.Designer.cs +++ b/src/Presentation/SmartStore.Web/App_GlobalResources/MvcLocalization.Designer.cs @@ -1,10 +1,10 @@ //------------------------------------------------------------------------------ // -// Dieser Code wurde von einem Tool generiert. -// Laufzeitversion:4.0.30319.34209 +// This code was generated by a tool. +// Runtime Version:4.0.30319.42000 // -// Änderungen an dieser Datei können falsches Verhalten verursachen und gehen verloren, wenn -// der Code erneut generiert wird. +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. // //------------------------------------------------------------------------------ @@ -13,12 +13,12 @@ namespace Resources { /// - /// Eine stark typisierte Ressourcenklasse zum Suchen von lokalisierten Zeichenfolgen usw. + /// A strongly-typed resource class, for looking up localized strings, etc. /// - // Diese Klasse wurde von der StronglyTypedResourceBuilder-Klasse - // über ein Tool wie ResGen oder Visual Studio automatisch generiert. - // Um einen Member hinzuzufügen oder zu entfernen, bearbeiten Sie die .ResX-Datei und führen dann ResGen - // mit der /str-Option erneut aus, oder Sie erstellen das Visual Studio-Projekt neu. + // This class was auto-generated by the StronglyTypedResourceBuilder + // class via a tool like ResGen or Visual Studio. + // To add or remove a member, edit your .ResX file then rerun ResGen + // with the /str option or rebuild the Visual Studio project. [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Web.Application.StronglyTypedResourceProxyBuilder", "12.0.0.0")] [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] @@ -33,7 +33,7 @@ internal MvcLocalization() { } /// - /// Gibt die zwischengespeicherte ResourceManager-Instanz zurück, die von dieser Klasse verwendet wird. + /// Returns the cached ResourceManager instance used by this class. /// [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] internal static global::System.Resources.ResourceManager ResourceManager { @@ -47,8 +47,8 @@ internal MvcLocalization() { } /// - /// Überschreibt die CurrentUICulture-Eigenschaft des aktuellen Threads für alle - /// Ressourcenlookups, die diese stark typisierte Ressourcenklasse verwenden. + /// Overrides the current thread's CurrentUICulture property for all + /// resource lookups using this strongly typed resource class. /// [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] internal static global::System.Globalization.CultureInfo Culture { @@ -61,7 +61,7 @@ internal MvcLocalization() { } /// - /// Sucht eine lokalisierte Zeichenfolge, die The field {0} must be a date. ähnelt. + /// Looks up a localized string similar to The field '{0}' must be a date.. /// internal static string FieldMustBeDate { get { @@ -70,7 +70,7 @@ internal static string FieldMustBeDate { } /// - /// Sucht eine lokalisierte Zeichenfolge, die The field {0} must be a number. ähnelt. + /// Looks up a localized string similar to The field '{0}' must be a number.. /// internal static string FieldMustBeNumeric { get { @@ -79,7 +79,7 @@ internal static string FieldMustBeNumeric { } /// - /// Sucht eine lokalisierte Zeichenfolge, die The value '{0}' is not valid for {1}. ähnelt. + /// Looks up a localized string similar to The value '{0}' is not valid for '{1}'.. /// internal static string PropertyValueInvalid { get { @@ -88,12 +88,21 @@ internal static string PropertyValueInvalid { } /// - /// Sucht eine lokalisierte Zeichenfolge, die A value is required. ähnelt. + /// Looks up a localized string similar to A value is required.. /// internal static string PropertyValueRequired { get { return ResourceManager.GetString("PropertyValueRequired", resourceCulture); } } + + /// + /// Looks up a localized string similar to The field '{0}' is required.. + /// + internal static string Required { + get { + return ResourceManager.GetString("Required", resourceCulture); + } + } } } diff --git a/src/Presentation/SmartStore.Web/App_GlobalResources/MvcLocalization.de.resx b/src/Presentation/SmartStore.Web/App_GlobalResources/MvcLocalization.de.resx index e1d0fa764f..fee5893b3b 100644 --- a/src/Presentation/SmartStore.Web/App_GlobalResources/MvcLocalization.de.resx +++ b/src/Presentation/SmartStore.Web/App_GlobalResources/MvcLocalization.de.resx @@ -118,15 +118,18 @@ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - Das Feld {0} muss ein Datum sein. + Das Feld '{0}' muss ein Datum sein. - Das Feld {0} muss numerisch sein. + Das Feld '{0}' muss numerisch sein. - Der Wert '{0}' für {1} ist ungültig. + Der Wert '{0}' für '{1}' ist ungültig. Ein Wert ist zwingend erforderlich. + + Das Feld '{0}' ist erforderlich. + \ No newline at end of file diff --git a/src/Presentation/SmartStore.Web/App_GlobalResources/MvcLocalization.resx b/src/Presentation/SmartStore.Web/App_GlobalResources/MvcLocalization.resx index da4a85fa32..0e272fccd2 100644 --- a/src/Presentation/SmartStore.Web/App_GlobalResources/MvcLocalization.resx +++ b/src/Presentation/SmartStore.Web/App_GlobalResources/MvcLocalization.resx @@ -118,15 +118,18 @@ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - The field {0} must be a date. + The field '{0}' must be a date. - The field {0} must be a number. + The field '{0}' must be a number. - The value '{0}' is not valid for {1}. + The value '{0}' is not valid for '{1}'. A value is required. + + The field '{0}' is required. + \ No newline at end of file From 4f5247fe220897b012ab5e180ba5e944deceeebe Mon Sep 17 00:00:00 2001 From: Marcus Gesing Date: Wed, 4 Nov 2015 20:50:40 +0100 Subject: [PATCH 003/707] Web-API: Added OData endpoint for shipment items --- .../Domain/Shipping/Shipment.cs | 1 + .../Domain/Shipping/ShipmentItem.cs | 6 ++++ .../Shipping/ShipmentService.cs | 31 ++++++++++++++++-- .../OData/ShipmentItemsController.cs | 32 +++++++++++++++++++ src/Plugins/SmartStore.WebApi/Description.txt | 2 +- .../SmartStore.WebApi.csproj | 1 + .../WebApiConfigurationProvider.cs | 2 ++ src/Plugins/SmartStore.WebApi/changelog.md | 4 +++ 8 files changed, 75 insertions(+), 4 deletions(-) create mode 100644 src/Plugins/SmartStore.WebApi/Controllers/OData/ShipmentItemsController.cs diff --git a/src/Libraries/SmartStore.Core/Domain/Shipping/Shipment.cs b/src/Libraries/SmartStore.Core/Domain/Shipping/Shipment.cs index d0841d1dd6..e189e22b12 100644 --- a/src/Libraries/SmartStore.Core/Domain/Shipping/Shipment.cs +++ b/src/Libraries/SmartStore.Core/Domain/Shipping/Shipment.cs @@ -59,6 +59,7 @@ public partial class Shipment : BaseEntity /// /// Gets or sets the shipment items /// + [DataMember] public virtual ICollection ShipmentItems { get { return _shipmentItems ?? (_shipmentItems = new HashSet()); } diff --git a/src/Libraries/SmartStore.Core/Domain/Shipping/ShipmentItem.cs b/src/Libraries/SmartStore.Core/Domain/Shipping/ShipmentItem.cs index 48db08b9e1..fc77fb18b2 100644 --- a/src/Libraries/SmartStore.Core/Domain/Shipping/ShipmentItem.cs +++ b/src/Libraries/SmartStore.Core/Domain/Shipping/ShipmentItem.cs @@ -1,29 +1,35 @@ +using System.Runtime.Serialization; namespace SmartStore.Core.Domain.Shipping { /// /// Represents a shipment order product variant /// + [DataContract] public partial class ShipmentItem : BaseEntity { /// /// Gets or sets the shipment identifier /// + [DataMember] public int ShipmentId { get; set; } /// /// Gets or sets the order item identifier /// + [DataMember] public int OrderItemId { get; set; } /// /// Gets or sets the quantity /// + [DataMember] public int Quantity { get; set; } /// /// Gets the shipment /// + [DataMember] public virtual Shipment Shipment { get; set; } } } \ No newline at end of file diff --git a/src/Libraries/SmartStore.Services/Shipping/ShipmentService.cs b/src/Libraries/SmartStore.Services/Shipping/ShipmentService.cs index 301122a7fc..3a8c261164 100644 --- a/src/Libraries/SmartStore.Services/Shipping/ShipmentService.cs +++ b/src/Libraries/SmartStore.Services/Shipping/ShipmentService.cs @@ -7,7 +7,6 @@ using SmartStore.Core.Domain.Orders; using SmartStore.Core.Domain.Shipping; using SmartStore.Core.Events; -using SmartStore.Core.Plugins; using SmartStore.Services.Orders; namespace SmartStore.Services.Shipping @@ -240,7 +239,20 @@ public virtual void InsertShipmentItem(ShipmentItem shipmentItem) //event notifications _eventPublisher.EntityInserted(shipmentItem); - _eventPublisher.PublishOrderUpdated(shipmentItem.Shipment.Order); + + if (shipmentItem.Shipment != null && shipmentItem.Shipment.Order != null) + { + _eventPublisher.PublishOrderUpdated(shipmentItem.Shipment.Order); + } + else + { + var shipment = _shipmentRepository.Table + .Expand(x => x.Order) + .FirstOrDefault(x => x.Id == shipmentItem.ShipmentId); + + if (shipment != null) + _eventPublisher.PublishOrderUpdated(shipment.Order); + } } /// @@ -256,7 +268,20 @@ public virtual void UpdateShipmentItem(ShipmentItem shipmentItem) //event notifications _eventPublisher.EntityUpdated(shipmentItem); - _eventPublisher.PublishOrderUpdated(shipmentItem.Shipment.Order); + + if (shipmentItem.Shipment != null && shipmentItem.Shipment.Order != null) + { + _eventPublisher.PublishOrderUpdated(shipmentItem.Shipment.Order); + } + else + { + var shipment = _shipmentRepository.Table + .Expand(x => x.Order) + .FirstOrDefault(x => x.Id == shipmentItem.ShipmentId); + + if (shipment != null) + _eventPublisher.PublishOrderUpdated(shipment.Order); + } } #endregion diff --git a/src/Plugins/SmartStore.WebApi/Controllers/OData/ShipmentItemsController.cs b/src/Plugins/SmartStore.WebApi/Controllers/OData/ShipmentItemsController.cs new file mode 100644 index 0000000000..47fdf9982a --- /dev/null +++ b/src/Plugins/SmartStore.WebApi/Controllers/OData/ShipmentItemsController.cs @@ -0,0 +1,32 @@ +using System.Web.Http; +using SmartStore.Core.Domain.Shipping; +using SmartStore.Services.Shipping; +using SmartStore.Web.Framework.WebApi; +using SmartStore.Web.Framework.WebApi.OData; +using SmartStore.Web.Framework.WebApi.Security; + +namespace SmartStore.WebApi.Controllers.OData +{ + [WebApiAuthenticate(Permission = "ManageOrders")] + public class ShipmentItemsController : WebApiEntityController + { + protected override void Insert(ShipmentItem entity) + { + Service.InsertShipmentItem(entity); + } + protected override void Update(ShipmentItem entity) + { + Service.UpdateShipmentItem(entity); + } + protected override void Delete(ShipmentItem entity) + { + Service.DeleteShipmentItem(entity); + } + + [WebApiQueryable] + public SingleResult GetShipmentItem(int key) + { + return GetSingleResult(key); + } + } +} diff --git a/src/Plugins/SmartStore.WebApi/Description.txt b/src/Plugins/SmartStore.WebApi/Description.txt index cbe8fe9af5..085a7c5a09 100644 --- a/src/Plugins/SmartStore.WebApi/Description.txt +++ b/src/Plugins/SmartStore.WebApi/Description.txt @@ -1,6 +1,6 @@ FriendlyName: SmartStore.NET Web Api SystemName: SmartStore.WebApi -Version: 2.2.0.3 +Version: 2.2.0.4 Group: Api MinAppVersion: 2.2.0 Author: SmartStore AG diff --git a/src/Plugins/SmartStore.WebApi/SmartStore.WebApi.csproj b/src/Plugins/SmartStore.WebApi/SmartStore.WebApi.csproj index feaadf8fcc..20e3fc318c 100644 --- a/src/Plugins/SmartStore.WebApi/SmartStore.WebApi.csproj +++ b/src/Plugins/SmartStore.WebApi/SmartStore.WebApi.csproj @@ -215,6 +215,7 @@ + diff --git a/src/Plugins/SmartStore.WebApi/WebApiConfigurationProvider.cs b/src/Plugins/SmartStore.WebApi/WebApiConfigurationProvider.cs index 40c3a8b75c..db3d1f3377 100644 --- a/src/Plugins/SmartStore.WebApi/WebApiConfigurationProvider.cs +++ b/src/Plugins/SmartStore.WebApi/WebApiConfigurationProvider.cs @@ -92,6 +92,7 @@ public void Configure(WebApiConfigurationBroadcaster configData) m.EntitySet(WebApiOdataEntitySet.ReturnRequests); m.EntitySet(WebApiOdataEntitySet.Settings); m.EntitySet(WebApiOdataEntitySet.Shipments); + m.EntitySet(WebApiOdataEntitySet.ShipmentItems); m.EntitySet(WebApiOdataEntitySet.ShippingMethods); m.EntitySet(WebApiOdataEntitySet.SpecificationAttributeOptions); m.EntitySet(WebApiOdataEntitySet.SpecificationAttributes); @@ -145,6 +146,7 @@ public static class WebApiOdataEntitySet public static string ReturnRequests { get { return "ReturnRequests"; } } public static string Settings { get { return "Settings"; } } public static string Shipments { get { return "Shipments"; } } + public static string ShipmentItems { get { return "ShipmentItems"; } } public static string ShippingMethods { get { return "ShippingMethods"; } } public static string SpecificationAttributeOptions { get { return "SpecificationAttributeOptions"; } } public static string SpecificationAttributes { get { return "SpecificationAttributes"; } } diff --git a/src/Plugins/SmartStore.WebApi/changelog.md b/src/Plugins/SmartStore.WebApi/changelog.md index 6c5bd87808..2191a7d055 100644 --- a/src/Plugins/SmartStore.WebApi/changelog.md +++ b/src/Plugins/SmartStore.WebApi/changelog.md @@ -1,5 +1,9 @@ #Release Notes +##Web Api 2.2.0.4 +###New Features +* Added OData endpoint for shipment items + ##Web Api 2.2.0.3 ###New Features * Added OData endpoint for payment method From fdf1c6349c2b8c8d660fafc51742a841d600d310 Mon Sep 17 00:00:00 2001 From: Murat Cakir Date: Wed, 4 Nov 2015 22:44:13 +0100 Subject: [PATCH 004/707] Export Framework: Refactored enums --- .../{ExportCore.cs => ExportEnums.cs} | 26 ++++----- .../Domain/DataExchange/ExportProfile.cs | 2 +- .../Domain/DataExchange/ExportProjection.cs | 4 +- .../Plugins/Providers/ProviderMetadata.cs | 2 +- .../SmartStore.Core/SmartStore.Core.csproj | 2 +- src/Libraries/SmartStore.Core/XmlHelper.cs | 56 +++++++------------ .../DataExchange/ExportExtensions.cs | 9 +-- ...tributes.cs => ExportFeaturesAttribute.cs} | 8 +-- .../DataExchange/ExportService.cs | 4 +- .../ExportTask/ExportProfileTask.cs | 21 +++---- .../ExportTask/ExportProfileTaskContext.cs | 10 ++-- .../SmartStore.Services.csproj | 2 +- .../Providers/ProductExportXmlProvider.cs | 18 +++--- .../DependencyRegistrar.cs | 12 ++-- .../Models/DataExchange/ExportProfileModel.cs | 2 +- .../custom/telerik/telerik.smartstore.less | 2 +- 16 files changed, 83 insertions(+), 97 deletions(-) rename src/Libraries/SmartStore.Core/Domain/DataExchange/{ExportCore.cs => ExportEnums.cs} (87%) rename src/Libraries/SmartStore.Services/DataExchange/{ExportAttributes.cs => ExportFeaturesAttribute.cs} (68%) diff --git a/src/Libraries/SmartStore.Core/Domain/DataExchange/ExportCore.cs b/src/Libraries/SmartStore.Core/Domain/DataExchange/ExportEnums.cs similarity index 87% rename from src/Libraries/SmartStore.Core/Domain/DataExchange/ExportCore.cs rename to src/Libraries/SmartStore.Core/Domain/DataExchange/ExportEnums.cs index f9a5dcc18e..b7f041fed5 100644 --- a/src/Libraries/SmartStore.Core/Domain/DataExchange/ExportCore.cs +++ b/src/Libraries/SmartStore.Core/Domain/DataExchange/ExportEnums.cs @@ -61,62 +61,62 @@ public enum ExportAttributeValueMerging /// /// Controls data processing and projection items supported by export provider /// - public enum ExportSupport + public enum ExportFeatures { /// /// Whether to automatically create a file based public deployment when an export profile is created /// - CreateInitialPublicDeployment = 0, + CreatesInitialPublicDeployment = 0, /// /// Whether to offer option to include\exclude grouped products /// - ProjectionNoGroupedProducts, + CanOmitGroupedProducts, /// /// Whether to offer option to export attribute combinations as products /// - ProjectionAttributeCombinationAsProduct, + CanProjectAttributeCombinations, /// /// Whether to offer further options to manipulate the product description /// - ProjectionDescription, + CanProjectDescription, /// /// Whether to offer option to enter a brand fallback /// - ProjectionBrand, + OffersBrandFallback, /// /// Whether to offer option to set a picture size and to get the URL of the main image /// - ProjectionMainPictureUrl, + CanIncludeMainPicture, /// /// Whether to use SKU as manufacturer part number if MPN is empty /// - ProjectionUseOwnProductNo, + UsesSkuAsMpnFallback, /// /// Whether to offer option to enter a shipping time fallback /// - ProjectionShippingTime, + OffersShippingTimeFallback, /// /// Whether to offer option to enter a shipping costs fallback and a free shipping threshold /// - ProjectionShippingCosts, + OffersShippingCostsFallback, /// /// Whether to get the calculated old product price /// - ProjectionOldPrice, + UsesOldPrice, /// - /// Whether to get the calculated special and regular (ignoring special offers) price + /// Whether to get the calculated special and regular price (ignoring special offers) /// - ProjectionSpecialPrice + UsesSpecialPrice } /// diff --git a/src/Libraries/SmartStore.Core/Domain/DataExchange/ExportProfile.cs b/src/Libraries/SmartStore.Core/Domain/DataExchange/ExportProfile.cs index 75331d4a2c..ea98e0838b 100644 --- a/src/Libraries/SmartStore.Core/Domain/DataExchange/ExportProfile.cs +++ b/src/Libraries/SmartStore.Core/Domain/DataExchange/ExportProfile.cs @@ -88,7 +88,7 @@ public ExportProfile() public bool PerStore { get; set; } /// - /// Identifier of an email account used to send a notification message of the completion of the export + /// Email Account identifier used to send a notification message an export completes /// public int EmailAccountId { get; set; } diff --git a/src/Libraries/SmartStore.Core/Domain/DataExchange/ExportProjection.cs b/src/Libraries/SmartStore.Core/Domain/DataExchange/ExportProjection.cs index abe979107d..472c94e114 100644 --- a/src/Libraries/SmartStore.Core/Domain/DataExchange/ExportProjection.cs +++ b/src/Libraries/SmartStore.Core/Domain/DataExchange/ExportProjection.cs @@ -7,7 +7,9 @@ namespace SmartStore.Core.Domain.DataExchange /// /// Settings projected onto an export /// - /// Note possible projection controlling: a) developer controls, b) merchant controls, c) developer controls what the merchant can control + /// + /// Note possible projection controlling: a) developer controls, b) merchant controls, c) developer controls what the merchant can control + /// [Serializable] public class ExportProjection { diff --git a/src/Libraries/SmartStore.Core/Plugins/Providers/ProviderMetadata.cs b/src/Libraries/SmartStore.Core/Plugins/Providers/ProviderMetadata.cs index b1da4a1304..31d98942d4 100644 --- a/src/Libraries/SmartStore.Core/Plugins/Providers/ProviderMetadata.cs +++ b/src/Libraries/SmartStore.Core/Plugins/Providers/ProviderMetadata.cs @@ -76,7 +76,7 @@ public class ProviderMetadata /// /// Gets or sets an array of values that reflects what export data processing is supported by a provider /// - public ExportSupport[] ExportSupport { get; set; } + public ExportFeatures[] ExportSupport { get; set; } /// /// Gets or sets an array of widget system names, which depend on the current provider diff --git a/src/Libraries/SmartStore.Core/SmartStore.Core.csproj b/src/Libraries/SmartStore.Core/SmartStore.Core.csproj index ab5fd94130..afe41e0061 100644 --- a/src/Libraries/SmartStore.Core/SmartStore.Core.csproj +++ b/src/Libraries/SmartStore.Core/SmartStore.Core.csproj @@ -166,7 +166,7 @@ - + diff --git a/src/Libraries/SmartStore.Core/XmlHelper.cs b/src/Libraries/SmartStore.Core/XmlHelper.cs index b73c914f03..6d9f60def4 100644 --- a/src/Libraries/SmartStore.Core/XmlHelper.cs +++ b/src/Libraries/SmartStore.Core/XmlHelper.cs @@ -123,17 +123,7 @@ public static DateTime DeserializeDateTime(string dateTime) /// XML string public static string Serialize(T instance) { - if (instance != null) - { - using (var writer = new StringWriter()) - { - var xmlSerializer = new XmlSerializer(typeof(T)); - - xmlSerializer.Serialize(writer, instance); - return writer.ToString(); - } - } - return null; + return Serialize(instance, typeof(T)); } /// @@ -144,17 +134,18 @@ public static string Serialize(T instance) /// XML string public static string Serialize(object instance, Type type) { - if (instance != null) + if (instance == null) + return null; + + Guard.NotNull(() => type); + + using (var writer = new StringWriter()) { - using (var writer = new StringWriter()) - { - var xmlSerializer = new XmlSerializer(type); + var xmlSerializer = new XmlSerializer(type); - xmlSerializer.Serialize(writer, instance); - return writer.ToString(); - } + xmlSerializer.Serialize(writer, instance); + return writer.ToString(); } - return null; } /// @@ -165,16 +156,7 @@ public static string Serialize(object instance, Type type) /// Object instance public static T Deserialize(string xml) { - if (xml.HasValue()) - { - using (var reader = new StringReader(xml)) - { - var serializer = new XmlSerializer(typeof(T)); - - return (T)serializer.Deserialize(reader); - } - } - return (T)Activator.CreateInstance(typeof(T)); + return (T)Deserialize(xml, typeof(T)); } /// @@ -185,16 +167,16 @@ public static T Deserialize(string xml) /// Object instance public static object Deserialize(string xml, Type type) { - if (xml.HasValue()) - { - using (var reader = new StringReader(xml)) - { - var serializer = new XmlSerializer(type); + Guard.NotNull(() => type); - return serializer.Deserialize(reader); - } + if (xml.IsEmpty()) + return Activator.CreateInstance(type); + + using (var reader = new StringReader(xml)) + { + var serializer = new XmlSerializer(type); + return serializer.Deserialize(reader); } - return Activator.CreateInstance(type); } #endregion diff --git a/src/Libraries/SmartStore.Services/DataExchange/ExportExtensions.cs b/src/Libraries/SmartStore.Services/DataExchange/ExportExtensions.cs index c7f6827bb0..ae5b8ff6ce 100644 --- a/src/Libraries/SmartStore.Services/DataExchange/ExportExtensions.cs +++ b/src/Libraries/SmartStore.Services/DataExchange/ExportExtensions.cs @@ -21,19 +21,20 @@ public static class ExportExtensions /// true provider is valid, false provider is invalid. public static bool IsValid(this Provider provider) { - return (provider != null); + return provider != null; } /// /// Returns a value indicating whether the export provider supports a projection type /// /// Export provider - /// The type to check + /// The feature to check /// true provider supports type, false provider does not support type. - public static bool Supports(this Provider provider, ExportSupport type) + public static bool Supports(this Provider provider, ExportFeatures feature) { if (provider != null) - return provider.Metadata.ExportSupport.Contains(type); + return provider.Metadata.ExportSupport.Contains(feature); + return false; } diff --git a/src/Libraries/SmartStore.Services/DataExchange/ExportAttributes.cs b/src/Libraries/SmartStore.Services/DataExchange/ExportFeaturesAttribute.cs similarity index 68% rename from src/Libraries/SmartStore.Services/DataExchange/ExportAttributes.cs rename to src/Libraries/SmartStore.Services/DataExchange/ExportFeaturesAttribute.cs index ece4d81d38..d29f5641d3 100644 --- a/src/Libraries/SmartStore.Services/DataExchange/ExportAttributes.cs +++ b/src/Libraries/SmartStore.Services/DataExchange/ExportFeaturesAttribute.cs @@ -8,13 +8,13 @@ namespace SmartStore.Services.DataExchange /// Projection type controls whether to display corresponding projection fields while editing an export profile. /// [AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = false)] - public sealed class ExportSupportingAttribute : Attribute + public sealed class ExportFeaturesAttribute : Attribute { - public ExportSupportingAttribute(params ExportSupport[] types) + public ExportFeaturesAttribute(params ExportFeatures[] features) { - Types = types; + Features = features; } - public ExportSupport[] Types { get; set; } + public ExportFeatures[] Features { get; set; } } } diff --git a/src/Libraries/SmartStore.Services/DataExchange/ExportService.cs b/src/Libraries/SmartStore.Services/DataExchange/ExportService.cs index 250e0eecff..aea03c6fa9 100644 --- a/src/Libraries/SmartStore.Services/DataExchange/ExportService.cs +++ b/src/Libraries/SmartStore.Services/DataExchange/ExportService.cs @@ -116,7 +116,7 @@ public virtual ExportProfile InsertExportProfile(Provider provi RemoveCriticalCharacters = true, CriticalCharacters = "¼,½,¾", PriceType = PriceDisplayType.PreSelectedPrice, - NoGroupedProducts = (provider.Supports(ExportSupport.ProjectionNoGroupedProducts) ? true : false) + NoGroupedProducts = (provider.Supports(ExportFeatures.CanOmitGroupedProducts) ? true : false) }; var filter = new ExportFilter @@ -150,7 +150,7 @@ public virtual ExportProfile InsertExportProfile(Provider provi { if (cloneProfile == null) { - if (provider.Supports(ExportSupport.CreateInitialPublicDeployment)) + if (provider.Supports(ExportFeatures.CreatesInitialPublicDeployment)) { profile.Deployments.Add(new ExportDeployment { diff --git a/src/Libraries/SmartStore.Services/DataExchange/ExportTask/ExportProfileTask.cs b/src/Libraries/SmartStore.Services/DataExchange/ExportTask/ExportProfileTask.cs index 66698ab1a3..d9a6a17a36 100644 --- a/src/Libraries/SmartStore.Services/DataExchange/ExportTask/ExportProfileTask.cs +++ b/src/Libraries/SmartStore.Services/DataExchange/ExportTask/ExportProfileTask.cs @@ -1556,7 +1556,7 @@ private List ConvertToExpando(ExportProfileTaskContext ctx, Product pro var productTemplate = ctx.ProductTemplates.FirstOrDefault(x => x.Key == product.ProductTemplateId); var pictureSize = _mediaSettings.Value.ProductDetailsPictureSize; - if (ctx.Supporting[ExportSupport.ProjectionMainPictureUrl] && ctx.Projection.PictureSize > 0) + if (ctx.SupportedFeatures[ExportFeatures.CanIncludeMainPicture] && ctx.Projection.PictureSize > 0) pictureSize = ctx.Projection.PictureSize; var perfLoadId = (ctx.IsPreview ? 0 : product.Id); // perf preview (it's a compromise) @@ -1762,12 +1762,12 @@ private List ConvertToExpando(ExportProfileTaskContext ctx, Product pro #region more attribute controlled data - if (ctx.Supports(ExportSupport.ProjectionDescription)) + if (ctx.Supports(ExportFeatures.CanProjectDescription)) { PrepareProductDescription(ctx, expando, product); } - if (ctx.Supports(ExportSupport.ProjectionBrand)) + if (ctx.Supports(ExportFeatures.OffersBrandFallback)) { string brand = null; var productManus = ctx.DataContextProduct.ProductManufacturers.Load(perfLoadId); @@ -1781,7 +1781,7 @@ private List ConvertToExpando(ExportProfileTaskContext ctx, Product pro expando._Brand = brand; } - if (ctx.Supports(ExportSupport.ProjectionMainPictureUrl)) + if (ctx.Supports(ExportFeatures.CanIncludeMainPicture)) { if (productPictures != null && productPictures.Any()) expando._MainPictureUrl = _pictureService.Value.GetPictureUrl(productPictures.First().Picture, ctx.Projection.PictureSize, storeLocation: ctx.Store.Url); @@ -1823,18 +1823,18 @@ private List ConvertToExpando(ExportProfileTaskContext ctx, Product pro // navigation properties GetDeliveryTimeAndQuantityUnit(ctx, exp, product.DeliveryTimeId, product.QuantityUnitId); - if (ctx.Supports(ExportSupport.ProjectionUseOwnProductNo) && product.ManufacturerPartNumber.IsEmpty()) + if (ctx.Supports(ExportFeatures.UsesSkuAsMpnFallback) && product.ManufacturerPartNumber.IsEmpty()) { exp.ManufacturerPartNumber = product.Sku; } - if (ctx.Supports(ExportSupport.ProjectionShippingTime)) + if (ctx.Supports(ExportFeatures.OffersShippingTimeFallback)) { dynamic deliveryTime = exp.DeliveryTime; exp._ShippingTime = (deliveryTime == null ? ctx.Projection.ShippingTime : deliveryTime.Name); } - if (ctx.Supports(ExportSupport.ProjectionShippingCosts)) + if (ctx.Supports(ExportFeatures.OffersShippingCostsFallback)) { exp._FreeShippingThreshold = ctx.Projection.FreeShippingThreshold; @@ -1844,7 +1844,7 @@ private List ConvertToExpando(ExportProfileTaskContext ctx, Product pro exp._ShippingCosts = ctx.Projection.ShippingCosts; } - if (ctx.Supports(ExportSupport.ProjectionOldPrice)) + if (ctx.Supports(ExportFeatures.UsesOldPrice)) { if (product.OldPrice != decimal.Zero && product.OldPrice != (decimal)exp.Price && !(product.ProductType == ProductType.BundledProduct && product.BundlePerItemPricing)) { @@ -1864,7 +1864,7 @@ private List ConvertToExpando(ExportProfileTaskContext ctx, Product pro } } - if (ctx.Supports(ExportSupport.ProjectionSpecialPrice)) + if (ctx.Supports(ExportFeatures.UsesSpecialPrice)) { exp._SpecialPrice = null; exp._RegularPrice = null; // price if a special price would not exist @@ -2907,7 +2907,8 @@ public void Execute(TaskExecutionContext taskContext) /// Any data passed on IExportExecuteContext.CustomProperties /// Product query that supersede profile filtering /// Export execute result - public ExportExecuteResult Execute(string providerSystemName, + public ExportExecuteResult Execute( + string providerSystemName, IComponentContext context, CancellationToken cancellationToken, ExportProfile profile = null, diff --git a/src/Libraries/SmartStore.Services/DataExchange/ExportTask/ExportProfileTaskContext.cs b/src/Libraries/SmartStore.Services/DataExchange/ExportTask/ExportProfileTaskContext.cs index 2beab3db1b..5fee680634 100644 --- a/src/Libraries/SmartStore.Services/DataExchange/ExportTask/ExportProfileTaskContext.cs +++ b/src/Libraries/SmartStore.Services/DataExchange/ExportTask/ExportProfileTaskContext.cs @@ -40,8 +40,8 @@ public ExportProfileTaskContext( EntityIdsSelected = selectedIds.SplitSafe(",").Select(x => x.ToInt()).ToList(); PreviewData = previewData; - Supporting = Enum.GetValues(typeof(ExportSupport)) - .Cast() + SupportedFeatures = Enum.GetValues(typeof(ExportFeatures)) + .Cast() .ToDictionary(x => x, x => Provider.Supports(x)); FolderContent = FileSystemHelper.TempDir(@"Profile\Export\{0}\Content".FormatInvariant(profile.FolderName)); @@ -83,10 +83,10 @@ public bool IsPreview public ExportProfile Profile { get; private set; } public Provider Provider { get; private set; } - public Dictionary Supporting { get; private set; } - public bool Supports(ExportSupport type) + public Dictionary SupportedFeatures { get; private set; } + public bool Supports(ExportFeatures feature) { - return (!IsPreview && Supporting[type]); + return (!IsPreview && SupportedFeatures[feature]); } public ExportFilter Filter { get; private set; } diff --git a/src/Libraries/SmartStore.Services/SmartStore.Services.csproj b/src/Libraries/SmartStore.Services/SmartStore.Services.csproj index 2de19dd74f..3c3f321c24 100644 --- a/src/Libraries/SmartStore.Services/SmartStore.Services.csproj +++ b/src/Libraries/SmartStore.Services/SmartStore.Services.csproj @@ -192,7 +192,7 @@ - + diff --git a/src/Plugins/SmartStore.GoogleMerchantCenter/Providers/ProductExportXmlProvider.cs b/src/Plugins/SmartStore.GoogleMerchantCenter/Providers/ProductExportXmlProvider.cs index ed7eb62390..03ed6a00ff 100644 --- a/src/Plugins/SmartStore.GoogleMerchantCenter/Providers/ProductExportXmlProvider.cs +++ b/src/Plugins/SmartStore.GoogleMerchantCenter/Providers/ProductExportXmlProvider.cs @@ -19,15 +19,15 @@ namespace SmartStore.GoogleMerchantCenter.Providers [SystemName("Feeds.GoogleMerchantCenterProductXml")] [FriendlyName("Google Merchant Center XML product feed")] [DisplayOrder(1)] - [ExportSupporting( - ExportSupport.CreateInitialPublicDeployment, - ExportSupport.ProjectionNoGroupedProducts, - ExportSupport.ProjectionAttributeCombinationAsProduct, - ExportSupport.ProjectionDescription, - ExportSupport.ProjectionUseOwnProductNo, - ExportSupport.ProjectionBrand, - ExportSupport.ProjectionMainPictureUrl, - ExportSupport.ProjectionSpecialPrice)] + [ExportFeatures( + ExportFeatures.CreatesInitialPublicDeployment, + ExportFeatures.CanOmitGroupedProducts, + ExportFeatures.CanProjectAttributeCombinations, + ExportFeatures.CanProjectDescription, + ExportFeatures.UsesSkuAsMpnFallback, + ExportFeatures.OffersBrandFallback, + ExportFeatures.CanIncludeMainPicture, + ExportFeatures.UsesSpecialPrice)] public class ProductExportXmlProvider : IExportProvider { private const string _googleNamespace = "http://base.google.com/ns/1.0"; diff --git a/src/Presentation/SmartStore.Web.Framework/DependencyRegistrar.cs b/src/Presentation/SmartStore.Web.Framework/DependencyRegistrar.cs index d9b7ca9b43..ee70cae011 100644 --- a/src/Presentation/SmartStore.Web.Framework/DependencyRegistrar.cs +++ b/src/Presentation/SmartStore.Web.Framework/DependencyRegistrar.cs @@ -768,7 +768,7 @@ protected override void Load(ContainerBuilder builder) var isConfigurable = typeof(IConfigurable).IsAssignableFrom(type); var isEditable = typeof(IUserEditable).IsAssignableFrom(type); var isHidden = GetIsHidden(type); - var exportSupport = GetExportSupport(type); + var exportSupport = GetExportFeatures(type); var registration = builder.RegisterType(type).Named(systemName).InstancePerRequest().PropertiesAutowired(PropertyWiringOptions.None); registration.WithMetadata(m => @@ -863,16 +863,16 @@ private bool GetIsHidden(Type type) return false; } - private ExportSupport[] GetExportSupport(Type type) + private ExportFeatures[] GetExportFeatures(Type type) { - var attr = type.GetAttribute(false); + var attr = type.GetAttribute(false); - if (attr != null && attr.Types != null) + if (attr != null && attr.Features != null) { - return attr.Types; + return attr.Features; } - return new ExportSupport[0]; + return new ExportFeatures[0]; } private Tuple GetFriendlyName(Type type, PluginDescriptor descriptor) diff --git a/src/Presentation/SmartStore.Web/Administration/Models/DataExchange/ExportProfileModel.cs b/src/Presentation/SmartStore.Web/Administration/Models/DataExchange/ExportProfileModel.cs index 80dce133e9..3ebf4350d9 100644 --- a/src/Presentation/SmartStore.Web/Administration/Models/DataExchange/ExportProfileModel.cs +++ b/src/Presentation/SmartStore.Web/Administration/Models/DataExchange/ExportProfileModel.cs @@ -94,7 +94,7 @@ public class ProviderModel public Type ConfigDataType { get; set; } public object ConfigData { get; set; } - public ExportSupport[] Supporting { get; set; } + public ExportFeatures[] Supporting { get; set; } [SmartResourceDisplayName("Common.Image")] public string ThumbnailUrl { get; set; } diff --git a/src/Presentation/SmartStore.Web/Content/bootstrap/custom/telerik/telerik.smartstore.less b/src/Presentation/SmartStore.Web/Content/bootstrap/custom/telerik/telerik.smartstore.less index 6b333e4237..ab27daa31b 100644 --- a/src/Presentation/SmartStore.Web/Content/bootstrap/custom/telerik/telerik.smartstore.less +++ b/src/Presentation/SmartStore.Web/Content/bootstrap/custom/telerik/telerik.smartstore.less @@ -153,7 +153,7 @@ } .t-numerictextbox .t-input { - width: 252px; + width: 301px; padding: 6px 8px 6px 3px; } .t-numerictextbox.small .t-input { From 17fcdd3af7b2a1d25971fe2a082b3cfb22ec7a90 Mon Sep 17 00:00:00 2001 From: Murat Cakir Date: Wed, 4 Nov 2015 23:11:09 +0100 Subject: [PATCH 005/707] Export framework: minor refactoring --- .../ExportCategoryXmlProvider.cs | 2 +- .../ExportCustomerXlsxProvider.cs | 2 +- .../ExportCustomerXmlProvider.cs | 2 +- .../ExportManufacturerXmlProvider.cs | 2 +- .../ExportNewsSubscriptionCsvProvider.cs | 2 +- .../ExportProvider/ExportOrderXlsxProvider.cs | 2 +- .../ExportProvider/ExportOrderXmlProvider.cs | 2 +- .../ExportProductXlsxProvider.cs | 2 +- .../ExportProductXmlProvider.cs | 2 +- .../ExportTask/ExportDataContextCategory.cs | 3 +- .../ExportTask/ExportDataContextCustomer.cs | 3 +- .../ExportDataContextManufacturer.cs | 3 +- .../ExportTask/ExportDataContextProduct.cs | 3 +- .../ExportTask/ExportProfileTask.cs | 35 ++++++++++--------- .../DataExchange/IExportProvider.cs | 2 +- .../DataExchange/IExportService.cs | 2 +- .../Providers/ProductExportXmlProvider.cs | 2 +- .../Views/Export/_Tab.Projection.cshtml | 14 ++++---- 18 files changed, 46 insertions(+), 39 deletions(-) diff --git a/src/Libraries/SmartStore.Services/DataExchange/ExportProvider/ExportCategoryXmlProvider.cs b/src/Libraries/SmartStore.Services/DataExchange/ExportProvider/ExportCategoryXmlProvider.cs index 7e4e6f9fba..6bd4aa3d2f 100644 --- a/src/Libraries/SmartStore.Services/DataExchange/ExportProvider/ExportCategoryXmlProvider.cs +++ b/src/Libraries/SmartStore.Services/DataExchange/ExportProvider/ExportCategoryXmlProvider.cs @@ -105,7 +105,7 @@ public void Execute(IExportExecuteContext context) } } - public void ExecuteEnded(IExportExecuteContext context) + public void OnExecuted(IExportExecuteContext context) { // nothing to do } diff --git a/src/Libraries/SmartStore.Services/DataExchange/ExportProvider/ExportCustomerXlsxProvider.cs b/src/Libraries/SmartStore.Services/DataExchange/ExportProvider/ExportCustomerXlsxProvider.cs index c2f4722f1a..2ab8dcb6b0 100644 --- a/src/Libraries/SmartStore.Services/DataExchange/ExportProvider/ExportCustomerXlsxProvider.cs +++ b/src/Libraries/SmartStore.Services/DataExchange/ExportProvider/ExportCustomerXlsxProvider.cs @@ -215,7 +215,7 @@ public void Execute(IExportExecuteContext context) } } - public void ExecuteEnded(IExportExecuteContext context) + public void OnExecuted(IExportExecuteContext context) { // nothing to do } diff --git a/src/Libraries/SmartStore.Services/DataExchange/ExportProvider/ExportCustomerXmlProvider.cs b/src/Libraries/SmartStore.Services/DataExchange/ExportProvider/ExportCustomerXmlProvider.cs index cbf1c80719..4573e6c69c 100644 --- a/src/Libraries/SmartStore.Services/DataExchange/ExportProvider/ExportCustomerXmlProvider.cs +++ b/src/Libraries/SmartStore.Services/DataExchange/ExportProvider/ExportCustomerXmlProvider.cs @@ -88,7 +88,7 @@ public void Execute(IExportExecuteContext context) } } - public void ExecuteEnded(IExportExecuteContext context) + public void OnExecuted(IExportExecuteContext context) { // nothing to do } diff --git a/src/Libraries/SmartStore.Services/DataExchange/ExportProvider/ExportManufacturerXmlProvider.cs b/src/Libraries/SmartStore.Services/DataExchange/ExportProvider/ExportManufacturerXmlProvider.cs index ebe52eb5f9..5341411be7 100644 --- a/src/Libraries/SmartStore.Services/DataExchange/ExportProvider/ExportManufacturerXmlProvider.cs +++ b/src/Libraries/SmartStore.Services/DataExchange/ExportProvider/ExportManufacturerXmlProvider.cs @@ -105,7 +105,7 @@ public void Execute(IExportExecuteContext context) } } - public void ExecuteEnded(IExportExecuteContext context) + public void OnExecuted(IExportExecuteContext context) { // nothing to do } diff --git a/src/Libraries/SmartStore.Services/DataExchange/ExportProvider/ExportNewsSubscriptionCsvProvider.cs b/src/Libraries/SmartStore.Services/DataExchange/ExportProvider/ExportNewsSubscriptionCsvProvider.cs index 00400d64e9..36479f946f 100644 --- a/src/Libraries/SmartStore.Services/DataExchange/ExportProvider/ExportNewsSubscriptionCsvProvider.cs +++ b/src/Libraries/SmartStore.Services/DataExchange/ExportProvider/ExportNewsSubscriptionCsvProvider.cs @@ -74,7 +74,7 @@ public void Execute(IExportExecuteContext context) } } - public void ExecuteEnded(IExportExecuteContext context) + public void OnExecuted(IExportExecuteContext context) { // nothing to do } diff --git a/src/Libraries/SmartStore.Services/DataExchange/ExportProvider/ExportOrderXlsxProvider.cs b/src/Libraries/SmartStore.Services/DataExchange/ExportProvider/ExportOrderXlsxProvider.cs index 4cd8a5c5e2..ba85cc3b0d 100644 --- a/src/Libraries/SmartStore.Services/DataExchange/ExportProvider/ExportOrderXlsxProvider.cs +++ b/src/Libraries/SmartStore.Services/DataExchange/ExportProvider/ExportOrderXlsxProvider.cs @@ -251,7 +251,7 @@ public void Execute(IExportExecuteContext context) } } - public void ExecuteEnded(IExportExecuteContext context) + public void OnExecuted(IExportExecuteContext context) { // nothing to do } diff --git a/src/Libraries/SmartStore.Services/DataExchange/ExportProvider/ExportOrderXmlProvider.cs b/src/Libraries/SmartStore.Services/DataExchange/ExportProvider/ExportOrderXmlProvider.cs index e04e6829bf..185181c013 100644 --- a/src/Libraries/SmartStore.Services/DataExchange/ExportProvider/ExportOrderXmlProvider.cs +++ b/src/Libraries/SmartStore.Services/DataExchange/ExportProvider/ExportOrderXmlProvider.cs @@ -261,7 +261,7 @@ public void Execute(IExportExecuteContext context) } } - public void ExecuteEnded(IExportExecuteContext context) + public void OnExecuted(IExportExecuteContext context) { // nothing to do } diff --git a/src/Libraries/SmartStore.Services/DataExchange/ExportProvider/ExportProductXlsxProvider.cs b/src/Libraries/SmartStore.Services/DataExchange/ExportProvider/ExportProductXlsxProvider.cs index 516d05488a..e9ec1bbc59 100644 --- a/src/Libraries/SmartStore.Services/DataExchange/ExportProvider/ExportProductXlsxProvider.cs +++ b/src/Libraries/SmartStore.Services/DataExchange/ExportProvider/ExportProductXlsxProvider.cs @@ -415,7 +415,7 @@ public void Execute(IExportExecuteContext context) GC.Collect(); } - public void ExecuteEnded(IExportExecuteContext context) + public void OnExecuted(IExportExecuteContext context) { // nothing to do } diff --git a/src/Libraries/SmartStore.Services/DataExchange/ExportProvider/ExportProductXmlProvider.cs b/src/Libraries/SmartStore.Services/DataExchange/ExportProvider/ExportProductXmlProvider.cs index a6894b4242..6352c98b03 100644 --- a/src/Libraries/SmartStore.Services/DataExchange/ExportProvider/ExportProductXmlProvider.cs +++ b/src/Libraries/SmartStore.Services/DataExchange/ExportProvider/ExportProductXmlProvider.cs @@ -88,7 +88,7 @@ public void Execute(IExportExecuteContext context) } } - public void ExecuteEnded(IExportExecuteContext context) + public void OnExecuted(IExportExecuteContext context) { // nothing to do } diff --git a/src/Libraries/SmartStore.Services/DataExchange/ExportTask/ExportDataContextCategory.cs b/src/Libraries/SmartStore.Services/DataExchange/ExportTask/ExportDataContextCategory.cs index f19fb56f47..8e2efa0f93 100644 --- a/src/Libraries/SmartStore.Services/DataExchange/ExportTask/ExportDataContextCategory.cs +++ b/src/Libraries/SmartStore.Services/DataExchange/ExportTask/ExportDataContextCategory.cs @@ -18,7 +18,8 @@ internal class ExportDataContextCategory private LazyMultimap _productCategories; private LazyMultimap _pictures; - public ExportDataContextCategory(IEnumerable categories, + public ExportDataContextCategory( + IEnumerable categories, Func> productCategories, Func> pictures) { diff --git a/src/Libraries/SmartStore.Services/DataExchange/ExportTask/ExportDataContextCustomer.cs b/src/Libraries/SmartStore.Services/DataExchange/ExportTask/ExportDataContextCustomer.cs index ac85860cc9..f7c027a27d 100644 --- a/src/Libraries/SmartStore.Services/DataExchange/ExportTask/ExportDataContextCustomer.cs +++ b/src/Libraries/SmartStore.Services/DataExchange/ExportTask/ExportDataContextCustomer.cs @@ -15,7 +15,8 @@ public class ExportDataContextCustomer private LazyMultimap _genericAttributes; - public ExportDataContextCustomer(IEnumerable customers, + public ExportDataContextCustomer( + IEnumerable customers, Func> genericAttributes) { if (customers == null) diff --git a/src/Libraries/SmartStore.Services/DataExchange/ExportTask/ExportDataContextManufacturer.cs b/src/Libraries/SmartStore.Services/DataExchange/ExportTask/ExportDataContextManufacturer.cs index 79bd1558ca..9d2002be35 100644 --- a/src/Libraries/SmartStore.Services/DataExchange/ExportTask/ExportDataContextManufacturer.cs +++ b/src/Libraries/SmartStore.Services/DataExchange/ExportTask/ExportDataContextManufacturer.cs @@ -18,7 +18,8 @@ internal class ExportDataContextManufacturer private LazyMultimap _productManufacturers; private LazyMultimap _pictures; - public ExportDataContextManufacturer(IEnumerable manufacturers, + public ExportDataContextManufacturer( + IEnumerable manufacturers, Func> productManufacturers, Func> pictures) { diff --git a/src/Libraries/SmartStore.Services/DataExchange/ExportTask/ExportDataContextProduct.cs b/src/Libraries/SmartStore.Services/DataExchange/ExportTask/ExportDataContextProduct.cs index 14f9168be4..bb0d6ea6c1 100644 --- a/src/Libraries/SmartStore.Services/DataExchange/ExportTask/ExportDataContextProduct.cs +++ b/src/Libraries/SmartStore.Services/DataExchange/ExportTask/ExportDataContextProduct.cs @@ -24,7 +24,8 @@ internal class ExportDataContextProduct : PriceCalculationContext private LazyMultimap _productSpecificationAttributes; private LazyMultimap _productBundleItems; - public ExportDataContextProduct(IEnumerable products, + public ExportDataContextProduct( + IEnumerable products, Func> attributes, Func> attributeCombinations, Func> tierPrices, diff --git a/src/Libraries/SmartStore.Services/DataExchange/ExportTask/ExportProfileTask.cs b/src/Libraries/SmartStore.Services/DataExchange/ExportTask/ExportProfileTask.cs index d9a6a17a36..e6016546ef 100644 --- a/src/Libraries/SmartStore.Services/DataExchange/ExportTask/ExportProfileTask.cs +++ b/src/Libraries/SmartStore.Services/DataExchange/ExportTask/ExportProfileTask.cs @@ -51,6 +51,7 @@ using SmartStore.Services.Tax; using SmartStore.Utilities; using SmartStore.Utilities.Threading; +using SmartStore.Core.Localization; // note: namespace persisted in ScheduleTask.Type namespace SmartStore.Services.DataExchange.ExportTask @@ -132,6 +133,8 @@ private void InitDependencies(TaskExecutionContext context) _subscriptionRepository = context.Resolve>>(); } + public Localizer T { get; set; } + #endregion #region Utilities @@ -2598,7 +2601,7 @@ private void ExportCoreInner(ExportProfileTaskContext ctx, Store store) if (ctx.Export.Abort != ExportAbortion.Hard) { - ctx.Provider.Value.ExecuteEnded(ctx.Export); + ctx.Provider.Value.OnExecuted(ctx.Export); } } } @@ -2624,7 +2627,7 @@ private void ExportCoreOuter(ExportProfileTaskContext ctx) ctx.Log = logger; ctx.Export.Log = logger; - ctx.ProgressInfo = _services.Localization.GetResource("Admin.DataExchange.Export.ProgressInfo"); + ctx.ProgressInfo = T("Admin.DataExchange.Export.ProgressInfo"); if (ctx.Profile.ProviderConfigData.HasValue()) { @@ -2637,9 +2640,9 @@ private void ExportCoreOuter(ExportProfileTaskContext ctx) using (var scope = new DbContextScope(_services.DbContext, autoDetectChanges: false, proxyCreation: true, validateOnSave: false, forceNoTracking: true)) { - ctx.DeliveryTimes = _deliveryTimeService.Value.GetAllDeliveryTimes().ToDictionary(x => x.Id, x => x); - ctx.QuantityUnits = _quantityUnitService.Value.GetAllQuantityUnits().ToDictionary(x => x.Id, x => x); - ctx.ProductTemplates = _productTemplateService.Value.GetAllProductTemplates().ToDictionary(x => x.Id, x => x); + ctx.DeliveryTimes = _deliveryTimeService.Value.GetAllDeliveryTimes().ToDictionary(x => x.Id); + ctx.QuantityUnits = _quantityUnitService.Value.GetAllQuantityUnits().ToDictionary(x => x.Id); + ctx.ProductTemplates = _productTemplateService.Value.GetAllProductTemplates().ToDictionary(x => x.Id); if (ctx.Provider.Value.EntityType == ExportEntityType.Product) { @@ -2681,7 +2684,7 @@ private void ExportCoreOuter(ExportProfileTaskContext ctx) ZipFile.CreateFromDirectory(ctx.FolderContent, ctx.ZipPath, CompressionLevel.Fastest, true); } - SetProgress(ctx, _services.Localization.GetResource("Common.Deployment")); + SetProgress(ctx, T("Common.Deployment")); foreach (var deployment in ctx.Profile.Deployments.OrderBy(x => x.DeploymentTypeId).Where(x => x.Enabled)) { @@ -2885,7 +2888,7 @@ public void Execute(TaskExecutionContext taskContext) var provider = _exportService.Value.LoadProvider(profile.ProviderSystemName); if (provider == null) - throw new SmartException(_services.Localization.GetResource("Admin.Common.ProviderNotLoaded").FormatInvariant(profile.ProviderSystemName.NaIfEmpty())); + throw new SmartException(T("Admin.Common.ProviderNotLoaded", profile.ProviderSystemName.NaIfEmpty())); var ctx = new ExportProfileTaskContext(taskContext, profile, provider, selectedEntityIds); @@ -2927,7 +2930,7 @@ public ExportExecuteResult Execute( var provider = _exportService.Value.LoadProvider(providerSystemName); if (provider == null) - throw new SmartException(_services.Localization.GetResource("Admin.Common.ProviderNotLoaded").FormatInvariant(providerSystemName.NaIfEmpty())); + throw new SmartException(T("Admin.Common.ProviderNotLoaded", providerSystemName.NaIfEmpty())); if (profile == null) profile = _exportService.Value.CreateVolatileProfile(provider); @@ -2950,24 +2953,24 @@ public ExportExecuteResult Execute( var extension = Path.GetExtension(ctx.Result.Files.First().FileName); if (provider.Value.EntityType == ExportEntityType.Product) - prefix = _services.Localization.GetResource("Admin.Catalog.Products"); + prefix = T("Admin.Catalog.Products"); else if (provider.Value.EntityType == ExportEntityType.Order) - prefix = _services.Localization.GetResource("Admin.Orders"); + prefix = T("Admin.Orders"); else if (provider.Value.EntityType == ExportEntityType.Category) - prefix = _services.Localization.GetResource("Admin.Catalog.Categories"); + prefix = T("Admin.Catalog.Categories"); else if (provider.Value.EntityType == ExportEntityType.Manufacturer) - prefix = _services.Localization.GetResource("Admin.Catalog.Manufacturers"); + prefix = T("Admin.Catalog.Manufacturers"); else if (provider.Value.EntityType == ExportEntityType.Customer) - prefix = _services.Localization.GetResource("Admin.Customers"); + prefix = T("Admin.Customers"); else if (provider.Value.EntityType == ExportEntityType.NewsLetterSubscription) - prefix = _services.Localization.GetResource("Admin.Promotions.NewsLetterSubscriptions"); + prefix = T("Admin.Promotions.NewsLetterSubscriptions"); else prefix = provider.Value.EntityType.ToString(); if (selectedEntityIds.HasValue()) - suffix = (selectedEntityIds.Contains(",") ? _services.Localization.GetResource("Admin.Common.Selected") : selectedEntityIds); + suffix = (selectedEntityIds.Contains(",") ? T("Admin.Common.Selected").Text : selectedEntityIds); else - suffix = _services.Localization.GetResource("Common.All"); + suffix = T("Common.All"); ctx.Result.DownloadFileName = string.Concat(prefix, "-", suffix).ToLower().ToValidFileName() + extension; } diff --git a/src/Libraries/SmartStore.Services/DataExchange/IExportProvider.cs b/src/Libraries/SmartStore.Services/DataExchange/IExportProvider.cs index c0e683a0e8..b0872ef1eb 100644 --- a/src/Libraries/SmartStore.Services/DataExchange/IExportProvider.cs +++ b/src/Libraries/SmartStore.Services/DataExchange/IExportProvider.cs @@ -30,6 +30,6 @@ public partial interface IExportProvider : IProvider, IUserEditable /// Called once per store when export execution ended /// /// Export execution context - void ExecuteEnded(IExportExecuteContext context); + void OnExecuted(IExportExecuteContext context); } } diff --git a/src/Libraries/SmartStore.Services/DataExchange/IExportService.cs b/src/Libraries/SmartStore.Services/DataExchange/IExportService.cs index 734777325f..e3823a7c4e 100644 --- a/src/Libraries/SmartStore.Services/DataExchange/IExportService.cs +++ b/src/Libraries/SmartStore.Services/DataExchange/IExportService.cs @@ -8,7 +8,7 @@ namespace SmartStore.Services.DataExchange public interface IExportService { /// - /// Creates a volatile export project + /// Creates a volatile export profile /// /// Export provider /// New export profile diff --git a/src/Plugins/SmartStore.GoogleMerchantCenter/Providers/ProductExportXmlProvider.cs b/src/Plugins/SmartStore.GoogleMerchantCenter/Providers/ProductExportXmlProvider.cs index 03ed6a00ff..bbcb1bcbda 100644 --- a/src/Plugins/SmartStore.GoogleMerchantCenter/Providers/ProductExportXmlProvider.cs +++ b/src/Plugins/SmartStore.GoogleMerchantCenter/Providers/ProductExportXmlProvider.cs @@ -401,7 +401,7 @@ public void Execute(IExportExecuteContext context) } } - public void ExecuteEnded(IExportExecuteContext context) + public void OnExecuted(IExportExecuteContext context) { // nothing to do } diff --git a/src/Presentation/SmartStore.Web/Administration/Views/Export/_Tab.Projection.cshtml b/src/Presentation/SmartStore.Web/Administration/Views/Export/_Tab.Projection.cshtml index 73113cc2a5..4815fba951 100644 --- a/src/Presentation/SmartStore.Web/Administration/Views/Export/_Tab.Projection.cshtml +++ b/src/Presentation/SmartStore.Web/Administration/Views/Export/_Tab.Projection.cshtml @@ -42,7 +42,7 @@ @if (Model.Provider.EntityType == ExportEntityType.Product) { - if (Model.Provider.Supporting.Contains(ExportSupport.ProjectionAttributeCombinationAsProduct)) + if (Model.Provider.Supporting.Contains(ExportFeatures.CanProjectAttributeCombinations)) { } - if (Model.Provider.Supporting.Contains(ExportSupport.ProjectionNoGroupedProducts)) + if (Model.Provider.Supporting.Contains(ExportFeatures.CanOmitGroupedProducts)) { - if (Model.Provider.Supporting.Contains(ExportSupport.ProjectionShippingTime)) + if (Model.Provider.Supporting.Contains(ExportFeatures.OffersShippingTimeFallback)) { } - if (Model.Provider.Supporting.Contains(ExportSupport.ProjectionShippingCosts)) + if (Model.Provider.Supporting.Contains(ExportFeatures.OffersShippingCostsFallback)) { } - if (Model.Provider.Supporting.Contains(ExportSupport.ProjectionMainPictureUrl)) + if (Model.Provider.Supporting.Contains(ExportFeatures.CanIncludeMainPicture)) { } - if (Model.Provider.Supporting.Contains(ExportSupport.ProjectionBrand)) + if (Model.Provider.Supporting.Contains(ExportFeatures.OffersBrandFallback)) { } - if (Model.Provider.Supporting.Contains(ExportSupport.ProjectionDescription)) + if (Model.Provider.Supporting.Contains(ExportFeatures.CanProjectDescription)) { } - if (Model.Provider.Supporting.Contains(ExportFeatures.CanOmitGroupedProducts)) + if (Model.Provider.Feature.HasFlag(ExportFeature.CanOmitGroupedProducts)) { - if (Model.Provider.Supporting.Contains(ExportFeatures.OffersShippingTimeFallback)) + if (Model.Provider.Feature.HasFlag(ExportFeature.OffersShippingTimeFallback)) { } - if (Model.Provider.Supporting.Contains(ExportFeatures.OffersShippingCostsFallback)) + if (Model.Provider.Feature.HasFlag(ExportFeature.OffersShippingCostsFallback)) { } - if (Model.Provider.Supporting.Contains(ExportFeatures.CanIncludeMainPicture)) + if (Model.Provider.Feature.HasFlag(ExportFeature.CanIncludeMainPicture)) { } - if (Model.Provider.Supporting.Contains(ExportFeatures.OffersBrandFallback)) + if (Model.Provider.Feature.HasFlag(ExportFeature.OffersBrandFallback)) { } - if (Model.Provider.Supporting.Contains(ExportFeatures.CanProjectDescription)) + if (Model.Provider.Feature.HasFlag(ExportFeature.CanProjectDescription)) { } - if (Model.Provider.Feature.HasFlag(ExportFeature.CanOmitGroupedProducts)) + if (Model.Provider.Feature.HasFlag(ExportFeatures.CanOmitGroupedProducts)) { - if (Model.Provider.Feature.HasFlag(ExportFeature.OffersShippingTimeFallback)) + if (Model.Provider.Feature.HasFlag(ExportFeatures.OffersShippingTimeFallback)) { } - if (Model.Provider.Feature.HasFlag(ExportFeature.OffersShippingCostsFallback)) + if (Model.Provider.Feature.HasFlag(ExportFeatures.OffersShippingCostsFallback)) { } - if (Model.Provider.Feature.HasFlag(ExportFeature.CanIncludeMainPicture)) + if (Model.Provider.Feature.HasFlag(ExportFeatures.CanIncludeMainPicture)) { } - if (Model.Provider.Feature.HasFlag(ExportFeature.OffersBrandFallback)) + if (Model.Provider.Feature.HasFlag(ExportFeatures.OffersBrandFallback)) { } - if (Model.Provider.Feature.HasFlag(ExportFeature.CanProjectDescription)) + if (Model.Provider.Feature.HasFlag(ExportFeatures.CanProjectDescription)) { + + + + + + + + + @@ -45,12 +46,20 @@ +
@Html.EditorFor(model => model.Slug) - @Html.Action("NamesPerEntity", "UrlRecord", new { entityName = Model.EntityName, entityId = @Model.EntityId }) @Html.ValidationMessageFor(model => model.Slug) + @Html.Action("NamesPerEntity", "UrlRecord", new { entityName = Model.EntityName, entityId = @Model.EntityId })
@@ -71,7 +71,7 @@
@@ -110,7 +110,7 @@
@@ -123,7 +123,7 @@
@@ -145,7 +145,7 @@
@@ -158,7 +158,7 @@
@@ -171,7 +171,7 @@
From 3f19750ae6e7c5f9e085e4b756e2b95dde55749e Mon Sep 17 00:00:00 2001 From: Murat Cakir Date: Thu, 5 Nov 2015 18:38:36 +0100 Subject: [PATCH 006/707] Fix #804: ShopBar conflicts with 'close store' feature --- .../SmartStore.Core/ComponentModel/Expando.cs | 5 + .../201509150931528_ExportFramework2.cs | 9 + .../ExportTask/ExportProfileTask.cs | 2 + .../DataExchange/Internal/ExpandoEntity.cs | 25 ++ .../DataExchange/Internal/ExpandoHelpers.cs | 240 ++++++++++++++++ .../SmartStore.Services.csproj | 3 + .../Controllers/StoreClosedAttribute.cs | 22 +- .../Controllers/CommonController.cs | 40 ++- .../Themes/Alpha/Content/header.less | 4 + .../Themes/Alpha/Content/layout.less | 1 + .../Views/Home/StoreClosed.cshtml | 3 +- src/SmartStoreNET.Minimal.sln | 270 ++++++++++++++++++ 12 files changed, 608 insertions(+), 16 deletions(-) create mode 100644 src/Libraries/SmartStore.Services/DataExchange/Internal/ExpandoEntity.cs create mode 100644 src/Libraries/SmartStore.Services/DataExchange/Internal/ExpandoHelpers.cs create mode 100644 src/SmartStoreNET.Minimal.sln diff --git a/src/Libraries/SmartStore.Core/ComponentModel/Expando.cs b/src/Libraries/SmartStore.Core/ComponentModel/Expando.cs index 81c2ecb4f7..c696b77e66 100644 --- a/src/Libraries/SmartStore.Core/ComponentModel/Expando.cs +++ b/src/Libraries/SmartStore.Core/ComponentModel/Expando.cs @@ -112,6 +112,11 @@ protected virtual void Initialize(object instance) _instanceType = instance.GetType(); } + protected object WrappedObject + { + get { return _instance; } + } + IList InstancePropertyInfo { get diff --git a/src/Libraries/SmartStore.Data/Migrations/201509150931528_ExportFramework2.cs b/src/Libraries/SmartStore.Data/Migrations/201509150931528_ExportFramework2.cs index 374cf79ba1..4cf5af7438 100644 --- a/src/Libraries/SmartStore.Data/Migrations/201509150931528_ExportFramework2.cs +++ b/src/Libraries/SmartStore.Data/Migrations/201509150931528_ExportFramework2.cs @@ -227,6 +227,15 @@ public void MigrateLocaleResources(LocaleResourcesBuilder builder) builder.Delete("Plugins.Widgets.OpenTrans.IsLexwareCompatibe"); builder.Delete("Admin.System.Maintenance.DeleteExportedFolders.TotalDeleted"); + + // Common + builder.AddOrUpdate("StoreClosed", + "We'll be back.", + "Wir sind bald wieder da."); + + builder.AddOrUpdate("StoreClosed.Hint", + "We're busy updating our online store for you and will be back soon.", + "Wir aktualisieren gerade das Angebot in unserem Online-Shop. Die Seite ist demnchst wieder verfgbar."); } } } diff --git a/src/Libraries/SmartStore.Services/DataExchange/ExportTask/ExportProfileTask.cs b/src/Libraries/SmartStore.Services/DataExchange/ExportTask/ExportProfileTask.cs index e6016546ef..d8bd7d7d4a 100644 --- a/src/Libraries/SmartStore.Services/DataExchange/ExportTask/ExportProfileTask.cs +++ b/src/Libraries/SmartStore.Services/DataExchange/ExportTask/ExportProfileTask.cs @@ -52,6 +52,7 @@ using SmartStore.Utilities; using SmartStore.Utilities.Threading; using SmartStore.Core.Localization; +using SmartStore.Services.DataExchange.Internal; // note: namespace persisted in ScheduleTask.Type namespace SmartStore.Services.DataExchange.ExportTask @@ -62,6 +63,7 @@ public class ExportProfileTask : ITask #region Dependencies + private ExpandoHelpers _expandoHelpers; private ICommonServices _services; private Lazy _exportService; private Lazy _dataExchangeSettings; diff --git a/src/Libraries/SmartStore.Services/DataExchange/Internal/ExpandoEntity.cs b/src/Libraries/SmartStore.Services/DataExchange/Internal/ExpandoEntity.cs new file mode 100644 index 0000000000..565f9e00e5 --- /dev/null +++ b/src/Libraries/SmartStore.Services/DataExchange/Internal/ExpandoEntity.cs @@ -0,0 +1,25 @@ +using SmartStore.ComponentModel; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Dynamic; + +namespace SmartStore.Services.DataExchange.Internal +{ + internal class ExpandoEntity : Expando + { + private readonly object _entity; + + public ExpandoEntity(object entity) + : base(entity) + { + } + + public object Entity + { + get { return base.WrappedObject; } + } + } +} diff --git a/src/Libraries/SmartStore.Services/DataExchange/Internal/ExpandoHelpers.cs b/src/Libraries/SmartStore.Services/DataExchange/Internal/ExpandoHelpers.cs new file mode 100644 index 0000000000..d8da9e6f8c --- /dev/null +++ b/src/Libraries/SmartStore.Services/DataExchange/Internal/ExpandoHelpers.cs @@ -0,0 +1,240 @@ +using SmartStore.ComponentModel; +using SmartStore.Core; +using SmartStore.Core.Domain.Common; +using SmartStore.Core.Domain.Customers; +using SmartStore.Core.Domain.Directory; +using SmartStore.Core.Domain.Localization; +using SmartStore.Core.Domain.Media; +using SmartStore.Core.Domain.Seo; +using SmartStore.Core.Domain.Stores; +using SmartStore.Services.DataExchange.ExportTask; +using SmartStore.Services.Localization; +using SmartStore.Services.Seo; +using System; +using System.Collections.Generic; +using System.Dynamic; +using System.Linq; +using System.Linq.Expressions; +using System.Reflection; +using System.Text; +using System.Threading.Tasks; + +namespace SmartStore.Services.DataExchange.Internal +{ + internal class ExpandoHelpers + { + private readonly ExportProfileTaskContext _ctx; + private readonly IUrlRecordService _urlRecordService; + private readonly ILocalizedEntityService _localizedEntityService; + + public ExpandoHelpers( + ExportProfileTaskContext context, + IUrlRecordService urlRecordService, + ILocalizedEntityService localizedEntityService) + { + _ctx = context; + _urlRecordService = urlRecordService; + _localizedEntityService = localizedEntityService; + } + + public dynamic ToExpando(Currency currency) + { + if (currency == null) + return null; + + dynamic expando = new ExpandoEntity(currency); + expando.Name = currency.GetLocalized(x => x.Name, _ctx.Projection.LanguageId ?? 0, true, false); + expando._Localized = GetLocalized(currency, x => x.Name); + + return expando; + } + + private dynamic ToExpando(Language language) + { + if (language == null) + return null; + + dynamic expando = new ExpandoEntity(language); + return expando; + } + + private dynamic ToExpando(Country country) + { + if (country == null) + return null; + + dynamic expando = new ExpandoEntity(country); + expando.Name = country.GetLocalized(x => x.Name, _ctx.Projection.LanguageId ?? 0, true, false); + expando._Localized = GetLocalized(country, x => x.Name); + + return expando; + } + + private dynamic ToExpando(Address address) + { + if (address == null) + return null; + + dynamic expando = new ExpandoEntity(address); + expando.Country = ToExpando(address.Country); + + if (address.StateProvinceId.GetValueOrDefault() > 0) + { + dynamic sp = new ExpandoEntity(address.StateProvince); + sp.Name = address.StateProvince.GetLocalized(x => x.Name, _ctx.Projection.LanguageId ?? 0, true, false); + sp._Localized = GetLocalized(address.StateProvince, x => x.Name); + expando.StateProvince = sp; + } + else + { + expando.StateProvince = null; + } + + return expando; + } + + private dynamic ToExpando(RewardPointsHistory points) + { + if (points == null) + return null; + + dynamic expando = new ExpandoEntity(points); + return expando; + } + + private dynamic ToExpando( Customer customer) + { + if (customer == null) + return null; + + dynamic expando = new ExpandoEntity(customer); + + expando.BillingAddress = null; + expando.ShippingAddress = null; + expando.Addresses = null; + expando.CustomerRoles = null; + + expando.RewardPointsHistory = null; + expando._RewardPointsBalance = 0; + + expando._GenericAttributes = null; + expando._HasNewsletterSubscription = false; + + return expando; + } + + private dynamic ToExpando(Store store) + { + if (store == null) + return null; + + dynamic expando = new ExpandoEntity(store); + expando.PrimaryStoreCurrency = ToExpando(store.PrimaryStoreCurrency); + expando.PrimaryExchangeRateCurrency = ToExpando(store.PrimaryExchangeRateCurrency); + + return expando; + } + + private dynamic ToExpando(DeliveryTime deliveryTime) + { + if (deliveryTime == null) + return null; + + dynamic expando = new ExpandoEntity(deliveryTime); + expando.Name = deliveryTime.GetLocalized(x => x.Name, _ctx.Projection.LanguageId ?? 0, true, false); + expando._Localized = GetLocalized(deliveryTime, x => x.Name); + + return expando; + } + + private dynamic ToExpando(QuantityUnit quantityUnit) + { + if (quantityUnit == null) + return null; + + dynamic expando = new ExpandoEntity(quantityUnit); + expando.Name = quantityUnit.GetLocalized(x => x.Name, _ctx.Projection.LanguageId ?? 0, true, false); + expando.Description = quantityUnit.GetLocalized(x => x.Description, _ctx.Projection.LanguageId ?? 0, true, false); + expando._Localized = GetLocalized(quantityUnit, + x => x.Name, + x => x.Description); + + return expando; + } + + private dynamic ToExpando(Picture picture, int thumbPictureSize, int detailsPictureSize) + { + if (picture == null) + return null; + + dynamic expando = new ExpandoEntity(picture); + + //// TODO!!!!! + //expando._ThumbImageUrl = _pictureService.Value.GetPictureUrl(picture, thumbPictureSize, false, _ctx.Store.Url); + //expando._ImageUrl = _pictureService.Value.GetPictureUrl(picture, detailsPictureSize, false, _ctx.Store.Url); + //expando._FullSizeImageUrl = _pictureService.Value.GetPictureUrl(picture, 0, false, _ctx.Store.Url); + + //var relativeUrl = _pictureService.Value.GetPictureUrl(picture); + //expando._FileName = relativeUrl.Substring(relativeUrl.LastIndexOf("/") + 1); + + //expando._ThumbLocalPath = _pictureService.Value.GetThumbLocalPath(picture); + + return expando; + } + + // TODO: weitermachen [...] + + private List GetLocalized(T entity, params Expression>[] keySelectors) + where T : BaseEntity, ILocalizedEntity + { + if (_ctx.Languages.Count <= 1) + return null; + + var localized = new List(); + + var localeKeyGroup = typeof(T).Name; + var isSlugSupported = typeof(ISlugSupported).IsAssignableFrom(typeof(T)); + + foreach (var language in _ctx.Languages) + { + var languageCulture = language.Value.LanguageCulture.EmptyNull().ToLower(); + + // add SeName + if (isSlugSupported) + { + var value = _urlRecordService.GetActiveSlug(entity.Id, localeKeyGroup, language.Value.Id); + if (value.HasValue()) + { + dynamic exp = new ExpandoObject(); + exp.Culture = languageCulture; + exp.LocaleKey = "SeName"; + exp.LocaleValue = value; + + localized.Add(exp); + } + } + + foreach (var keySelector in keySelectors) + { + var member = keySelector.Body as MemberExpression; + var propInfo = member.Member as PropertyInfo; + string localeKey = propInfo.Name; + var value = _localizedEntityService.GetLocalizedValue(language.Value.Id, entity.Id, localeKeyGroup, localeKey); + + // we better not export empty values. The risk is too high that they get reimported and unnecessarily pollute databases. + if (value.HasValue()) + { + dynamic exp = new ExpandoObject(); + exp.Culture = languageCulture; + exp.LocaleKey = localeKey; + exp.LocaleValue = value; + + localized.Add(exp); + } + } + } + + return (localized.Count == 0 ? null : localized); + } + } +} diff --git a/src/Libraries/SmartStore.Services/SmartStore.Services.csproj b/src/Libraries/SmartStore.Services/SmartStore.Services.csproj index 3c3f321c24..b5d926c04e 100644 --- a/src/Libraries/SmartStore.Services/SmartStore.Services.csproj +++ b/src/Libraries/SmartStore.Services/SmartStore.Services.csproj @@ -185,6 +185,8 @@ + + @@ -572,6 +574,7 @@ Nop_Services_EuropaCheckVatService_checkVatService + diff --git a/src/Presentation/SmartStore.Web.Framework/Controllers/StoreClosedAttribute.cs b/src/Presentation/SmartStore.Web.Framework/Controllers/StoreClosedAttribute.cs index b4cfa9c518..67cce55e92 100644 --- a/src/Presentation/SmartStore.Web.Framework/Controllers/StoreClosedAttribute.cs +++ b/src/Presentation/SmartStore.Web.Framework/Controllers/StoreClosedAttribute.cs @@ -7,6 +7,8 @@ using SmartStore.Core.Domain; using SmartStore.Core.Infrastructure; using SmartStore.Services.Customers; +using SmartStore.Services.Localization; +using SmartStore.Core.Logging; namespace SmartStore.Web.Framework.Controllers { @@ -20,7 +22,8 @@ public class StoreClosedAttribute : ActionFilterAttribute new Tuple("SmartStore.Web.Controllers.CommonController", "SetLanguage") }; - + public ILocalizationService Localizer { get; set; } + public Lazy Notifier { get; set; } public Lazy WorkContext { get; set; } public Lazy StoreInformationSettings { get; set; } @@ -60,8 +63,21 @@ public override void OnActionExecuting(ActionExecutingContext filterContext) } else { - var storeClosedUrl = new UrlHelper(filterContext.RequestContext).RouteUrl("StoreClosed"); - filterContext.Result = new RedirectResult(storeClosedUrl); + if (request.IsAjaxRequest()) + { + var storeClosedMessage = "{0} {1}".FormatCurrentUI( + Localizer.GetResource("StoreClosed", 0, false), + Localizer.GetResource("StoreClosed.Hint", 0, false)); + Notifier.Value.Error(storeClosedMessage); + + //filterContext.Result = new ContentResult { Content = "", ContentType = "text/html" }; + } + else + { + var storeClosedUrl = new UrlHelper(filterContext.RequestContext).RouteUrl("StoreClosed"); + filterContext.Result = new RedirectResult(storeClosedUrl); + } + } } } diff --git a/src/Presentation/SmartStore.Web/Controllers/CommonController.cs b/src/Presentation/SmartStore.Web/Controllers/CommonController.cs index 4c411f9238..36d72e8a38 100644 --- a/src/Presentation/SmartStore.Web/Controllers/CommonController.cs +++ b/src/Presentation/SmartStore.Web/Controllers/CommonController.cs @@ -42,6 +42,7 @@ using SmartStore.Web.Framework.UI; using SmartStore.Web.Infrastructure.Cache; using SmartStore.Web.Models.Common; +using SmartStore.Core.Domain; namespace SmartStore.Web.Controllers { @@ -57,10 +58,12 @@ public partial class CommonController : PublicControllerBase private readonly Lazy _forumservice; private readonly Lazy _genericAttributeService; private readonly Lazy _mobileDeviceHelper; + private readonly Lazy _compareProductsService; private readonly static string[] s_hints = new string[] { "Shopsystem", "Onlineshop Software", "Shopsoftware", "E-Commerce Solution" }; - private readonly CustomerSettings _customerSettings; + private readonly StoreInformationSettings _storeInfoSettings; + private readonly CustomerSettings _customerSettings; private readonly TaxSettings _taxSettings; private readonly CatalogSettings _catalogSettings; private readonly ThemeSettings _themeSettings; @@ -70,8 +73,8 @@ public partial class CommonController : PublicControllerBase private readonly ForumSettings _forumSettings; private readonly LocalizationSettings _localizationSettings; private readonly Lazy _securitySettings; - - private readonly IOrderTotalCalculationService _orderTotalCalculationService; + private readonly IOrderTotalCalculationService _orderTotalCalculationService; + private readonly IPriceFormatter _priceFormatter; private readonly IPageAssetsBuilder _pageAssetsBuilder; private readonly Lazy _pictureService; @@ -90,7 +93,9 @@ public CommonController( Lazy forumService, Lazy genericAttributeService, Lazy mobileDeviceHelper, - CustomerSettings customerSettings, + Lazy compareProductsService, + StoreInformationSettings storeInfoSettings, + CustomerSettings customerSettings, TaxSettings taxSettings, CatalogSettings catalogSettings, EmailAccountSettings emailAccountSettings, @@ -115,8 +120,10 @@ public CommonController( this._forumservice = forumService; this._genericAttributeService = genericAttributeService; this._mobileDeviceHelper = mobileDeviceHelper; - - this._customerSettings = customerSettings; + this._compareProductsService = compareProductsService; + + this._storeInfoSettings = storeInfoSettings; + this._customerSettings = customerSettings; this._taxSettings = taxSettings; this._catalogSettings = catalogSettings; this._commonSettings = commonSettings; @@ -506,7 +513,18 @@ public ActionResult ShopBar() { var customer = _services.WorkContext.CurrentCustomer; - var unreadMessageCount = GetUnreadPrivateMessages(); + var isAdmin = customer.IsAdmin(); + var isRegistered = isAdmin || customer.IsRegistered(); + + if (_storeInfoSettings.StoreClosed) + { + if (!isAdmin || !_storeInfoSettings.StoreClosedAllowForAdmins) + { + return Content(""); + } + } + + var unreadMessageCount = GetUnreadPrivateMessages(); var unreadMessage = string.Empty; var alertMessage = string.Empty; if (unreadMessageCount > 0) @@ -542,8 +560,8 @@ public ActionResult ShopBar() } var model = new ShopBarModel { - IsAuthenticated = customer.IsRegistered(), - CustomerEmailUsername = customer.IsRegistered() ? (_customerSettings.UsernamesEnabled ? customer.Username : customer.Email) : "", + IsAuthenticated = isRegistered, + CustomerEmailUsername = isRegistered ? (_customerSettings.UsernamesEnabled ? customer.Username : customer.Email) : "", IsCustomerImpersonated = _services.WorkContext.OriginalCustomerIfImpersonated != null, DisplayAdminLink = _services.Permissions.Authorize(StandardPermissionProvider.AccessAdminPanel), ShoppingCartEnabled = _services.Permissions.Authorize(StandardPermissionProvider.EnableShoppingCart), @@ -555,7 +573,7 @@ public ActionResult ShopBar() CompareProductsEnabled = _catalogSettings.CompareProductsEnabled }; - if (model.ShoppingCartEnabled || model.WishlistEnabled) + if (model.ShoppingCartEnabled || model.WishlistEnabled) { if (model.ShoppingCartEnabled) model.ShoppingCartItems = cart.GetTotalProducts(); @@ -566,7 +584,7 @@ public ActionResult ShopBar() if (_catalogSettings.CompareProductsEnabled) { - model.CompareItems = EngineContext.Current.Resolve().GetComparedProductsCount(); + model.CompareItems = _compareProductsService.Value.GetComparedProductsCount(); } return PartialView(model); diff --git a/src/Presentation/SmartStore.Web/Themes/Alpha/Content/header.less b/src/Presentation/SmartStore.Web/Themes/Alpha/Content/header.less index c783048936..012a75ee71 100644 --- a/src/Presentation/SmartStore.Web/Themes/Alpha/Content/header.less +++ b/src/Presentation/SmartStore.Web/Themes/Alpha/Content/header.less @@ -7,6 +7,10 @@ padding: 46px 0 0 0; } +.store-closed #header { + padding-top: 0; +} + #logobar { position: relative; padding: 10px 0; diff --git a/src/Presentation/SmartStore.Web/Themes/Alpha/Content/layout.less b/src/Presentation/SmartStore.Web/Themes/Alpha/Content/layout.less index ae6bc7a7fd..b6cb2e661c 100644 --- a/src/Presentation/SmartStore.Web/Themes/Alpha/Content/layout.less +++ b/src/Presentation/SmartStore.Web/Themes/Alpha/Content/layout.less @@ -11,6 +11,7 @@ #content-body { margin-top: 10px; padding-bottom: 10px; + min-height: 400px; } /* one column */ diff --git a/src/Presentation/SmartStore.Web/Views/Home/StoreClosed.cshtml b/src/Presentation/SmartStore.Web/Views/Home/StoreClosed.cshtml index e848f13ad2..f174ee3abe 100644 --- a/src/Presentation/SmartStore.Web/Views/Home/StoreClosed.cshtml +++ b/src/Presentation/SmartStore.Web/Views/Home/StoreClosed.cshtml @@ -3,13 +3,12 @@ //title Html.AddTitleParts(T("PageTitle.StoreClosed").Text); + Html.AddBodyCssClass("store-closed"); }

@T("StoreClosed")

-
-
@T("StoreClosed.Hint")
diff --git a/src/SmartStoreNET.Minimal.sln b/src/SmartStoreNET.Minimal.sln new file mode 100644 index 0000000000..feeb737168 --- /dev/null +++ b/src/SmartStoreNET.Minimal.sln @@ -0,0 +1,270 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 14 +VisualStudioVersion = 14.0.23107.0 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Plugins", "Plugins", "{7881B112-7843-4542-B1F7-F99553FB9BB7}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SmartStore.Services", "Libraries\SmartStore.Services\SmartStore.Services.csproj", "{210541AD-F659-47DA-8763-16F36C5CD2F4}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SmartStore.Data", "Libraries\SmartStore.Data\SmartStore.Data.csproj", "{CCD7F2C9-6A2C-4CF0-8E89-076B8FC0F144}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SmartStore.Core", "Libraries\SmartStore.Core\SmartStore.Core.csproj", "{6BDA8332-939F-45B7-A25E-7A797260AE59}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SmartStore.Web", "Presentation\SmartStore.Web\SmartStore.Web.csproj", "{4F1F649C-1020-45BE-A487-F416D9297FF3}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SmartStore.Admin", "Presentation\SmartStore.Web\Administration\SmartStore.Admin.csproj", "{152C761A-DD2E-4C1F-AF89-DFB2547A3BCA}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SmartStore.Web.Framework", "Presentation\SmartStore.Web.Framework\SmartStore.Web.Framework.csproj", "{75FD4163-333C-4DD5-854D-2EF294E45D94}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{E11A41CA-FA9F-4BB7-A35E-F80EE1084232}" + ProjectSection(SolutionItems) = preProject + AssemblySharedInfo.cs = AssemblySharedInfo.cs + AssemblyVersionInfo.cs = AssemblyVersionInfo.cs + EndProjectSection +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".nuget", ".nuget", "{C0A5A9AE-1509-4795-82CD-0BE7D6A17C69}" + ProjectSection(SolutionItems) = preProject + .nuget\NuGet.Config = .nuget\NuGet.Config + .nuget\NuGet.exe = .nuget\NuGet.exe + .nuget\NuGet.targets = .nuget\NuGet.targets + EndProjectSection +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SmartStore.OfflinePayment", "Plugins\SmartStore.OfflinePayment\SmartStore.OfflinePayment.csproj", "{692E9D31-1393-47BF-B372-63F671052F89}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SmartStore.Tax", "Plugins\SmartStore.Tax\SmartStore.Tax.csproj", "{94D1BEEB-64A3-4EB6-9017-D66AFAF4F2B2}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SmartStore.Shipping", "Plugins\SmartStore.Shipping\SmartStore.Shipping.csproj", "{ACC1E122-B2C8-4441-BDED-D4A77763331A}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SmartStore.DevTools", "Plugins\SmartStore.DevTools\SmartStore.DevTools.csproj", "{542B9C12-E2A1-49BB-9134-0E3484F9D669}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Debug|Mixed Platforms = Debug|Mixed Platforms + Debug|x86 = Debug|x86 + EFMigrations|Any CPU = EFMigrations|Any CPU + EFMigrations|Mixed Platforms = EFMigrations|Mixed Platforms + EFMigrations|x86 = EFMigrations|x86 + PluginDev|Any CPU = PluginDev|Any CPU + PluginDev|Mixed Platforms = PluginDev|Mixed Platforms + PluginDev|x86 = PluginDev|x86 + Release|Any CPU = Release|Any CPU + Release|Mixed Platforms = Release|Mixed Platforms + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {210541AD-F659-47DA-8763-16F36C5CD2F4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {210541AD-F659-47DA-8763-16F36C5CD2F4}.Debug|Any CPU.Build.0 = Debug|Any CPU + {210541AD-F659-47DA-8763-16F36C5CD2F4}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {210541AD-F659-47DA-8763-16F36C5CD2F4}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {210541AD-F659-47DA-8763-16F36C5CD2F4}.Debug|x86.ActiveCfg = Debug|Any CPU + {210541AD-F659-47DA-8763-16F36C5CD2F4}.EFMigrations|Any CPU.ActiveCfg = EFMigrations|Any CPU + {210541AD-F659-47DA-8763-16F36C5CD2F4}.EFMigrations|Any CPU.Build.0 = EFMigrations|Any CPU + {210541AD-F659-47DA-8763-16F36C5CD2F4}.EFMigrations|Mixed Platforms.ActiveCfg = EFMigrations|Any CPU + {210541AD-F659-47DA-8763-16F36C5CD2F4}.EFMigrations|Mixed Platforms.Build.0 = EFMigrations|Any CPU + {210541AD-F659-47DA-8763-16F36C5CD2F4}.EFMigrations|x86.ActiveCfg = EFMigrations|Any CPU + {210541AD-F659-47DA-8763-16F36C5CD2F4}.PluginDev|Any CPU.ActiveCfg = PluginDev|Any CPU + {210541AD-F659-47DA-8763-16F36C5CD2F4}.PluginDev|Any CPU.Build.0 = PluginDev|Any CPU + {210541AD-F659-47DA-8763-16F36C5CD2F4}.PluginDev|Mixed Platforms.ActiveCfg = PluginDev|Any CPU + {210541AD-F659-47DA-8763-16F36C5CD2F4}.PluginDev|Mixed Platforms.Build.0 = PluginDev|Any CPU + {210541AD-F659-47DA-8763-16F36C5CD2F4}.PluginDev|x86.ActiveCfg = PluginDev|Any CPU + {210541AD-F659-47DA-8763-16F36C5CD2F4}.Release|Any CPU.ActiveCfg = Release|Any CPU + {210541AD-F659-47DA-8763-16F36C5CD2F4}.Release|Any CPU.Build.0 = Release|Any CPU + {210541AD-F659-47DA-8763-16F36C5CD2F4}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {210541AD-F659-47DA-8763-16F36C5CD2F4}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {210541AD-F659-47DA-8763-16F36C5CD2F4}.Release|x86.ActiveCfg = Release|Any CPU + {CCD7F2C9-6A2C-4CF0-8E89-076B8FC0F144}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {CCD7F2C9-6A2C-4CF0-8E89-076B8FC0F144}.Debug|Any CPU.Build.0 = Debug|Any CPU + {CCD7F2C9-6A2C-4CF0-8E89-076B8FC0F144}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {CCD7F2C9-6A2C-4CF0-8E89-076B8FC0F144}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {CCD7F2C9-6A2C-4CF0-8E89-076B8FC0F144}.Debug|x86.ActiveCfg = Debug|Any CPU + {CCD7F2C9-6A2C-4CF0-8E89-076B8FC0F144}.EFMigrations|Any CPU.ActiveCfg = EFMigrations|Any CPU + {CCD7F2C9-6A2C-4CF0-8E89-076B8FC0F144}.EFMigrations|Any CPU.Build.0 = EFMigrations|Any CPU + {CCD7F2C9-6A2C-4CF0-8E89-076B8FC0F144}.EFMigrations|Mixed Platforms.ActiveCfg = EFMigrations|Any CPU + {CCD7F2C9-6A2C-4CF0-8E89-076B8FC0F144}.EFMigrations|Mixed Platforms.Build.0 = EFMigrations|Any CPU + {CCD7F2C9-6A2C-4CF0-8E89-076B8FC0F144}.EFMigrations|x86.ActiveCfg = EFMigrations|Any CPU + {CCD7F2C9-6A2C-4CF0-8E89-076B8FC0F144}.PluginDev|Any CPU.ActiveCfg = PluginDev|Any CPU + {CCD7F2C9-6A2C-4CF0-8E89-076B8FC0F144}.PluginDev|Any CPU.Build.0 = PluginDev|Any CPU + {CCD7F2C9-6A2C-4CF0-8E89-076B8FC0F144}.PluginDev|Mixed Platforms.ActiveCfg = PluginDev|Any CPU + {CCD7F2C9-6A2C-4CF0-8E89-076B8FC0F144}.PluginDev|Mixed Platforms.Build.0 = PluginDev|Any CPU + {CCD7F2C9-6A2C-4CF0-8E89-076B8FC0F144}.PluginDev|x86.ActiveCfg = PluginDev|Any CPU + {CCD7F2C9-6A2C-4CF0-8E89-076B8FC0F144}.Release|Any CPU.ActiveCfg = Release|Any CPU + {CCD7F2C9-6A2C-4CF0-8E89-076B8FC0F144}.Release|Any CPU.Build.0 = Release|Any CPU + {CCD7F2C9-6A2C-4CF0-8E89-076B8FC0F144}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {CCD7F2C9-6A2C-4CF0-8E89-076B8FC0F144}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {CCD7F2C9-6A2C-4CF0-8E89-076B8FC0F144}.Release|x86.ActiveCfg = Release|Any CPU + {6BDA8332-939F-45B7-A25E-7A797260AE59}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {6BDA8332-939F-45B7-A25E-7A797260AE59}.Debug|Any CPU.Build.0 = Debug|Any CPU + {6BDA8332-939F-45B7-A25E-7A797260AE59}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {6BDA8332-939F-45B7-A25E-7A797260AE59}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {6BDA8332-939F-45B7-A25E-7A797260AE59}.Debug|x86.ActiveCfg = Debug|Any CPU + {6BDA8332-939F-45B7-A25E-7A797260AE59}.EFMigrations|Any CPU.ActiveCfg = EFMigrations|Any CPU + {6BDA8332-939F-45B7-A25E-7A797260AE59}.EFMigrations|Any CPU.Build.0 = EFMigrations|Any CPU + {6BDA8332-939F-45B7-A25E-7A797260AE59}.EFMigrations|Mixed Platforms.ActiveCfg = EFMigrations|Any CPU + {6BDA8332-939F-45B7-A25E-7A797260AE59}.EFMigrations|Mixed Platforms.Build.0 = EFMigrations|Any CPU + {6BDA8332-939F-45B7-A25E-7A797260AE59}.EFMigrations|x86.ActiveCfg = EFMigrations|Any CPU + {6BDA8332-939F-45B7-A25E-7A797260AE59}.PluginDev|Any CPU.ActiveCfg = PluginDev|Any CPU + {6BDA8332-939F-45B7-A25E-7A797260AE59}.PluginDev|Any CPU.Build.0 = PluginDev|Any CPU + {6BDA8332-939F-45B7-A25E-7A797260AE59}.PluginDev|Mixed Platforms.ActiveCfg = PluginDev|Any CPU + {6BDA8332-939F-45B7-A25E-7A797260AE59}.PluginDev|Mixed Platforms.Build.0 = PluginDev|Any CPU + {6BDA8332-939F-45B7-A25E-7A797260AE59}.PluginDev|x86.ActiveCfg = PluginDev|Any CPU + {6BDA8332-939F-45B7-A25E-7A797260AE59}.Release|Any CPU.ActiveCfg = Release|Any CPU + {6BDA8332-939F-45B7-A25E-7A797260AE59}.Release|Any CPU.Build.0 = Release|Any CPU + {6BDA8332-939F-45B7-A25E-7A797260AE59}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {6BDA8332-939F-45B7-A25E-7A797260AE59}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {6BDA8332-939F-45B7-A25E-7A797260AE59}.Release|x86.ActiveCfg = Release|Any CPU + {4F1F649C-1020-45BE-A487-F416D9297FF3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {4F1F649C-1020-45BE-A487-F416D9297FF3}.Debug|Any CPU.Build.0 = Debug|Any CPU + {4F1F649C-1020-45BE-A487-F416D9297FF3}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {4F1F649C-1020-45BE-A487-F416D9297FF3}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {4F1F649C-1020-45BE-A487-F416D9297FF3}.Debug|x86.ActiveCfg = Debug|Any CPU + {4F1F649C-1020-45BE-A487-F416D9297FF3}.EFMigrations|Any CPU.ActiveCfg = EFMigrations|Any CPU + {4F1F649C-1020-45BE-A487-F416D9297FF3}.EFMigrations|Any CPU.Build.0 = EFMigrations|Any CPU + {4F1F649C-1020-45BE-A487-F416D9297FF3}.EFMigrations|Mixed Platforms.ActiveCfg = EFMigrations|Any CPU + {4F1F649C-1020-45BE-A487-F416D9297FF3}.EFMigrations|Mixed Platforms.Build.0 = EFMigrations|Any CPU + {4F1F649C-1020-45BE-A487-F416D9297FF3}.EFMigrations|x86.ActiveCfg = EFMigrations|Any CPU + {4F1F649C-1020-45BE-A487-F416D9297FF3}.PluginDev|Any CPU.ActiveCfg = PluginDev|Any CPU + {4F1F649C-1020-45BE-A487-F416D9297FF3}.PluginDev|Any CPU.Build.0 = PluginDev|Any CPU + {4F1F649C-1020-45BE-A487-F416D9297FF3}.PluginDev|Mixed Platforms.ActiveCfg = PluginDev|Any CPU + {4F1F649C-1020-45BE-A487-F416D9297FF3}.PluginDev|Mixed Platforms.Build.0 = PluginDev|Any CPU + {4F1F649C-1020-45BE-A487-F416D9297FF3}.PluginDev|x86.ActiveCfg = PluginDev|Any CPU + {4F1F649C-1020-45BE-A487-F416D9297FF3}.Release|Any CPU.ActiveCfg = Release|Any CPU + {4F1F649C-1020-45BE-A487-F416D9297FF3}.Release|Any CPU.Build.0 = Release|Any CPU + {4F1F649C-1020-45BE-A487-F416D9297FF3}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {4F1F649C-1020-45BE-A487-F416D9297FF3}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {4F1F649C-1020-45BE-A487-F416D9297FF3}.Release|x86.ActiveCfg = Release|Any CPU + {152C761A-DD2E-4C1F-AF89-DFB2547A3BCA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {152C761A-DD2E-4C1F-AF89-DFB2547A3BCA}.Debug|Any CPU.Build.0 = Debug|Any CPU + {152C761A-DD2E-4C1F-AF89-DFB2547A3BCA}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {152C761A-DD2E-4C1F-AF89-DFB2547A3BCA}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {152C761A-DD2E-4C1F-AF89-DFB2547A3BCA}.Debug|x86.ActiveCfg = Debug|Any CPU + {152C761A-DD2E-4C1F-AF89-DFB2547A3BCA}.EFMigrations|Any CPU.ActiveCfg = EFMigrations|Any CPU + {152C761A-DD2E-4C1F-AF89-DFB2547A3BCA}.EFMigrations|Any CPU.Build.0 = EFMigrations|Any CPU + {152C761A-DD2E-4C1F-AF89-DFB2547A3BCA}.EFMigrations|Mixed Platforms.ActiveCfg = EFMigrations|Any CPU + {152C761A-DD2E-4C1F-AF89-DFB2547A3BCA}.EFMigrations|Mixed Platforms.Build.0 = EFMigrations|Any CPU + {152C761A-DD2E-4C1F-AF89-DFB2547A3BCA}.EFMigrations|x86.ActiveCfg = EFMigrations|Any CPU + {152C761A-DD2E-4C1F-AF89-DFB2547A3BCA}.PluginDev|Any CPU.ActiveCfg = PluginDev|Any CPU + {152C761A-DD2E-4C1F-AF89-DFB2547A3BCA}.PluginDev|Any CPU.Build.0 = PluginDev|Any CPU + {152C761A-DD2E-4C1F-AF89-DFB2547A3BCA}.PluginDev|Mixed Platforms.ActiveCfg = PluginDev|Any CPU + {152C761A-DD2E-4C1F-AF89-DFB2547A3BCA}.PluginDev|Mixed Platforms.Build.0 = PluginDev|Any CPU + {152C761A-DD2E-4C1F-AF89-DFB2547A3BCA}.PluginDev|x86.ActiveCfg = PluginDev|Any CPU + {152C761A-DD2E-4C1F-AF89-DFB2547A3BCA}.Release|Any CPU.ActiveCfg = Release|Any CPU + {152C761A-DD2E-4C1F-AF89-DFB2547A3BCA}.Release|Any CPU.Build.0 = Release|Any CPU + {152C761A-DD2E-4C1F-AF89-DFB2547A3BCA}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {152C761A-DD2E-4C1F-AF89-DFB2547A3BCA}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {152C761A-DD2E-4C1F-AF89-DFB2547A3BCA}.Release|x86.ActiveCfg = Release|Any CPU + {75FD4163-333C-4DD5-854D-2EF294E45D94}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {75FD4163-333C-4DD5-854D-2EF294E45D94}.Debug|Any CPU.Build.0 = Debug|Any CPU + {75FD4163-333C-4DD5-854D-2EF294E45D94}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {75FD4163-333C-4DD5-854D-2EF294E45D94}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {75FD4163-333C-4DD5-854D-2EF294E45D94}.Debug|x86.ActiveCfg = Debug|Any CPU + {75FD4163-333C-4DD5-854D-2EF294E45D94}.EFMigrations|Any CPU.ActiveCfg = EFMigrations|Any CPU + {75FD4163-333C-4DD5-854D-2EF294E45D94}.EFMigrations|Any CPU.Build.0 = EFMigrations|Any CPU + {75FD4163-333C-4DD5-854D-2EF294E45D94}.EFMigrations|Mixed Platforms.ActiveCfg = EFMigrations|Any CPU + {75FD4163-333C-4DD5-854D-2EF294E45D94}.EFMigrations|Mixed Platforms.Build.0 = EFMigrations|Any CPU + {75FD4163-333C-4DD5-854D-2EF294E45D94}.EFMigrations|x86.ActiveCfg = EFMigrations|Any CPU + {75FD4163-333C-4DD5-854D-2EF294E45D94}.PluginDev|Any CPU.ActiveCfg = PluginDev|Any CPU + {75FD4163-333C-4DD5-854D-2EF294E45D94}.PluginDev|Any CPU.Build.0 = PluginDev|Any CPU + {75FD4163-333C-4DD5-854D-2EF294E45D94}.PluginDev|Mixed Platforms.ActiveCfg = PluginDev|Any CPU + {75FD4163-333C-4DD5-854D-2EF294E45D94}.PluginDev|Mixed Platforms.Build.0 = PluginDev|Any CPU + {75FD4163-333C-4DD5-854D-2EF294E45D94}.PluginDev|x86.ActiveCfg = PluginDev|Any CPU + {75FD4163-333C-4DD5-854D-2EF294E45D94}.Release|Any CPU.ActiveCfg = Release|Any CPU + {75FD4163-333C-4DD5-854D-2EF294E45D94}.Release|Any CPU.Build.0 = Release|Any CPU + {75FD4163-333C-4DD5-854D-2EF294E45D94}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {75FD4163-333C-4DD5-854D-2EF294E45D94}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {75FD4163-333C-4DD5-854D-2EF294E45D94}.Release|x86.ActiveCfg = Release|Any CPU + {692E9D31-1393-47BF-B372-63F671052F89}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {692E9D31-1393-47BF-B372-63F671052F89}.Debug|Any CPU.Build.0 = Debug|Any CPU + {692E9D31-1393-47BF-B372-63F671052F89}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {692E9D31-1393-47BF-B372-63F671052F89}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {692E9D31-1393-47BF-B372-63F671052F89}.Debug|x86.ActiveCfg = Debug|Any CPU + {692E9D31-1393-47BF-B372-63F671052F89}.EFMigrations|Any CPU.ActiveCfg = EFMigrations|Any CPU + {692E9D31-1393-47BF-B372-63F671052F89}.EFMigrations|Any CPU.Build.0 = EFMigrations|Any CPU + {692E9D31-1393-47BF-B372-63F671052F89}.EFMigrations|Mixed Platforms.ActiveCfg = EFMigrations|Any CPU + {692E9D31-1393-47BF-B372-63F671052F89}.EFMigrations|Mixed Platforms.Build.0 = EFMigrations|Any CPU + {692E9D31-1393-47BF-B372-63F671052F89}.EFMigrations|x86.ActiveCfg = EFMigrations|Any CPU + {692E9D31-1393-47BF-B372-63F671052F89}.PluginDev|Any CPU.ActiveCfg = PluginDev|Any CPU + {692E9D31-1393-47BF-B372-63F671052F89}.PluginDev|Any CPU.Build.0 = PluginDev|Any CPU + {692E9D31-1393-47BF-B372-63F671052F89}.PluginDev|Mixed Platforms.ActiveCfg = PluginDev|Any CPU + {692E9D31-1393-47BF-B372-63F671052F89}.PluginDev|Mixed Platforms.Build.0 = PluginDev|Any CPU + {692E9D31-1393-47BF-B372-63F671052F89}.PluginDev|x86.ActiveCfg = PluginDev|Any CPU + {692E9D31-1393-47BF-B372-63F671052F89}.Release|Any CPU.ActiveCfg = Release|Any CPU + {692E9D31-1393-47BF-B372-63F671052F89}.Release|Any CPU.Build.0 = Release|Any CPU + {692E9D31-1393-47BF-B372-63F671052F89}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {692E9D31-1393-47BF-B372-63F671052F89}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {692E9D31-1393-47BF-B372-63F671052F89}.Release|x86.ActiveCfg = Release|Any CPU + {94D1BEEB-64A3-4EB6-9017-D66AFAF4F2B2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {94D1BEEB-64A3-4EB6-9017-D66AFAF4F2B2}.Debug|Any CPU.Build.0 = Debug|Any CPU + {94D1BEEB-64A3-4EB6-9017-D66AFAF4F2B2}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {94D1BEEB-64A3-4EB6-9017-D66AFAF4F2B2}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {94D1BEEB-64A3-4EB6-9017-D66AFAF4F2B2}.Debug|x86.ActiveCfg = Debug|Any CPU + {94D1BEEB-64A3-4EB6-9017-D66AFAF4F2B2}.EFMigrations|Any CPU.ActiveCfg = EFMigrations|Any CPU + {94D1BEEB-64A3-4EB6-9017-D66AFAF4F2B2}.EFMigrations|Any CPU.Build.0 = EFMigrations|Any CPU + {94D1BEEB-64A3-4EB6-9017-D66AFAF4F2B2}.EFMigrations|Mixed Platforms.ActiveCfg = EFMigrations|Any CPU + {94D1BEEB-64A3-4EB6-9017-D66AFAF4F2B2}.EFMigrations|Mixed Platforms.Build.0 = EFMigrations|Any CPU + {94D1BEEB-64A3-4EB6-9017-D66AFAF4F2B2}.EFMigrations|x86.ActiveCfg = EFMigrations|Any CPU + {94D1BEEB-64A3-4EB6-9017-D66AFAF4F2B2}.PluginDev|Any CPU.ActiveCfg = PluginDev|Any CPU + {94D1BEEB-64A3-4EB6-9017-D66AFAF4F2B2}.PluginDev|Any CPU.Build.0 = PluginDev|Any CPU + {94D1BEEB-64A3-4EB6-9017-D66AFAF4F2B2}.PluginDev|Mixed Platforms.ActiveCfg = PluginDev|Any CPU + {94D1BEEB-64A3-4EB6-9017-D66AFAF4F2B2}.PluginDev|Mixed Platforms.Build.0 = PluginDev|Any CPU + {94D1BEEB-64A3-4EB6-9017-D66AFAF4F2B2}.PluginDev|x86.ActiveCfg = PluginDev|Any CPU + {94D1BEEB-64A3-4EB6-9017-D66AFAF4F2B2}.Release|Any CPU.ActiveCfg = Release|Any CPU + {94D1BEEB-64A3-4EB6-9017-D66AFAF4F2B2}.Release|Any CPU.Build.0 = Release|Any CPU + {94D1BEEB-64A3-4EB6-9017-D66AFAF4F2B2}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {94D1BEEB-64A3-4EB6-9017-D66AFAF4F2B2}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {94D1BEEB-64A3-4EB6-9017-D66AFAF4F2B2}.Release|x86.ActiveCfg = Release|Any CPU + {ACC1E122-B2C8-4441-BDED-D4A77763331A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {ACC1E122-B2C8-4441-BDED-D4A77763331A}.Debug|Any CPU.Build.0 = Debug|Any CPU + {ACC1E122-B2C8-4441-BDED-D4A77763331A}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {ACC1E122-B2C8-4441-BDED-D4A77763331A}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {ACC1E122-B2C8-4441-BDED-D4A77763331A}.Debug|x86.ActiveCfg = Debug|Any CPU + {ACC1E122-B2C8-4441-BDED-D4A77763331A}.EFMigrations|Any CPU.ActiveCfg = EFMigrations|Any CPU + {ACC1E122-B2C8-4441-BDED-D4A77763331A}.EFMigrations|Any CPU.Build.0 = EFMigrations|Any CPU + {ACC1E122-B2C8-4441-BDED-D4A77763331A}.EFMigrations|Mixed Platforms.ActiveCfg = EFMigrations|Any CPU + {ACC1E122-B2C8-4441-BDED-D4A77763331A}.EFMigrations|Mixed Platforms.Build.0 = EFMigrations|Any CPU + {ACC1E122-B2C8-4441-BDED-D4A77763331A}.EFMigrations|x86.ActiveCfg = EFMigrations|Any CPU + {ACC1E122-B2C8-4441-BDED-D4A77763331A}.PluginDev|Any CPU.ActiveCfg = PluginDev|Any CPU + {ACC1E122-B2C8-4441-BDED-D4A77763331A}.PluginDev|Any CPU.Build.0 = PluginDev|Any CPU + {ACC1E122-B2C8-4441-BDED-D4A77763331A}.PluginDev|Mixed Platforms.ActiveCfg = PluginDev|Any CPU + {ACC1E122-B2C8-4441-BDED-D4A77763331A}.PluginDev|Mixed Platforms.Build.0 = PluginDev|Any CPU + {ACC1E122-B2C8-4441-BDED-D4A77763331A}.PluginDev|x86.ActiveCfg = PluginDev|Any CPU + {ACC1E122-B2C8-4441-BDED-D4A77763331A}.Release|Any CPU.ActiveCfg = Release|Any CPU + {ACC1E122-B2C8-4441-BDED-D4A77763331A}.Release|Any CPU.Build.0 = Release|Any CPU + {ACC1E122-B2C8-4441-BDED-D4A77763331A}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {ACC1E122-B2C8-4441-BDED-D4A77763331A}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {ACC1E122-B2C8-4441-BDED-D4A77763331A}.Release|x86.ActiveCfg = Release|Any CPU + {542B9C12-E2A1-49BB-9134-0E3484F9D669}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {542B9C12-E2A1-49BB-9134-0E3484F9D669}.Debug|Any CPU.Build.0 = Debug|Any CPU + {542B9C12-E2A1-49BB-9134-0E3484F9D669}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {542B9C12-E2A1-49BB-9134-0E3484F9D669}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {542B9C12-E2A1-49BB-9134-0E3484F9D669}.Debug|x86.ActiveCfg = Debug|Any CPU + {542B9C12-E2A1-49BB-9134-0E3484F9D669}.EFMigrations|Any CPU.ActiveCfg = EFMigrations|Any CPU + {542B9C12-E2A1-49BB-9134-0E3484F9D669}.EFMigrations|Any CPU.Build.0 = EFMigrations|Any CPU + {542B9C12-E2A1-49BB-9134-0E3484F9D669}.EFMigrations|Mixed Platforms.ActiveCfg = EFMigrations|Any CPU + {542B9C12-E2A1-49BB-9134-0E3484F9D669}.EFMigrations|Mixed Platforms.Build.0 = EFMigrations|Any CPU + {542B9C12-E2A1-49BB-9134-0E3484F9D669}.EFMigrations|x86.ActiveCfg = EFMigrations|Any CPU + {542B9C12-E2A1-49BB-9134-0E3484F9D669}.PluginDev|Any CPU.ActiveCfg = PluginDev|Any CPU + {542B9C12-E2A1-49BB-9134-0E3484F9D669}.PluginDev|Any CPU.Build.0 = PluginDev|Any CPU + {542B9C12-E2A1-49BB-9134-0E3484F9D669}.PluginDev|Mixed Platforms.ActiveCfg = PluginDev|Any CPU + {542B9C12-E2A1-49BB-9134-0E3484F9D669}.PluginDev|Mixed Platforms.Build.0 = PluginDev|Any CPU + {542B9C12-E2A1-49BB-9134-0E3484F9D669}.PluginDev|x86.ActiveCfg = PluginDev|Any CPU + {542B9C12-E2A1-49BB-9134-0E3484F9D669}.Release|Any CPU.ActiveCfg = Release|Any CPU + {542B9C12-E2A1-49BB-9134-0E3484F9D669}.Release|Any CPU.Build.0 = Release|Any CPU + {542B9C12-E2A1-49BB-9134-0E3484F9D669}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {542B9C12-E2A1-49BB-9134-0E3484F9D669}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {542B9C12-E2A1-49BB-9134-0E3484F9D669}.Release|x86.ActiveCfg = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(NestedProjects) = preSolution + {692E9D31-1393-47BF-B372-63F671052F89} = {7881B112-7843-4542-B1F7-F99553FB9BB7} + {94D1BEEB-64A3-4EB6-9017-D66AFAF4F2B2} = {7881B112-7843-4542-B1F7-F99553FB9BB7} + {ACC1E122-B2C8-4441-BDED-D4A77763331A} = {7881B112-7843-4542-B1F7-F99553FB9BB7} + {542B9C12-E2A1-49BB-9134-0E3484F9D669} = {7881B112-7843-4542-B1F7-F99553FB9BB7} + EndGlobalSection + GlobalSection(NDepend) = preSolution + Project = ".\SmartStoreNET.ndproj" + EndGlobalSection +EndGlobal From 9de2317cb37303ace68b9b357acaf98722423dcd Mon Sep 17 00:00:00 2001 From: Marcus Gesing Date: Thu, 5 Nov 2015 18:41:41 +0100 Subject: [PATCH 007/707] Web-API: Added OData action to add a shipment to an order and to set it as shipped --- .../Orders/IOrderProcessingService.cs | 9 ++ .../Orders/OrderProcessingService.cs | 72 ++++++++++++++ .../Controllers/OData/OrdersController.cs | 25 +++++ .../WebApiConfigurationProvider.cs | 6 ++ src/Plugins/SmartStore.WebApi/changelog.md | 1 + .../WebApi/OData/WebApiQueryableAttribute.cs | 13 ++- .../WebApi/WebApiEntityController.cs | 17 ++++ .../WebApi/WebApiExtension.cs | 2 + .../Controllers/OrderController.cs | 95 +++++-------------- 9 files changed, 166 insertions(+), 74 deletions(-) diff --git a/src/Libraries/SmartStore.Services/Orders/IOrderProcessingService.cs b/src/Libraries/SmartStore.Services/Orders/IOrderProcessingService.cs index 9452f42b7b..9c3f825b03 100644 --- a/src/Libraries/SmartStore.Services/Orders/IOrderProcessingService.cs +++ b/src/Libraries/SmartStore.Services/Orders/IOrderProcessingService.cs @@ -266,5 +266,14 @@ public partial interface IOrderProcessingService /// Shopping cart /// true - OK; false - minimum order total amount is not reached bool ValidateMinOrderTotalAmount(IList cart); + + /// + /// Adds a shipment to an order + /// + /// Order + /// Tracking number + /// Quantities by order item identifiers. null to use the remaining total number of products for each order item. + /// New shipment, null if no shipment was added + Shipment AddShipment(Order order, string trackingNumber, Dictionary quantities); } } diff --git a/src/Libraries/SmartStore.Services/Orders/OrderProcessingService.cs b/src/Libraries/SmartStore.Services/Orders/OrderProcessingService.cs index 4995d1bd38..7c0e0f4bf6 100644 --- a/src/Libraries/SmartStore.Services/Orders/OrderProcessingService.cs +++ b/src/Libraries/SmartStore.Services/Orders/OrderProcessingService.cs @@ -2736,6 +2736,78 @@ public virtual bool ValidateMinOrderTotalAmount(IList return true; } + public virtual Shipment AddShipment(Order order, string trackingNumber, Dictionary quantities) + { + Guard.ArgumentNotNull(() => order); + + Shipment shipment = null; + decimal? totalWeight = null; + + foreach (var orderItem in order.OrderItems) + { + if (!orderItem.Product.IsShipEnabled) + continue; + + //ensure that this product can be shipped (have at least one item to ship) + var maxQtyToAdd = orderItem.GetTotalNumberOfItemsCanBeAddedToShipment(); + if (maxQtyToAdd <= 0) + continue; + + var qtyToAdd = 0; + + if (quantities != null && quantities.ContainsKey(orderItem.Id)) + qtyToAdd = quantities[orderItem.Id]; + else if (quantities == null) + qtyToAdd = maxQtyToAdd; + + if (qtyToAdd <= 0) + continue; + + if (qtyToAdd > maxQtyToAdd) + qtyToAdd = maxQtyToAdd; + + var orderItemTotalWeight = orderItem.ItemWeight.HasValue ? orderItem.ItemWeight * qtyToAdd : null; + if (orderItemTotalWeight.HasValue) + { + if (!totalWeight.HasValue) + totalWeight = 0; + totalWeight += orderItemTotalWeight.Value; + } + + if (shipment == null) + { + shipment = new Shipment + { + OrderId = order.Id, + Order = order, // otherwise order updated event would not be fired during InsertShipment + TrackingNumber = trackingNumber, + TotalWeight = null, + ShippedDateUtc = null, + DeliveryDateUtc = null, + CreatedOnUtc = DateTime.UtcNow, + }; + } + + var shipmentItem = new ShipmentItem + { + OrderItemId = orderItem.Id, + Quantity = qtyToAdd + }; + + shipment.ShipmentItems.Add(shipmentItem); + } + + if (shipment != null && shipment.ShipmentItems.Count > 0) + { + shipment.TotalWeight = totalWeight; + _shipmentService.InsertShipment(shipment); + + return shipment; + } + + return null; + } + #endregion } } diff --git a/src/Plugins/SmartStore.WebApi/Controllers/OData/OrdersController.cs b/src/Plugins/SmartStore.WebApi/Controllers/OData/OrdersController.cs index d633274612..2cf72507b8 100644 --- a/src/Plugins/SmartStore.WebApi/Controllers/OData/OrdersController.cs +++ b/src/Plugins/SmartStore.WebApi/Controllers/OData/OrdersController.cs @@ -168,5 +168,30 @@ public Order Cancel(int key) }); return entity; } + + [HttpPost] + public SingleResult AddShipment(int key, ODataActionParameters parameters) + { + var result = GetSingleResult(key); + var order = GetExpandedEntity(key, result, "OrderItems, OrderItems.Product, Shipments, Shipments.ShipmentItems"); + + this.ProcessEntity(() => + { + if (order.HasItemsToAddToShipment()) + { + var trackingNumber = parameters.GetValue("TrackingNumber"); + + var shipment = _orderProcessingService.Value.AddShipment(order, trackingNumber, null); + + if (shipment != null) + { + if (parameters.ContainsKey("SetAsShipped") && parameters.GetValue("SetAsShipped")) + _orderProcessingService.Value.Ship(shipment, true); + } + } + return null; + }); + return result; + } } } diff --git a/src/Plugins/SmartStore.WebApi/WebApiConfigurationProvider.cs b/src/Plugins/SmartStore.WebApi/WebApiConfigurationProvider.cs index db3d1f3377..7440806c04 100644 --- a/src/Plugins/SmartStore.WebApi/WebApiConfigurationProvider.cs +++ b/src/Plugins/SmartStore.WebApi/WebApiConfigurationProvider.cs @@ -35,6 +35,12 @@ private void AddActionsToOrder(EntityTypeConfiguration config) config.Action("Cancel") .ReturnsFromEntitySet(WebApiOdataEntitySet.Orders); + + var addShipment = config.Action("AddShipment") + .ReturnsFromEntitySet(WebApiOdataEntitySet.Orders); + + addShipment.Parameter("TrackingNumber"); + addShipment.Parameter("SetAsShipped"); } private void AddActionsToProduct(EntityTypeConfiguration config) diff --git a/src/Plugins/SmartStore.WebApi/changelog.md b/src/Plugins/SmartStore.WebApi/changelog.md index 2191a7d055..c844fe4dbb 100644 --- a/src/Plugins/SmartStore.WebApi/changelog.md +++ b/src/Plugins/SmartStore.WebApi/changelog.md @@ -3,6 +3,7 @@ ##Web Api 2.2.0.4 ###New Features * Added OData endpoint for shipment items +* Added OData action to add a shipment to an order and to set it as shipped ##Web Api 2.2.0.3 ###New Features diff --git a/src/Presentation/SmartStore.Web.Framework/WebApi/OData/WebApiQueryableAttribute.cs b/src/Presentation/SmartStore.Web.Framework/WebApi/OData/WebApiQueryableAttribute.cs index f3487d624a..b71ce1700a 100644 --- a/src/Presentation/SmartStore.Web.Framework/WebApi/OData/WebApiQueryableAttribute.cs +++ b/src/Presentation/SmartStore.Web.Framework/WebApi/OData/WebApiQueryableAttribute.cs @@ -17,11 +17,16 @@ protected virtual bool MissingClientPaging(HttpActionExecutedContext actionExecu try { - var responseContent = actionExecutedContext.Response.Content as ObjectContent; - bool singleResult = (responseContent != null && responseContent.Value is SingleResult); + var content = actionExecutedContext.Response.Content as ObjectContent; - if (singleResult) - return false; // 'true' would result in a 500 'internal server error' + if (content != null) + { + if (content.Value is HttpError) + return false; + + if (content.Value is SingleResult) + return false; // 'true' would result in a 500 'internal server error' + } var query = actionExecutedContext.Request.RequestUri.Query; diff --git a/src/Presentation/SmartStore.Web.Framework/WebApi/WebApiEntityController.cs b/src/Presentation/SmartStore.Web.Framework/WebApi/WebApiEntityController.cs index 894b9d9400..4354426a9f 100644 --- a/src/Presentation/SmartStore.Web.Framework/WebApi/WebApiEntityController.cs +++ b/src/Presentation/SmartStore.Web.Framework/WebApi/WebApiEntityController.cs @@ -258,6 +258,23 @@ protected internal virtual TEntity GetExpandedEntity(int key, string properties) return entity; } + protected internal virtual TEntity GetExpandedEntity(int key, SingleResult result, string path) + { + var query = result.Queryable; + + foreach (var property in path.SplitSafe(",")) + { + query = query.Expand(property.Trim()); + } + + var entity = query.FirstOrDefault(x => x.Id == key); + + if (entity == null) + throw ExceptionEntityNotFound(key); + + return entity; + } + protected internal virtual TProperty GetExpandedProperty(int key, Expression> path) { var entity = GetExpandedEntity(key, path); diff --git a/src/Presentation/SmartStore.Web.Framework/WebApi/WebApiExtension.cs b/src/Presentation/SmartStore.Web.Framework/WebApi/WebApiExtension.cs index 9051894b20..9b9c41a1c4 100644 --- a/src/Presentation/SmartStore.Web.Framework/WebApi/WebApiExtension.cs +++ b/src/Presentation/SmartStore.Web.Framework/WebApi/WebApiExtension.cs @@ -1,10 +1,12 @@ using System; +using System.Linq; using System.Linq.Expressions; using System.Net; using System.Net.Http; using System.Reflection; using System.Web.Http; using System.Web.Http.OData.Routing; +using SmartStore.Core; using SmartStore.Utilities; namespace SmartStore.Web.Framework.WebApi diff --git a/src/Presentation/SmartStore.Web/Administration/Controllers/OrderController.cs b/src/Presentation/SmartStore.Web/Administration/Controllers/OrderController.cs index 186f1905b3..f2a096e559 100644 --- a/src/Presentation/SmartStore.Web/Administration/Controllers/OrderController.cs +++ b/src/Presentation/SmartStore.Web/Administration/Controllers/OrderController.cs @@ -2119,84 +2119,39 @@ public ActionResult AddShipment(int orderId, FormCollection form, bool continueE var order = _orderService.GetOrderById(orderId); if (order == null) - //No order found with the specified id return RedirectToAction("List"); - Shipment shipment = null; - - decimal? totalWeight = null; - foreach (var orderItem in order.OrderItems) - { - //is shippable - if (!orderItem.Product.IsShipEnabled) - continue; - - //ensure that this product can be shipped (have at least one item to ship) - var maxQtyToAdd = orderItem.GetTotalNumberOfItemsCanBeAddedToShipment(); - if (maxQtyToAdd <= 0) - continue; - - int qtyToAdd = 0; //parse quantity - foreach (string formKey in form.AllKeys) - if (formKey.Equals(string.Format("qtyToAdd{0}", orderItem.Id), StringComparison.InvariantCultureIgnoreCase)) - { - int.TryParse(form[formKey], out qtyToAdd); - break; - } - - //validate quantity - if (qtyToAdd <= 0) - continue; - if (qtyToAdd > maxQtyToAdd) - qtyToAdd = maxQtyToAdd; - - //ok. we have at least one item. let's create a shipment (if it does not exist) + var quantities = new Dictionary(); + var trackingNumber = form["TrackingNumber"]; - var orderItemTotalWeight = orderItem.ItemWeight.HasValue ? orderItem.ItemWeight * qtyToAdd : null; - if (orderItemTotalWeight.HasValue) - { - if (!totalWeight.HasValue) - totalWeight = 0; - totalWeight += orderItemTotalWeight.Value; - } + foreach (var orderItem in order.OrderItems) + { + foreach (string formKey in form.AllKeys) + { + if (formKey.Equals(string.Format("qtyToAdd{0}", orderItem.Id), StringComparison.InvariantCultureIgnoreCase)) + { + quantities.Add(orderItem.Id, form[formKey].ToInt()); + break; + } + } + } - if (shipment == null) - { - shipment = new Shipment() - { - OrderId = order.Id, - TrackingNumber = form["TrackingNumber"], - TotalWeight = null, - ShippedDateUtc = null, - DeliveryDateUtc = null, - CreatedOnUtc = DateTime.UtcNow, - }; - } - //create a shipment item - var shipmentItem = new ShipmentItem() - { - OrderItemId = orderItem.Id, - Quantity = qtyToAdd, - }; - shipment.ShipmentItems.Add(shipmentItem); - } + var shipment = _orderProcessingService.AddShipment(order, trackingNumber, quantities); - //if we have at least one item in the shipment, then save it - if (shipment != null && shipment.ShipmentItems.Count > 0) - { - shipment.TotalWeight = totalWeight; - _shipmentService.InsertShipment(shipment); + if (shipment != null) + { + NotifySuccess(_localizationService.GetResource("Admin.Orders.Shipments.Added")); - NotifySuccess(_localizationService.GetResource("Admin.Orders.Shipments.Added")); - return continueEditing - ? RedirectToAction("ShipmentDetails", new {id = shipment.Id}) - : RedirectToAction("Edit", new { id = orderId }); - } - else - { + return continueEditing + ? RedirectToAction("ShipmentDetails", new { id = shipment.Id }) + : RedirectToAction("Edit", new { id = orderId }); + } + else + { NotifyError(_localizationService.GetResource("Admin.Orders.Shipments.NoProductsSelected")); + return RedirectToAction("AddShipment", new { orderId = orderId }); - } + } } public ActionResult ShipmentDetails(int id) From 2abf201e18d5042ba8b134178f70079d61bf7e4b Mon Sep 17 00:00:00 2001 From: Marcus Gesing Date: Thu, 5 Nov 2015 21:48:11 +0100 Subject: [PATCH 008/707] Web-API: OData actions should return SingleResult (instead of entity instance) to let expand option be recognized Fixed "Member 'CurrentValues' cannot be called for the entity of type 'TEntity' because the entity does not exist in the context. To add an entity to the context call the Add or Attach method of DbSet." --- .../SmartStore.Data/ObjectContextBase.cs | 18 ++++--- .../Controllers/OData/OrdersController.cs | 49 +++++++++++-------- src/Plugins/SmartStore.WebApi/changelog.md | 2 + 3 files changed, 43 insertions(+), 26 deletions(-) diff --git a/src/Libraries/SmartStore.Data/ObjectContextBase.cs b/src/Libraries/SmartStore.Data/ObjectContextBase.cs index 5fff7f7588..5f722e155f 100644 --- a/src/Libraries/SmartStore.Data/ObjectContextBase.cs +++ b/src/Libraries/SmartStore.Data/ObjectContextBase.cs @@ -333,12 +333,18 @@ public IDictionary GetModifiedProperties(BaseEntity entity) var props = new Dictionary(); var entry = this.Entry(entity); - var modifiedPropertyNames = from p in entry.CurrentValues.PropertyNames - where entry.Property(p).IsModified - select p; - foreach (var name in modifiedPropertyNames) + + // be aware of the entity state. you cannot get modified properties for detached entities. + if (entry.State != System.Data.Entity.EntityState.Detached) { - props.Add(name, entry.Property(name).OriginalValue); + var modifiedPropertyNames = from p in entry.CurrentValues.PropertyNames + where entry.Property(p).IsModified + select p; + + foreach (var name in modifiedPropertyNames) + { + props.Add(name, entry.Property(name).OriginalValue); + } } return props; @@ -381,7 +387,7 @@ public override Task SaveChangesAsync() return result; } - // codehint: sm-add (required for UoW implementation) + // required for UoW implementation public string Alias { get; internal set; } // performance on bulk inserts diff --git a/src/Plugins/SmartStore.WebApi/Controllers/OData/OrdersController.cs b/src/Plugins/SmartStore.WebApi/Controllers/OData/OrdersController.cs index 2cf72507b8..f0f1c0eb9b 100644 --- a/src/Plugins/SmartStore.WebApi/Controllers/OData/OrdersController.cs +++ b/src/Plugins/SmartStore.WebApi/Controllers/OData/OrdersController.cs @@ -95,24 +95,26 @@ public IQueryable GetOrderItems(int key) // actions [HttpPost] - public Order PaymentPending(int key) + public SingleResult PaymentPending(int key) { - var entity = GetEntityByKeyNotNull(key); + var result = GetSingleResult(key); + var order = GetExpandedEntity(key, result, null); this.ProcessEntity(() => { - entity.PaymentStatus = PaymentStatus.Pending; - Service.UpdateOrder(entity); + order.PaymentStatus = PaymentStatus.Pending; + Service.UpdateOrder(order); return null; }); - return entity; + return result; } [HttpPost] - public Order PaymentPaid(int key, ODataActionParameters parameters) + public SingleResult PaymentPaid(int key, ODataActionParameters parameters) { - var entity = GetEntityByKeyNotNull(key); + var result = GetSingleResult(key); + var order = GetExpandedEntity(key, result, null); this.ProcessEntity(() => { @@ -120,20 +122,23 @@ public Order PaymentPaid(int key, ODataActionParameters parameters) if (paymentMethodName != null) { - entity.PaymentMethodSystemName = paymentMethodName; - Service.UpdateOrder(entity); + order.PaymentMethodSystemName = paymentMethodName; + Service.UpdateOrder(order); } - _orderProcessingService.Value.MarkOrderAsPaid(entity); + _orderProcessingService.Value.MarkOrderAsPaid(order); + return null; }); - return entity; + + return result; } [HttpPost] - public Order PaymentRefund(int key, ODataActionParameters parameters) + public SingleResult PaymentRefund(int key, ODataActionParameters parameters) { - var entity = GetEntityByKeyNotNull(key); + var result = GetSingleResult(key); + var order = GetExpandedEntity(key, result, null); this.ProcessEntity(() => { @@ -141,32 +146,35 @@ public Order PaymentRefund(int key, ODataActionParameters parameters) if (online) { - var errors = _orderProcessingService.Value.Refund(entity); + var errors = _orderProcessingService.Value.Refund(order); if (errors.Count > 0) return errors[0]; } else { - _orderProcessingService.Value.RefundOffline(entity); + _orderProcessingService.Value.RefundOffline(order); } return null; }); - return entity; + + return result; } [HttpPost] - public Order Cancel(int key) + public SingleResult Cancel(int key) { - var entity = GetEntityByKeyNotNull(key); + var result = GetSingleResult(key); + var order = GetExpandedEntity(key, result, "OrderItems, OrderItems.Product"); this.ProcessEntity(() => { - _orderProcessingService.Value.CancelOrder(entity, true); + _orderProcessingService.Value.CancelOrder(order, true); return null; }); - return entity; + + return result; } [HttpPost] @@ -191,6 +199,7 @@ public SingleResult AddShipment(int key, ODataActionParameters parameters } return null; }); + return result; } } diff --git a/src/Plugins/SmartStore.WebApi/changelog.md b/src/Plugins/SmartStore.WebApi/changelog.md index c844fe4dbb..23143ca0fc 100644 --- a/src/Plugins/SmartStore.WebApi/changelog.md +++ b/src/Plugins/SmartStore.WebApi/changelog.md @@ -4,6 +4,8 @@ ###New Features * Added OData endpoint for shipment items * Added OData action to add a shipment to an order and to set it as shipped +###Improvements +* OData actions should return SingleResult (instead of entity instance) to let expand option be recognized ##Web Api 2.2.0.3 ###New Features From 0fee2bbc2539a43a975bcadaab5ae49b7a52b73b Mon Sep 17 00:00:00 2001 From: Murat Cakir Date: Thu, 5 Nov 2015 23:21:01 +0100 Subject: [PATCH 009/707] Export framework: refactoring --- .../SmartStore.Core/ComponentModel/Expando.cs | 279 +++++++++--------- .../ComponentModel/PropertyBag.cs | 3 +- .../Extensions/TypeExtensions.cs | 18 +- .../SmartStore.Core/Utilities/TypeHelper.cs | 1 + ...portService.cs => ExportProfileService.cs} | 4 +- .../DataExchange/ExportSegmenter.cs | 4 +- .../ExportTask/ExportProfileTask.cs | 16 +- .../DataExchange/IDataExporter.cs | 48 +++ ...ortService.cs => IExportProfileService.cs} | 2 +- .../DataExchange/Internal/DynamicEntity.cs | 53 ++++ .../DataExchange/Internal/ExpandoEntity.cs | 25 -- .../DataExchange/Internal/ExpandoHelpers.cs | 22 +- .../SmartStore.Services.csproj | 7 +- .../Tasks/TaskExecutionContext.cs | 30 +- .../FeedGoogleMerchantCenterController.cs | 10 +- ...XmlProvider.cs => GmcExportXmlProvider.cs} | 4 +- .../SmartStore.GoogleMerchantCenter.csproj | 3 +- .../DependencyRegistrar.cs | 2 +- .../Controllers/ExportController.cs | 4 +- 19 files changed, 293 insertions(+), 242 deletions(-) rename src/Libraries/SmartStore.Services/DataExchange/{ExportService.cs => ExportProfileService.cs} (98%) create mode 100644 src/Libraries/SmartStore.Services/DataExchange/IDataExporter.cs rename src/Libraries/SmartStore.Services/DataExchange/{IExportService.cs => IExportProfileService.cs} (98%) create mode 100644 src/Libraries/SmartStore.Services/DataExchange/Internal/DynamicEntity.cs delete mode 100644 src/Libraries/SmartStore.Services/DataExchange/Internal/ExpandoEntity.cs rename src/Plugins/SmartStore.GoogleMerchantCenter/Providers/{ProductExportXmlProvider.cs => GmcExportXmlProvider.cs} (99%) diff --git a/src/Libraries/SmartStore.Core/ComponentModel/Expando.cs b/src/Libraries/SmartStore.Core/ComponentModel/Expando.cs index c696b77e66..c97e82ed75 100644 --- a/src/Libraries/SmartStore.Core/ComponentModel/Expando.cs +++ b/src/Libraries/SmartStore.Core/ComponentModel/Expando.cs @@ -36,7 +36,6 @@ using System.Linq; using System.Dynamic; using System.Reflection; -using Fasterflect; namespace SmartStore.ComponentModel { @@ -59,7 +58,7 @@ namespace SmartStore.ComponentModel /// Dictionary: Any of the extended properties are accessible via IDictionary interface /// [Serializable] - public class Expando : DynamicObject, IDynamicMetaObjectProvider + public class Expando : DynamicObject { /// /// Instance of object passed in @@ -71,7 +70,7 @@ public class Expando : DynamicObject, IDynamicMetaObjectProvider /// private Type _instanceType; - private IList _instancePropertyInfo; + private IList _instancePropertyInfos; /// /// String Dictionary that contains the extra dynamic values @@ -104,7 +103,6 @@ public Expando(object instance) Initialize(instance); } - protected virtual void Initialize(object instance) { _instance = instance; @@ -117,13 +115,13 @@ protected object WrappedObject get { return _instance; } } - IList InstancePropertyInfo + IList InstancePropertyInfos { get { - if (_instancePropertyInfo == null && _instance != null) - _instancePropertyInfo = _instance.GetType().Properties(Flags.InstancePublicDeclaredOnly); - return _instancePropertyInfo; + if (_instancePropertyInfos == null && _instance != null) + _instancePropertyInfos = Fasterflect.PropertyExtensions.Properties(_instance.GetType(), Fasterflect.Flags.InstancePublicDeclaredOnly); + return _instancePropertyInfos; } } @@ -143,68 +141,76 @@ public override IEnumerable GetDynamicMemberNames() /// public override bool TryGetMember(GetMemberBinder binder, out object result) { - result = null; - - // first check the Properties collection for member - if (Properties.Keys.Contains(binder.Name)) - { - result = Properties[binder.Name]; - return true; - } - - - // Next check for Public properties via Reflection - if (_instance != null) - { - try - { - return GetProperty(_instance, binder.Name, out result); - } - catch { } - } - - // failed to retrieve a property - result = null; - return false; + return TryGetMemberCore(binder.Name, out result); } + protected virtual bool TryGetMemberCore(string name, out object result) + { + result = null; + + // first check the Properties collection for member + if (Properties.Keys.Contains(name)) + { + result = Properties[name]; + return true; + } + + // Next check for public properties via Reflection + if (_instance != null) + { + try + { + return GetProperty(_instance, name, out result); + } + catch { } + } + + // failed to retrieve a property + result = null; + return false; + } - /// - /// Property setter implementation tries to retrieve value from instance - /// first then into this object - /// - /// - /// - /// - public override bool TrySetMember(SetMemberBinder binder, object value) - { - - // first check to see if there's a native property to set - if (_instance != null) - { - try - { - bool result = SetProperty(_instance, binder.Name, value); - if (result) - return true; - } - catch { } - } - // no match - set or add to dictionary - Properties[binder.Name] = value; - return true; + /// + /// Property setter implementation tries to retrieve value from instance + /// first then into this object + /// + /// + /// + /// + public override bool TrySetMember(SetMemberBinder binder, object value) + { + return TrySetMemberCore(binder.Name, value); } - /// - /// Dynamic invocation method. Currently allows only for Reflection based - /// operation (no ability to add methods dynamically). - /// - /// - /// - /// - /// - public override bool TryInvokeMember(InvokeMemberBinder binder, object[] args, out object result) + protected virtual bool TrySetMemberCore(string name, object value) + { + // first check to see if there's a native property to set + if (_instance != null) + { + try + { + bool result = SetProperty(_instance, name, value); + if (result) + return true; + } + catch { } + } + + // no match - set or add to dictionary + Properties[name] = value; + return true; + } + + /// + /// Dynamic invocation method. Currently allows only for Reflection based + /// operation (no ability to add methods dynamically). + /// + /// + /// + /// + /// + public override bool TryInvokeMember(InvokeMemberBinder binder, object[] args, out object result) { if (_instance != null) { @@ -231,13 +237,10 @@ public override bool TryInvokeMember(InvokeMemberBinder binder, object[] args, o /// protected bool GetProperty(object instance, string name, out object result) { - if (instance == null) - instance = this; - - var pi = _instanceType.Property(name, Flags.InstancePublic); + var pi = GetPropertyInfo(name); if (pi != null) { - result = instance.GetPropertyValue(pi.Name); + result = Fasterflect.PropertyExtensions.GetPropertyValue(instance ?? this, pi.Name); return true; } @@ -245,6 +248,16 @@ protected bool GetProperty(object instance, string name, out object result) return false; } + /// + /// Gets a PropertyInfo instance from the wrapped object + /// + /// Property name + protected PropertyInfo GetPropertyInfo(string name) + { + var pi = Fasterflect.PropertyExtensions.Property(_instanceType, name, Fasterflect.Flags.InstancePublic); + return pi; + } + /// /// Reflection helper method to set a property value /// @@ -254,13 +267,10 @@ protected bool GetProperty(object instance, string name, out object result) /// protected bool SetProperty(object instance, string name, object value) { - if (instance == null) - instance = this; - - var pi = _instanceType.Property(name, Flags.InstancePublic); + var pi = GetPropertyInfo(name); if (pi != null) { - instance.SetPropertyValue(pi.Name, value); + Fasterflect.PropertyInfoExtensions.Set(pi, instance ?? this, value); return true; } return false; @@ -276,16 +286,12 @@ protected bool SetProperty(object instance, string name, object value) /// protected bool InvokeMethod(object instance, string name, object[] args, out object result) { - if (instance == null) - instance = this; - // Look at the instanceType - var mi = _instanceType.Method(name, Flags.InstancePublic); - + var mi = Fasterflect.MethodExtensions.Method(_instanceType, name, Fasterflect.Flags.InstancePublic); if (mi != null) { - result = _instance.CallMethod(mi.Name, args); - return true; + result = Fasterflect.MethodInfoExtensions.Call(mi, instance ?? this, args); + return true; } result = null; @@ -293,73 +299,54 @@ protected bool InvokeMethod(object instance, string name, object[] args, out obj } - /// - /// Convenience method that provides a string Indexer - /// to the Properties collection AND the strongly typed - /// properties of the object by name. - /// - /// // dynamic - /// exp["Address"] = "112 nowhere lane"; - /// // strong - /// var name = exp["StronglyTypedProperty"] as string; - /// - /// - /// The getter checks the Properties dictionary first - /// then looks in PropertyInfo for properties. - /// The setter checks the instance properties before - /// checking the Properties dictionary. - /// - /// - /// - /// - public object this[string key] - { - get - { - try - { - // try to get from properties collection first - return Properties[key]; - } - catch (KeyNotFoundException) - { - // try reflection on instanceType - object result = null; - if (GetProperty(_instance, key, out result)) - return result; - - // no doesn't exist - throw; - } - } - set - { - if (Properties.ContainsKey(key)) - { - Properties[key] = value; - return; - } - - // check instance for existance of type first - var pi = _instanceType.Property(key, Flags.Public); - if (pi != null) - SetProperty(_instance, key, value); - else - Properties[key] = value; - } - } + /// + /// Convenience method that provides a string Indexer + /// to the Properties collection AND the strongly typed + /// properties of the object by name. + /// + /// // dynamic + /// exp["Address"] = "112 nowhere lane"; + /// // strong + /// var name = exp["StronglyTypedProperty"] as string; + /// + /// + /// The getter checks the Properties dictionary first + /// then looks in PropertyInfo for properties. + /// The setter checks the instance properties before + /// checking the Properties dictionary. + /// + /// + /// + /// + public object this[string key] + { + get + { + object result = null; + if (TryGetMemberCore(key, out result)) + { + return result; + } + + throw new KeyNotFoundException(); + } + set + { + TrySetMemberCore(key, value); + } + } - /// - /// Returns and the properties of - /// - /// - /// - public IEnumerable> GetProperties(bool includeInstanceProperties = false) + /// + /// Returns all properties + /// + /// + /// + public IEnumerable> GetProperties(bool includeInstanceProperties = false) { if (includeInstanceProperties && _instance != null) { - foreach (var prop in this.InstancePropertyInfo) + foreach (var prop in this.InstancePropertyInfos) yield return new KeyValuePair(prop.Name, prop.GetValue(_instance, null)); } @@ -388,13 +375,13 @@ public bool Contains(KeyValuePair item, bool includeInstanceProp /// public bool Contains(string propertyName, bool includeInstanceProperties = false) { - bool res = Properties.ContainsKey(propertyName); - if (res) + bool contains = Properties.ContainsKey(propertyName); + if (contains) return true; if (includeInstanceProperties && _instance != null) { - foreach (var prop in this.InstancePropertyInfo) + foreach (var prop in this.InstancePropertyInfos) { if (prop.Name == propertyName) return true; diff --git a/src/Libraries/SmartStore.Core/ComponentModel/PropertyBag.cs b/src/Libraries/SmartStore.Core/ComponentModel/PropertyBag.cs index fb2ab77767..d67fbb85b3 100644 --- a/src/Libraries/SmartStore.Core/ComponentModel/PropertyBag.cs +++ b/src/Libraries/SmartStore.Core/ComponentModel/PropertyBag.cs @@ -306,8 +306,7 @@ public bool FromXml(string xml) if (string.IsNullOrEmpty(xml)) return true; - var result = SerializationUtils.DeSerializeObject(xml, - this.GetType()) as PropertyBag; + var result = SerializationUtils.DeSerializeObject(xml, this.GetType()) as PropertyBag; if (result != null) { foreach (var item in result) diff --git a/src/Libraries/SmartStore.Core/Extensions/TypeExtensions.cs b/src/Libraries/SmartStore.Core/Extensions/TypeExtensions.cs index 69752367c2..d2ca8d9df9 100644 --- a/src/Libraries/SmartStore.Core/Extensions/TypeExtensions.cs +++ b/src/Libraries/SmartStore.Core/Extensions/TypeExtensions.cs @@ -45,15 +45,8 @@ public static bool IsPredefinedSimpleType(this Type type) { return true; } + return s_predefinedTypes.Any(t => t == type); - //foreach (Type type2 in s_predefinedTypes) - //{ - // if (type2 == type) - // { - // return true; - // } - //} - //return false; } public static bool IsStruct(this Type type) @@ -75,15 +68,8 @@ public static bool IsPredefinedGenericType(this Type type) { return false; } + return s_predefinedGenericTypes.Any(t => t == type); - //foreach (Type type2 in s_predefinedGenericTypes) - //{ - // if (type2 == type) - // { - // return true; - // } - //} - //return false; } public static bool IsPredefinedType(this Type type) diff --git a/src/Libraries/SmartStore.Core/Utilities/TypeHelper.cs b/src/Libraries/SmartStore.Core/Utilities/TypeHelper.cs index a887d720c1..34dbf27b18 100644 --- a/src/Libraries/SmartStore.Core/Utilities/TypeHelper.cs +++ b/src/Libraries/SmartStore.Core/Utilities/TypeHelper.cs @@ -61,6 +61,7 @@ public static Type GetElementType(Type type) return GetElementType(type3); } } + return type; } diff --git a/src/Libraries/SmartStore.Services/DataExchange/ExportService.cs b/src/Libraries/SmartStore.Services/DataExchange/ExportProfileService.cs similarity index 98% rename from src/Libraries/SmartStore.Services/DataExchange/ExportService.cs rename to src/Libraries/SmartStore.Services/DataExchange/ExportProfileService.cs index aea03c6fa9..dac3287770 100644 --- a/src/Libraries/SmartStore.Services/DataExchange/ExportService.cs +++ b/src/Libraries/SmartStore.Services/DataExchange/ExportProfileService.cs @@ -16,7 +16,7 @@ namespace SmartStore.Services.DataExchange { - public partial class ExportService : IExportService + public partial class ExportProfileService : IExportProfileService { private const string _defaultFileNamePattern = "%Store.Id%-%ExportProfile.Id%-%Misc.FileNumber%-%ExportProfile.SeoName%"; @@ -28,7 +28,7 @@ public partial class ExportService : IExportService private readonly DataExchangeSettings _dataExchangeSettings; private readonly ILocalizationService _localizationService; - public ExportService( + public ExportProfileService( IRepository exportProfileRepository, IRepository exportDeploymentRepository, IEventPublisher eventPublisher, diff --git a/src/Libraries/SmartStore.Services/DataExchange/ExportSegmenter.cs b/src/Libraries/SmartStore.Services/DataExchange/ExportSegmenter.cs index b86df2cb45..6d5c6fb937 100644 --- a/src/Libraries/SmartStore.Services/DataExchange/ExportSegmenter.cs +++ b/src/Libraries/SmartStore.Services/DataExchange/ExportSegmenter.cs @@ -9,7 +9,7 @@ public interface IExportSegmenterConsumer /// /// Total number of records /// - int RecordTotal { get; } + int TotalRecords { get; } /// /// Gets current data segment @@ -78,7 +78,7 @@ public ExportSegmenter( /// /// Total number of records /// - public int RecordTotal + public int TotalRecords { get { diff --git a/src/Libraries/SmartStore.Services/DataExchange/ExportTask/ExportProfileTask.cs b/src/Libraries/SmartStore.Services/DataExchange/ExportTask/ExportProfileTask.cs index d8bd7d7d4a..e4e9d02f8f 100644 --- a/src/Libraries/SmartStore.Services/DataExchange/ExportTask/ExportProfileTask.cs +++ b/src/Libraries/SmartStore.Services/DataExchange/ExportTask/ExportProfileTask.cs @@ -65,7 +65,7 @@ public class ExportProfileTask : ITask private ExpandoHelpers _expandoHelpers; private ICommonServices _services; - private Lazy _exportService; + private Lazy _exportProfileService; private Lazy _dataExchangeSettings; private Lazy _productService; private Lazy _pictureService; @@ -101,7 +101,7 @@ public class ExportProfileTask : ITask private void InitDependencies(TaskExecutionContext context) { _services = context.Resolve(); - _exportService = context.Resolve>(); + _exportProfileService = context.Resolve>(); _dataExchangeSettings = context.Resolve>(); _productService = context.Resolve>(); _pictureService = context.Resolve>(); @@ -2546,7 +2546,7 @@ private void ExportCoreInner(ExportProfileTaskContext ctx, Store store) throw new SmartException("Unsupported entity type '{0}'".FormatInvariant(ctx.Provider.Value.EntityType.ToString())); } - if (segmenter.RecordTotal <= 0) + if (segmenter.TotalRecords <= 0) { ctx.Log.Information("There are no records to export"); } @@ -2735,7 +2735,7 @@ private void ExportCoreOuter(ExportProfileTaskContext ctx) { ctx.Profile.ResultInfo = XmlHelper.Serialize(ctx.Result); - _exportService.Value.UpdateExportProfile(ctx.Profile); + _exportProfileService.Value.UpdateExportProfile(ctx.Profile); } } catch { } @@ -2882,12 +2882,12 @@ public void Execute(TaskExecutionContext taskContext) InitDependencies(taskContext); var profileId = taskContext.ScheduleTask.Alias.ToInt(); - var profile = _exportService.Value.GetExportProfileById(profileId); + var profile = _exportProfileService.Value.GetExportProfileById(profileId); var selectedIdsCacheKey = profile.GetSelectedEntityIdsCacheKey(); var selectedEntityIds = HttpRuntime.Cache[selectedIdsCacheKey] as string; - var provider = _exportService.Value.LoadProvider(profile.ProviderSystemName); + var provider = _exportProfileService.Value.LoadProvider(profile.ProviderSystemName); if (provider == null) throw new SmartException(T("Admin.Common.ProviderNotLoaded", profile.ProviderSystemName.NaIfEmpty())); @@ -2929,13 +2929,13 @@ public ExportExecuteResult Execute( InitDependencies(taskContext); - var provider = _exportService.Value.LoadProvider(providerSystemName); + var provider = _exportProfileService.Value.LoadProvider(providerSystemName); if (provider == null) throw new SmartException(T("Admin.Common.ProviderNotLoaded", providerSystemName.NaIfEmpty())); if (profile == null) - profile = _exportService.Value.CreateVolatileProfile(provider); + profile = _exportProfileService.Value.CreateVolatileProfile(provider); var ctx = new ExportProfileTaskContext(taskContext, profile, provider, selectedEntityIds); ctx.QueryProducts = queryProducts; diff --git a/src/Libraries/SmartStore.Services/DataExchange/IDataExporter.cs b/src/Libraries/SmartStore.Services/DataExchange/IDataExporter.cs new file mode 100644 index 0000000000..a2a31ac863 --- /dev/null +++ b/src/Libraries/SmartStore.Services/DataExchange/IDataExporter.cs @@ -0,0 +1,48 @@ +using SmartStore.Core.Domain; +using SmartStore.Core.Plugins; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading; +using System.Threading.Tasks; + +namespace SmartStore.Services.DataExchange +{ + public delegate void ProgressSetter(int value, int maximum, string message); + + public interface IDataExporter + { + void Export(DataExportRequest request, CancellationToken cancellationToken); + } + + public class DataExportRequest + { + private readonly static ProgressSetter _voidProgressSetter = DataExportRequest.SetProgress; + + public DataExportRequest(ExportProfile profile) + { + Guard.ArgumentNotNull(() => profile); + + CustomData = new Dictionary(StringComparer.OrdinalIgnoreCase); + ProgressSetter = _voidProgressSetter; + Profile = profile; + } + + public ExportProfile Profile { get; private set; } + + public Provider Provider { get; set; } + + public IEnumerable EntitiesToExport { get; set; } + + public ProgressSetter ProgressSetter { get; set; } + + public IDictionary CustomData { get; private set; } + + + private static void SetProgress(int val, int max, string msg) + { + // do nothing + } + } +} diff --git a/src/Libraries/SmartStore.Services/DataExchange/IExportService.cs b/src/Libraries/SmartStore.Services/DataExchange/IExportProfileService.cs similarity index 98% rename from src/Libraries/SmartStore.Services/DataExchange/IExportService.cs rename to src/Libraries/SmartStore.Services/DataExchange/IExportProfileService.cs index e3823a7c4e..92ccb543a5 100644 --- a/src/Libraries/SmartStore.Services/DataExchange/IExportService.cs +++ b/src/Libraries/SmartStore.Services/DataExchange/IExportProfileService.cs @@ -5,7 +5,7 @@ namespace SmartStore.Services.DataExchange { - public interface IExportService + public interface IExportProfileService { /// /// Creates a volatile export profile diff --git a/src/Libraries/SmartStore.Services/DataExchange/Internal/DynamicEntity.cs b/src/Libraries/SmartStore.Services/DataExchange/Internal/DynamicEntity.cs new file mode 100644 index 0000000000..0a098c5055 --- /dev/null +++ b/src/Libraries/SmartStore.Services/DataExchange/Internal/DynamicEntity.cs @@ -0,0 +1,53 @@ +using SmartStore.ComponentModel; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Dynamic; +using SmartStore.Utilities; + +namespace SmartStore.Services.DataExchange.Internal +{ + internal class DynamicEntity : Expando + { + private readonly object _entity; + + public DynamicEntity(object entity) + : base(entity) + { + } + + // TODO: Umbenennen!!! + public object _Entity + { + get { return base.WrappedObject; } + } + + protected override bool TrySetMemberCore(string name, object value) + { + // Virtual navigation properties of entities should not be set as is. + // A previously created ExpandoEntity instance is set instead. + // But assigning the value to the wrapped entity instance would result + // in a type mismatch error, as both types obviously don't match. + // Therefore we save reference values in the local values dictionary. + + var pi = base.GetPropertyInfo(name); + + if (pi != null && (pi.PropertyType.IsPredefinedType() || !pi.GetMethod.IsVirtual)) + { + // Property exists, is NOT complex, or IS complex but NOT virtual + try + { + Fasterflect.PropertyInfoExtensions.Set(pi, WrappedObject, value); + return true; + } + catch { } + } + + // Property does not exist, or is virtual complex + Properties[name] = value; + return true; + } + } +} diff --git a/src/Libraries/SmartStore.Services/DataExchange/Internal/ExpandoEntity.cs b/src/Libraries/SmartStore.Services/DataExchange/Internal/ExpandoEntity.cs deleted file mode 100644 index 565f9e00e5..0000000000 --- a/src/Libraries/SmartStore.Services/DataExchange/Internal/ExpandoEntity.cs +++ /dev/null @@ -1,25 +0,0 @@ -using SmartStore.ComponentModel; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using System.Dynamic; - -namespace SmartStore.Services.DataExchange.Internal -{ - internal class ExpandoEntity : Expando - { - private readonly object _entity; - - public ExpandoEntity(object entity) - : base(entity) - { - } - - public object Entity - { - get { return base.WrappedObject; } - } - } -} diff --git a/src/Libraries/SmartStore.Services/DataExchange/Internal/ExpandoHelpers.cs b/src/Libraries/SmartStore.Services/DataExchange/Internal/ExpandoHelpers.cs index d8da9e6f8c..657a6675ed 100644 --- a/src/Libraries/SmartStore.Services/DataExchange/Internal/ExpandoHelpers.cs +++ b/src/Libraries/SmartStore.Services/DataExchange/Internal/ExpandoHelpers.cs @@ -42,7 +42,7 @@ public dynamic ToExpando(Currency currency) if (currency == null) return null; - dynamic expando = new ExpandoEntity(currency); + dynamic expando = new DynamicEntity(currency); expando.Name = currency.GetLocalized(x => x.Name, _ctx.Projection.LanguageId ?? 0, true, false); expando._Localized = GetLocalized(currency, x => x.Name); @@ -54,7 +54,7 @@ private dynamic ToExpando(Language language) if (language == null) return null; - dynamic expando = new ExpandoEntity(language); + dynamic expando = new DynamicEntity(language); return expando; } @@ -63,7 +63,7 @@ private dynamic ToExpando(Country country) if (country == null) return null; - dynamic expando = new ExpandoEntity(country); + dynamic expando = new DynamicEntity(country); expando.Name = country.GetLocalized(x => x.Name, _ctx.Projection.LanguageId ?? 0, true, false); expando._Localized = GetLocalized(country, x => x.Name); @@ -75,12 +75,12 @@ private dynamic ToExpando(Address address) if (address == null) return null; - dynamic expando = new ExpandoEntity(address); + dynamic expando = new DynamicEntity(address); expando.Country = ToExpando(address.Country); if (address.StateProvinceId.GetValueOrDefault() > 0) { - dynamic sp = new ExpandoEntity(address.StateProvince); + dynamic sp = new DynamicEntity(address.StateProvince); sp.Name = address.StateProvince.GetLocalized(x => x.Name, _ctx.Projection.LanguageId ?? 0, true, false); sp._Localized = GetLocalized(address.StateProvince, x => x.Name); expando.StateProvince = sp; @@ -98,7 +98,7 @@ private dynamic ToExpando(RewardPointsHistory points) if (points == null) return null; - dynamic expando = new ExpandoEntity(points); + dynamic expando = new DynamicEntity(points); return expando; } @@ -107,7 +107,7 @@ private dynamic ToExpando( Customer customer) if (customer == null) return null; - dynamic expando = new ExpandoEntity(customer); + dynamic expando = new DynamicEntity(customer); expando.BillingAddress = null; expando.ShippingAddress = null; @@ -128,7 +128,7 @@ private dynamic ToExpando(Store store) if (store == null) return null; - dynamic expando = new ExpandoEntity(store); + dynamic expando = new DynamicEntity(store); expando.PrimaryStoreCurrency = ToExpando(store.PrimaryStoreCurrency); expando.PrimaryExchangeRateCurrency = ToExpando(store.PrimaryExchangeRateCurrency); @@ -140,7 +140,7 @@ private dynamic ToExpando(DeliveryTime deliveryTime) if (deliveryTime == null) return null; - dynamic expando = new ExpandoEntity(deliveryTime); + dynamic expando = new DynamicEntity(deliveryTime); expando.Name = deliveryTime.GetLocalized(x => x.Name, _ctx.Projection.LanguageId ?? 0, true, false); expando._Localized = GetLocalized(deliveryTime, x => x.Name); @@ -152,7 +152,7 @@ private dynamic ToExpando(QuantityUnit quantityUnit) if (quantityUnit == null) return null; - dynamic expando = new ExpandoEntity(quantityUnit); + dynamic expando = new DynamicEntity(quantityUnit); expando.Name = quantityUnit.GetLocalized(x => x.Name, _ctx.Projection.LanguageId ?? 0, true, false); expando.Description = quantityUnit.GetLocalized(x => x.Description, _ctx.Projection.LanguageId ?? 0, true, false); expando._Localized = GetLocalized(quantityUnit, @@ -167,7 +167,7 @@ private dynamic ToExpando(Picture picture, int thumbPictureSize, int detailsPict if (picture == null) return null; - dynamic expando = new ExpandoEntity(picture); + dynamic expando = new DynamicEntity(picture); //// TODO!!!!! //expando._ThumbImageUrl = _pictureService.Value.GetPictureUrl(picture, thumbPictureSize, false, _ctx.Store.Url); diff --git a/src/Libraries/SmartStore.Services/SmartStore.Services.csproj b/src/Libraries/SmartStore.Services/SmartStore.Services.csproj index b5d926c04e..a6af2b2012 100644 --- a/src/Libraries/SmartStore.Services/SmartStore.Services.csproj +++ b/src/Libraries/SmartStore.Services/SmartStore.Services.csproj @@ -185,7 +185,8 @@ - + + @@ -198,9 +199,9 @@ - + - + diff --git a/src/Libraries/SmartStore.Services/Tasks/TaskExecutionContext.cs b/src/Libraries/SmartStore.Services/Tasks/TaskExecutionContext.cs index f18a23e6ca..838065d364 100644 --- a/src/Libraries/SmartStore.Services/Tasks/TaskExecutionContext.cs +++ b/src/Libraries/SmartStore.Services/Tasks/TaskExecutionContext.cs @@ -45,6 +45,21 @@ public T ResolveNamed(string name) where T : class public ScheduleTask ScheduleTask { get; set; } + /// + /// Persists a task's progress information to the database + /// + /// Progress value (numerator) + /// Progress maximum (denominator) + /// Progress message. Can be null. + /// if true, saves the updated task entity immediately, or lazily with the next database commit otherwise. + public void SetProgress(int value, int maximum, string message, bool immediately = false) + { + float fraction = (float)value / (float)Math.Max(maximum, 1f); + int percentage = (int)Math.Round(fraction * 100f, 0); + + SetProgress(Math.Min(Math.Max(percentage, 0), 100), message, immediately); + } + /// /// Persists a task's progress information to the database /// @@ -75,20 +90,5 @@ public void SetProgress(int? progress, string message, bool immediately = false catch { } } } - - /// - /// Persists a task's progress information to the database - /// - /// Progress numerator - /// Progress denominator - /// Progress message. Can be null. - /// if true, saves the updated task entity immediately, or lazily with the next database commit otherwise. - public void SetProgress(int numerator, int denominator, string message, bool immediately = false) - { - float fraction = (float)numerator / (float)Math.Max(denominator, 1f); - int percentage = (int)Math.Round(fraction * 100f, 0); - - SetProgress(Math.Min(Math.Max(percentage, 0), 100), message, immediately); - } } } diff --git a/src/Plugins/SmartStore.GoogleMerchantCenter/Controllers/FeedGoogleMerchantCenterController.cs b/src/Plugins/SmartStore.GoogleMerchantCenter/Controllers/FeedGoogleMerchantCenterController.cs index 86eb437175..7a310a4c18 100644 --- a/src/Plugins/SmartStore.GoogleMerchantCenter/Controllers/FeedGoogleMerchantCenterController.cs +++ b/src/Plugins/SmartStore.GoogleMerchantCenter/Controllers/FeedGoogleMerchantCenterController.cs @@ -18,12 +18,12 @@ public class FeedGoogleMerchantCenterController : PluginControllerBase { private readonly IGoogleFeedService _googleFeedService; private readonly AdminAreaSettings _adminAreaSettings; - private readonly IExportService _exportService; + private readonly IExportProfileService _exportService; public FeedGoogleMerchantCenterController( IGoogleFeedService googleFeedService, AdminAreaSettings adminAreaSettings, - IExportService exportService) + IExportProfileService exportService) { _googleFeedService = googleFeedService; _adminAreaSettings = adminAreaSettings; @@ -61,7 +61,7 @@ public ActionResult ProductEditTab(int productId) ViewBag.DefaultAgeGroup = T("Common.Auto"); // we do not have export profile context here, so we simply use the first profile - var profile = _exportService.GetExportProfilesBySystemName(ProductExportXmlProvider.SystemName).FirstOrDefault(); + var profile = _exportService.GetExportProfilesBySystemName(GmcExportXmlProvider.SystemName).FirstOrDefault(); if (profile != null) { var config = XmlHelper.Deserialize(profile.ProviderConfigData, typeof(ProfileConfigurationModel)) as ProfileConfigurationModel; @@ -73,12 +73,12 @@ public ActionResult ProductEditTab(int productId) ViewBag.DefaultMaterial = config.Material; ViewBag.DefaultPattern = config.Pattern; - if (config.Gender.HasValue() && config.Gender != ProductExportXmlProvider.Unspecified) + if (config.Gender.HasValue() && config.Gender != GmcExportXmlProvider.Unspecified) { ViewBag.DefaultGender = T("Plugins.Feed.Froogle.Gender" + culture.TextInfo.ToTitleCase(config.Gender)); } - if (config.AgeGroup.HasValue() && config.AgeGroup != ProductExportXmlProvider.Unspecified) + if (config.AgeGroup.HasValue() && config.AgeGroup != GmcExportXmlProvider.Unspecified) { ViewBag.DefaultAgeGroup = T("Plugins.Feed.Froogle.AgeGroup" + culture.TextInfo.ToTitleCase(config.AgeGroup)); } diff --git a/src/Plugins/SmartStore.GoogleMerchantCenter/Providers/ProductExportXmlProvider.cs b/src/Plugins/SmartStore.GoogleMerchantCenter/Providers/GmcExportXmlProvider.cs similarity index 99% rename from src/Plugins/SmartStore.GoogleMerchantCenter/Providers/ProductExportXmlProvider.cs rename to src/Plugins/SmartStore.GoogleMerchantCenter/Providers/GmcExportXmlProvider.cs index bbcb1bcbda..412737afc7 100644 --- a/src/Plugins/SmartStore.GoogleMerchantCenter/Providers/ProductExportXmlProvider.cs +++ b/src/Plugins/SmartStore.GoogleMerchantCenter/Providers/GmcExportXmlProvider.cs @@ -28,7 +28,7 @@ namespace SmartStore.GoogleMerchantCenter.Providers ExportFeatures.OffersBrandFallback, ExportFeatures.CanIncludeMainPicture, ExportFeatures.UsesSpecialPrice)] - public class ProductExportXmlProvider : IExportProvider + public class GmcExportXmlProvider : IExportProvider { private const string _googleNamespace = "http://base.google.com/ns/1.0"; @@ -36,7 +36,7 @@ public class ProductExportXmlProvider : IExportProvider private readonly IMeasureService _measureService; private readonly MeasureSettings _measureSettings; - public ProductExportXmlProvider( + public GmcExportXmlProvider( IGoogleFeedService googleFeedService, IMeasureService measureService, MeasureSettings measureSettings) diff --git a/src/Plugins/SmartStore.GoogleMerchantCenter/SmartStore.GoogleMerchantCenter.csproj b/src/Plugins/SmartStore.GoogleMerchantCenter/SmartStore.GoogleMerchantCenter.csproj index e571790b5d..0826ad5831 100644 --- a/src/Plugins/SmartStore.GoogleMerchantCenter/SmartStore.GoogleMerchantCenter.csproj +++ b/src/Plugins/SmartStore.GoogleMerchantCenter/SmartStore.GoogleMerchantCenter.csproj @@ -42,6 +42,7 @@ + true @@ -175,7 +176,7 @@ - + diff --git a/src/Presentation/SmartStore.Web.Framework/DependencyRegistrar.cs b/src/Presentation/SmartStore.Web.Framework/DependencyRegistrar.cs index ee70cae011..1daa71bd03 100644 --- a/src/Presentation/SmartStore.Web.Framework/DependencyRegistrar.cs +++ b/src/Presentation/SmartStore.Web.Framework/DependencyRegistrar.cs @@ -221,7 +221,7 @@ public virtual void Register(ContainerBuilder builder, ITypeFinder typeFinder, b builder.RegisterType().As().InstancePerRequest(); builder.RegisterType().As().InstancePerRequest(); - builder.RegisterType().As().InstancePerRequest(); + builder.RegisterType().As().InstancePerRequest(); builder.RegisterType().As().InstancePerRequest(); builder.RegisterType().As().InstancePerRequest(); diff --git a/src/Presentation/SmartStore.Web/Administration/Controllers/ExportController.cs b/src/Presentation/SmartStore.Web/Administration/Controllers/ExportController.cs index 33d35d9fbb..a244d1f807 100644 --- a/src/Presentation/SmartStore.Web/Administration/Controllers/ExportController.cs +++ b/src/Presentation/SmartStore.Web/Administration/Controllers/ExportController.cs @@ -38,7 +38,7 @@ namespace SmartStore.Admin.Controllers public class ExportController : AdminControllerBase { private readonly ICommonServices _services; - private readonly IExportService _exportService; + private readonly IExportProfileService _exportService; private readonly PluginMediator _pluginMediator; private readonly ICategoryService _categoryService; private readonly IManufacturerService _manufacturerService; @@ -53,7 +53,7 @@ public class ExportController : AdminControllerBase public ExportController( ICommonServices services, - IExportService exportService, + IExportProfileService exportService, PluginMediator pluginMediator, ICategoryService categoryService, IManufacturerService manufacturerService, From cdfb6aad69170a0abd3592945b7c5858919578ae Mon Sep 17 00:00:00 2001 From: Murat Cakir Date: Fri, 6 Nov 2015 03:14:13 +0100 Subject: [PATCH 010/707] Export framework: further refactoring --- .../{Expando.cs => HybridExpando.cs} | 146 ++++++- .../SmartStore.Core/SmartStore.Core.csproj | 2 +- .../ExportTask/ExportProfileTask.cs | 380 +++++++----------- .../DataExchange/Internal/DynamicEntity.cs | 15 +- .../DataExchange/Internal/ExpandoHelpers.cs | 240 ----------- .../SmartStore.Services.csproj | 5 +- .../Tasks/ITaskExecutor.cs | 6 +- .../Tasks/ITaskScheduler.cs | 3 +- .../Tasks/TaskExecutionContext.cs | 3 + .../SmartStore.Services/Tasks/TaskExecutor.cs | 9 +- .../Tasks/TaskScheduler.cs | 14 +- .../Controllers/TaskSchedulerController.cs | 6 +- 12 files changed, 325 insertions(+), 504 deletions(-) rename src/Libraries/SmartStore.Core/ComponentModel/{Expando.cs => HybridExpando.cs} (80%) delete mode 100644 src/Libraries/SmartStore.Services/DataExchange/Internal/ExpandoHelpers.cs diff --git a/src/Libraries/SmartStore.Core/ComponentModel/Expando.cs b/src/Libraries/SmartStore.Core/ComponentModel/HybridExpando.cs similarity index 80% rename from src/Libraries/SmartStore.Core/ComponentModel/Expando.cs rename to src/Libraries/SmartStore.Core/ComponentModel/HybridExpando.cs index c97e82ed75..42061fad53 100644 --- a/src/Libraries/SmartStore.Core/ComponentModel/Expando.cs +++ b/src/Libraries/SmartStore.Core/ComponentModel/HybridExpando.cs @@ -36,6 +36,7 @@ using System.Linq; using System.Dynamic; using System.Reflection; +using System.Collections; namespace SmartStore.ComponentModel { @@ -58,7 +59,7 @@ namespace SmartStore.ComponentModel /// Dictionary: Any of the extended properties are accessible via IDictionary interface /// [Serializable] - public class Expando : DynamicObject + public class HybridExpando : DynamicObject, IDictionary { /// /// Instance of object passed in @@ -85,7 +86,7 @@ public class Expando : DynamicObject /// /// Note you can subclass Expando. /// - public Expando() + public HybridExpando() { Initialize(this); } @@ -98,7 +99,7 @@ public Expando() /// check native properties and only check the Dictionary! /// /// - public Expando(object instance) + public HybridExpando(object instance) { Initialize(instance); } @@ -120,12 +121,12 @@ IList InstancePropertyInfos get { if (_instancePropertyInfos == null && _instance != null) - _instancePropertyInfos = Fasterflect.PropertyExtensions.Properties(_instance.GetType(), Fasterflect.Flags.InstancePublicDeclaredOnly); + _instancePropertyInfos = Fasterflect.PropertyExtensions.Properties(_instanceType, Fasterflect.Flags.InstancePublic); return _instancePropertyInfos; } } - public override IEnumerable GetDynamicMemberNames() + public override IEnumerable GetDynamicMemberNames() { foreach (var prop in this.GetProperties(false)) yield return prop.Key; @@ -344,15 +345,22 @@ public object this[string key] /// public IEnumerable> GetProperties(bool includeInstanceProperties = false) { - if (includeInstanceProperties && _instance != null) + foreach (var key in this.Properties.Keys) + { + yield return new KeyValuePair(key, this.Properties[key]); + } + + if (includeInstanceProperties && _instance != null) { foreach (var prop in this.InstancePropertyInfos) - yield return new KeyValuePair(prop.Name, prop.GetValue(_instance, null)); + { + if (!this.Properties.ContainsKey(prop.Name)) + { + yield return new KeyValuePair(prop.Name, prop.GetValue(_instance, null)); + } + } } - foreach (var key in this.Properties.Keys) - yield return new KeyValuePair(key, this.Properties[key]); - } /// @@ -391,18 +399,116 @@ public bool Contains(string propertyName, bool includeInstanceProperties = false return false; } - public bool TryGetValue(string propertyName, out object value) - { - value = null; + #region IDictionary - if (this.Contains(propertyName, true)) - { - value = this[propertyName]; - return true; - } + ICollection IDictionary.Keys + { + get + { + return GetProperties(true).Select(x => x.Key).AsReadOnly(); + } + } - return false; + ICollection IDictionary.Values + { + get + { + return GetProperties(true).Select(x => x.Value).AsReadOnly(); + } + } + + int ICollection>.Count + { + get + { + return Properties.Count + InstancePropertyInfos.Count; + } + } + + bool ICollection>.IsReadOnly + { + get + { + return false; + } + } + + object IDictionary.this[string key] + { + get + { + return this[key]; + } + + set + { + this[key] = value; + } + } + + bool IDictionary.ContainsKey(string key) + { + return Contains(key, true); + } + + void IDictionary.Add(string key, object value) + { + throw new NotImplementedException(); + } + + bool IDictionary.Remove(string key) + { + throw new NotImplementedException(); + } + + public bool TryGetValue(string key, out object value) + { + value = null; + + if (this.Contains(key, true)) + { + value = this[key]; + return true; + } + + return false; + } + + void ICollection>.Add(KeyValuePair item) + { + throw new NotImplementedException(); + } + + void ICollection>.Clear() + { + throw new NotImplementedException(); + } + + bool ICollection>.Contains(KeyValuePair item) + { + return Contains(item.Key, true); + } + + void ICollection>.CopyTo(KeyValuePair[] array, int arrayIndex) + { + throw new NotImplementedException(); + } + + bool ICollection>.Remove(KeyValuePair item) + { + throw new NotImplementedException(); + } + + IEnumerator> IEnumerable>.GetEnumerator() + { + return GetProperties(true).GetEnumerator(); } - } + IEnumerator IEnumerable.GetEnumerator() + { + return GetProperties(true).GetEnumerator(); + } + + #endregion + } } \ No newline at end of file diff --git a/src/Libraries/SmartStore.Core/SmartStore.Core.csproj b/src/Libraries/SmartStore.Core/SmartStore.Core.csproj index afe41e0061..b23a0d7b0f 100644 --- a/src/Libraries/SmartStore.Core/SmartStore.Core.csproj +++ b/src/Libraries/SmartStore.Core/SmartStore.Core.csproj @@ -303,7 +303,7 @@ - + diff --git a/src/Libraries/SmartStore.Services/DataExchange/ExportTask/ExportProfileTask.cs b/src/Libraries/SmartStore.Services/DataExchange/ExportTask/ExportProfileTask.cs index e4e9d02f8f..7e8b6e66c7 100644 --- a/src/Libraries/SmartStore.Services/DataExchange/ExportTask/ExportProfileTask.cs +++ b/src/Libraries/SmartStore.Services/DataExchange/ExportTask/ExportProfileTask.cs @@ -63,7 +63,6 @@ public class ExportProfileTask : ITask #region Dependencies - private ExpandoHelpers _expandoHelpers; private ICommonServices _services; private Lazy _exportProfileService; private Lazy _dataExchangeSettings; @@ -727,22 +726,8 @@ private dynamic ToExpando(ExportProfileTaskContext ctx, Currency currency) if (currency == null) return null; - dynamic expando = new ExpandoObject(); - expando._Entity = currency; - - expando.Id = currency.Id; + dynamic expando = new DynamicEntity(currency); expando.Name = currency.GetLocalized(x => x.Name, ctx.Projection.LanguageId ?? 0, true, false); - expando.CurrencyCode = currency.CurrencyCode; - expando.Rate = currency.Rate; - expando.DisplayLocale = currency.DisplayLocale; - expando.CustomFormatting = currency.CustomFormatting; - expando.LimitedToStores = currency.LimitedToStores; - expando.Published = currency.Published; - expando.DisplayOrder = currency.DisplayOrder; - expando.CreatedOnUtc = currency.CreatedOnUtc; - expando.UpdatedOnUtc = currency.UpdatedOnUtc; - expando.DomainEndings = currency.DomainEndings; - expando._Localized = GetLocalized(ctx, currency, x => x.Name); return expando; @@ -753,19 +738,7 @@ private dynamic ToExpando(ExportProfileTaskContext ctx, Language language) if (language == null) return null; - dynamic expando = new ExpandoObject(); - expando._Entity = language; - - expando.Id = language.Id; - expando.Name = language.Name; - expando.LanguageCulture = language.LanguageCulture; - expando.UniqueSeoCode = language.UniqueSeoCode; - expando.FlagImageFileName = language.FlagImageFileName; - expando.Rtl = language.Rtl; - expando.LimitedToStores = language.LimitedToStores; - expando.Published = language.Published; - expando.DisplayOrder = language.DisplayOrder; - + dynamic expando = new DynamicEntity(language); return expando; } @@ -774,21 +747,8 @@ private dynamic ToExpando(ExportProfileTaskContext ctx, Country country) if (country == null) return null; - dynamic expando = new ExpandoObject(); - expando._Entity = country; - - expando.Id = country.Id; + dynamic expando = new DynamicEntity(country); expando.Name = country.GetLocalized(x => x.Name, ctx.Projection.LanguageId ?? 0, true, false); - expando.AllowsBilling = country.AllowsBilling; - expando.AllowsShipping = country.AllowsShipping; - expando.TwoLetterIsoCode = country.TwoLetterIsoCode; - expando.ThreeLetterIsoCode = country.ThreeLetterIsoCode; - expando.NumericIsoCode = country.NumericIsoCode; - expando.SubjectToVat = country.SubjectToVat; - expando.Published = country.Published; - expando.DisplayOrder = country.DisplayOrder; - expando.LimitedToStores = country.LimitedToStores; - expando._Localized = GetLocalized(ctx, country, x => x.Name); return expando; @@ -799,39 +759,14 @@ private dynamic ToExpando(ExportProfileTaskContext ctx, Address address) if (address == null) return null; - dynamic expando = new ExpandoObject(); - expando._Entity = address; - - expando.Id = address.Id; - expando.FirstName = address.FirstName; - expando.LastName = address.LastName; - expando.Email = address.Email; - expando.Company = address.Company; - expando.CountryId = address.CountryId; - expando.StateProvinceId = address.StateProvinceId; - expando.City = address.City; - expando.Address1 = address.Address1; - expando.Address2 = address.Address2; - expando.ZipPostalCode = address.ZipPostalCode; - expando.PhoneNumber = address.PhoneNumber; - expando.FaxNumber = address.FaxNumber; - expando.CreatedOnUtc = address.CreatedOnUtc; - + dynamic expando = new DynamicEntity(address); expando.Country = ToExpando(ctx, address.Country); - if (address.StateProvince != null) + if (address.StateProvinceId.GetValueOrDefault() > 0) { - dynamic sp = new ExpandoObject(); - sp._Entity = address.StateProvince; - sp.Id = address.StateProvince.Id; - sp.CountryId = address.StateProvince.CountryId; + dynamic sp = new DynamicEntity(address.StateProvince); sp.Name = address.StateProvince.GetLocalized(x => x.Name, ctx.Projection.LanguageId ?? 0, true, false); - sp.Abbreviation = address.StateProvince.Abbreviation; - sp.Published = address.StateProvince.Published; - sp.DisplayOrder = address.StateProvince.DisplayOrder; - sp._Localized = GetLocalized(ctx, address.StateProvince, x => x.Name); - expando.StateProvince = sp; } else @@ -1053,25 +988,7 @@ private dynamic ToExpando(ExportProfileTaskContext ctx, ProductVariantAttributeC if (pvac == null) return null; - dynamic expando = new ExpandoObject(); - expando._Entity = pvac; - - expando.Id = pvac.Id; - expando.StockQuantity = pvac.StockQuantity; - expando.AllowOutOfStockOrders = pvac.AllowOutOfStockOrders; - expando.AttributesXml = pvac.AttributesXml; - expando.Sku = pvac.Sku; - expando.Gtin = pvac.Gtin; - expando.ManufacturerPartNumber = pvac.ManufacturerPartNumber; - expando.Price = pvac.Price; - expando.Length = pvac.Length; - expando.Width = pvac.Width; - expando.Height = pvac.Height; - expando.BasePriceAmount = pvac.BasePriceAmount; - expando.BasePriceBaseAmount = pvac.BasePriceBaseAmount; - expando.AssignedPictureIds = pvac.AssignedPictureIds; - expando.DeliveryTimeId = pvac.DeliveryTimeId; - expando.IsActive = pvac.IsActive; + dynamic expando = new DynamicEntity(pvac); GetDeliveryTimeAndQuantityUnit(ctx, expando, pvac.DeliveryTimeId, pvac.QuantityUnitId); @@ -1083,27 +1000,13 @@ private dynamic ToExpando(ExportProfileTaskContext ctx, Manufacturer manufacture if (manufacturer == null) return null; - dynamic expando = new ExpandoObject(); - expando._Entity = manufacturer; - - expando.Id = manufacturer.Id; + dynamic expando = new DynamicEntity(manufacturer); expando.Name = manufacturer.GetLocalized(x => x.Name, ctx.Projection.LanguageId ?? 0, true, false); expando.SeName = manufacturer.GetSeName(ctx.Projection.LanguageId ?? 0, true, false); expando.Description = manufacturer.GetLocalized(x => x.Description, ctx.Projection.LanguageId ?? 0, true, false); - expando.ManufacturerTemplateId = manufacturer.ManufacturerTemplateId; expando.MetaKeywords = manufacturer.GetLocalized(x => x.MetaKeywords, ctx.Projection.LanguageId ?? 0, true, false); expando.MetaDescription = manufacturer.GetLocalized(x => x.MetaDescription, ctx.Projection.LanguageId ?? 0, true, false); expando.MetaTitle = manufacturer.GetLocalized(x => x.MetaTitle, ctx.Projection.LanguageId ?? 0, true, false); - expando.PictureId = manufacturer.PictureId; - expando.PageSize = manufacturer.PageSize; - expando.AllowCustomersToSelectPageSize = manufacturer.AllowCustomersToSelectPageSize; - expando.PageSizeOptions = manufacturer.PageSizeOptions; - expando.PriceRanges = manufacturer.PriceRanges; - expando.Published = manufacturer.Published; - expando.Deleted = manufacturer.Deleted; - expando.DisplayOrder = manufacturer.DisplayOrder; - expando.CreatedOnUtc = manufacturer.CreatedOnUtc; - expando.UpdatedOnUtc = manufacturer.UpdatedOnUtc; expando.Picture = null; @@ -1122,36 +1025,15 @@ private dynamic ToExpando(ExportProfileTaskContext ctx, Category category) if (category == null) return null; - dynamic expando = new ExpandoObject(); - expando._Entity = category; - - expando.Id = category.Id; + dynamic expando = new DynamicEntity(category); expando.Name = category.GetLocalized(x => x.Name, ctx.Projection.LanguageId ?? 0, true, false); expando.SeName = category.GetSeName(ctx.Projection.LanguageId ?? 0, true, false); expando.FullName = category.GetLocalized(x => x.FullName, ctx.Projection.LanguageId ?? 0, true, false); expando.Description = category.GetLocalized(x => x.Description, ctx.Projection.LanguageId ?? 0, true, false); expando.BottomDescription = category.GetLocalized(x => x.BottomDescription, ctx.Projection.LanguageId ?? 0, true, false); - expando.CategoryTemplateId = category.CategoryTemplateId; expando.MetaKeywords = category.GetLocalized(x => x.MetaKeywords, ctx.Projection.LanguageId ?? 0, true, false); expando.MetaDescription = category.GetLocalized(x => x.MetaDescription, ctx.Projection.LanguageId ?? 0, true, false); expando.MetaTitle = category.GetLocalized(x => x.MetaTitle, ctx.Projection.LanguageId ?? 0, true, false); - expando.ParentCategoryId = category.ParentCategoryId; - expando.PictureId = category.PictureId; - expando.PageSize = category.PageSize; - expando.AllowCustomersToSelectPageSize = category.AllowCustomersToSelectPageSize; - expando.PageSizeOptions = category.PageSizeOptions; - expando.PriceRanges = category.PriceRanges; - expando.ShowOnHomePage = category.ShowOnHomePage; - expando.HasDiscountsApplied = category.HasDiscountsApplied; - expando.Published = category.Published; - expando.Deleted = category.Deleted; - expando.DisplayOrder = category.DisplayOrder; - expando.CreatedOnUtc = category.CreatedOnUtc; - expando.UpdatedOnUtc = category.UpdatedOnUtc; - expando.SubjectToAcl = category.SubjectToAcl; - expando.LimitedToStores = category.LimitedToStores; - expando.Alias = category.Alias; - expando.DefaultViewMode = category.DefaultViewMode; expando.Picture = null; @@ -1172,111 +1054,18 @@ private dynamic ToExpando(ExportProfileTaskContext ctx, Product product) if (product == null) return null; - dynamic expando = new ExpandoObject(); - expando._Entity = product; + dynamic expando = new DynamicEntity(product); - expando.Id = product.Id; - expando.ProductTypeId = product.ProductTypeId; - expando.ParentGroupedProductId = product.ParentGroupedProductId; - expando.VisibleIndividually = product.VisibleIndividually; expando.Name = product.GetLocalized(x => x.Name, ctx.Projection.LanguageId ?? 0, true, false); expando.SeName = product.GetSeName(ctx.Projection.LanguageId ?? 0, true, false); expando.ShortDescription = product.GetLocalized(x => x.ShortDescription, ctx.Projection.LanguageId ?? 0, true, false); expando.FullDescription = product.GetLocalized(x => x.FullDescription, ctx.Projection.LanguageId ?? 0, true, false); - expando.AdminComment = product.AdminComment; - expando.ProductTemplateId = product.ProductTemplateId; - expando.ShowOnHomePage = product.ShowOnHomePage; - expando.HomePageDisplayOrder = product.HomePageDisplayOrder; expando.MetaKeywords = product.GetLocalized(x => x.MetaKeywords, ctx.Projection.LanguageId ?? 0, true, false); expando.MetaDescription = product.GetLocalized(x => x.MetaDescription, ctx.Projection.LanguageId ?? 0, true, false); expando.MetaTitle = product.GetLocalized(x => x.MetaTitle, ctx.Projection.LanguageId ?? 0, true, false); - expando.AllowCustomerReviews = product.AllowCustomerReviews; - expando.ApprovedRatingSum = product.ApprovedRatingSum; - expando.NotApprovedRatingSum = product.NotApprovedRatingSum; - expando.ApprovedTotalReviews = product.ApprovedTotalReviews; - expando.NotApprovedTotalReviews = product.NotApprovedTotalReviews; - expando.SubjectToAcl = product.SubjectToAcl; - expando.LimitedToStores = product.LimitedToStores; - expando.Sku = product.Sku; - expando.ManufacturerPartNumber = product.ManufacturerPartNumber; - expando.Gtin = product.Gtin; - expando.IsGiftCard = product.IsGiftCard; - expando.GiftCardTypeId = product.GiftCardTypeId; - expando.RequireOtherProducts = product.RequireOtherProducts; - expando.RequiredProductIds = product.RequiredProductIds; - expando.AutomaticallyAddRequiredProducts = product.AutomaticallyAddRequiredProducts; - expando.IsDownload = product.IsDownload; - expando.DownloadId = product.DownloadId; - expando.UnlimitedDownloads = product.UnlimitedDownloads; - expando.MaxNumberOfDownloads = product.MaxNumberOfDownloads; - expando.DownloadExpirationDays = product.DownloadExpirationDays; - expando.DownloadActivationTypeId = product.DownloadActivationTypeId; - expando.HasSampleDownload = product.HasSampleDownload; - expando.SampleDownloadId = product.SampleDownloadId; - expando.HasUserAgreement = product.HasUserAgreement; - expando.UserAgreementText = product.UserAgreementText; - expando.IsRecurring = product.IsRecurring; - expando.RecurringCycleLength = product.RecurringCycleLength; - expando.RecurringCyclePeriodId = product.RecurringCyclePeriodId; - expando.RecurringTotalCycles = product.RecurringTotalCycles; - expando.IsShipEnabled = product.IsShipEnabled; - expando.IsFreeShipping = product.IsFreeShipping; - expando.AdditionalShippingCharge = product.AdditionalShippingCharge; - expando.IsTaxExempt = product.IsTaxExempt; - expando.IsEsd = product.IsEsd; - expando.TaxCategoryId = product.TaxCategoryId; - expando.ManageInventoryMethodId = product.ManageInventoryMethodId; - expando.StockQuantity = product.StockQuantity; - expando.DisplayStockAvailability = product.DisplayStockAvailability; - expando.DisplayStockQuantity = product.DisplayStockQuantity; - expando.MinStockQuantity = product.MinStockQuantity; - expando.LowStockActivityId = product.LowStockActivityId; - expando.NotifyAdminForQuantityBelow = product.NotifyAdminForQuantityBelow; - expando.BackorderModeId = product.BackorderModeId; - expando.AllowBackInStockSubscriptions = product.AllowBackInStockSubscriptions; - expando.OrderMinimumQuantity = product.OrderMinimumQuantity; - expando.OrderMaximumQuantity = product.OrderMaximumQuantity; - expando.AllowedQuantities = product.AllowedQuantities; - expando.DisableBuyButton = product.DisableBuyButton; - expando.DisableWishlistButton = product.DisableWishlistButton; - expando.AvailableForPreOrder = product.AvailableForPreOrder; - expando.CallForPrice = product.CallForPrice; - expando.Price = product.Price; - expando.OldPrice = product.OldPrice; - expando.ProductCost = product.ProductCost; - expando.SpecialPrice = product.SpecialPrice; - expando.SpecialPriceStartDateTimeUtc = product.SpecialPriceStartDateTimeUtc; - expando.SpecialPriceEndDateTimeUtc = product.SpecialPriceEndDateTimeUtc; - expando.CustomerEntersPrice = product.CustomerEntersPrice; - expando.MinimumCustomerEnteredPrice = product.MinimumCustomerEnteredPrice; - expando.MaximumCustomerEnteredPrice = product.MaximumCustomerEnteredPrice; - expando.HasTierPrices = product.HasTierPrices; - expando.LowestAttributeCombinationPrice = product.LowestAttributeCombinationPrice; - expando.HasDiscountsApplied = product.HasDiscountsApplied; - expando.Weight = product.Weight; - expando.Length = product.Length; - expando.Width = product.Width; - expando.Height = product.Height; - expando.AvailableStartDateTimeUtc = product.AvailableStartDateTimeUtc; - expando.AvailableEndDateTimeUtc = product.AvailableEndDateTimeUtc; - expando.DisplayOrder = product.DisplayOrder; - expando.Published = product.Published; - expando.Deleted = product.Deleted; - expando.CreatedOnUtc = product.CreatedOnUtc; - expando.UpdatedOnUtc = product.UpdatedOnUtc; - expando.DeliveryTimeId = product.DeliveryTimeId; - expando.QuantityUnitId = product.QuantityUnitId; - expando.BasePriceEnabled = product.BasePriceEnabled; - expando.BasePriceMeasureUnit = product.BasePriceMeasureUnit; - expando.BasePriceAmount = product.BasePriceAmount; - expando.BasePriceBaseAmount = product.BasePriceBaseAmount; - expando.BasePriceHasValue = product.BasePriceHasValue; expando.BundleTitleText = product.GetLocalized(x => x.BundleTitleText, ctx.Projection.LanguageId ?? 0, true, false); - expando.BundlePerItemShipping = product.BundlePerItemShipping; - expando.BundlePerItemPricing = product.BundlePerItemPricing; - expando.BundlePerItemShoppingCart = product.BundlePerItemShoppingCart; - - expando.AppliedDiscounts = null; + + expando.AppliedDiscounts = null; expando.TierPrices = null; expando.ProductAttributes = null; expando.ProductAttributeCombinations = null; @@ -1299,6 +1088,138 @@ private dynamic ToExpando(ExportProfileTaskContext ctx, Product product) return expando; } + //private dynamic ToExpando(ExportProfileTaskContext ctx, Product product) + //{ + // if (product == null) + // return null; + + // dynamic expando = new ExpandoObject(); + // expando._Entity = product; + + // expando.Id = product.Id; + // expando.ProductTypeId = product.ProductTypeId; + // expando.ParentGroupedProductId = product.ParentGroupedProductId; + // expando.VisibleIndividually = product.VisibleIndividually; + // expando.Name = product.GetLocalized(x => x.Name, ctx.Projection.LanguageId ?? 0, true, false); + // expando.SeName = product.GetSeName(ctx.Projection.LanguageId ?? 0, true, false); + // expando.ShortDescription = product.GetLocalized(x => x.ShortDescription, ctx.Projection.LanguageId ?? 0, true, false); + // expando.FullDescription = product.GetLocalized(x => x.FullDescription, ctx.Projection.LanguageId ?? 0, true, false); + // expando.AdminComment = product.AdminComment; + // expando.ProductTemplateId = product.ProductTemplateId; + // expando.ShowOnHomePage = product.ShowOnHomePage; + // expando.HomePageDisplayOrder = product.HomePageDisplayOrder; + // expando.MetaKeywords = product.GetLocalized(x => x.MetaKeywords, ctx.Projection.LanguageId ?? 0, true, false); + // expando.MetaDescription = product.GetLocalized(x => x.MetaDescription, ctx.Projection.LanguageId ?? 0, true, false); + // expando.MetaTitle = product.GetLocalized(x => x.MetaTitle, ctx.Projection.LanguageId ?? 0, true, false); + // expando.AllowCustomerReviews = product.AllowCustomerReviews; + // expando.ApprovedRatingSum = product.ApprovedRatingSum; + // expando.NotApprovedRatingSum = product.NotApprovedRatingSum; + // expando.ApprovedTotalReviews = product.ApprovedTotalReviews; + // expando.NotApprovedTotalReviews = product.NotApprovedTotalReviews; + // expando.SubjectToAcl = product.SubjectToAcl; + // expando.LimitedToStores = product.LimitedToStores; + // expando.Sku = product.Sku; + // expando.ManufacturerPartNumber = product.ManufacturerPartNumber; + // expando.Gtin = product.Gtin; + // expando.IsGiftCard = product.IsGiftCard; + // expando.GiftCardTypeId = product.GiftCardTypeId; + // expando.RequireOtherProducts = product.RequireOtherProducts; + // expando.RequiredProductIds = product.RequiredProductIds; + // expando.AutomaticallyAddRequiredProducts = product.AutomaticallyAddRequiredProducts; + // expando.IsDownload = product.IsDownload; + // expando.DownloadId = product.DownloadId; + // expando.UnlimitedDownloads = product.UnlimitedDownloads; + // expando.MaxNumberOfDownloads = product.MaxNumberOfDownloads; + // expando.DownloadExpirationDays = product.DownloadExpirationDays; + // expando.DownloadActivationTypeId = product.DownloadActivationTypeId; + // expando.HasSampleDownload = product.HasSampleDownload; + // expando.SampleDownloadId = product.SampleDownloadId; + // expando.HasUserAgreement = product.HasUserAgreement; + // expando.UserAgreementText = product.UserAgreementText; + // expando.IsRecurring = product.IsRecurring; + // expando.RecurringCycleLength = product.RecurringCycleLength; + // expando.RecurringCyclePeriodId = product.RecurringCyclePeriodId; + // expando.RecurringTotalCycles = product.RecurringTotalCycles; + // expando.IsShipEnabled = product.IsShipEnabled; + // expando.IsFreeShipping = product.IsFreeShipping; + // expando.AdditionalShippingCharge = product.AdditionalShippingCharge; + // expando.IsTaxExempt = product.IsTaxExempt; + // expando.IsEsd = product.IsEsd; + // expando.TaxCategoryId = product.TaxCategoryId; + // expando.ManageInventoryMethodId = product.ManageInventoryMethodId; + // expando.StockQuantity = product.StockQuantity; + // expando.DisplayStockAvailability = product.DisplayStockAvailability; + // expando.DisplayStockQuantity = product.DisplayStockQuantity; + // expando.MinStockQuantity = product.MinStockQuantity; + // expando.LowStockActivityId = product.LowStockActivityId; + // expando.NotifyAdminForQuantityBelow = product.NotifyAdminForQuantityBelow; + // expando.BackorderModeId = product.BackorderModeId; + // expando.AllowBackInStockSubscriptions = product.AllowBackInStockSubscriptions; + // expando.OrderMinimumQuantity = product.OrderMinimumQuantity; + // expando.OrderMaximumQuantity = product.OrderMaximumQuantity; + // expando.AllowedQuantities = product.AllowedQuantities; + // expando.DisableBuyButton = product.DisableBuyButton; + // expando.DisableWishlistButton = product.DisableWishlistButton; + // expando.AvailableForPreOrder = product.AvailableForPreOrder; + // expando.CallForPrice = product.CallForPrice; + // expando.Price = product.Price; + // expando.OldPrice = product.OldPrice; + // expando.ProductCost = product.ProductCost; + // expando.SpecialPrice = product.SpecialPrice; + // expando.SpecialPriceStartDateTimeUtc = product.SpecialPriceStartDateTimeUtc; + // expando.SpecialPriceEndDateTimeUtc = product.SpecialPriceEndDateTimeUtc; + // expando.CustomerEntersPrice = product.CustomerEntersPrice; + // expando.MinimumCustomerEnteredPrice = product.MinimumCustomerEnteredPrice; + // expando.MaximumCustomerEnteredPrice = product.MaximumCustomerEnteredPrice; + // expando.HasTierPrices = product.HasTierPrices; + // expando.LowestAttributeCombinationPrice = product.LowestAttributeCombinationPrice; + // expando.HasDiscountsApplied = product.HasDiscountsApplied; + // expando.Weight = product.Weight; + // expando.Length = product.Length; + // expando.Width = product.Width; + // expando.Height = product.Height; + // expando.AvailableStartDateTimeUtc = product.AvailableStartDateTimeUtc; + // expando.AvailableEndDateTimeUtc = product.AvailableEndDateTimeUtc; + // expando.DisplayOrder = product.DisplayOrder; + // expando.Published = product.Published; + // expando.Deleted = product.Deleted; + // expando.CreatedOnUtc = product.CreatedOnUtc; + // expando.UpdatedOnUtc = product.UpdatedOnUtc; + // expando.DeliveryTimeId = product.DeliveryTimeId; + // expando.QuantityUnitId = product.QuantityUnitId; + // expando.BasePriceEnabled = product.BasePriceEnabled; + // expando.BasePriceMeasureUnit = product.BasePriceMeasureUnit; + // expando.BasePriceAmount = product.BasePriceAmount; + // expando.BasePriceBaseAmount = product.BasePriceBaseAmount; + // expando.BasePriceHasValue = product.BasePriceHasValue; + // expando.BundleTitleText = product.GetLocalized(x => x.BundleTitleText, ctx.Projection.LanguageId ?? 0, true, false); + // expando.BundlePerItemShipping = product.BundlePerItemShipping; + // expando.BundlePerItemPricing = product.BundlePerItemPricing; + // expando.BundlePerItemShoppingCart = product.BundlePerItemShoppingCart; + + // expando.AppliedDiscounts = null; + // expando.TierPrices = null; + // expando.ProductAttributes = null; + // expando.ProductAttributeCombinations = null; + // expando.ProductPictures = null; + // expando.ProductCategories = null; + // expando.ProductManufacturers = null; + // expando.ProductTags = null; + // expando.ProductSpecificationAttributes = null; + // expando.ProductBundleItems = null; + + // expando._Localized = GetLocalized(ctx, product, + // x => x.Name, + // x => x.ShortDescription, + // x => x.FullDescription, + // x => x.MetaKeywords, + // x => x.MetaDescription, + // x => x.MetaTitle, + // x => x.BundleTitleText); + + // return expando; + //} + private dynamic ToExpando(ExportProfileTaskContext ctx, Order order) { if (order == null) @@ -1901,10 +1822,15 @@ private List ConvertToExpando(ExportProfileTaskContext ctx, Product pro foreach (var combination in productAttributeCombinations.Where(x => x.IsActive)) { - var expandoCombination = ((IDictionary)expando).ToExpandoObject(); // clone - - matterOfDataMerging(expandoCombination, combination); - result.Add(expandoCombination); + // TODO: Das ist nocht nicht zu Ende gedacht, wegen MergeWithCombination etc. + var clone = new ExpandoObject(); + clone.Merge((IDictionary)expando, true); + matterOfDataMerging(clone, combination); + result.Add(clone); + + //var expandoCombination = ((IDictionary)expando).ToExpandoObject(); // clone + //matterOfDataMerging(expandoCombination, combination); + //result.Add(expandoCombination); } } else diff --git a/src/Libraries/SmartStore.Services/DataExchange/Internal/DynamicEntity.cs b/src/Libraries/SmartStore.Services/DataExchange/Internal/DynamicEntity.cs index 0a098c5055..6cccfb958a 100644 --- a/src/Libraries/SmartStore.Services/DataExchange/Internal/DynamicEntity.cs +++ b/src/Libraries/SmartStore.Services/DataExchange/Internal/DynamicEntity.cs @@ -9,19 +9,24 @@ namespace SmartStore.Services.DataExchange.Internal { - internal class DynamicEntity : Expando + internal class DynamicEntity : HybridExpando { - private readonly object _entity; + public DynamicEntity(DynamicEntity dynamicEntity) + : this(dynamicEntity.WrappedObject) + { + base.Properties.Merge(dynamicEntity, true); + } public DynamicEntity(object entity) : base(entity) { + // TODO: Umbenennen!!! + base.Properties["_Entity"] = entity; } - // TODO: Umbenennen!!! - public object _Entity + public void Merge() { - get { return base.WrappedObject; } + } protected override bool TrySetMemberCore(string name, object value) diff --git a/src/Libraries/SmartStore.Services/DataExchange/Internal/ExpandoHelpers.cs b/src/Libraries/SmartStore.Services/DataExchange/Internal/ExpandoHelpers.cs deleted file mode 100644 index 657a6675ed..0000000000 --- a/src/Libraries/SmartStore.Services/DataExchange/Internal/ExpandoHelpers.cs +++ /dev/null @@ -1,240 +0,0 @@ -using SmartStore.ComponentModel; -using SmartStore.Core; -using SmartStore.Core.Domain.Common; -using SmartStore.Core.Domain.Customers; -using SmartStore.Core.Domain.Directory; -using SmartStore.Core.Domain.Localization; -using SmartStore.Core.Domain.Media; -using SmartStore.Core.Domain.Seo; -using SmartStore.Core.Domain.Stores; -using SmartStore.Services.DataExchange.ExportTask; -using SmartStore.Services.Localization; -using SmartStore.Services.Seo; -using System; -using System.Collections.Generic; -using System.Dynamic; -using System.Linq; -using System.Linq.Expressions; -using System.Reflection; -using System.Text; -using System.Threading.Tasks; - -namespace SmartStore.Services.DataExchange.Internal -{ - internal class ExpandoHelpers - { - private readonly ExportProfileTaskContext _ctx; - private readonly IUrlRecordService _urlRecordService; - private readonly ILocalizedEntityService _localizedEntityService; - - public ExpandoHelpers( - ExportProfileTaskContext context, - IUrlRecordService urlRecordService, - ILocalizedEntityService localizedEntityService) - { - _ctx = context; - _urlRecordService = urlRecordService; - _localizedEntityService = localizedEntityService; - } - - public dynamic ToExpando(Currency currency) - { - if (currency == null) - return null; - - dynamic expando = new DynamicEntity(currency); - expando.Name = currency.GetLocalized(x => x.Name, _ctx.Projection.LanguageId ?? 0, true, false); - expando._Localized = GetLocalized(currency, x => x.Name); - - return expando; - } - - private dynamic ToExpando(Language language) - { - if (language == null) - return null; - - dynamic expando = new DynamicEntity(language); - return expando; - } - - private dynamic ToExpando(Country country) - { - if (country == null) - return null; - - dynamic expando = new DynamicEntity(country); - expando.Name = country.GetLocalized(x => x.Name, _ctx.Projection.LanguageId ?? 0, true, false); - expando._Localized = GetLocalized(country, x => x.Name); - - return expando; - } - - private dynamic ToExpando(Address address) - { - if (address == null) - return null; - - dynamic expando = new DynamicEntity(address); - expando.Country = ToExpando(address.Country); - - if (address.StateProvinceId.GetValueOrDefault() > 0) - { - dynamic sp = new DynamicEntity(address.StateProvince); - sp.Name = address.StateProvince.GetLocalized(x => x.Name, _ctx.Projection.LanguageId ?? 0, true, false); - sp._Localized = GetLocalized(address.StateProvince, x => x.Name); - expando.StateProvince = sp; - } - else - { - expando.StateProvince = null; - } - - return expando; - } - - private dynamic ToExpando(RewardPointsHistory points) - { - if (points == null) - return null; - - dynamic expando = new DynamicEntity(points); - return expando; - } - - private dynamic ToExpando( Customer customer) - { - if (customer == null) - return null; - - dynamic expando = new DynamicEntity(customer); - - expando.BillingAddress = null; - expando.ShippingAddress = null; - expando.Addresses = null; - expando.CustomerRoles = null; - - expando.RewardPointsHistory = null; - expando._RewardPointsBalance = 0; - - expando._GenericAttributes = null; - expando._HasNewsletterSubscription = false; - - return expando; - } - - private dynamic ToExpando(Store store) - { - if (store == null) - return null; - - dynamic expando = new DynamicEntity(store); - expando.PrimaryStoreCurrency = ToExpando(store.PrimaryStoreCurrency); - expando.PrimaryExchangeRateCurrency = ToExpando(store.PrimaryExchangeRateCurrency); - - return expando; - } - - private dynamic ToExpando(DeliveryTime deliveryTime) - { - if (deliveryTime == null) - return null; - - dynamic expando = new DynamicEntity(deliveryTime); - expando.Name = deliveryTime.GetLocalized(x => x.Name, _ctx.Projection.LanguageId ?? 0, true, false); - expando._Localized = GetLocalized(deliveryTime, x => x.Name); - - return expando; - } - - private dynamic ToExpando(QuantityUnit quantityUnit) - { - if (quantityUnit == null) - return null; - - dynamic expando = new DynamicEntity(quantityUnit); - expando.Name = quantityUnit.GetLocalized(x => x.Name, _ctx.Projection.LanguageId ?? 0, true, false); - expando.Description = quantityUnit.GetLocalized(x => x.Description, _ctx.Projection.LanguageId ?? 0, true, false); - expando._Localized = GetLocalized(quantityUnit, - x => x.Name, - x => x.Description); - - return expando; - } - - private dynamic ToExpando(Picture picture, int thumbPictureSize, int detailsPictureSize) - { - if (picture == null) - return null; - - dynamic expando = new DynamicEntity(picture); - - //// TODO!!!!! - //expando._ThumbImageUrl = _pictureService.Value.GetPictureUrl(picture, thumbPictureSize, false, _ctx.Store.Url); - //expando._ImageUrl = _pictureService.Value.GetPictureUrl(picture, detailsPictureSize, false, _ctx.Store.Url); - //expando._FullSizeImageUrl = _pictureService.Value.GetPictureUrl(picture, 0, false, _ctx.Store.Url); - - //var relativeUrl = _pictureService.Value.GetPictureUrl(picture); - //expando._FileName = relativeUrl.Substring(relativeUrl.LastIndexOf("/") + 1); - - //expando._ThumbLocalPath = _pictureService.Value.GetThumbLocalPath(picture); - - return expando; - } - - // TODO: weitermachen [...] - - private List GetLocalized(T entity, params Expression>[] keySelectors) - where T : BaseEntity, ILocalizedEntity - { - if (_ctx.Languages.Count <= 1) - return null; - - var localized = new List(); - - var localeKeyGroup = typeof(T).Name; - var isSlugSupported = typeof(ISlugSupported).IsAssignableFrom(typeof(T)); - - foreach (var language in _ctx.Languages) - { - var languageCulture = language.Value.LanguageCulture.EmptyNull().ToLower(); - - // add SeName - if (isSlugSupported) - { - var value = _urlRecordService.GetActiveSlug(entity.Id, localeKeyGroup, language.Value.Id); - if (value.HasValue()) - { - dynamic exp = new ExpandoObject(); - exp.Culture = languageCulture; - exp.LocaleKey = "SeName"; - exp.LocaleValue = value; - - localized.Add(exp); - } - } - - foreach (var keySelector in keySelectors) - { - var member = keySelector.Body as MemberExpression; - var propInfo = member.Member as PropertyInfo; - string localeKey = propInfo.Name; - var value = _localizedEntityService.GetLocalizedValue(language.Value.Id, entity.Id, localeKeyGroup, localeKey); - - // we better not export empty values. The risk is too high that they get reimported and unnecessarily pollute databases. - if (value.HasValue()) - { - dynamic exp = new ExpandoObject(); - exp.Culture = languageCulture; - exp.LocaleKey = localeKey; - exp.LocaleValue = value; - - localized.Add(exp); - } - } - } - - return (localized.Count == 0 ? null : localized); - } - } -} diff --git a/src/Libraries/SmartStore.Services/SmartStore.Services.csproj b/src/Libraries/SmartStore.Services/SmartStore.Services.csproj index a6af2b2012..1c3348629e 100644 --- a/src/Libraries/SmartStore.Services/SmartStore.Services.csproj +++ b/src/Libraries/SmartStore.Services/SmartStore.Services.csproj @@ -187,7 +187,6 @@ - @@ -575,7 +574,9 @@ Nop_Services_EuropaCheckVatService_checkVatService - + + + diff --git a/src/Libraries/SmartStore.Services/Tasks/ITaskExecutor.cs b/src/Libraries/SmartStore.Services/Tasks/ITaskExecutor.cs index b14c0e7c22..053cf45937 100644 --- a/src/Libraries/SmartStore.Services/Tasks/ITaskExecutor.cs +++ b/src/Libraries/SmartStore.Services/Tasks/ITaskExecutor.cs @@ -1,10 +1,14 @@ using System; +using System.Collections.Generic; using SmartStore.Core.Domain.Tasks; namespace SmartStore.Services.Tasks { public interface ITaskExecutor { - void Execute(ScheduleTask task, bool throwOnError = false); + void Execute( + ScheduleTask task, + IDictionary taskParameters = null, + bool throwOnError = false); } } diff --git a/src/Libraries/SmartStore.Services/Tasks/ITaskScheduler.cs b/src/Libraries/SmartStore.Services/Tasks/ITaskScheduler.cs index c1805dc7a8..f852d12952 100644 --- a/src/Libraries/SmartStore.Services/Tasks/ITaskScheduler.cs +++ b/src/Libraries/SmartStore.Services/Tasks/ITaskScheduler.cs @@ -53,7 +53,8 @@ public interface ITaskScheduler /// Executes a single task immediately /// /// - void RunSingleTask(int scheduleTaskId); + /// Optional task parameters + void RunSingleTask(int scheduleTaskId, IDictionary taskParameters = null); /// /// Verifies the authentication token which is generated right before the HTTP endpoint gets called. diff --git a/src/Libraries/SmartStore.Services/Tasks/TaskExecutionContext.cs b/src/Libraries/SmartStore.Services/Tasks/TaskExecutionContext.cs index 838065d364..8efba4376f 100644 --- a/src/Libraries/SmartStore.Services/Tasks/TaskExecutionContext.cs +++ b/src/Libraries/SmartStore.Services/Tasks/TaskExecutionContext.cs @@ -21,6 +21,7 @@ internal TaskExecutionContext(IComponentContext componentContext, ScheduleTask o { this._componentContext = componentContext; this._originalTask = originalTask; + this.Parameters = new Dictionary(); } public T Resolve(object key = null) where T : class @@ -45,6 +46,8 @@ public T ResolveNamed(string name) where T : class public ScheduleTask ScheduleTask { get; set; } + public IDictionary Parameters { get; set; } + /// /// Persists a task's progress information to the database /// diff --git a/src/Libraries/SmartStore.Services/Tasks/TaskExecutor.cs b/src/Libraries/SmartStore.Services/Tasks/TaskExecutor.cs index 92e7fa4668..18408a15c0 100644 --- a/src/Libraries/SmartStore.Services/Tasks/TaskExecutor.cs +++ b/src/Libraries/SmartStore.Services/Tasks/TaskExecutor.cs @@ -10,6 +10,7 @@ using SmartStore.Core; using SmartStore.Core.Domain.Customers; using System.Diagnostics; +using System.Collections.Generic; namespace SmartStore.Services.Tasks { @@ -43,7 +44,10 @@ public TaskExecutor( public ILogger Logger { get; set; } - public void Execute(ScheduleTask task, bool throwOnError = false) + public void Execute( + ScheduleTask task, + IDictionary taskParameters = null, + bool throwOnError = false) { if (task.IsRunning) return; @@ -102,7 +106,8 @@ public void Execute(ScheduleTask task, bool throwOnError = false) var ctx = new TaskExecutionContext(_componentContext, task) { ScheduleTask = task.Clone(), - CancellationToken = cts.Token + CancellationToken = cts.Token, + Parameters = taskParameters ?? new Dictionary() }; instance.Execute(ctx); diff --git a/src/Libraries/SmartStore.Services/Tasks/TaskScheduler.cs b/src/Libraries/SmartStore.Services/Tasks/TaskScheduler.cs index 30eb8b8288..3ff2e5e04f 100644 --- a/src/Libraries/SmartStore.Services/Tasks/TaskScheduler.cs +++ b/src/Libraries/SmartStore.Services/Tasks/TaskScheduler.cs @@ -10,6 +10,7 @@ using SmartStore.Core.Async; using SmartStore.Core.Domain.Tasks; using SmartStore.Core.Logging; +using SmartStore.Collections; namespace SmartStore.Services.Tasks { @@ -101,9 +102,18 @@ public bool VerifyAuthToken(string authToken) return _authTokens.TryRemove(authToken, out val); } - public void RunSingleTask(int scheduleTaskId) + public void RunSingleTask(int scheduleTaskId, IDictionary taskParameters = null) { - CallEndpoint(_baseUrl + "/Execute/{0}".FormatInvariant(scheduleTaskId)); + string query = ""; + + if (taskParameters != null && taskParameters.Any()) + { + var qs = new QueryString(); + taskParameters.Each(x => qs.Add(x.Key, x.Value)); + query = qs.ToString(); + } + + CallEndpoint(_baseUrl + "/Execute/{0}{1}".FormatInvariant(scheduleTaskId, query)); } private void Elapsed(object sender, System.Timers.ElapsedEventArgs e) diff --git a/src/Presentation/SmartStore.Web/Controllers/TaskSchedulerController.cs b/src/Presentation/SmartStore.Web/Controllers/TaskSchedulerController.cs index b52e1c033b..9b7b6763c2 100644 --- a/src/Presentation/SmartStore.Web/Controllers/TaskSchedulerController.cs +++ b/src/Presentation/SmartStore.Web/Controllers/TaskSchedulerController.cs @@ -9,7 +9,7 @@ using SmartStore.Web.Framework.Controllers; using SmartStore.Services.Security; using SmartStore.Services; - +using SmartStore.Collections; namespace SmartStore.Web.Controllers { @@ -77,8 +77,8 @@ public ActionResult Execute(int id /* taskId */) var task = _scheduledTaskService.GetTaskById(id); if (task == null) return HttpNotFound(); - - _taskExecutor.Execute(task); + + _taskExecutor.Execute(task, QueryString.Current.ToDictionary()); return Content("Task '{0}' executed".FormatCurrent(task.Name)); } From daf63a30a9745770b3c3bf43bafee33bd94062c1 Mon Sep 17 00:00:00 2001 From: Murat Cakir Date: Fri, 6 Nov 2015 18:14:34 +0100 Subject: [PATCH 011/707] Export framework: minor refactoring --- .../Extensions/DictionaryExtensions.cs | 29 ++++++++++--------- .../ExportTask/ExportProfileTask.cs | 7 ++++- .../DataExchange/Internal/DynamicEntity.cs | 10 ++++++- 3 files changed, 31 insertions(+), 15 deletions(-) diff --git a/src/Libraries/SmartStore.Core/Extensions/DictionaryExtensions.cs b/src/Libraries/SmartStore.Core/Extensions/DictionaryExtensions.cs index 6b91605920..8cfb8c1142 100644 --- a/src/Libraries/SmartStore.Core/Extensions/DictionaryExtensions.cs +++ b/src/Libraries/SmartStore.Core/Extensions/DictionaryExtensions.cs @@ -12,7 +12,7 @@ namespace SmartStore public static class DictionaryExtensions { - public static void AddRange(this IDictionary values, IEnumerable> other) + public static void AddRange(this IDictionary values, IEnumerable> other) { foreach (var kvp in other) { @@ -37,13 +37,13 @@ public static void Merge(this IDictionary instance, object value instance.Merge(new RouteValueDictionary(values), replaceExisting); } - public static void Merge(this IDictionary instance, IDictionary from, bool replaceExisting = true) + public static void Merge(this IDictionary instance, IDictionary from, bool replaceExisting = true) { - foreach (KeyValuePair keyValuePair in from) + foreach (var kvp in from) { - if (replaceExisting || !instance.ContainsKey(keyValuePair.Key)) + if (replaceExisting || !instance.ContainsKey(kvp.Key)) { - instance[keyValuePair.Key] = keyValuePair.Value; + instance[kvp.Key] = kvp.Value; } } } @@ -60,28 +60,31 @@ public static void PrependInValue(this IDictionary instance, str public static string ToAttributeString(this IDictionary instance) { - StringBuilder builder = new StringBuilder(); + var sb = new StringBuilder(); foreach (KeyValuePair pair in instance) { object[] args = new object[] { HttpUtility.HtmlAttributeEncode(pair.Key), HttpUtility.HtmlAttributeEncode(pair.Value.ToString()) }; - builder.Append(" {0}=\"{1}\"".FormatWith(args)); + sb.Append(" {0}=\"{1}\"".FormatWith(args)); } - return builder.ToString(); + return sb.ToString(); } - public static T GetValue(this IDictionary instance, K key) + public static TValue GetValue(this IDictionary instance, TKey key) { try { object val; if (instance != null && instance.TryGetValue(key, out val) && val != null) - return (T)Convert.ChangeType(val, typeof(T), CultureInfo.InvariantCulture); + { + return (TValue)Convert.ChangeType(val, typeof(TValue), CultureInfo.InvariantCulture); + } } - catch (Exception exc) + catch (Exception ex) { - exc.Dump(); + ex.Dump(); } - return default(T); + + return default(TValue); } public static ExpandoObject ToExpandoObject(this IDictionary source, bool castIfPossible = false) diff --git a/src/Libraries/SmartStore.Services/DataExchange/ExportTask/ExportProfileTask.cs b/src/Libraries/SmartStore.Services/DataExchange/ExportTask/ExportProfileTask.cs index 7e8b6e66c7..b36699541b 100644 --- a/src/Libraries/SmartStore.Services/DataExchange/ExportTask/ExportProfileTask.cs +++ b/src/Libraries/SmartStore.Services/DataExchange/ExportTask/ExportProfileTask.cs @@ -1824,10 +1824,15 @@ private List ConvertToExpando(ExportProfileTaskContext ctx, Product pro { // TODO: Das ist nocht nicht zu Ende gedacht, wegen MergeWithCombination etc. var clone = new ExpandoObject(); - clone.Merge((IDictionary)expando, true); + clone.Merge((IDictionary)expando); matterOfDataMerging(clone, combination); result.Add(clone); + // TODO: das hier ist besser. Aber ein Product-Klon muss immer noch erstellt werden. + //var clone = new DynamicEntity((DynamicEntity)expando); + //matterOfDataMerging(clone, combination); + //result.Add(clone); + //var expandoCombination = ((IDictionary)expando).ToExpandoObject(); // clone //matterOfDataMerging(expandoCombination, combination); //result.Add(expandoCombination); diff --git a/src/Libraries/SmartStore.Services/DataExchange/Internal/DynamicEntity.cs b/src/Libraries/SmartStore.Services/DataExchange/Internal/DynamicEntity.cs index 6cccfb958a..6940371341 100644 --- a/src/Libraries/SmartStore.Services/DataExchange/Internal/DynamicEntity.cs +++ b/src/Libraries/SmartStore.Services/DataExchange/Internal/DynamicEntity.cs @@ -24,9 +24,17 @@ public DynamicEntity(object entity) base.Properties["_Entity"] = entity; } - public void Merge() + public void Merge(string name, object value) { + Properties[name] = value; + } + public void MergeRange(IDictionary other) + { + foreach (var kvp in other) + { + Properties[kvp.Key] = kvp.Value; + } } protected override bool TrySetMemberCore(string name, object value) From 3fd05481dbd7b12b53313cbb44a0606651820f8c Mon Sep 17 00:00:00 2001 From: Murat Cakir Date: Fri, 6 Nov 2015 19:28:04 +0100 Subject: [PATCH 012/707] Export framework: renaming --- ...rtExecuteResult.cs => DataExportResult.cs} | 8 +-- .../DataExchange/Deployment/IFilePublisher.cs | 18 +++++ ...ortSegmenter.cs => ExportDataSegmenter.cs} | 14 ++-- .../DataExchange/ExportExecuteContext.cs | 8 +-- .../ExportTask/ExportProfileTask.cs | 36 +++++----- .../ExportTask/ExportProfileTaskContext.cs | 65 ++++++++++--------- .../DataExchange/IDataExporter.cs | 9 ++- .../CategoryExportContext.cs} | 6 +- .../CustomerExportContext.cs} | 6 +- .../ManufacturerExportContext.cs} | 6 +- .../OrderExportContext.cs} | 6 +- .../ProductExportContext.cs} | 6 +- .../CategoryXmlExportProvider.cs} | 4 +- .../CustomerXlsxExportProvider.cs} | 4 +- .../CustomerXmlExportProvider.cs} | 4 +- .../ManufacturerXmlExportProvider.cs} | 4 +- .../OrderXlsxExportProvider.cs} | 4 +- .../OrderXmlExportProvider.cs} | 4 +- .../ProductXlsxExportProvider.cs} | 6 +- .../ProductXmlExportProvider.cs} | 4 +- .../SubscriberCsvExportProvider.cs} | 4 +- .../DataExchange/_Pseudo/AdminController.cs | 19 ++++++ .../DataExchange/_Pseudo/DataExportTask.cs | 62 ++++++++++++++++++ .../SmartStore.Services.csproj | 39 +++++------ .../FeedGoogleMerchantCenterController.cs | 6 +- ...XmlProvider.cs => GmcXmlExportProvider.cs} | 4 +- .../SmartStore.GoogleMerchantCenter.csproj | 2 +- .../Controllers/CategoryController.cs | 4 +- .../Controllers/CustomerController.cs | 10 +-- .../Controllers/ExportController.cs | 2 +- .../Controllers/ManufacturerController.cs | 4 +- .../NewsLetterSubscriptionController.cs | 4 +- .../Controllers/OrderController.cs | 10 +-- .../Controllers/ProductController.cs | 10 +-- 34 files changed, 255 insertions(+), 147 deletions(-) rename src/Libraries/SmartStore.Services/DataExchange/{ExportExecuteResult.cs => DataExportResult.cs} (85%) create mode 100644 src/Libraries/SmartStore.Services/DataExchange/Deployment/IFilePublisher.cs rename src/Libraries/SmartStore.Services/DataExchange/{ExportSegmenter.cs => ExportDataSegmenter.cs} (89%) rename src/Libraries/SmartStore.Services/DataExchange/{ExportTask/ExportDataContextCategory.cs => Internal/CategoryExportContext.cs} (92%) rename src/Libraries/SmartStore.Services/DataExchange/{ExportTask/ExportDataContextCustomer.cs => Internal/CustomerExportContext.cs} (89%) rename src/Libraries/SmartStore.Services/DataExchange/{ExportTask/ExportDataContextManufacturer.cs => Internal/ManufacturerExportContext.cs} (92%) rename src/Libraries/SmartStore.Services/DataExchange/{ExportTask/ExportDataContextOrder.cs => Internal/OrderExportContext.cs} (95%) rename src/Libraries/SmartStore.Services/DataExchange/{ExportTask/ExportDataContextProduct.cs => Internal/ProductExportContext.cs} (96%) rename src/Libraries/SmartStore.Services/DataExchange/{ExportProvider/ExportCategoryXmlProvider.cs => Providers/CategoryXmlExportProvider.cs} (96%) rename src/Libraries/SmartStore.Services/DataExchange/{ExportProvider/ExportCustomerXlsxProvider.cs => Providers/CustomerXlsxExportProvider.cs} (98%) rename src/Libraries/SmartStore.Services/DataExchange/{ExportProvider/ExportCustomerXmlProvider.cs => Providers/CustomerXmlExportProvider.cs} (94%) rename src/Libraries/SmartStore.Services/DataExchange/{ExportProvider/ExportManufacturerXmlProvider.cs => Providers/ManufacturerXmlExportProvider.cs} (96%) rename src/Libraries/SmartStore.Services/DataExchange/{ExportProvider/ExportOrderXlsxProvider.cs => Providers/OrderXlsxExportProvider.cs} (98%) rename src/Libraries/SmartStore.Services/DataExchange/{ExportProvider/ExportOrderXmlProvider.cs => Providers/OrderXmlExportProvider.cs} (99%) rename src/Libraries/SmartStore.Services/DataExchange/{ExportProvider/ExportProductXlsxProvider.cs => Providers/ProductXlsxExportProvider.cs} (99%) rename src/Libraries/SmartStore.Services/DataExchange/{ExportProvider/ExportProductXmlProvider.cs => Providers/ProductXmlExportProvider.cs} (94%) rename src/Libraries/SmartStore.Services/DataExchange/{ExportProvider/ExportNewsSubscriptionCsvProvider.cs => Providers/SubscriberCsvExportProvider.cs} (93%) create mode 100644 src/Libraries/SmartStore.Services/DataExchange/_Pseudo/AdminController.cs create mode 100644 src/Libraries/SmartStore.Services/DataExchange/_Pseudo/DataExportTask.cs rename src/Plugins/SmartStore.GoogleMerchantCenter/Providers/{GmcExportXmlProvider.cs => GmcXmlExportProvider.cs} (99%) diff --git a/src/Libraries/SmartStore.Services/DataExchange/ExportExecuteResult.cs b/src/Libraries/SmartStore.Services/DataExchange/DataExportResult.cs similarity index 85% rename from src/Libraries/SmartStore.Services/DataExchange/ExportExecuteResult.cs rename to src/Libraries/SmartStore.Services/DataExchange/DataExportResult.cs index 6bb8a87429..0e1f708763 100644 --- a/src/Libraries/SmartStore.Services/DataExchange/ExportExecuteResult.cs +++ b/src/Libraries/SmartStore.Services/DataExchange/DataExportResult.cs @@ -5,11 +5,11 @@ namespace SmartStore.Services.DataExchange { [Serializable] - public class ExportExecuteResult + public class DataExportResult { - public ExportExecuteResult() + public DataExportResult() { - Files = new List(); + Files = new List(); } /// @@ -29,7 +29,7 @@ public bool Succeeded /// /// Files created by last export /// - public List Files { get; set; } + public IList Files { get; set; } /// /// The path of the folder with the export files diff --git a/src/Libraries/SmartStore.Services/DataExchange/Deployment/IFilePublisher.cs b/src/Libraries/SmartStore.Services/DataExchange/Deployment/IFilePublisher.cs new file mode 100644 index 0000000000..2f0211fd2b --- /dev/null +++ b/src/Libraries/SmartStore.Services/DataExchange/Deployment/IFilePublisher.cs @@ -0,0 +1,18 @@ +using SmartStore.Core.Domain; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace SmartStore.Services.DataExchange.Deployment +{ + public interface IFilePublisher + { + void Publish(DataExportResult result, ExportDeployment deployment); + } + + /* + Implement without IoC: HttpFilePublisher, EmailFilePublisher, FtpFilePublisher, FileSystemFilePublisher + */ +} diff --git a/src/Libraries/SmartStore.Services/DataExchange/ExportSegmenter.cs b/src/Libraries/SmartStore.Services/DataExchange/ExportDataSegmenter.cs similarity index 89% rename from src/Libraries/SmartStore.Services/DataExchange/ExportSegmenter.cs rename to src/Libraries/SmartStore.Services/DataExchange/ExportDataSegmenter.cs index 6d5c6fb937..a5be05b008 100644 --- a/src/Libraries/SmartStore.Services/DataExchange/ExportSegmenter.cs +++ b/src/Libraries/SmartStore.Services/DataExchange/ExportDataSegmenter.cs @@ -4,7 +4,7 @@ namespace SmartStore.Services.DataExchange { - public interface IExportSegmenterConsumer + public interface IExportDataSegmenterConsumer { /// /// Total number of records @@ -14,7 +14,7 @@ public interface IExportSegmenterConsumer /// /// Gets current data segment /// - List CurrentSegment { get; } + IReadOnlyCollection CurrentSegment { get; } /// /// Reads the next segment @@ -23,7 +23,7 @@ public interface IExportSegmenterConsumer bool ReadNextSegment(); } - internal interface IExportSegmenterProvider : IExportSegmenterConsumer, IDisposable + internal interface IExportDataSegmenterProvider : IExportDataSegmenterConsumer, IDisposable { /// /// Whether there is data available @@ -36,7 +36,7 @@ internal interface IExportSegmenterProvider : IExportSegmenterConsumer, IDisposa int RecordPerSegmentCount { get; set; } } - public class ExportSegmenter : IExportSegmenterProvider where T : BaseEntity + public class ExportDataSegmenter : IExportDataSegmenterProvider where T : BaseEntity { private Func> _load; private Action> _loaded; @@ -53,7 +53,7 @@ public class ExportSegmenter : IExportSegmenterProvider where T : BaseEntity private Queue _data; - public ExportSegmenter( + public ExportDataSegmenter( Func> load, Action> loaded, Func> convert, @@ -127,7 +127,7 @@ public bool HasData /// /// Gets current data segment /// - public List CurrentSegment + public IReadOnlyCollection CurrentSegment { get { @@ -136,7 +136,7 @@ public List CurrentSegment while (_data.Count > 0 && (entity = _data.Dequeue()) != null) { - _convert(entity).ForEach(x => records.Add(x)); + _convert(entity).Each(x => records.Add(x)); if (++_countRecords >= _limit && _limit > 0) return records; diff --git a/src/Libraries/SmartStore.Services/DataExchange/ExportExecuteContext.cs b/src/Libraries/SmartStore.Services/DataExchange/ExportExecuteContext.cs index 1459463bfb..17ae53a8bf 100644 --- a/src/Libraries/SmartStore.Services/DataExchange/ExportExecuteContext.cs +++ b/src/Libraries/SmartStore.Services/DataExchange/ExportExecuteContext.cs @@ -11,7 +11,7 @@ public interface IExportExecuteContext /// /// Provides the data to be exported /// - IExportSegmenterConsumer Segmenter { get; } + IExportDataSegmenterConsumer Segmenter { get; } /// /// The store context to be used for the export @@ -116,11 +116,11 @@ public interface IExportExecuteContext public class ExportExecuteContext : IExportExecuteContext { - private ExportExecuteResult _result; + private DataExportResult _result; private CancellationToken _cancellation; private ExportAbortion _providerAbort; - internal ExportExecuteContext(ExportExecuteResult result, CancellationToken cancellation, string folder) + internal ExportExecuteContext(DataExportResult result, CancellationToken cancellation, string folder) { _result = result; _cancellation = cancellation; @@ -129,7 +129,7 @@ internal ExportExecuteContext(ExportExecuteResult result, CancellationToken canc CustomProperties = new Dictionary(); } - public IExportSegmenterConsumer Segmenter { get; set; } + public IExportDataSegmenterConsumer Segmenter { get; set; } public dynamic Store { get; internal set; } public dynamic Customer { get; internal set; } diff --git a/src/Libraries/SmartStore.Services/DataExchange/ExportTask/ExportProfileTask.cs b/src/Libraries/SmartStore.Services/DataExchange/ExportTask/ExportProfileTask.cs index b36699541b..48c50afc11 100644 --- a/src/Libraries/SmartStore.Services/DataExchange/ExportTask/ExportProfileTask.cs +++ b/src/Libraries/SmartStore.Services/DataExchange/ExportTask/ExportProfileTask.cs @@ -193,7 +193,7 @@ private List GetLocalized(ExportProfileTaskContext ctx, T entity, pa return (localized.Count == 0 ? null : localized); } - private IExportSegmenterProvider CreateSegmenter(ExportProfileTaskContext ctx, int pageIndex = 0) + private IExportDataSegmenterProvider CreateSegmenter(ExportProfileTaskContext ctx, int pageIndex = 0) { var offset = ctx.Profile.Offset + (pageIndex * PageSize); @@ -206,13 +206,13 @@ private IExportSegmenterProvider CreateSegmenter(ExportProfileTaskContext ctx, i switch (ctx.Provider.Value.EntityType) { case ExportEntityType.Product: - ctx.Export.Segmenter = new ExportSegmenter + ctx.Export.Segmenter = new ExportDataSegmenter ( skip => GetProducts(ctx, skip), entities => { // load data behind navigation properties for current queue in one go - ctx.DataContextProduct = new ExportDataContextProduct(entities, + ctx.DataContextProduct = new ProductExportContext(entities, x => _productAttributeService.Value.GetProductVariantAttributesByProductIds(x, null), x => _productAttributeService.Value.GetProductVariantAttributeCombinations(x), x => _productService.Value.GetTierPricesByProductIds(x, (ctx.Projection.CurrencyId ?? 0) != 0 ? ctx.ContextCustomer : null, ctx.Store.Id), @@ -231,12 +231,12 @@ private IExportSegmenterProvider CreateSegmenter(ExportProfileTaskContext ctx, i break; case ExportEntityType.Order: - ctx.Export.Segmenter = new ExportSegmenter + ctx.Export.Segmenter = new ExportDataSegmenter ( skip => GetOrders(ctx, skip), entities => { - ctx.DataContextOrder = new ExportDataContextOrder(entities, + ctx.DataContextOrder = new OrderExportContext(entities, x => _customerService.Value.GetCustomersByIds(x), x => _customerService.Value.GetRewardPointsHistoriesByCustomerIds(x), x => _addressesService.Value.GetAddressByIds(x), @@ -250,12 +250,12 @@ private IExportSegmenterProvider CreateSegmenter(ExportProfileTaskContext ctx, i break; case ExportEntityType.Manufacturer: - ctx.Export.Segmenter = new ExportSegmenter + ctx.Export.Segmenter = new ExportDataSegmenter ( skip => GetManufacturers(ctx, skip), entities => { - ctx.DataContextManufacturer = new ExportDataContextManufacturer(entities, + ctx.DataContextManufacturer = new ManufacturerExportContext(entities, x => _manufacturerService.Value.GetProductManufacturersByManufacturerIds(x), x => _pictureService.Value.GetPicturesByIds(x) ); @@ -266,12 +266,12 @@ private IExportSegmenterProvider CreateSegmenter(ExportProfileTaskContext ctx, i break; case ExportEntityType.Category: - ctx.Export.Segmenter = new ExportSegmenter + ctx.Export.Segmenter = new ExportDataSegmenter ( skip => GetCategories(ctx, skip), entities => { - ctx.DataContextCategory = new ExportDataContextCategory(entities, + ctx.DataContextCategory = new CategoryExportContext(entities, x => _categoryService.Value.GetProductCategoriesByCategoryIds(x), x => _pictureService.Value.GetPicturesByIds(x) ); @@ -282,12 +282,12 @@ private IExportSegmenterProvider CreateSegmenter(ExportProfileTaskContext ctx, i break; case ExportEntityType.Customer: - ctx.Export.Segmenter = new ExportSegmenter + ctx.Export.Segmenter = new ExportDataSegmenter ( skip => GetCustomers(ctx, skip), entities => { - ctx.DataContextCustomer = new ExportDataContextCustomer(entities, + ctx.DataContextCustomer = new CustomerExportContext(entities, x => _genericAttributeService.Value.GetAttributesForEntity(x, "Customer") ); }, @@ -297,7 +297,7 @@ private IExportSegmenterProvider CreateSegmenter(ExportProfileTaskContext ctx, i break; case ExportEntityType.NewsLetterSubscription: - ctx.Export.Segmenter = new ExportSegmenter + ctx.Export.Segmenter = new ExportDataSegmenter ( skip => GetNewsLetterSubscriptions(ctx, skip), null, @@ -311,7 +311,7 @@ private IExportSegmenterProvider CreateSegmenter(ExportProfileTaskContext ctx, i break; } - return ctx.Export.Segmenter as IExportSegmenterProvider; + return ctx.Export.Segmenter as IExportDataSegmenterProvider; } private void PrepareProductDescription(ExportProfileTaskContext ctx, dynamic expando, Product product) @@ -2504,7 +2504,7 @@ private void ExportCoreInner(ExportProfileTaskContext ctx, Store store) // create info for deployment list in profile edit if (File.Exists(ctx.Export.FilePath)) { - ctx.Result.Files.Add(new ExportExecuteResult.ExportFileInfo + ctx.Result.Files.Add(new DataExportResult.ExportFileInfo { StoreId = ctx.Store.Id, FileName = ctx.Export.FileName @@ -2664,7 +2664,7 @@ private void ExportCoreOuter(ExportProfileTaskContext ctx) { if (!ctx.IsPreview && ctx.Profile.Id != 0) { - ctx.Profile.ResultInfo = XmlHelper.Serialize(ctx.Result); + ctx.Profile.ResultInfo = XmlHelper.Serialize(ctx.Result); _exportProfileService.Value.UpdateExportProfile(ctx.Profile); } @@ -2773,7 +2773,7 @@ public static FileStreamResult Export(string providerSystemName, string selected error = null; var cancellation = new CancellationTokenSource(TimeSpan.FromHours(3.0)); - var task = AsyncRunner.Run((container, ct) => + var task = AsyncRunner.Run((container, ct) => { var exportTask = new ExportProfileTask(); return exportTask.Execute(providerSystemName, container, ct, null, selectedEntityIds); @@ -2843,7 +2843,7 @@ public void Execute(TaskExecutionContext taskContext) /// Any data passed on IExportExecuteContext.CustomProperties /// Product query that supersede profile filtering /// Export execute result - public ExportExecuteResult Execute( + public DataExportResult Execute( string providerSystemName, IComponentContext context, CancellationToken cancellationToken, @@ -2949,7 +2949,7 @@ public void Preview(ExportProfile profile, Provider provider, I while (segmenter.ReadNextSegment()) { - segmenter.CurrentSegment.ForEach(x => ctx.PreviewData(x)); + segmenter.CurrentSegment.Each(x => ctx.PreviewData(x)); } } } diff --git a/src/Libraries/SmartStore.Services/DataExchange/ExportTask/ExportProfileTaskContext.cs b/src/Libraries/SmartStore.Services/DataExchange/ExportTask/ExportProfileTaskContext.cs index 5fee680634..576b1ffc08 100644 --- a/src/Libraries/SmartStore.Services/DataExchange/ExportTask/ExportProfileTaskContext.cs +++ b/src/Libraries/SmartStore.Services/DataExchange/ExportTask/ExportProfileTaskContext.cs @@ -14,16 +14,17 @@ using SmartStore.Core.Plugins; using SmartStore.Services.Tasks; using SmartStore.Utilities; +using SmartStore.Services.DataExchange.Internal; namespace SmartStore.Services.DataExchange.ExportTask { internal class ExportProfileTaskContext { - private ExportDataContextProduct _dataContextProduct; - private ExportDataContextOrder _dataContextOrder; - private ExportDataContextManufacturer _dataContextManufacturer; - private ExportDataContextCategory _dataContextCategory; - private ExportDataContextCustomer _dataContextCustomer; + private ProductExportContext _productExportContext; + private OrderExportContext _orderExportContext; + private ManufacturerExportContext _manufacturerExportContext; + private CategoryExportContext _categoryExportContext; + private CustomerExportContext _customerExportContext; public ExportProfileTaskContext( TaskExecutionContext taskContext, @@ -56,7 +57,7 @@ public ExportProfileTaskContext( RecordsPerStore = new Dictionary(); EntityIdsLoaded = new List(); - Result = new ExportExecuteResult + Result = new DataExportResult { FileFolder = (IsFileBasedExport ? FolderContent : null) }; @@ -140,78 +141,78 @@ public string[] GetDeploymentFiles(ExportDeployment deployment) public HashSet NewsletterSubscriptions { get; set; } // data loaded once per page - public ExportDataContextProduct DataContextProduct + public ProductExportContext DataContextProduct { get { - return _dataContextProduct; + return _productExportContext; } set { - if (_dataContextProduct != null) - _dataContextProduct.Clear(); + if (_productExportContext != null) + _productExportContext.Clear(); - _dataContextProduct = value; + _productExportContext = value; } } - public ExportDataContextOrder DataContextOrder + public OrderExportContext DataContextOrder { get { - return _dataContextOrder; + return _orderExportContext; } set { - if (_dataContextOrder != null) - _dataContextOrder.Clear(); + if (_orderExportContext != null) + _orderExportContext.Clear(); - _dataContextOrder = value; + _orderExportContext = value; } } - public ExportDataContextManufacturer DataContextManufacturer + public ManufacturerExportContext DataContextManufacturer { get { - return _dataContextManufacturer; + return _manufacturerExportContext; } set { - if (_dataContextManufacturer != null) - _dataContextManufacturer.Clear(); + if (_manufacturerExportContext != null) + _manufacturerExportContext.Clear(); - _dataContextManufacturer = value; + _manufacturerExportContext = value; } } - public ExportDataContextCategory DataContextCategory + public CategoryExportContext DataContextCategory { get { - return _dataContextCategory; + return _categoryExportContext; } set { - if (_dataContextCategory != null) - _dataContextCategory.Clear(); + if (_categoryExportContext != null) + _categoryExportContext.Clear(); - _dataContextCategory = value; + _categoryExportContext = value; } } - public ExportDataContextCustomer DataContextCustomer + public CustomerExportContext DataContextCustomer { get { - return _dataContextCustomer; + return _customerExportContext; } set { - if (_dataContextCustomer != null) - _dataContextCustomer.Clear(); + if (_customerExportContext != null) + _customerExportContext.Clear(); - _dataContextCustomer = value; + _customerExportContext = value; } } public ExportExecuteContext Export { get; set; } - public ExportExecuteResult Result { get; set; } + public DataExportResult Result { get; set; } } } diff --git a/src/Libraries/SmartStore.Services/DataExchange/IDataExporter.cs b/src/Libraries/SmartStore.Services/DataExchange/IDataExporter.cs index a2a31ac863..036fa99739 100644 --- a/src/Libraries/SmartStore.Services/DataExchange/IDataExporter.cs +++ b/src/Libraries/SmartStore.Services/DataExchange/IDataExporter.cs @@ -13,7 +13,14 @@ namespace SmartStore.Services.DataExchange public interface IDataExporter { - void Export(DataExportRequest request, CancellationToken cancellationToken); + DataExportResult Export(DataExportRequest request, CancellationToken cancellationToken); + + // Handle model conversion for grid in backend's controller + IList Preview(DataExportRequest request); + + // useful for decision making whether export should + // be processed sync or async + long GetDataCount(DataExportRequest request); } public class DataExportRequest diff --git a/src/Libraries/SmartStore.Services/DataExchange/ExportTask/ExportDataContextCategory.cs b/src/Libraries/SmartStore.Services/DataExchange/Internal/CategoryExportContext.cs similarity index 92% rename from src/Libraries/SmartStore.Services/DataExchange/ExportTask/ExportDataContextCategory.cs rename to src/Libraries/SmartStore.Services/DataExchange/Internal/CategoryExportContext.cs index 8e2efa0f93..179189c0db 100644 --- a/src/Libraries/SmartStore.Services/DataExchange/ExportTask/ExportDataContextCategory.cs +++ b/src/Libraries/SmartStore.Services/DataExchange/Internal/CategoryExportContext.cs @@ -5,9 +5,9 @@ using SmartStore.Core.Domain.Catalog; using SmartStore.Core.Domain.Media; -namespace SmartStore.Services.DataExchange.ExportTask +namespace SmartStore.Services.DataExchange.Internal { - internal class ExportDataContextCategory + internal class CategoryExportContext { protected List _categoryIds; protected List _pictureIds; @@ -18,7 +18,7 @@ internal class ExportDataContextCategory private LazyMultimap _productCategories; private LazyMultimap _pictures; - public ExportDataContextCategory( + public CategoryExportContext( IEnumerable categories, Func> productCategories, Func> pictures) diff --git a/src/Libraries/SmartStore.Services/DataExchange/ExportTask/ExportDataContextCustomer.cs b/src/Libraries/SmartStore.Services/DataExchange/Internal/CustomerExportContext.cs similarity index 89% rename from src/Libraries/SmartStore.Services/DataExchange/ExportTask/ExportDataContextCustomer.cs rename to src/Libraries/SmartStore.Services/DataExchange/Internal/CustomerExportContext.cs index f7c027a27d..e765815557 100644 --- a/src/Libraries/SmartStore.Services/DataExchange/ExportTask/ExportDataContextCustomer.cs +++ b/src/Libraries/SmartStore.Services/DataExchange/Internal/CustomerExportContext.cs @@ -5,9 +5,9 @@ using SmartStore.Core.Domain.Common; using SmartStore.Core.Domain.Customers; -namespace SmartStore.Services.DataExchange.ExportTask +namespace SmartStore.Services.DataExchange.Internal { - public class ExportDataContextCustomer + public class CustomerExportContext { protected List _customerIds; @@ -15,7 +15,7 @@ public class ExportDataContextCustomer private LazyMultimap _genericAttributes; - public ExportDataContextCustomer( + public CustomerExportContext( IEnumerable customers, Func> genericAttributes) { diff --git a/src/Libraries/SmartStore.Services/DataExchange/ExportTask/ExportDataContextManufacturer.cs b/src/Libraries/SmartStore.Services/DataExchange/Internal/ManufacturerExportContext.cs similarity index 92% rename from src/Libraries/SmartStore.Services/DataExchange/ExportTask/ExportDataContextManufacturer.cs rename to src/Libraries/SmartStore.Services/DataExchange/Internal/ManufacturerExportContext.cs index 9d2002be35..83445889cc 100644 --- a/src/Libraries/SmartStore.Services/DataExchange/ExportTask/ExportDataContextManufacturer.cs +++ b/src/Libraries/SmartStore.Services/DataExchange/Internal/ManufacturerExportContext.cs @@ -5,9 +5,9 @@ using SmartStore.Core.Domain.Catalog; using SmartStore.Core.Domain.Media; -namespace SmartStore.Services.DataExchange.ExportTask +namespace SmartStore.Services.DataExchange.Internal { - internal class ExportDataContextManufacturer + internal class ManufacturerExportContext { protected List _manufacturerIds; protected List _pictureIds; @@ -18,7 +18,7 @@ internal class ExportDataContextManufacturer private LazyMultimap _productManufacturers; private LazyMultimap _pictures; - public ExportDataContextManufacturer( + public ManufacturerExportContext( IEnumerable manufacturers, Func> productManufacturers, Func> pictures) diff --git a/src/Libraries/SmartStore.Services/DataExchange/ExportTask/ExportDataContextOrder.cs b/src/Libraries/SmartStore.Services/DataExchange/Internal/OrderExportContext.cs similarity index 95% rename from src/Libraries/SmartStore.Services/DataExchange/ExportTask/ExportDataContextOrder.cs rename to src/Libraries/SmartStore.Services/DataExchange/Internal/OrderExportContext.cs index 38fa4893ae..6ae1998304 100644 --- a/src/Libraries/SmartStore.Services/DataExchange/ExportTask/ExportDataContextOrder.cs +++ b/src/Libraries/SmartStore.Services/DataExchange/Internal/OrderExportContext.cs @@ -7,9 +7,9 @@ using SmartStore.Core.Domain.Orders; using SmartStore.Core.Domain.Shipping; -namespace SmartStore.Services.DataExchange.ExportTask +namespace SmartStore.Services.DataExchange.Internal { - internal class ExportDataContextOrder + internal class OrderExportContext { protected List _orderIds; protected List _customerIds; @@ -27,7 +27,7 @@ internal class ExportDataContextOrder private LazyMultimap _orderItems; private LazyMultimap _shipments; - public ExportDataContextOrder(IEnumerable orders, + public OrderExportContext(IEnumerable orders, Func> customers, Func> rewardPointsHistory, Func> addresses, diff --git a/src/Libraries/SmartStore.Services/DataExchange/ExportTask/ExportDataContextProduct.cs b/src/Libraries/SmartStore.Services/DataExchange/Internal/ProductExportContext.cs similarity index 96% rename from src/Libraries/SmartStore.Services/DataExchange/ExportTask/ExportDataContextProduct.cs rename to src/Libraries/SmartStore.Services/DataExchange/Internal/ProductExportContext.cs index bb0d6ea6c1..503e3db6db 100644 --- a/src/Libraries/SmartStore.Services/DataExchange/ExportTask/ExportDataContextProduct.cs +++ b/src/Libraries/SmartStore.Services/DataExchange/Internal/ProductExportContext.cs @@ -6,9 +6,9 @@ using SmartStore.Core.Domain.Discounts; using SmartStore.Services.Catalog; -namespace SmartStore.Services.DataExchange.ExportTask +namespace SmartStore.Services.DataExchange.Internal { - internal class ExportDataContextProduct : PriceCalculationContext + internal class ProductExportContext : PriceCalculationContext { private List _productIdsBundleItems; @@ -24,7 +24,7 @@ internal class ExportDataContextProduct : PriceCalculationContext private LazyMultimap _productSpecificationAttributes; private LazyMultimap _productBundleItems; - public ExportDataContextProduct( + public ProductExportContext( IEnumerable products, Func> attributes, Func> attributeCombinations, diff --git a/src/Libraries/SmartStore.Services/DataExchange/ExportProvider/ExportCategoryXmlProvider.cs b/src/Libraries/SmartStore.Services/DataExchange/Providers/CategoryXmlExportProvider.cs similarity index 96% rename from src/Libraries/SmartStore.Services/DataExchange/ExportProvider/ExportCategoryXmlProvider.cs rename to src/Libraries/SmartStore.Services/DataExchange/Providers/CategoryXmlExportProvider.cs index 6bd4aa3d2f..5b72bc9d64 100644 --- a/src/Libraries/SmartStore.Services/DataExchange/ExportProvider/ExportCategoryXmlProvider.cs +++ b/src/Libraries/SmartStore.Services/DataExchange/Providers/CategoryXmlExportProvider.cs @@ -8,7 +8,7 @@ using SmartStore.Core.Logging; using SmartStore.Core.Plugins; -namespace SmartStore.Services.DataExchange.ExportProvider +namespace SmartStore.Services.DataExchange.Providers { /// /// Exports XML formatted category data to a file @@ -16,7 +16,7 @@ namespace SmartStore.Services.DataExchange.ExportProvider [SystemName("Exports.SmartStoreCategoryXml")] [FriendlyName("SmartStore XML category export")] [IsHidden(true)] - public class ExportCategoryXmlProvider : IExportProvider + public class CategoryXmlExportProvider : IExportProvider { public static string SystemName { diff --git a/src/Libraries/SmartStore.Services/DataExchange/ExportProvider/ExportCustomerXlsxProvider.cs b/src/Libraries/SmartStore.Services/DataExchange/Providers/CustomerXlsxExportProvider.cs similarity index 98% rename from src/Libraries/SmartStore.Services/DataExchange/ExportProvider/ExportCustomerXlsxProvider.cs rename to src/Libraries/SmartStore.Services/DataExchange/Providers/CustomerXlsxExportProvider.cs index 2ab8dcb6b0..22a9d229ec 100644 --- a/src/Libraries/SmartStore.Services/DataExchange/ExportProvider/ExportCustomerXlsxProvider.cs +++ b/src/Libraries/SmartStore.Services/DataExchange/Providers/CustomerXlsxExportProvider.cs @@ -10,7 +10,7 @@ using SmartStore.Core.Plugins; using SmartStore.Services.Customers; -namespace SmartStore.Services.DataExchange.ExportProvider +namespace SmartStore.Services.DataExchange.Providers { /// /// Exports Excel formatted customer data to a file @@ -18,7 +18,7 @@ namespace SmartStore.Services.DataExchange.ExportProvider [SystemName("Exports.SmartStoreCustomerXlsx")] [FriendlyName("SmartStore Excel customer export")] [IsHidden(true)] - public class ExportCustomerXlsxProvider : IExportProvider + public class CustomerXlsxExportProvider : IExportProvider { private string[] Properties { diff --git a/src/Libraries/SmartStore.Services/DataExchange/ExportProvider/ExportCustomerXmlProvider.cs b/src/Libraries/SmartStore.Services/DataExchange/Providers/CustomerXmlExportProvider.cs similarity index 94% rename from src/Libraries/SmartStore.Services/DataExchange/ExportProvider/ExportCustomerXmlProvider.cs rename to src/Libraries/SmartStore.Services/DataExchange/Providers/CustomerXmlExportProvider.cs index 4573e6c69c..b88d3d8cd3 100644 --- a/src/Libraries/SmartStore.Services/DataExchange/ExportProvider/ExportCustomerXmlProvider.cs +++ b/src/Libraries/SmartStore.Services/DataExchange/Providers/CustomerXmlExportProvider.cs @@ -8,7 +8,7 @@ using SmartStore.Core.Logging; using SmartStore.Core.Plugins; -namespace SmartStore.Services.DataExchange.ExportProvider +namespace SmartStore.Services.DataExchange.Providers { /// /// Exports XML formatted customer data to a file @@ -16,7 +16,7 @@ namespace SmartStore.Services.DataExchange.ExportProvider [SystemName("Exports.SmartStoreCustomerXml")] [FriendlyName("SmartStore XML customer export")] [IsHidden(true)] - public class ExportCustomerXmlProvider : IExportProvider + public class CustomerXmlExportProvider : IExportProvider { public static string SystemName { diff --git a/src/Libraries/SmartStore.Services/DataExchange/ExportProvider/ExportManufacturerXmlProvider.cs b/src/Libraries/SmartStore.Services/DataExchange/Providers/ManufacturerXmlExportProvider.cs similarity index 96% rename from src/Libraries/SmartStore.Services/DataExchange/ExportProvider/ExportManufacturerXmlProvider.cs rename to src/Libraries/SmartStore.Services/DataExchange/Providers/ManufacturerXmlExportProvider.cs index 5341411be7..edc60a007d 100644 --- a/src/Libraries/SmartStore.Services/DataExchange/ExportProvider/ExportManufacturerXmlProvider.cs +++ b/src/Libraries/SmartStore.Services/DataExchange/Providers/ManufacturerXmlExportProvider.cs @@ -8,7 +8,7 @@ using SmartStore.Core.Logging; using SmartStore.Core.Plugins; -namespace SmartStore.Services.DataExchange.ExportProvider +namespace SmartStore.Services.DataExchange.Providers { /// /// Exports XML formatted manufacturer data to a file @@ -16,7 +16,7 @@ namespace SmartStore.Services.DataExchange.ExportProvider [SystemName("Exports.SmartStoreManufacturerXml")] [FriendlyName("SmartStore XML manufacturer export")] [IsHidden(true)] - public class ExportManufacturerXmlProvider : IExportProvider + public class ManufacturerXmlExportProvider : IExportProvider { public static string SystemName { diff --git a/src/Libraries/SmartStore.Services/DataExchange/ExportProvider/ExportOrderXlsxProvider.cs b/src/Libraries/SmartStore.Services/DataExchange/Providers/OrderXlsxExportProvider.cs similarity index 98% rename from src/Libraries/SmartStore.Services/DataExchange/ExportProvider/ExportOrderXlsxProvider.cs rename to src/Libraries/SmartStore.Services/DataExchange/Providers/OrderXlsxExportProvider.cs index ba85cc3b0d..9f468e071f 100644 --- a/src/Libraries/SmartStore.Services/DataExchange/ExportProvider/ExportOrderXlsxProvider.cs +++ b/src/Libraries/SmartStore.Services/DataExchange/Providers/OrderXlsxExportProvider.cs @@ -7,7 +7,7 @@ using SmartStore.Core.Logging; using SmartStore.Core.Plugins; -namespace SmartStore.Services.DataExchange.ExportProvider +namespace SmartStore.Services.DataExchange.Providers { /// /// Exports Excel formatted order data to a file @@ -15,7 +15,7 @@ namespace SmartStore.Services.DataExchange.ExportProvider [SystemName("Exports.SmartStoreOrderXlsx")] [FriendlyName("SmartStore Excel order export")] [IsHidden(true)] - public class ExportOrderXlsxProvider : IExportProvider + public class OrderXlsxExportProvider : IExportProvider { private string[] Properties { diff --git a/src/Libraries/SmartStore.Services/DataExchange/ExportProvider/ExportOrderXmlProvider.cs b/src/Libraries/SmartStore.Services/DataExchange/Providers/OrderXmlExportProvider.cs similarity index 99% rename from src/Libraries/SmartStore.Services/DataExchange/ExportProvider/ExportOrderXmlProvider.cs rename to src/Libraries/SmartStore.Services/DataExchange/Providers/OrderXmlExportProvider.cs index 185181c013..a21a94d2f9 100644 --- a/src/Libraries/SmartStore.Services/DataExchange/ExportProvider/ExportOrderXmlProvider.cs +++ b/src/Libraries/SmartStore.Services/DataExchange/Providers/OrderXmlExportProvider.cs @@ -8,7 +8,7 @@ using SmartStore.Core.Logging; using SmartStore.Core.Plugins; -namespace SmartStore.Services.DataExchange.ExportProvider +namespace SmartStore.Services.DataExchange.Providers { /// /// Exports XML formatted order data to a file @@ -16,7 +16,7 @@ namespace SmartStore.Services.DataExchange.ExportProvider [SystemName("Exports.SmartStoreOrderXml")] [FriendlyName("SmartStore XML order export")] [IsHidden(true)] - public class ExportOrderXmlProvider : IExportProvider + public class OrderXmlExportProvider : IExportProvider { public static string SystemName { diff --git a/src/Libraries/SmartStore.Services/DataExchange/ExportProvider/ExportProductXlsxProvider.cs b/src/Libraries/SmartStore.Services/DataExchange/Providers/ProductXlsxExportProvider.cs similarity index 99% rename from src/Libraries/SmartStore.Services/DataExchange/ExportProvider/ExportProductXlsxProvider.cs rename to src/Libraries/SmartStore.Services/DataExchange/Providers/ProductXlsxExportProvider.cs index e9ec1bbc59..a433bf5c8d 100644 --- a/src/Libraries/SmartStore.Services/DataExchange/ExportProvider/ExportProductXlsxProvider.cs +++ b/src/Libraries/SmartStore.Services/DataExchange/Providers/ProductXlsxExportProvider.cs @@ -14,7 +14,7 @@ using SmartStore.Services.Localization; using SmartStore.Services.Stores; -namespace SmartStore.Services.DataExchange.ExportProvider +namespace SmartStore.Services.DataExchange.Providers { /// /// Exports Excel formatted product data to a file @@ -22,7 +22,7 @@ namespace SmartStore.Services.DataExchange.ExportProvider [SystemName("Exports.SmartStoreProductXlsx")] [FriendlyName("SmartStore Excel product export")] [IsHidden(true)] - public class ExportProductXlsxProvider : IExportProvider + public class ProductXlsxExportProvider : IExportProvider { private readonly ILanguageService _languageService; private readonly IProductService _productService; @@ -130,7 +130,7 @@ private string[] Properties } } - public ExportProductXlsxProvider( + public ProductXlsxExportProvider( ILanguageService languageService, IProductService productService, IStoreMappingService storeMappingService) diff --git a/src/Libraries/SmartStore.Services/DataExchange/ExportProvider/ExportProductXmlProvider.cs b/src/Libraries/SmartStore.Services/DataExchange/Providers/ProductXmlExportProvider.cs similarity index 94% rename from src/Libraries/SmartStore.Services/DataExchange/ExportProvider/ExportProductXmlProvider.cs rename to src/Libraries/SmartStore.Services/DataExchange/Providers/ProductXmlExportProvider.cs index 6352c98b03..a0cc291bf1 100644 --- a/src/Libraries/SmartStore.Services/DataExchange/ExportProvider/ExportProductXmlProvider.cs +++ b/src/Libraries/SmartStore.Services/DataExchange/Providers/ProductXmlExportProvider.cs @@ -8,7 +8,7 @@ using SmartStore.Core.Logging; using SmartStore.Core.Plugins; -namespace SmartStore.Services.DataExchange.ExportProvider +namespace SmartStore.Services.DataExchange.Providers { /// /// Exports XML formatted product data to a file @@ -16,7 +16,7 @@ namespace SmartStore.Services.DataExchange.ExportProvider [SystemName("Exports.SmartStoreProductXml")] [FriendlyName("SmartStore XML product export")] [IsHidden(true)] - public class ExportProductXmlProvider : IExportProvider + public class ProductXmlExportProvider : IExportProvider { public static string SystemName { diff --git a/src/Libraries/SmartStore.Services/DataExchange/ExportProvider/ExportNewsSubscriptionCsvProvider.cs b/src/Libraries/SmartStore.Services/DataExchange/Providers/SubscriberCsvExportProvider.cs similarity index 93% rename from src/Libraries/SmartStore.Services/DataExchange/ExportProvider/ExportNewsSubscriptionCsvProvider.cs rename to src/Libraries/SmartStore.Services/DataExchange/Providers/SubscriberCsvExportProvider.cs index 36479f946f..2ca56f48f8 100644 --- a/src/Libraries/SmartStore.Services/DataExchange/ExportProvider/ExportNewsSubscriptionCsvProvider.cs +++ b/src/Libraries/SmartStore.Services/DataExchange/Providers/SubscriberCsvExportProvider.cs @@ -5,7 +5,7 @@ using SmartStore.Core.Logging; using SmartStore.Core.Plugins; -namespace SmartStore.Services.DataExchange.ExportProvider +namespace SmartStore.Services.DataExchange.Providers { /// /// Exports CSV formatted newsletter subscription data to a file @@ -13,7 +13,7 @@ namespace SmartStore.Services.DataExchange.ExportProvider [SystemName("Exports.SmartStoreNewsSubscriptionCsv")] [FriendlyName("SmartStore CSV newsletter subscription export")] [IsHidden(true)] - public class ExportNewsSubscriptionCsvProvider : IExportProvider + public class SubscriberCsvExportProvider : IExportProvider { public static string SystemName { diff --git a/src/Libraries/SmartStore.Services/DataExchange/_Pseudo/AdminController.cs b/src/Libraries/SmartStore.Services/DataExchange/_Pseudo/AdminController.cs new file mode 100644 index 0000000000..e0661ccf40 --- /dev/null +++ b/src/Libraries/SmartStore.Services/DataExchange/_Pseudo/AdminController.cs @@ -0,0 +1,19 @@ +//using SmartStore.Core.Infrastructure; +//using System; +//using System.Collections.Generic; +//using System.Linq; +//using System.Text; +//using System.Threading.Tasks; +//using System.Web; +//using System.Web.Mvc; + +//namespace SmartStore.Services.DataExchange +//{ +// internal class AdminController : Controller +// { +// protected ActionResult Export(string providerSystemName, string selectedIds) +// { +// var exporter = EngineContext.Current.Resolve(); +// } +// } +//} diff --git a/src/Libraries/SmartStore.Services/DataExchange/_Pseudo/DataExportTask.cs b/src/Libraries/SmartStore.Services/DataExchange/_Pseudo/DataExportTask.cs new file mode 100644 index 0000000000..57c80834f6 --- /dev/null +++ b/src/Libraries/SmartStore.Services/DataExchange/_Pseudo/DataExportTask.cs @@ -0,0 +1,62 @@ +using SmartStore.Core.Localization; +using SmartStore.Services.Tasks; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading; +using System.Threading.Tasks; +using System.Web; + +namespace SmartStore.Services.DataExchange +{ + internal class DataExportTask : ITask + { + private readonly IDataExporter _exporter; + private readonly IExportProfileService _exportProfileService; + + public DataExportTask( + IDataExporter exporter, + IExportProfileService exportProfileService) + { + _exporter = exporter; + _exportProfileService = exportProfileService; + } + + public Localizer T { get; set; } + + public void Execute(TaskExecutionContext ctx) + { + // TODO: proper error handling + + var profileId = ctx.ScheduleTask.Alias.ToInt(); + var profile = _exportProfileService.GetExportProfileById(profileId); + + // TODO: find a better way to transmit selected entity ids (e.g. new TaskExecutionContext.Parameters property) + var selectedIdsCacheKey = profile.GetSelectedEntityIdsCacheKey(); + var selectedEntityIds = HttpRuntime.Cache[selectedIdsCacheKey] as string; + HttpRuntime.Cache.Remove(selectedIdsCacheKey); + + // load provider + var provider = _exportProfileService.LoadProvider(profile.ProviderSystemName); + if (provider == null) + throw new SmartException(T("Admin.Common.ProviderNotLoaded", profile.ProviderSystemName.NaIfEmpty())); + + // build export request + var request = new DataExportRequest(profile); + request.ProgressSetter = delegate(int val, int max, string msg) + { + ctx.SetProgress(val, max, msg); + }; + if (selectedEntityIds.HasValue()) + { + request.EntitiesToExport = selectedEntityIds.ToIntArray(); + } + + // process! + _exporter.Export(request, ctx.CancellationToken); + + ctx.CancellationToken.ThrowIfCancellationRequested(); + } + } +} diff --git a/src/Libraries/SmartStore.Services/SmartStore.Services.csproj b/src/Libraries/SmartStore.Services/SmartStore.Services.csproj index 1c3348629e..f63d565765 100644 --- a/src/Libraries/SmartStore.Services/SmartStore.Services.csproj +++ b/src/Libraries/SmartStore.Services/SmartStore.Services.csproj @@ -169,33 +169,36 @@ + - - - - - - - - - - - - + + + + + + + + + + + + - + - - + + - + + + @@ -574,9 +577,7 @@ Nop_Services_EuropaCheckVatService_checkVatService - - - + diff --git a/src/Plugins/SmartStore.GoogleMerchantCenter/Controllers/FeedGoogleMerchantCenterController.cs b/src/Plugins/SmartStore.GoogleMerchantCenter/Controllers/FeedGoogleMerchantCenterController.cs index 7a310a4c18..55425cbc7e 100644 --- a/src/Plugins/SmartStore.GoogleMerchantCenter/Controllers/FeedGoogleMerchantCenterController.cs +++ b/src/Plugins/SmartStore.GoogleMerchantCenter/Controllers/FeedGoogleMerchantCenterController.cs @@ -61,7 +61,7 @@ public ActionResult ProductEditTab(int productId) ViewBag.DefaultAgeGroup = T("Common.Auto"); // we do not have export profile context here, so we simply use the first profile - var profile = _exportService.GetExportProfilesBySystemName(GmcExportXmlProvider.SystemName).FirstOrDefault(); + var profile = _exportService.GetExportProfilesBySystemName(GmcXmlExportProvider.SystemName).FirstOrDefault(); if (profile != null) { var config = XmlHelper.Deserialize(profile.ProviderConfigData, typeof(ProfileConfigurationModel)) as ProfileConfigurationModel; @@ -73,12 +73,12 @@ public ActionResult ProductEditTab(int productId) ViewBag.DefaultMaterial = config.Material; ViewBag.DefaultPattern = config.Pattern; - if (config.Gender.HasValue() && config.Gender != GmcExportXmlProvider.Unspecified) + if (config.Gender.HasValue() && config.Gender != GmcXmlExportProvider.Unspecified) { ViewBag.DefaultGender = T("Plugins.Feed.Froogle.Gender" + culture.TextInfo.ToTitleCase(config.Gender)); } - if (config.AgeGroup.HasValue() && config.AgeGroup != GmcExportXmlProvider.Unspecified) + if (config.AgeGroup.HasValue() && config.AgeGroup != GmcXmlExportProvider.Unspecified) { ViewBag.DefaultAgeGroup = T("Plugins.Feed.Froogle.AgeGroup" + culture.TextInfo.ToTitleCase(config.AgeGroup)); } diff --git a/src/Plugins/SmartStore.GoogleMerchantCenter/Providers/GmcExportXmlProvider.cs b/src/Plugins/SmartStore.GoogleMerchantCenter/Providers/GmcXmlExportProvider.cs similarity index 99% rename from src/Plugins/SmartStore.GoogleMerchantCenter/Providers/GmcExportXmlProvider.cs rename to src/Plugins/SmartStore.GoogleMerchantCenter/Providers/GmcXmlExportProvider.cs index 412737afc7..3f1dac0bd2 100644 --- a/src/Plugins/SmartStore.GoogleMerchantCenter/Providers/GmcExportXmlProvider.cs +++ b/src/Plugins/SmartStore.GoogleMerchantCenter/Providers/GmcXmlExportProvider.cs @@ -28,7 +28,7 @@ namespace SmartStore.GoogleMerchantCenter.Providers ExportFeatures.OffersBrandFallback, ExportFeatures.CanIncludeMainPicture, ExportFeatures.UsesSpecialPrice)] - public class GmcExportXmlProvider : IExportProvider + public class GmcXmlExportProvider : IExportProvider { private const string _googleNamespace = "http://base.google.com/ns/1.0"; @@ -36,7 +36,7 @@ public class GmcExportXmlProvider : IExportProvider private readonly IMeasureService _measureService; private readonly MeasureSettings _measureSettings; - public GmcExportXmlProvider( + public GmcXmlExportProvider( IGoogleFeedService googleFeedService, IMeasureService measureService, MeasureSettings measureSettings) diff --git a/src/Plugins/SmartStore.GoogleMerchantCenter/SmartStore.GoogleMerchantCenter.csproj b/src/Plugins/SmartStore.GoogleMerchantCenter/SmartStore.GoogleMerchantCenter.csproj index 0826ad5831..a2b1919903 100644 --- a/src/Plugins/SmartStore.GoogleMerchantCenter/SmartStore.GoogleMerchantCenter.csproj +++ b/src/Plugins/SmartStore.GoogleMerchantCenter/SmartStore.GoogleMerchantCenter.csproj @@ -176,7 +176,7 @@ - + diff --git a/src/Presentation/SmartStore.Web/Administration/Controllers/CategoryController.cs b/src/Presentation/SmartStore.Web/Administration/Controllers/CategoryController.cs index 76d0abdaf9..10b7fab549 100644 --- a/src/Presentation/SmartStore.Web/Administration/Controllers/CategoryController.cs +++ b/src/Presentation/SmartStore.Web/Administration/Controllers/CategoryController.cs @@ -13,7 +13,7 @@ using SmartStore.Services.Catalog; using SmartStore.Services.Common; using SmartStore.Services.Customers; -using SmartStore.Services.DataExchange.ExportProvider; +using SmartStore.Services.DataExchange.Providers; using SmartStore.Services.Discounts; using SmartStore.Services.Filter; using SmartStore.Services.Helpers; @@ -759,7 +759,7 @@ public ActionResult ExportXml() if (!_permissionService.Authorize(StandardPermissionProvider.ManageCatalog)) return AccessDeniedView(); - return Export(ExportCategoryXmlProvider.SystemName, null); + return Export(CategoryXmlExportProvider.SystemName, null); } #endregion diff --git a/src/Presentation/SmartStore.Web/Administration/Controllers/CustomerController.cs b/src/Presentation/SmartStore.Web/Administration/Controllers/CustomerController.cs index 96de99a9d5..ab57549c4e 100644 --- a/src/Presentation/SmartStore.Web/Administration/Controllers/CustomerController.cs +++ b/src/Presentation/SmartStore.Web/Administration/Controllers/CustomerController.cs @@ -24,7 +24,7 @@ using SmartStore.Services.Catalog; using SmartStore.Services.Common; using SmartStore.Services.Customers; -using SmartStore.Services.DataExchange.ExportProvider; +using SmartStore.Services.DataExchange.Providers; using SmartStore.Services.Directory; using SmartStore.Services.Forums; using SmartStore.Services.Helpers; @@ -1765,7 +1765,7 @@ public ActionResult ExportExcelAll() if (!_permissionService.Authorize(StandardPermissionProvider.ManageCustomers)) return AccessDeniedView(); - return Export(ExportCustomerXlsxProvider.SystemName, null); + return Export(CustomerXlsxExportProvider.SystemName, null); } [Compress] @@ -1774,7 +1774,7 @@ public ActionResult ExportExcelSelected(string selectedIds) if (!_permissionService.Authorize(StandardPermissionProvider.ManageCustomers)) return AccessDeniedView(); - return Export(ExportCustomerXlsxProvider.SystemName, selectedIds); + return Export(CustomerXlsxExportProvider.SystemName, selectedIds); } [Compress] @@ -1783,7 +1783,7 @@ public ActionResult ExportXmlAll() if (!_permissionService.Authorize(StandardPermissionProvider.ManageCustomers)) return AccessDeniedView(); - return Export(ExportCustomerXmlProvider.SystemName, null); + return Export(CustomerXmlExportProvider.SystemName, null); } [Compress] @@ -1792,7 +1792,7 @@ public ActionResult ExportXmlSelected(string selectedIds) if (!_permissionService.Authorize(StandardPermissionProvider.ManageCustomers)) return AccessDeniedView(); - return Export(ExportCustomerXmlProvider.SystemName, selectedIds); + return Export(CustomerXmlExportProvider.SystemName, selectedIds); } #endregion diff --git a/src/Presentation/SmartStore.Web/Administration/Controllers/ExportController.cs b/src/Presentation/SmartStore.Web/Administration/Controllers/ExportController.cs index a244d1f807..984f3641a1 100644 --- a/src/Presentation/SmartStore.Web/Administration/Controllers/ExportController.cs +++ b/src/Presentation/SmartStore.Web/Administration/Controllers/ExportController.cs @@ -244,7 +244,7 @@ private void PrepareProfileModelForEdit(ExportProfileModel model, ExportProfile try { var publicFolder = Path.Combine(HttpRuntime.AppDomainAppPath, ExportProfileTask.PublicFolder); - var resultInfo = XmlHelper.Deserialize(profile.ResultInfo); + var resultInfo = XmlHelper.Deserialize(profile.ResultInfo); if (resultInfo != null && resultInfo.Files != null) { diff --git a/src/Presentation/SmartStore.Web/Administration/Controllers/ManufacturerController.cs b/src/Presentation/SmartStore.Web/Administration/Controllers/ManufacturerController.cs index 840cecc2e4..d08dd31393 100644 --- a/src/Presentation/SmartStore.Web/Administration/Controllers/ManufacturerController.cs +++ b/src/Presentation/SmartStore.Web/Administration/Controllers/ManufacturerController.cs @@ -10,7 +10,7 @@ using SmartStore.Core.Logging; using SmartStore.Services.Catalog; using SmartStore.Services.Common; -using SmartStore.Services.DataExchange.ExportProvider; +using SmartStore.Services.DataExchange.Providers; using SmartStore.Services.Helpers; using SmartStore.Services.Localization; using SmartStore.Services.Media; @@ -444,7 +444,7 @@ public ActionResult ExportXml() if (!_permissionService.Authorize(StandardPermissionProvider.ManageCatalog)) return AccessDeniedView(); - return Export(ExportManufacturerXmlProvider.SystemName, null); + return Export(ManufacturerXmlExportProvider.SystemName, null); } #endregion diff --git a/src/Presentation/SmartStore.Web/Administration/Controllers/NewsLetterSubscriptionController.cs b/src/Presentation/SmartStore.Web/Administration/Controllers/NewsLetterSubscriptionController.cs index 8ba0f92043..19cccae106 100644 --- a/src/Presentation/SmartStore.Web/Administration/Controllers/NewsLetterSubscriptionController.cs +++ b/src/Presentation/SmartStore.Web/Administration/Controllers/NewsLetterSubscriptionController.cs @@ -3,7 +3,7 @@ using System.Web.Mvc; using SmartStore.Admin.Models.Messages; using SmartStore.Core.Domain.Common; -using SmartStore.Services.DataExchange.ExportProvider; +using SmartStore.Services.DataExchange.Providers; using SmartStore.Services.Helpers; using SmartStore.Services.Messages; using SmartStore.Services.Security; @@ -156,7 +156,7 @@ public ActionResult ExportCsv() if (!_permissionService.Authorize(StandardPermissionProvider.ManageNewsletterSubscribers)) return AccessDeniedView(); - return Export(ExportNewsSubscriptionCsvProvider.SystemName, null); + return Export(SubscriberCsvExportProvider.SystemName, null); } [HttpPost] diff --git a/src/Presentation/SmartStore.Web/Administration/Controllers/OrderController.cs b/src/Presentation/SmartStore.Web/Administration/Controllers/OrderController.cs index f2a096e559..55e8e13585 100644 --- a/src/Presentation/SmartStore.Web/Administration/Controllers/OrderController.cs +++ b/src/Presentation/SmartStore.Web/Administration/Controllers/OrderController.cs @@ -20,7 +20,7 @@ using SmartStore.Services.Catalog; using SmartStore.Services.Common; using SmartStore.Services.Customers; -using SmartStore.Services.DataExchange.ExportProvider; +using SmartStore.Services.DataExchange.Providers; using SmartStore.Services.Directory; using SmartStore.Services.Helpers; using SmartStore.Services.Localization; @@ -877,7 +877,7 @@ public ActionResult ExportXmlAll() if (!_permissionService.Authorize(StandardPermissionProvider.ManageOrders)) return AccessDeniedView(); - return Export(ExportOrderXmlProvider.SystemName, null); + return Export(OrderXmlExportProvider.SystemName, null); } [HttpPost, Compress] @@ -886,7 +886,7 @@ public ActionResult ExportXmlSelected(string selectedIds) if (!_permissionService.Authorize(StandardPermissionProvider.ManageOrders)) return AccessDeniedView(); - return Export(ExportOrderXmlProvider.SystemName, selectedIds); + return Export(OrderXmlExportProvider.SystemName, selectedIds); } [Compress] @@ -895,7 +895,7 @@ public ActionResult ExportExcelAll() if (!_permissionService.Authorize(StandardPermissionProvider.ManageOrders)) return AccessDeniedView(); - return Export(ExportOrderXlsxProvider.SystemName, null); + return Export(OrderXlsxExportProvider.SystemName, null); } [HttpPost, Compress] @@ -904,7 +904,7 @@ public ActionResult ExportExcelSelected(string selectedIds) if (!_permissionService.Authorize(StandardPermissionProvider.ManageOrders)) return AccessDeniedView(); - return Export(ExportOrderXlsxProvider.SystemName, selectedIds); + return Export(OrderXlsxExportProvider.SystemName, selectedIds); } public ActionResult ExportPdf(bool all, string selectedIds = null) diff --git a/src/Presentation/SmartStore.Web/Administration/Controllers/ProductController.cs b/src/Presentation/SmartStore.Web/Administration/Controllers/ProductController.cs index 5b79e00770..5e22159a4c 100644 --- a/src/Presentation/SmartStore.Web/Administration/Controllers/ProductController.cs +++ b/src/Presentation/SmartStore.Web/Administration/Controllers/ProductController.cs @@ -27,7 +27,7 @@ using SmartStore.Services.Catalog; using SmartStore.Services.Common; using SmartStore.Services.Customers; -using SmartStore.Services.DataExchange.ExportProvider; +using SmartStore.Services.DataExchange.Providers; using SmartStore.Services.Directory; using SmartStore.Services.Discounts; using SmartStore.Services.ExportImport; @@ -2796,7 +2796,7 @@ public ActionResult ExportXmlAll() if (!_permissionService.Authorize(StandardPermissionProvider.ManageCatalog)) return AccessDeniedView(); - return Export(ExportProductXmlProvider.SystemName, null); + return Export(ProductXmlExportProvider.SystemName, null); } [HttpPost, Compress] @@ -2805,7 +2805,7 @@ public ActionResult ExportXmlSelected(string selectedIds) if (!_permissionService.Authorize(StandardPermissionProvider.ManageCatalog)) return AccessDeniedView(); - return Export(ExportProductXmlProvider.SystemName, selectedIds); + return Export(ProductXmlExportProvider.SystemName, selectedIds); } [Compress] @@ -2814,7 +2814,7 @@ public ActionResult ExportExcelAll() if (!_permissionService.Authorize(StandardPermissionProvider.ManageCatalog)) return AccessDeniedView(); - return Export(ExportProductXlsxProvider.SystemName, null); + return Export(ProductXlsxExportProvider.SystemName, null); } [HttpPost, Compress] @@ -2823,7 +2823,7 @@ public ActionResult ExportExcelSelected(string selectedIds) if (!_permissionService.Authorize(StandardPermissionProvider.ManageCatalog)) return AccessDeniedView(); - return Export(ExportProductXlsxProvider.SystemName, selectedIds); + return Export(ProductXlsxExportProvider.SystemName, selectedIds); } public ActionResult ExportPdf(bool all, string selectedIds = null) From f84479657188817ff57b96744375f0927720342f Mon Sep 17 00:00:00 2001 From: Murat Cakir Date: Sat, 7 Nov 2015 02:12:51 +0100 Subject: [PATCH 013/707] Export framework: minor renaming --- .../ComponentModel/HybridExpando.cs | 13 +- .../ExportTask/ExportProfileTask.cs | 154 +++++++++--------- .../ExportTask/ExportProfileTaskContext.cs | 19 ++- .../DataExchange/Internal/DynamicEntity.cs | 32 +--- 4 files changed, 98 insertions(+), 120 deletions(-) diff --git a/src/Libraries/SmartStore.Core/ComponentModel/HybridExpando.cs b/src/Libraries/SmartStore.Core/ComponentModel/HybridExpando.cs index 42061fad53..6697e19d0c 100644 --- a/src/Libraries/SmartStore.Core/ComponentModel/HybridExpando.cs +++ b/src/Libraries/SmartStore.Core/ComponentModel/HybridExpando.cs @@ -324,12 +324,12 @@ public object this[string key] get { object result = null; - if (TryGetMemberCore(key, out result)) + if (!TryGetMemberCore(key, out result)) { - return result; + throw new KeyNotFoundException(); } - throw new KeyNotFoundException(); + return result; } set { @@ -383,9 +383,10 @@ public bool Contains(KeyValuePair item, bool includeInstanceProp /// public bool Contains(string propertyName, bool includeInstanceProperties = false) { - bool contains = Properties.ContainsKey(propertyName); - if (contains) - return true; + if (Properties.ContainsKey(propertyName)) + { + return true; + } if (includeInstanceProperties && _instance != null) { diff --git a/src/Libraries/SmartStore.Services/DataExchange/ExportTask/ExportProfileTask.cs b/src/Libraries/SmartStore.Services/DataExchange/ExportTask/ExportProfileTask.cs index 48c50afc11..86c909fc27 100644 --- a/src/Libraries/SmartStore.Services/DataExchange/ExportTask/ExportProfileTask.cs +++ b/src/Libraries/SmartStore.Services/DataExchange/ExportTask/ExportProfileTask.cs @@ -206,13 +206,13 @@ private IExportDataSegmenterProvider CreateSegmenter(ExportProfileTaskContext ct switch (ctx.Provider.Value.EntityType) { case ExportEntityType.Product: - ctx.Export.Segmenter = new ExportDataSegmenter + ctx.ExecuteContext.Segmenter = new ExportDataSegmenter ( skip => GetProducts(ctx, skip), entities => { // load data behind navigation properties for current queue in one go - ctx.DataContextProduct = new ProductExportContext(entities, + ctx.ProductExportContext = new ProductExportContext(entities, x => _productAttributeService.Value.GetProductVariantAttributesByProductIds(x, null), x => _productAttributeService.Value.GetProductVariantAttributeCombinations(x), x => _productService.Value.GetTierPricesByProductIds(x, (ctx.Projection.CurrencyId ?? 0) != 0 ? ctx.ContextCustomer : null, ctx.Store.Id), @@ -231,12 +231,12 @@ private IExportDataSegmenterProvider CreateSegmenter(ExportProfileTaskContext ct break; case ExportEntityType.Order: - ctx.Export.Segmenter = new ExportDataSegmenter + ctx.ExecuteContext.Segmenter = new ExportDataSegmenter ( skip => GetOrders(ctx, skip), entities => { - ctx.DataContextOrder = new OrderExportContext(entities, + ctx.OrderExportContext = new OrderExportContext(entities, x => _customerService.Value.GetCustomersByIds(x), x => _customerService.Value.GetRewardPointsHistoriesByCustomerIds(x), x => _addressesService.Value.GetAddressByIds(x), @@ -250,12 +250,12 @@ private IExportDataSegmenterProvider CreateSegmenter(ExportProfileTaskContext ct break; case ExportEntityType.Manufacturer: - ctx.Export.Segmenter = new ExportDataSegmenter + ctx.ExecuteContext.Segmenter = new ExportDataSegmenter ( skip => GetManufacturers(ctx, skip), entities => { - ctx.DataContextManufacturer = new ManufacturerExportContext(entities, + ctx.ManufacturerExportContext = new ManufacturerExportContext(entities, x => _manufacturerService.Value.GetProductManufacturersByManufacturerIds(x), x => _pictureService.Value.GetPicturesByIds(x) ); @@ -266,12 +266,12 @@ private IExportDataSegmenterProvider CreateSegmenter(ExportProfileTaskContext ct break; case ExportEntityType.Category: - ctx.Export.Segmenter = new ExportDataSegmenter + ctx.ExecuteContext.Segmenter = new ExportDataSegmenter ( skip => GetCategories(ctx, skip), entities => { - ctx.DataContextCategory = new CategoryExportContext(entities, + ctx.CategoryExportContext = new CategoryExportContext(entities, x => _categoryService.Value.GetProductCategoriesByCategoryIds(x), x => _pictureService.Value.GetPicturesByIds(x) ); @@ -282,12 +282,12 @@ private IExportDataSegmenterProvider CreateSegmenter(ExportProfileTaskContext ct break; case ExportEntityType.Customer: - ctx.Export.Segmenter = new ExportDataSegmenter + ctx.ExecuteContext.Segmenter = new ExportDataSegmenter ( skip => GetCustomers(ctx, skip), entities => { - ctx.DataContextCustomer = new CustomerExportContext(entities, + ctx.CustomerExportContext = new CustomerExportContext(entities, x => _genericAttributeService.Value.GetAttributesForEntity(x, "Customer") ); }, @@ -297,7 +297,7 @@ private IExportDataSegmenterProvider CreateSegmenter(ExportProfileTaskContext ct break; case ExportEntityType.NewsLetterSubscription: - ctx.Export.Segmenter = new ExportDataSegmenter + ctx.ExecuteContext.Segmenter = new ExportDataSegmenter ( skip => GetNewsLetterSubscriptions(ctx, skip), null, @@ -307,11 +307,11 @@ private IExportDataSegmenterProvider CreateSegmenter(ExportProfileTaskContext ct break; default: - ctx.Export.Segmenter = null; + ctx.ExecuteContext.Segmenter = null; break; } - return ctx.Export.Segmenter as IExportDataSegmenterProvider; + return ctx.ExecuteContext.Segmenter as IExportDataSegmenterProvider; } private void PrepareProductDescription(ExportProfileTaskContext ctx, dynamic expando, Product product) @@ -352,7 +352,7 @@ private void PrepareProductDescription(ExportProfileTaskContext ctx, dynamic exp else if (ctx.Projection.DescriptionMerging == ExportDescriptionMerging.ManufacturerAndNameAndShortDescription || ctx.Projection.DescriptionMerging == ExportDescriptionMerging.ManufacturerAndNameAndDescription) { - var productManus = ctx.DataContextProduct.ProductManufacturers.Load(product.Id); + var productManus = ctx.ProductExportContext.ProductManufacturers.Load(product.Id); if (productManus != null && productManus.Any()) description = productManus.First().Manufacturer.GetLocalized(x => x.Name, languageId, true, false); @@ -429,7 +429,7 @@ private decimal CalculatePrice(ExportProfileTaskContext ctx, Product product, bo // price type if (ctx.Projection.PriceType.HasValue && !forAttributeCombination) { - var priceCalculationContext = ctx.DataContextProduct as PriceCalculationContext; + var priceCalculationContext = ctx.ProductExportContext as PriceCalculationContext; if (ctx.Projection.PriceType.Value == PriceDisplayType.LowestPrice) { @@ -1486,13 +1486,13 @@ private List ConvertToExpando(ExportProfileTaskContext ctx, Product pro pictureSize = ctx.Projection.PictureSize; var perfLoadId = (ctx.IsPreview ? 0 : product.Id); // perf preview (it's a compromise) - var productPictures = ctx.DataContextProduct.ProductPictures.Load(perfLoadId); - var productManufacturers = ctx.DataContextProduct.ProductManufacturers.Load(perfLoadId); - var productCategories = ctx.DataContextProduct.ProductCategories.Load(product.Id); - var productAttributes = ctx.DataContextProduct.Attributes.Load(product.Id); - var productAttributeCombinations = ctx.DataContextProduct.AttributeCombinations.Load(product.Id); - var productTags = ctx.DataContextProduct.ProductTags.Load(perfLoadId); - var specificationAttributes = ctx.DataContextProduct.ProductSpecificationAttributes.Load(perfLoadId); + var productPictures = ctx.ProductExportContext.ProductPictures.Load(perfLoadId); + var productManufacturers = ctx.ProductExportContext.ProductManufacturers.Load(perfLoadId); + var productCategories = ctx.ProductExportContext.ProductCategories.Load(product.Id); + var productAttributes = ctx.ProductExportContext.Attributes.Load(product.Id); + var productAttributeCombinations = ctx.ProductExportContext.AttributeCombinations.Load(product.Id); + var productTags = ctx.ProductExportContext.ProductTags.Load(perfLoadId); + var specificationAttributes = ctx.ProductExportContext.ProductSpecificationAttributes.Load(perfLoadId); dynamic expando = ToExpando(ctx, product); @@ -1609,7 +1609,7 @@ private List ConvertToExpando(ExportProfileTaskContext ctx, Product pro if (product.HasTierPrices) { - var tierPrices = ctx.DataContextProduct.TierPrices.Load(product.Id) + var tierPrices = ctx.ProductExportContext.TierPrices.Load(product.Id) .RemoveDuplicatedQuantities(); expando.TierPrices = tierPrices @@ -1630,7 +1630,7 @@ private List ConvertToExpando(ExportProfileTaskContext ctx, Product pro if (product.HasDiscountsApplied) { - var appliedDiscounts = ctx.DataContextProduct.AppliedDiscounts.Load(product.Id); + var appliedDiscounts = ctx.ProductExportContext.AppliedDiscounts.Load(product.Id); expando.AppliedDiscounts = appliedDiscounts .Select(x => ToExpando(ctx, x)) @@ -1656,7 +1656,7 @@ private List ConvertToExpando(ExportProfileTaskContext ctx, Product pro if (product.ProductType == ProductType.BundledProduct) { - var bundleItems = ctx.DataContextProduct.ProductBundleItems.Load(perfLoadId); + var bundleItems = ctx.ProductExportContext.ProductBundleItems.Load(perfLoadId); expando.ProductBundleItems = bundleItems .Select(x => @@ -1696,7 +1696,7 @@ private List ConvertToExpando(ExportProfileTaskContext ctx, Product pro if (ctx.Supports(ExportFeatures.OffersBrandFallback)) { string brand = null; - var productManus = ctx.DataContextProduct.ProductManufacturers.Load(perfLoadId); + var productManus = ctx.ProductExportContext.ProductManufacturers.Load(perfLoadId); if (productManus != null && productManus.Any()) brand = productManus.First().Manufacturer.GetLocalized(x => x.Name, languageId, true, false); @@ -1851,14 +1851,14 @@ private List ConvertToExpando(ExportProfileTaskContext ctx, Order order { var result = new List(); - ctx.DataContextOrder.Addresses.Collect(order.ShippingAddressId ?? 0); + ctx.OrderExportContext.Addresses.Collect(order.ShippingAddressId ?? 0); var perfLoadId = (ctx.IsPreview ? 0 : order.Id); - var addresses = ctx.DataContextOrder.Addresses.Load(ctx.IsPreview ? 0 : order.BillingAddressId); - var customers = ctx.DataContextOrder.Customers.Load(order.CustomerId); - var rewardPointsHistories = ctx.DataContextOrder.RewardPointsHistories.Load(ctx.IsPreview ? 0 : order.CustomerId); - var orderItems = ctx.DataContextOrder.OrderItems.Load(perfLoadId); - var shipments = ctx.DataContextOrder.Shipments.Load(perfLoadId); + var addresses = ctx.OrderExportContext.Addresses.Load(ctx.IsPreview ? 0 : order.BillingAddressId); + var customers = ctx.OrderExportContext.Customers.Load(order.CustomerId); + var rewardPointsHistories = ctx.OrderExportContext.RewardPointsHistories.Load(ctx.IsPreview ? 0 : order.CustomerId); + var orderItems = ctx.OrderExportContext.OrderItems.Load(perfLoadId); + var shipments = ctx.OrderExportContext.Shipments.Load(perfLoadId); dynamic expando = ToExpando(ctx, order); @@ -1918,13 +1918,13 @@ private List ConvertToExpando(ExportProfileTaskContext ctx, Manufacture { var result = new List(); - var productManufacturers = ctx.DataContextManufacturer.ProductManufacturers.Load(manu.Id); + var productManufacturers = ctx.ManufacturerExportContext.ProductManufacturers.Load(manu.Id); dynamic expando = ToExpando(ctx, manu); if (!ctx.IsPreview && manu.PictureId.HasValue) { - var pictures = ctx.DataContextManufacturer.Pictures.Load(manu.PictureId.Value); + var pictures = ctx.ManufacturerExportContext.Pictures.Load(manu.PictureId.Value); if (pictures.Count > 0) expando.Picture = ToExpando(ctx, pictures.First(), _mediaSettings.Value.ManufacturerThumbPictureSize, _mediaSettings.Value.ManufacturerThumbPictureSize); @@ -1954,13 +1954,13 @@ private List ConvertToExpando(ExportProfileTaskContext ctx, Category ca { var result = new List(); - var productCategories = ctx.DataContextCategory.ProductCategories.Load(category.Id); + var productCategories = ctx.CategoryExportContext.ProductCategories.Load(category.Id); dynamic expando = ToExpando(ctx, category); if (!ctx.IsPreview && category.PictureId.HasValue) { - var pictures = ctx.DataContextCategory.Pictures.Load(category.PictureId.Value); + var pictures = ctx.CategoryExportContext.Pictures.Load(category.PictureId.Value); if (pictures.Count > 0) expando.Picture = ToExpando(ctx, pictures.First(), _mediaSettings.Value.CategoryThumbPictureSize, _mediaSettings.Value.CategoryThumbPictureSize); @@ -1991,7 +1991,7 @@ private List ConvertToExpando(ExportProfileTaskContext ctx, Customer cu var result = new List(); var perfLoadId = (ctx.IsPreview ? 0 : customer.Id); - var genericAttributes = ctx.DataContextCustomer.GenericAttributes.Load(perfLoadId); + var genericAttributes = ctx.CustomerExportContext.GenericAttributes.Load(perfLoadId); dynamic expando = ToExpando(ctx, customer); @@ -2142,7 +2142,7 @@ private List GetProducts(ExportProfileTaskContext ctx, int skip) { SetProgress(ctx, products.Count); - _services.DbContext.DetachEntities(result); + _services.DbContext.DetachEntities(result); } catch { } @@ -2430,7 +2430,7 @@ private List Init(ExportProfileTaskContext ctx, int? totalRecords = null) private void ExportCoreInner(ExportProfileTaskContext ctx, Store store) { - if (ctx.Export.Abort != ExportAbortion.None) + if (ctx.ExecuteContext.Abort != ExportAbortion.None) return; int fileIndex = 0; @@ -2459,15 +2459,15 @@ private void ExportCoreInner(ExportProfileTaskContext ctx, Store store) ctx.Log.Information(logHead.ToString()); } - ctx.Export.Store = ToExpando(ctx, ctx.Store); + ctx.ExecuteContext.Store = ToExpando(ctx, ctx.Store); - ctx.Export.MaxFileNameLength = _dataExchangeSettings.Value.MaxFileNameLength; + ctx.ExecuteContext.MaxFileNameLength = _dataExchangeSettings.Value.MaxFileNameLength; - ctx.Export.FileExtension = (ctx.Provider.Value.FileExtension.HasValue() ? ctx.Provider.Value.FileExtension.ToLower().EnsureStartsWith(".") : ""); + ctx.ExecuteContext.FileExtension = (ctx.Provider.Value.FileExtension.HasValue() ? ctx.Provider.Value.FileExtension.ToLower().EnsureStartsWith(".") : ""); - ctx.Export.HasPublicDeployment = ctx.Profile.Deployments.Any(x => x.IsPublic && x.DeploymentType == ExportDeploymentType.FileSystem); + ctx.ExecuteContext.HasPublicDeployment = ctx.Profile.Deployments.Any(x => x.IsPublic && x.DeploymentType == ExportDeploymentType.FileSystem); - ctx.Export.PublicFolderPath = (ctx.Export.HasPublicDeployment ? Path.Combine(HttpRuntime.AppDomainAppPath, PublicFolder) : null); + ctx.ExecuteContext.PublicFolderPath = (ctx.ExecuteContext.HasPublicDeployment ? Path.Combine(HttpRuntime.AppDomainAppPath, PublicFolder) : null); using (var segmenter = CreateSegmenter(ctx)) @@ -2482,59 +2482,59 @@ private void ExportCoreInner(ExportProfileTaskContext ctx, Store store) ctx.Log.Information("There are no records to export"); } - while (ctx.Export.Abort == ExportAbortion.None && segmenter.HasData) + while (ctx.ExecuteContext.Abort == ExportAbortion.None && segmenter.HasData) { segmenter.RecordPerSegmentCount = 0; - ctx.Export.RecordsSucceeded = 0; + ctx.ExecuteContext.RecordsSucceeded = 0; try { if (ctx.IsFileBasedExport) { - var resolvedPattern = ctx.Profile.ResolveFileNamePattern(ctx.Store, ++fileIndex, ctx.Export.MaxFileNameLength); + var resolvedPattern = ctx.Profile.ResolveFileNamePattern(ctx.Store, ++fileIndex, ctx.ExecuteContext.MaxFileNameLength); - ctx.Export.FileName = resolvedPattern + ctx.Export.FileExtension; - ctx.Export.FilePath = Path.Combine(ctx.Export.Folder, ctx.Export.FileName); + ctx.ExecuteContext.FileName = resolvedPattern + ctx.ExecuteContext.FileExtension; + ctx.ExecuteContext.FilePath = Path.Combine(ctx.ExecuteContext.Folder, ctx.ExecuteContext.FileName); - if (ctx.Export.HasPublicDeployment) - ctx.Export.PublicFileUrl = ctx.Store.Url.EnsureEndsWith("/") + PublicFolder.EnsureEndsWith("/") + ctx.Export.FileName; + if (ctx.ExecuteContext.HasPublicDeployment) + ctx.ExecuteContext.PublicFileUrl = ctx.Store.Url.EnsureEndsWith("/") + PublicFolder.EnsureEndsWith("/") + ctx.ExecuteContext.FileName; - ctx.Provider.Value.Execute(ctx.Export); + ctx.Provider.Value.Execute(ctx.ExecuteContext); // create info for deployment list in profile edit - if (File.Exists(ctx.Export.FilePath)) + if (File.Exists(ctx.ExecuteContext.FilePath)) { ctx.Result.Files.Add(new DataExportResult.ExportFileInfo { StoreId = ctx.Store.Id, - FileName = ctx.Export.FileName + FileName = ctx.ExecuteContext.FileName }); } } else { - ctx.Provider.Value.Execute(ctx.Export); + ctx.Provider.Value.Execute(ctx.ExecuteContext); } - ctx.Log.Information("Provider reports {0} successful exported record(s)".FormatInvariant(ctx.Export.RecordsSucceeded)); + ctx.Log.Information("Provider reports {0} successful exported record(s)".FormatInvariant(ctx.ExecuteContext.RecordsSucceeded)); } catch (Exception exc) { - ctx.Export.Abort = ExportAbortion.Hard; + ctx.ExecuteContext.Abort = ExportAbortion.Hard; ctx.Log.Error("The provider failed to execute the export: " + exc.ToAllMessages(), exc); ctx.Result.LastError = exc.ToString(); } - if (ctx.Export.IsMaxFailures) + if (ctx.ExecuteContext.IsMaxFailures) ctx.Log.Warning("Export aborted. The maximum number of failures has been reached"); if (ctx.TaskContext.CancellationToken.IsCancellationRequested) ctx.Log.Warning("Export aborted. A cancellation has been requested"); } - if (ctx.Export.Abort != ExportAbortion.Hard) + if (ctx.ExecuteContext.Abort != ExportAbortion.Hard) { - ctx.Provider.Value.OnExecuted(ctx.Export); + ctx.Provider.Value.OnExecuted(ctx.ExecuteContext); } } } @@ -2559,7 +2559,7 @@ private void ExportCoreOuter(ExportProfileTaskContext ctx) } ctx.Log = logger; - ctx.Export.Log = logger; + ctx.ExecuteContext.Log = logger; ctx.ProgressInfo = T("Admin.DataExchange.Export.ProgressInfo"); if (ctx.Profile.ProviderConfigData.HasValue()) @@ -2567,7 +2567,7 @@ private void ExportCoreOuter(ExportProfileTaskContext ctx) var configInfo = ctx.Provider.Value.ConfigurationInfo; if (configInfo != null) { - ctx.Export.ConfigurationData = XmlHelper.Deserialize(ctx.Profile.ProviderConfigData, configInfo.ModelType); + ctx.ExecuteContext.ConfigurationData = XmlHelper.Deserialize(ctx.Profile.ProviderConfigData, configInfo.ModelType); } } @@ -2601,14 +2601,14 @@ private void ExportCoreOuter(ExportProfileTaskContext ctx) var stores = Init(ctx); - ctx.Export.Language = ToExpando(ctx, ctx.ContextLanguage); - ctx.Export.Customer = ToExpando(ctx, ctx.ContextCustomer); - ctx.Export.Currency = ToExpando(ctx, ctx.ContextCurrency); + ctx.ExecuteContext.Language = ToExpando(ctx, ctx.ContextLanguage); + ctx.ExecuteContext.Customer = ToExpando(ctx, ctx.ContextCustomer); + ctx.ExecuteContext.Currency = ToExpando(ctx, ctx.ContextCurrency); stores.ForEach(x => ExportCoreInner(ctx, x)); } - if (!ctx.IsPreview && ctx.Export.Abort != ExportAbortion.Hard) + if (!ctx.IsPreview && ctx.ExecuteContext.Abort != ExportAbortion.Hard) { if (ctx.IsFileBasedExport) { @@ -2673,7 +2673,7 @@ private void ExportCoreOuter(ExportProfileTaskContext ctx) try { - if (ctx.IsFileBasedExport && ctx.Export.Abort != ExportAbortion.Hard && ctx.Profile.Cleanup) + if (ctx.IsFileBasedExport && ctx.ExecuteContext.Abort != ExportAbortion.Hard && ctx.Profile.Cleanup) { FileSystemHelper.ClearDirectory(ctx.FolderContent, false); } @@ -2691,21 +2691,21 @@ private void ExportCoreOuter(ExportProfileTaskContext ctx) ctx.CategoryPathes.Clear(); ctx.Categories.Clear(); ctx.EntityIdsSelected.Clear(); - ctx.DataContextProduct = null; - ctx.DataContextOrder = null; - ctx.DataContextManufacturer = null; - ctx.DataContextCategory = null; - ctx.DataContextCustomer = null; - - ctx.Export.CustomProperties.Clear(); - ctx.Export.Log = null; + ctx.ProductExportContext = null; + ctx.OrderExportContext = null; + ctx.ManufacturerExportContext = null; + ctx.CategoryExportContext = null; + ctx.CustomerExportContext = null; + + ctx.ExecuteContext.CustomProperties.Clear(); + ctx.ExecuteContext.Log = null; ctx.Log = null; } catch { } } } - if (ctx.IsPreview || ctx.Export.Abort == ExportAbortion.Hard) + if (ctx.IsPreview || ctx.ExecuteContext.Abort == ExportAbortion.Hard) return; // post process order entities @@ -2874,7 +2874,7 @@ public DataExportResult Execute( if (customProperties != null) { foreach (var item in customProperties) - ctx.Export.CustomProperties.Add(item.Key, item.Value); + ctx.ExecuteContext.CustomProperties.Add(item.Key, item.Value); } ExportCoreOuter(ctx); diff --git a/src/Libraries/SmartStore.Services/DataExchange/ExportTask/ExportProfileTaskContext.cs b/src/Libraries/SmartStore.Services/DataExchange/ExportTask/ExportProfileTaskContext.cs index 576b1ffc08..8c1286b5d6 100644 --- a/src/Libraries/SmartStore.Services/DataExchange/ExportTask/ExportProfileTaskContext.cs +++ b/src/Libraries/SmartStore.Services/DataExchange/ExportTask/ExportProfileTaskContext.cs @@ -62,8 +62,8 @@ public ExportProfileTaskContext( FileFolder = (IsFileBasedExport ? FolderContent : null) }; - Export = new ExportExecuteContext(Result, TaskContext.CancellationToken, FolderContent); - Export.Projection = XmlHelper.Deserialize(profile.Projection); + ExecuteContext = new ExportExecuteContext(Result, TaskContext.CancellationToken, FolderContent); + ExecuteContext.Projection = XmlHelper.Deserialize(profile.Projection); } public List EntityIdsSelected { get; private set; } @@ -141,7 +141,7 @@ public string[] GetDeploymentFiles(ExportDeployment deployment) public HashSet NewsletterSubscriptions { get; set; } // data loaded once per page - public ProductExportContext DataContextProduct + public ProductExportContext ProductExportContext { get { @@ -155,7 +155,8 @@ public ProductExportContext DataContextProduct _productExportContext = value; } } - public OrderExportContext DataContextOrder + + public OrderExportContext OrderExportContext { get { @@ -169,7 +170,8 @@ public OrderExportContext DataContextOrder _orderExportContext = value; } } - public ManufacturerExportContext DataContextManufacturer + + public ManufacturerExportContext ManufacturerExportContext { get { @@ -183,7 +185,8 @@ public ManufacturerExportContext DataContextManufacturer _manufacturerExportContext = value; } } - public CategoryExportContext DataContextCategory + + public CategoryExportContext CategoryExportContext { get { @@ -197,7 +200,7 @@ public CategoryExportContext DataContextCategory _categoryExportContext = value; } } - public CustomerExportContext DataContextCustomer + public CustomerExportContext CustomerExportContext { get { @@ -212,7 +215,7 @@ public CustomerExportContext DataContextCustomer } } - public ExportExecuteContext Export { get; set; } + public ExportExecuteContext ExecuteContext { get; set; } public DataExportResult Result { get; set; } } } diff --git a/src/Libraries/SmartStore.Services/DataExchange/Internal/DynamicEntity.cs b/src/Libraries/SmartStore.Services/DataExchange/Internal/DynamicEntity.cs index 6940371341..287927315d 100644 --- a/src/Libraries/SmartStore.Services/DataExchange/Internal/DynamicEntity.cs +++ b/src/Libraries/SmartStore.Services/DataExchange/Internal/DynamicEntity.cs @@ -1,11 +1,5 @@ -using SmartStore.ComponentModel; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using System.Dynamic; -using SmartStore.Utilities; +using System.Collections.Generic; +using SmartStore.ComponentModel; namespace SmartStore.Services.DataExchange.Internal { @@ -14,7 +8,7 @@ internal class DynamicEntity : HybridExpando public DynamicEntity(DynamicEntity dynamicEntity) : this(dynamicEntity.WrappedObject) { - base.Properties.Merge(dynamicEntity, true); + MergeRange(dynamicEntity); } public DynamicEntity(object entity) @@ -39,26 +33,6 @@ public void MergeRange(IDictionary other) protected override bool TrySetMemberCore(string name, object value) { - // Virtual navigation properties of entities should not be set as is. - // A previously created ExpandoEntity instance is set instead. - // But assigning the value to the wrapped entity instance would result - // in a type mismatch error, as both types obviously don't match. - // Therefore we save reference values in the local values dictionary. - - var pi = base.GetPropertyInfo(name); - - if (pi != null && (pi.PropertyType.IsPredefinedType() || !pi.GetMethod.IsVirtual)) - { - // Property exists, is NOT complex, or IS complex but NOT virtual - try - { - Fasterflect.PropertyInfoExtensions.Set(pi, WrappedObject, value); - return true; - } - catch { } - } - - // Property does not exist, or is virtual complex Properties[name] = value; return true; } From 2123d82c033d56894346cb9047e8744fa46689f9 Mon Sep 17 00:00:00 2001 From: Marcus Gesing Date: Sat, 7 Nov 2015 11:33:03 +0100 Subject: [PATCH 014/707] Refactoring: Cleaner not to have MVC related code in service layer --- .../201509150931528_ExportFramework2.cs | 4 + .../SmartStore.Services/Blogs/BlogService.cs | 51 --------- .../SmartStore.Services/Blogs/IBlogService.cs | 10 -- .../Catalog/IProductService.cs | 9 -- .../Catalog/ProductService.cs | 87 +-------------- .../Forums/ForumService.cs | 103 ------------------ .../Forums/IForumService.cs | 16 --- .../SmartStore.Services/News/INewsService.cs | 10 -- .../SmartStore.Services/News/NewsService.cs | 56 ---------- .../Controllers/BlogController.cs | 43 +++++++- .../Controllers/BoardsController.cs | 76 ++++++++++++- .../Controllers/CatalogController.cs | 58 +++++++++- .../Controllers/NewsController.cs | 39 ++++++- 13 files changed, 212 insertions(+), 350 deletions(-) diff --git a/src/Libraries/SmartStore.Data/Migrations/201509150931528_ExportFramework2.cs b/src/Libraries/SmartStore.Data/Migrations/201509150931528_ExportFramework2.cs index 4cf5af7438..174f2d1f44 100644 --- a/src/Libraries/SmartStore.Data/Migrations/201509150931528_ExportFramework2.cs +++ b/src/Libraries/SmartStore.Data/Migrations/201509150931528_ExportFramework2.cs @@ -59,6 +59,10 @@ public void MigrateLocaleResources(LocaleResourcesBuilder builder) "Edited payment method '{0}' ({1})", "Zahlungsart '{0}' ({1}) bearbeitet"); + builder.AddOrUpdate("Admin.Configuration.Settings.Blog.ShowHeaderRSSUrl.Hint", + "Check to enable the blog RSS feed link in customers browser address bar.", + "Legt fest, ob der RSS-Feed-Link in der Adressleiste des Browsers angezeigt werden soll."); + builder.AddOrUpdate("Admin.System.SeNames", "SEO Names", "SEO Namen"); builder.Delete("Admin.System.SeNames.DeleteSelected"); diff --git a/src/Libraries/SmartStore.Services/Blogs/BlogService.cs b/src/Libraries/SmartStore.Services/Blogs/BlogService.cs index c616abefbe..f3bb8103bb 100644 --- a/src/Libraries/SmartStore.Services/Blogs/BlogService.cs +++ b/src/Libraries/SmartStore.Services/Blogs/BlogService.cs @@ -1,16 +1,12 @@ using System; using System.Collections.Generic; using System.Linq; -using System.ServiceModel.Syndication; -using System.Web.Mvc; using SmartStore.Core; using SmartStore.Core.Data; using SmartStore.Core.Domain.Blogs; using SmartStore.Core.Domain.Stores; using SmartStore.Core.Events; using SmartStore.Services.Localization; -using SmartStore.Services.Seo; -using SmartStore.Utilities; namespace SmartStore.Services.Blogs { @@ -260,53 +256,6 @@ public virtual void UpdateCommentTotals(BlogPost blogPost) UpdateBlogPost(blogPost); } - /// - /// Creates a RSS feed with blog posts - /// - /// UrlHelper to generate URLs - /// Language identifier - /// SmartSyndicationFeed object - public virtual SmartSyndicationFeed CreateRssFeed(UrlHelper urlHelper, int languageId) - { - if (urlHelper == null) - throw new ArgumentNullException("urlHelper"); - - DateTime? maxAge = null; - var protocol = _services.WebHelper.IsCurrentConnectionSecured() ? "https" : "http"; - var selfLink = urlHelper.RouteUrl("BlogRSS", new { languageId = languageId }, protocol); - var blogLink = urlHelper.RouteUrl("Blog", null, protocol); - - var title = "{0} - Blog".FormatInvariant(_services.StoreContext.CurrentStore.Name); - - if (_blogSettings.MaxAgeInDays > 0) - maxAge = DateTime.UtcNow.Subtract(new TimeSpan(_blogSettings.MaxAgeInDays, 0, 0, 0)); - - var language = _languageService.GetLanguageById(languageId); - var feed = new SmartSyndicationFeed(new Uri(blogLink), title); - - feed.AddNamespaces(false); - feed.Init(selfLink, language); - - if (!_blogSettings.Enabled) - return feed; - - var items = new List(); - var blogPosts = GetAllBlogPosts(_services.StoreContext.CurrentStore.Id, languageId, null, null, 0, int.MaxValue, false, maxAge); - - foreach (var blogPost in blogPosts) - { - var blogPostUrl = urlHelper.RouteUrl("BlogPost", new { SeName = blogPost.GetSeName(blogPost.LanguageId, ensureTwoPublishedLanguages: false) }, "http"); - - var item = feed.CreateItem(blogPost.Title, blogPost.Body, blogPostUrl, blogPost.CreatedOnUtc); - - items.Add(item); - } - - feed.Items = items; - - return feed; - } - #endregion } } diff --git a/src/Libraries/SmartStore.Services/Blogs/IBlogService.cs b/src/Libraries/SmartStore.Services/Blogs/IBlogService.cs index 983932b0bf..682ddbe191 100644 --- a/src/Libraries/SmartStore.Services/Blogs/IBlogService.cs +++ b/src/Libraries/SmartStore.Services/Blogs/IBlogService.cs @@ -1,9 +1,7 @@ using System; using System.Collections.Generic; -using System.Web.Mvc; using SmartStore.Core; using SmartStore.Core.Domain.Blogs; -using SmartStore.Utilities; namespace SmartStore.Services.Blogs { @@ -79,13 +77,5 @@ IPagedList GetAllBlogPostsByTag(int storeId, int languageId, string ta /// /// Blog post void UpdateCommentTotals(BlogPost blogPost); - - /// - /// Creates a RSS feed with blog posts - /// - /// UrlHelper to generate URLs - /// Language identifier - /// SmartSyndicationFeed object - SmartSyndicationFeed CreateRssFeed(UrlHelper urlHelper, int languageId); } } diff --git a/src/Libraries/SmartStore.Services/Catalog/IProductService.cs b/src/Libraries/SmartStore.Services/Catalog/IProductService.cs index 69a8c2254b..eb7dfa9fb9 100644 --- a/src/Libraries/SmartStore.Services/Catalog/IProductService.cs +++ b/src/Libraries/SmartStore.Services/Catalog/IProductService.cs @@ -2,14 +2,12 @@ using System.Collections.Generic; using System.Linq; using System.Linq.Expressions; -using System.Web.Mvc; using SmartStore.Collections; using SmartStore.Core; using SmartStore.Core.Domain.Catalog; using SmartStore.Core.Domain.Customers; using SmartStore.Core.Domain.Discounts; using SmartStore.Core.Domain.Orders; -using SmartStore.Utilities; namespace SmartStore.Services.Catalog { @@ -156,13 +154,6 @@ public partial interface IProductService /// Product void UpdateHasDiscountsApplied(Product product); - /// - /// Creates a RSS feed with recently added products - /// - /// UrlHelper to generate URLs - /// SmartSyndicationFeed object - SmartSyndicationFeed CreateRecentlyAddedProductsRssFeed(UrlHelper urlHelper); - /// /// Get product tags by product identifiers /// diff --git a/src/Libraries/SmartStore.Services/Catalog/ProductService.cs b/src/Libraries/SmartStore.Services/Catalog/ProductService.cs index c18f230bf5..6f273c7bfa 100644 --- a/src/Libraries/SmartStore.Services/Catalog/ProductService.cs +++ b/src/Libraries/SmartStore.Services/Catalog/ProductService.cs @@ -4,8 +4,6 @@ using System.Globalization; using System.Linq; using System.Linq.Expressions; -using System.ServiceModel.Syndication; -using System.Web.Mvc; using SmartStore.Collections; using SmartStore.Core; using SmartStore.Core.Caching; @@ -15,17 +13,13 @@ using SmartStore.Core.Domain.Customers; using SmartStore.Core.Domain.Discounts; using SmartStore.Core.Domain.Localization; -using SmartStore.Core.Domain.Media; using SmartStore.Core.Domain.Orders; using SmartStore.Core.Domain.Security; using SmartStore.Core.Domain.Stores; using SmartStore.Core.Events; using SmartStore.Services.Localization; -using SmartStore.Services.Media; using SmartStore.Services.Messages; using SmartStore.Services.Orders; -using SmartStore.Services.Seo; -using SmartStore.Utilities; namespace SmartStore.Services.Catalog { @@ -64,9 +58,6 @@ public partial class ProductService : IProductService private readonly LocalizationSettings _localizationSettings; private readonly CommonSettings _commonSettings; private readonly ICommonServices _services; - private readonly CatalogSettings _catalogSettings; - private readonly MediaSettings _mediaSettings; - private readonly IPictureService _pictureService; #endregion @@ -117,10 +108,7 @@ public ProductService( ICacheManager cacheManager, LocalizationSettings localizationSettings, CommonSettings commonSettings, - ICommonServices services, - CatalogSettings catalogSettings, - MediaSettings mediaSettings, - IPictureService pictureService) + ICommonServices services) { this._productRepository = productRepository; this._relatedProductRepository = relatedProductRepository; @@ -143,9 +131,6 @@ public ProductService( this._localizationSettings = localizationSettings; this._commonSettings = commonSettings; this._services = services; - this._catalogSettings = catalogSettings; - this._mediaSettings = mediaSettings; - this._pictureService = pictureService; this.QuerySettings = DbQuerySettings.Default; } @@ -1369,76 +1354,6 @@ public virtual void UpdateHasDiscountsApplied(Product product) UpdateProduct(product); } - /// - /// Creates a RSS feed with recently added products - /// - /// UrlHelper to generate URLs - /// SmartSyndicationFeed object - public virtual SmartSyndicationFeed CreateRecentlyAddedProductsRssFeed(UrlHelper urlHelper) - { - if (urlHelper == null) - throw new ArgumentNullException("urlHelper"); - - var protocol = _services.WebHelper.IsCurrentConnectionSecured() ? "https" : "http"; - var selfLink = urlHelper.RouteUrl("RecentlyAddedProductsRSS", null, protocol); - var recentProductsLink = urlHelper.RouteUrl("RecentlyAddedProducts", null, protocol); - - var title = "{0} - {1}".FormatInvariant(_services.StoreContext.CurrentStore.Name, _services.Localization.GetResource("RSS.RecentlyAddedProducts")); - - var feed = new SmartSyndicationFeed(new Uri(recentProductsLink), title, _services.Localization.GetResource("RSS.InformationAboutProducts")); - - feed.AddNamespaces(true); - feed.Init(selfLink, _services.WorkContext.WorkingLanguage); - - if (!_catalogSettings.RecentlyAddedProductsEnabled) - return feed; - - var items = new List(); - var searchContext = new ProductSearchContext - { - LanguageId = _services.WorkContext.WorkingLanguage.Id, - OrderBy = ProductSortingEnum.CreatedOn, - PageSize = _catalogSettings.RecentlyAddedProductsNumber, - StoreId = _services.StoreContext.CurrentStoreIdIfMultiStoreMode, - VisibleIndividuallyOnly = true - }; - - var products = SearchProducts(searchContext); - var storeUrl = _services.StoreContext.CurrentStore.Url; - - foreach (var product in products) - { - string productUrl = urlHelper.RouteUrl("Product", new { SeName = product.GetSeName() }, "http"); - if (productUrl.HasValue()) - { - var item = feed.CreateItem( - product.GetLocalized(x => x.Name), - product.GetLocalized(x => x.ShortDescription), - productUrl, - product.CreatedOnUtc, - product.FullDescription); - - try - { - // we add only the first picture - var picture = product.ProductPictures.OrderBy(x => x.DisplayOrder).Select(x => x.Picture).FirstOrDefault(); - - if (picture != null) - { - feed.AddEnclosue(item, picture, _pictureService.GetPictureUrl(picture, _mediaSettings.ProductDetailsPictureSize, false, storeUrl)); - } - } - catch { } - - items.Add(item); - } - } - - feed.Items = items; - - return feed; - } - public virtual Multimap GetProductTagsByProductIds(int[] productIds) { Guard.ArgumentNotNull(() => productIds); diff --git a/src/Libraries/SmartStore.Services/Forums/ForumService.cs b/src/Libraries/SmartStore.Services/Forums/ForumService.cs index c9f9e63dbd..5871f34ab6 100644 --- a/src/Libraries/SmartStore.Services/Forums/ForumService.cs +++ b/src/Libraries/SmartStore.Services/Forums/ForumService.cs @@ -1,8 +1,6 @@ using System; using System.Collections.Generic; using System.Linq; -using System.ServiceModel.Syndication; -using System.Web.Mvc; using SmartStore.Core; using SmartStore.Core.Caching; using SmartStore.Core.Data; @@ -12,10 +10,7 @@ using SmartStore.Core.Events; using SmartStore.Services.Common; using SmartStore.Services.Customers; -using SmartStore.Services.Localization; using SmartStore.Services.Messages; -using SmartStore.Services.Seo; -using SmartStore.Utilities; namespace SmartStore.Services.Forums { @@ -1477,104 +1472,6 @@ public virtual int CalculateTopicPageIndex(int forumTopicId, int pageSize, int p return pageIndex; } - /// - /// Creates a RSS feed with active discussions - /// - /// UrlHelper to generate URLs - /// SmartSyndicationFeed object - public virtual SmartSyndicationFeed CreateActiveDiscussionsRssFeed(UrlHelper urlHelper, int forumId) - { - if (urlHelper == null) - throw new ArgumentNullException("urlHelper"); - - var language = _services.WorkContext.WorkingLanguage; - var protocol = _services.WebHelper.IsCurrentConnectionSecured() ? "https" : "http"; - var selfLink = urlHelper.Action("ActiveDiscussionsRSS", "Boards", null, protocol); - var discussionLink = urlHelper.Action("ActiveDiscussions", "Boards", null, protocol); - - var title = "{0} - {1}".FormatInvariant(_services.StoreContext.CurrentStore.Name, _services.Localization.GetResource("Forum.ActiveDiscussionsFeedTitle")); - - var feed = new SmartSyndicationFeed(new Uri(discussionLink), title, _services.Localization.GetResource("Forum.ActiveDiscussionsFeedDescription")); - - feed.AddNamespaces(false); - feed.Init(selfLink, language); - - if (!_forumSettings.ActiveDiscussionsFeedEnabled) - return feed; - - var items = new List(); - var topics = GetActiveTopics(forumId, _forumSettings.ActiveDiscussionsFeedCount); - - var viewsText = _services.Localization.GetResource("Forum.Views"); - var repliesText = _services.Localization.GetResource("Forum.Replies"); - - foreach (var topic in topics) - { - string topicUrl = urlHelper.RouteUrl("TopicSlug", new { id = topic.Id, slug = topic.GetSeName() }, "http"); - var synopsis = "{0}: {1}, {2}: {3}".FormatInvariant(repliesText, topic.NumReplies, viewsText, topic.Views); - - var item = feed.CreateItem(topic.Subject, synopsis, topicUrl, topic.LastPostTime ?? topic.UpdatedOnUtc); - - items.Add(item); - } - - feed.Items = items; - - return feed; - } - - /// - /// Creates a RSS feed with forum topics - /// - /// UrlHelper to generate URLs - /// SmartSyndicationFeed object - public virtual SmartSyndicationFeed CreateForumRssFeed(UrlHelper urlHelper, int forumId) - { - if (urlHelper == null) - throw new ArgumentNullException("urlHelper"); - - var language = _services.WorkContext.WorkingLanguage; - var protocol = _services.WebHelper.IsCurrentConnectionSecured() ? "https" : "http"; - var selfLink = urlHelper.Action("ForumRSS", "Boards", null, protocol); - var forumLink = urlHelper.Action("Forum", "Boards", new { id = forumId }, protocol); - - var feed = new SmartSyndicationFeed(new Uri(forumLink), _services.StoreContext.CurrentStore.Name, _services.Localization.GetResource("Forum.ForumFeedDescription")); - - feed.AddNamespaces(false); - feed.Init(selfLink, language); - - if (!_forumSettings.ForumFeedsEnabled) - return feed; - - var forum = GetForumById(forumId); - - if (forum == null) - return feed; - - feed.Title = new TextSyndicationContent("{0} - {1}".FormatInvariant(_services.StoreContext.CurrentStore.Name, forum.GetLocalized(x => x.Name, language.Id))); - - var items = new List(); - var topics = GetAllTopics(forumId, 0, string.Empty, ForumSearchType.All, 0, 0, _forumSettings.ForumFeedCount); - - var viewsText = _services.Localization.GetResource("Forum.Views"); - var repliesText = _services.Localization.GetResource("Forum.Replies"); - - foreach (var topic in topics) - { - string topicUrl = urlHelper.RouteUrl("TopicSlug", new { id = topic.Id, slug = topic.GetSeName() }, "http"); - var synopsis = "{0}: {1}, {2}: {3}".FormatInvariant(repliesText, topic.NumReplies, viewsText, topic.Views); - - var item = feed.CreateItem(topic.Subject, synopsis, topicUrl, topic.LastPostTime ?? topic.UpdatedOnUtc); - - items.Add(item); - } - - feed.Items = items; - - return feed; - } - - #endregion } } diff --git a/src/Libraries/SmartStore.Services/Forums/IForumService.cs b/src/Libraries/SmartStore.Services/Forums/IForumService.cs index efcd21fa32..46e0f2f428 100644 --- a/src/Libraries/SmartStore.Services/Forums/IForumService.cs +++ b/src/Libraries/SmartStore.Services/Forums/IForumService.cs @@ -1,9 +1,7 @@ using System.Collections.Generic; -using System.Web.Mvc; using SmartStore.Core; using SmartStore.Core.Domain.Customers; using SmartStore.Core.Domain.Forums; -using SmartStore.Utilities; namespace SmartStore.Services.Forums { @@ -346,19 +344,5 @@ IPagedList GetAllSubscriptions(int customerId, int forumId, /// Post identifier /// Page index int CalculateTopicPageIndex(int forumTopicId, int pageSize, int postId); - - /// - /// Creates a RSS feed with active discussions - /// - /// UrlHelper to generate URLs - /// SmartSyndicationFeed object - SmartSyndicationFeed CreateActiveDiscussionsRssFeed(UrlHelper urlHelper, int forumId); - - /// - /// Creates a RSS feed with forum topics - /// - /// UrlHelper to generate URLs - /// SmartSyndicationFeed object - SmartSyndicationFeed CreateForumRssFeed(UrlHelper urlHelper, int forumId); } } diff --git a/src/Libraries/SmartStore.Services/News/INewsService.cs b/src/Libraries/SmartStore.Services/News/INewsService.cs index c07cceb570..d25a8d8afa 100644 --- a/src/Libraries/SmartStore.Services/News/INewsService.cs +++ b/src/Libraries/SmartStore.Services/News/INewsService.cs @@ -1,9 +1,7 @@ using System; using System.Linq; -using System.Web.Mvc; using SmartStore.Core; using SmartStore.Core.Domain.News; -using SmartStore.Utilities; namespace SmartStore.Services.News { @@ -61,13 +59,5 @@ public partial interface INewsService /// /// News item void UpdateCommentTotals(NewsItem newsItem); - - /// - /// Creates a RSS feed with news items - /// - /// UrlHelper to generate URLs - /// Language identifier - /// SmartSyndicationFeed object - SmartSyndicationFeed CreateRssFeed(UrlHelper urlHelper, int languageId); } } diff --git a/src/Libraries/SmartStore.Services/News/NewsService.cs b/src/Libraries/SmartStore.Services/News/NewsService.cs index 66adadf90e..743ab7f9f4 100644 --- a/src/Libraries/SmartStore.Services/News/NewsService.cs +++ b/src/Libraries/SmartStore.Services/News/NewsService.cs @@ -1,16 +1,10 @@ using System; -using System.Collections.Generic; using System.Linq; -using System.ServiceModel.Syndication; -using System.Web.Mvc; using SmartStore.Core; using SmartStore.Core.Data; using SmartStore.Core.Domain.News; using SmartStore.Core.Domain.Stores; using SmartStore.Core.Events; -using SmartStore.Services.Localization; -using SmartStore.Services.Seo; -using SmartStore.Utilities; namespace SmartStore.Services.News { @@ -24,7 +18,6 @@ public partial class NewsService : INewsService private readonly IRepository _newsItemRepository; private readonly IRepository _storeMappingRepository; private readonly ICommonServices _services; - private readonly ILanguageService _languageService; private readonly NewsSettings _newsSettings; @@ -35,13 +28,11 @@ public partial class NewsService : INewsService public NewsService(IRepository newsItemRepository, IRepository storeMappingRepository, ICommonServices services, - ILanguageService languageService, NewsSettings newsSettings) { _newsItemRepository = newsItemRepository; _storeMappingRepository = storeMappingRepository; _services = services; - _languageService = languageService; _newsSettings = newsSettings; this.QuerySettings = DbQuerySettings.Default; @@ -211,53 +202,6 @@ public virtual void UpdateCommentTotals(NewsItem newsItem) UpdateNews(newsItem); } - /// - /// Creates a RSS feed with news items - /// - /// UrlHelper to generate URLs - /// Language identifier - /// SmartSyndicationFeed object - public virtual SmartSyndicationFeed CreateRssFeed(UrlHelper urlHelper, int languageId) - { - if (urlHelper == null) - throw new ArgumentNullException("urlHelper"); - - DateTime? maxAge = null; - var protocol = _services.WebHelper.IsCurrentConnectionSecured() ? "https" : "http"; - var selfLink = urlHelper.Action("rss", "News", new { languageId = languageId }, protocol); - var newsLink = urlHelper.RouteUrl("NewsArchive", null, protocol); - - var title = "{0} - News".FormatInvariant(_services.StoreContext.CurrentStore.Name); - - if (_newsSettings.MaxAgeInDays > 0) - maxAge = DateTime.UtcNow.Subtract(new TimeSpan(_newsSettings.MaxAgeInDays, 0, 0, 0)); - - var language = _languageService.GetLanguageById(languageId); - var feed = new SmartSyndicationFeed(new Uri(newsLink), title); - - feed.AddNamespaces(true); - feed.Init(selfLink, language); - - if (!_newsSettings.Enabled) - return feed; - - var items = new List(); - var newsItems = GetAllNews(languageId, _services.StoreContext.CurrentStore.Id, 0, int.MaxValue, false, maxAge); - - foreach (var news in newsItems) - { - var newsUrl = urlHelper.RouteUrl("NewsItem", new { SeName = news.GetSeName(news.LanguageId, ensureTwoPublishedLanguages: false) }, "http"); - - var item = feed.CreateItem(news.Title, news.Short, newsUrl, news.CreatedOnUtc, news.Full); - - items.Add(item); - } - - feed.Items = items; - - return feed; - } - #endregion } } diff --git a/src/Presentation/SmartStore.Web/Controllers/BlogController.cs b/src/Presentation/SmartStore.Web/Controllers/BlogController.cs index ad683bda9f..88aa37ffba 100644 --- a/src/Presentation/SmartStore.Web/Controllers/BlogController.cs +++ b/src/Presentation/SmartStore.Web/Controllers/BlogController.cs @@ -6,28 +6,27 @@ using System.Web.Routing; using SmartStore.Core; using SmartStore.Core.Caching; -using SmartStore.Core.Domain; using SmartStore.Core.Domain.Blogs; using SmartStore.Core.Domain.Customers; using SmartStore.Core.Domain.Localization; using SmartStore.Core.Domain.Media; +using SmartStore.Core.Logging; using SmartStore.Services.Blogs; using SmartStore.Services.Common; using SmartStore.Services.Customers; using SmartStore.Services.Helpers; using SmartStore.Services.Localization; -using SmartStore.Core.Logging; using SmartStore.Services.Media; using SmartStore.Services.Messages; using SmartStore.Services.Seo; using SmartStore.Services.Stores; -using SmartStore.Web.Framework; +using SmartStore.Utilities; using SmartStore.Web.Framework.Controllers; +using SmartStore.Web.Framework.Mvc; using SmartStore.Web.Framework.Security; using SmartStore.Web.Framework.UI.Captcha; using SmartStore.Web.Infrastructure.Cache; using SmartStore.Web.Models.Blogs; -using SmartStore.Web.Framework.Mvc; namespace SmartStore.Web.Controllers { @@ -48,6 +47,7 @@ public partial class BlogController : PublicControllerBase private readonly ICacheManager _cacheManager; private readonly ICustomerActivityService _customerActivityService; private readonly IStoreMappingService _storeMappingService; + private readonly ILanguageService _languageService; private readonly MediaSettings _mediaSettings; private readonly BlogSettings _blogSettings; @@ -71,6 +71,7 @@ public BlogController(IBlogService blogService, ICacheManager cacheManager, ICustomerActivityService customerActivityService, IStoreMappingService storeMappingService, + ILanguageService languageService, MediaSettings mediaSettings, BlogSettings blogSettings, LocalizationSettings localizationSettings, @@ -89,6 +90,7 @@ public BlogController(IBlogService blogService, this._cacheManager = cacheManager; this._customerActivityService = customerActivityService; this._storeMappingService = storeMappingService; + this._languageService = languageService; this._mediaSettings = mediaSettings; this._blogSettings = blogSettings; @@ -232,7 +234,38 @@ public ActionResult BlogByMonth(BlogPagingFilteringModel command) [Compress] public ActionResult ListRss(int languageId) { - var feed = _blogService.CreateRssFeed(Url, languageId); + DateTime? maxAge = null; + var protocol = _webHelper.IsCurrentConnectionSecured() ? "https" : "http"; + var selfLink = Url.RouteUrl("BlogRSS", new { languageId = languageId }, protocol); + var blogLink = Url.RouteUrl("Blog", null, protocol); + + var title = "{0} - Blog".FormatInvariant(_storeContext.CurrentStore.Name); + + if (_blogSettings.MaxAgeInDays > 0) + maxAge = DateTime.UtcNow.Subtract(new TimeSpan(_blogSettings.MaxAgeInDays, 0, 0, 0)); + + var language = _languageService.GetLanguageById(languageId); + var feed = new SmartSyndicationFeed(new Uri(blogLink), title); + + feed.AddNamespaces(false); + feed.Init(selfLink, language); + + if (!_blogSettings.Enabled) + return new RssActionResult { Feed = feed }; + + var items = new List(); + var blogPosts = _blogService.GetAllBlogPosts(_storeContext.CurrentStore.Id, languageId, null, null, 0, int.MaxValue, false, maxAge); + + foreach (var blogPost in blogPosts) + { + var blogPostUrl = Url.RouteUrl("BlogPost", new { SeName = blogPost.GetSeName(blogPost.LanguageId, ensureTwoPublishedLanguages: false) }, "http"); + + var item = feed.CreateItem(blogPost.Title, blogPost.Body, blogPostUrl, blogPost.CreatedOnUtc); + + items.Add(item); + } + + feed.Items = items; return new RssActionResult { Feed = feed }; } diff --git a/src/Presentation/SmartStore.Web/Controllers/BoardsController.cs b/src/Presentation/SmartStore.Web/Controllers/BoardsController.cs index 441d1a6b9d..10d668eb81 100644 --- a/src/Presentation/SmartStore.Web/Controllers/BoardsController.cs +++ b/src/Presentation/SmartStore.Web/Controllers/BoardsController.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Linq; +using System.ServiceModel.Syndication; using System.Web.Mvc; using SmartStore.Core; using SmartStore.Core.Domain.Customers; @@ -15,6 +16,7 @@ using SmartStore.Services.Localization; using SmartStore.Services.Media; using SmartStore.Services.Seo; +using SmartStore.Utilities; using SmartStore.Web.Framework; using SmartStore.Web.Framework.Controllers; using SmartStore.Web.Framework.Mvc; @@ -34,6 +36,7 @@ public partial class BoardsController : PublicControllerBase private readonly ICountryService _countryService; private readonly IWebHelper _webHelper; private readonly IWorkContext _workContext; + private readonly IStoreContext _storeContext; private readonly ForumSettings _forumSettings; private readonly CustomerSettings _customerSettings; private readonly MediaSettings _mediaSettings; @@ -49,6 +52,7 @@ public BoardsController(IForumService forumService, ICountryService countryService, IWebHelper webHelper, IWorkContext workContext, + IStoreContext storeContext, ForumSettings forumSettings, CustomerSettings customerSettings, MediaSettings mediaSettings, @@ -60,6 +64,7 @@ public BoardsController(IForumService forumService, this._countryService = countryService; this._webHelper = webHelper; this._workContext = workContext; + this._storeContext = storeContext; this._forumSettings = forumSettings; this._customerSettings = customerSettings; this._mediaSettings = mediaSettings; @@ -266,7 +271,38 @@ public ActionResult ActiveDiscussionsRss(int forumId = 0) if (!_forumSettings.ForumsEnabled) return HttpNotFound(); - var feed = _forumService.CreateActiveDiscussionsRssFeed(Url, forumId); + var language = _workContext.WorkingLanguage; + var protocol = _webHelper.IsCurrentConnectionSecured() ? "https" : "http"; + var selfLink = Url.Action("ActiveDiscussionsRSS", "Boards", null, protocol); + var discussionLink = Url.Action("ActiveDiscussions", "Boards", null, protocol); + + var title = "{0} - {1}".FormatInvariant(_storeContext.CurrentStore.Name, T("Forum.ActiveDiscussionsFeedTitle")); + + var feed = new SmartSyndicationFeed(new Uri(discussionLink), title, T("Forum.ActiveDiscussionsFeedDescription")); + + feed.AddNamespaces(false); + feed.Init(selfLink, language); + + if (!_forumSettings.ActiveDiscussionsFeedEnabled) + return new RssActionResult { Feed = feed }; + + var items = new List(); + var topics = _forumService.GetActiveTopics(forumId, _forumSettings.ActiveDiscussionsFeedCount); + + var viewsText = T("Forum.Views"); + var repliesText = T("Forum.Replies"); + + foreach (var topic in topics) + { + string topicUrl = Url.RouteUrl("TopicSlug", new { id = topic.Id, slug = topic.GetSeName() }, "http"); + var synopsis = "{0}: {1}, {2}: {3}".FormatInvariant(repliesText, topic.NumReplies, viewsText, topic.Views); + + var item = feed.CreateItem(topic.Subject, synopsis, topicUrl, topic.LastPostTime ?? topic.UpdatedOnUtc); + + items.Add(item); + } + + feed.Items = items; return new RssActionResult { Feed = feed }; } @@ -349,7 +385,43 @@ public ActionResult ForumRss(int id) if (!_forumSettings.ForumsEnabled) return HttpNotFound(); - var feed = _forumService.CreateForumRssFeed(Url, id); + var language = _workContext.WorkingLanguage; + var protocol = _webHelper.IsCurrentConnectionSecured() ? "https" : "http"; + var selfLink = Url.Action("ForumRSS", "Boards", null, protocol); + var forumLink = Url.Action("Forum", "Boards", new { id = id }, protocol); + + var feed = new SmartSyndicationFeed(new Uri(forumLink), _storeContext.CurrentStore.Name, T("Forum.ForumFeedDescription")); + + feed.AddNamespaces(false); + feed.Init(selfLink, language); + + if (!_forumSettings.ForumFeedsEnabled) + return new RssActionResult { Feed = feed }; + + var forum = _forumService.GetForumById(id); + + if (forum == null) + return new RssActionResult { Feed = feed }; + + feed.Title = new TextSyndicationContent("{0} - {1}".FormatInvariant(_storeContext.CurrentStore.Name, forum.GetLocalized(x => x.Name, language.Id))); + + var items = new List(); + var topics = _forumService.GetAllTopics(id, 0, string.Empty, ForumSearchType.All, 0, 0, _forumSettings.ForumFeedCount); + + var viewsText = T("Forum.Views"); + var repliesText = T("Forum.Replies"); + + foreach (var topic in topics) + { + string topicUrl = Url.RouteUrl("TopicSlug", new { id = topic.Id, slug = topic.GetSeName() }, "http"); + var synopsis = "{0}: {1}, {2}: {3}".FormatInvariant(repliesText, topic.NumReplies, viewsText, topic.Views); + + var item = feed.CreateItem(topic.Subject, synopsis, topicUrl, topic.LastPostTime ?? topic.UpdatedOnUtc); + + items.Add(item); + } + + feed.Items = items; return new RssActionResult { Feed = feed }; } diff --git a/src/Presentation/SmartStore.Web/Controllers/CatalogController.cs b/src/Presentation/SmartStore.Web/Controllers/CatalogController.cs index 7c18223245..f5957907fa 100644 --- a/src/Presentation/SmartStore.Web/Controllers/CatalogController.cs +++ b/src/Presentation/SmartStore.Web/Controllers/CatalogController.cs @@ -21,6 +21,7 @@ using SmartStore.Services.Security; using SmartStore.Services.Seo; using SmartStore.Services.Stores; +using SmartStore.Utilities; using SmartStore.Web.Framework.Controllers; using SmartStore.Web.Framework.Mvc; using SmartStore.Web.Framework.Security; @@ -847,7 +848,62 @@ public ActionResult RecentlyAddedProducts(CatalogPagingFilteringModel command) [Compress] public ActionResult RecentlyAddedProductsRss() { - var feed = _productService.CreateRecentlyAddedProductsRssFeed(Url); + var protocol = _services.WebHelper.IsCurrentConnectionSecured() ? "https" : "http"; + var selfLink = Url.RouteUrl("RecentlyAddedProductsRSS", null, protocol); + var recentProductsLink = Url.RouteUrl("RecentlyAddedProducts", null, protocol); + + var title = "{0} - {1}".FormatInvariant(_services.StoreContext.CurrentStore.Name, T("RSS.RecentlyAddedProducts")); + + var feed = new SmartSyndicationFeed(new Uri(recentProductsLink), title, T("RSS.InformationAboutProducts")); + + feed.AddNamespaces(true); + feed.Init(selfLink, _services.WorkContext.WorkingLanguage); + + if (!_catalogSettings.RecentlyAddedProductsEnabled) + return new RssActionResult { Feed = feed }; + + var items = new List(); + var searchContext = new ProductSearchContext + { + LanguageId = _services.WorkContext.WorkingLanguage.Id, + OrderBy = ProductSortingEnum.CreatedOn, + PageSize = _catalogSettings.RecentlyAddedProductsNumber, + StoreId = _services.StoreContext.CurrentStoreIdIfMultiStoreMode, + VisibleIndividuallyOnly = true + }; + + var products = _productService.SearchProducts(searchContext); + var storeUrl = _services.StoreContext.CurrentStore.Url; + + foreach (var product in products) + { + string productUrl = Url.RouteUrl("Product", new { SeName = product.GetSeName() }, "http"); + if (productUrl.HasValue()) + { + var item = feed.CreateItem( + product.GetLocalized(x => x.Name), + product.GetLocalized(x => x.ShortDescription), + productUrl, + product.CreatedOnUtc, + product.FullDescription); + + try + { + // we add only the first picture + var picture = product.ProductPictures.OrderBy(x => x.DisplayOrder).Select(x => x.Picture).FirstOrDefault(); + + if (picture != null) + { + feed.AddEnclosue(item, picture, _pictureService.GetPictureUrl(picture, _mediaSettings.ProductDetailsPictureSize, false, storeUrl)); + } + } + catch { } + + items.Add(item); + } + } + + feed.Items = items; return new RssActionResult { Feed = feed }; } diff --git a/src/Presentation/SmartStore.Web/Controllers/NewsController.cs b/src/Presentation/SmartStore.Web/Controllers/NewsController.cs index 2234247d80..dacb180485 100644 --- a/src/Presentation/SmartStore.Web/Controllers/NewsController.cs +++ b/src/Presentation/SmartStore.Web/Controllers/NewsController.cs @@ -1,5 +1,7 @@ using System; +using System.Collections.Generic; using System.Linq; +using System.ServiceModel.Syndication; using System.Web.Mvc; using SmartStore.Core; using SmartStore.Core.Caching; @@ -17,6 +19,7 @@ using SmartStore.Services.News; using SmartStore.Services.Seo; using SmartStore.Services.Stores; +using SmartStore.Utilities; using SmartStore.Web.Framework.Controllers; using SmartStore.Web.Framework.Mvc; using SmartStore.Web.Framework.Security; @@ -43,6 +46,7 @@ public partial class NewsController : PublicControllerBase private readonly ICacheManager _cacheManager; private readonly ICustomerActivityService _customerActivityService; private readonly IStoreMappingService _storeMappingService; + private readonly ILanguageService _languageService; private readonly MediaSettings _mediaSettings; private readonly NewsSettings _newsSettings; @@ -61,6 +65,7 @@ public NewsController(INewsService newsService, IWorkflowMessageService workflowMessageService, IWebHelper webHelper, ICacheManager cacheManager, ICustomerActivityService customerActivityService, IStoreMappingService storeMappingService, + ILanguageService languageService, MediaSettings mediaSettings, NewsSettings newsSettings, LocalizationSettings localizationSettings, CustomerSettings customerSettings, CaptchaSettings captchaSettings) @@ -77,6 +82,7 @@ public NewsController(INewsService newsService, this._cacheManager = cacheManager; this._customerActivityService = customerActivityService; this._storeMappingService = storeMappingService; + this._languageService = languageService; this._mediaSettings = mediaSettings; this._newsSettings = newsSettings; @@ -208,7 +214,38 @@ public ActionResult List(NewsPagingFilteringModel command) [ActionName("rss"), Compress] public ActionResult ListRss(int languageId) { - var feed = _newsService.CreateRssFeed(Url, languageId); + DateTime? maxAge = null; + var protocol = _webHelper.IsCurrentConnectionSecured() ? "https" : "http"; + var selfLink = Url.Action("rss", "News", new { languageId = languageId }, protocol); + var newsLink = Url.RouteUrl("NewsArchive", null, protocol); + + var title = "{0} - News".FormatInvariant(_storeContext.CurrentStore.Name); + + if (_newsSettings.MaxAgeInDays > 0) + maxAge = DateTime.UtcNow.Subtract(new TimeSpan(_newsSettings.MaxAgeInDays, 0, 0, 0)); + + var language = _languageService.GetLanguageById(languageId); + var feed = new SmartSyndicationFeed(new Uri(newsLink), title); + + feed.AddNamespaces(true); + feed.Init(selfLink, language); + + if (!_newsSettings.Enabled) + return new RssActionResult { Feed = feed }; + + var items = new List(); + var newsItems = _newsService.GetAllNews(languageId, _storeContext.CurrentStore.Id, 0, int.MaxValue, false, maxAge); + + foreach (var news in newsItems) + { + var newsUrl = Url.RouteUrl("NewsItem", new { SeName = news.GetSeName(news.LanguageId, ensureTwoPublishedLanguages: false) }, "http"); + + var item = feed.CreateItem(news.Title, news.Short, newsUrl, news.CreatedOnUtc, news.Full); + + items.Add(item); + } + + feed.Items = items; return new RssActionResult { Feed = feed }; } From f7382dea1c622148fbc1e3ef1adbe13bd70eb75d Mon Sep 17 00:00:00 2001 From: Marcus Gesing Date: Sat, 7 Nov 2015 12:22:39 +0100 Subject: [PATCH 015/707] Added class ExportProviderBase --- .../DataExchange/ExportProviderBase.cs | 47 +++++++++++++++++++ .../DataExchange/IExportProvider.cs | 2 +- .../Providers/CategoryXmlExportProvider.cs | 18 ++----- .../Providers/CustomerXlsxExportProvider.cs | 18 ++----- .../Providers/CustomerXmlExportProvider.cs | 18 ++----- .../ManufacturerXmlExportProvider.cs | 18 ++----- .../Providers/OrderXlsxExportProvider.cs | 18 ++----- .../Providers/OrderXmlExportProvider.cs | 18 ++----- .../Providers/ProductXlsxExportProvider.cs | 18 ++----- .../Providers/ProductXmlExportProvider.cs | 18 ++----- .../Providers/SubscriberCsvExportProvider.cs | 18 ++----- .../SmartStore.Services.csproj | 1 + .../Providers/GmcXmlExportProvider.cs | 18 ++----- 13 files changed, 89 insertions(+), 141 deletions(-) create mode 100644 src/Libraries/SmartStore.Services/DataExchange/ExportProviderBase.cs diff --git a/src/Libraries/SmartStore.Services/DataExchange/ExportProviderBase.cs b/src/Libraries/SmartStore.Services/DataExchange/ExportProviderBase.cs new file mode 100644 index 0000000000..f0dd39a95e --- /dev/null +++ b/src/Libraries/SmartStore.Services/DataExchange/ExportProviderBase.cs @@ -0,0 +1,47 @@ +using SmartStore.Core.Domain.DataExchange; + +namespace SmartStore.Services.DataExchange +{ + public abstract class ExportProviderBase : IExportProvider + { + /// + /// The exported entity type + /// + public virtual ExportEntityType EntityType + { + get { return ExportEntityType.Product; } + } + + /// + /// File extension of the export files (without dot). Return null for a non file based, on-the-fly export. + /// + public virtual string FileExtension + { + get { return null; } + } + + /// + /// Get provider specific configuration information. Return null when no provider specific configuration is required. + /// + public virtual ExportConfigurationInfo ConfigurationInfo + { + get { return null; } + } + + /// + /// Export data to a file + /// + /// Export execution context + public virtual void Execute(IExportExecuteContext context) + { + } + + /// + /// Called once per store when export execution ended + /// + /// Export execution context + public virtual void OnExecuted(IExportExecuteContext context) + { + } + } +} diff --git a/src/Libraries/SmartStore.Services/DataExchange/IExportProvider.cs b/src/Libraries/SmartStore.Services/DataExchange/IExportProvider.cs index b0872ef1eb..450c30ed77 100644 --- a/src/Libraries/SmartStore.Services/DataExchange/IExportProvider.cs +++ b/src/Libraries/SmartStore.Services/DataExchange/IExportProvider.cs @@ -6,7 +6,7 @@ namespace SmartStore.Services.DataExchange public partial interface IExportProvider : IProvider, IUserEditable { /// - /// Th exported entity type + /// The exported entity type /// ExportEntityType EntityType { get; } diff --git a/src/Libraries/SmartStore.Services/DataExchange/Providers/CategoryXmlExportProvider.cs b/src/Libraries/SmartStore.Services/DataExchange/Providers/CategoryXmlExportProvider.cs index 5b72bc9d64..e473a28ad2 100644 --- a/src/Libraries/SmartStore.Services/DataExchange/Providers/CategoryXmlExportProvider.cs +++ b/src/Libraries/SmartStore.Services/DataExchange/Providers/CategoryXmlExportProvider.cs @@ -16,29 +16,24 @@ namespace SmartStore.Services.DataExchange.Providers [SystemName("Exports.SmartStoreCategoryXml")] [FriendlyName("SmartStore XML category export")] [IsHidden(true)] - public class CategoryXmlExportProvider : IExportProvider + public class CategoryXmlExportProvider : ExportProviderBase { public static string SystemName { get { return "Exports.SmartStoreCategoryXml"; } } - public ExportConfigurationInfo ConfigurationInfo - { - get { return null; } - } - - public ExportEntityType EntityType + public override ExportEntityType EntityType { get { return ExportEntityType.Category; } } - public string FileExtension + public override string FileExtension { get { return "XML"; } } - public void Execute(IExportExecuteContext context) + public override void Execute(IExportExecuteContext context) { var settings = new XmlWriterSettings { @@ -104,10 +99,5 @@ public void Execute(IExportExecuteContext context) writer.WriteEndDocument(); } } - - public void OnExecuted(IExportExecuteContext context) - { - // nothing to do - } } } diff --git a/src/Libraries/SmartStore.Services/DataExchange/Providers/CustomerXlsxExportProvider.cs b/src/Libraries/SmartStore.Services/DataExchange/Providers/CustomerXlsxExportProvider.cs index 22a9d229ec..4ab09bd5c5 100644 --- a/src/Libraries/SmartStore.Services/DataExchange/Providers/CustomerXlsxExportProvider.cs +++ b/src/Libraries/SmartStore.Services/DataExchange/Providers/CustomerXlsxExportProvider.cs @@ -18,7 +18,7 @@ namespace SmartStore.Services.DataExchange.Providers [SystemName("Exports.SmartStoreCustomerXlsx")] [FriendlyName("SmartStore Excel customer export")] [IsHidden(true)] - public class CustomerXlsxExportProvider : IExportProvider + public class CustomerXlsxExportProvider : ExportProviderBase { private string[] Properties { @@ -97,22 +97,17 @@ public static string SystemName get { return "Exports.SmartStoreCustomerXlsx"; } } - public ExportConfigurationInfo ConfigurationInfo - { - get { return null; } - } - - public ExportEntityType EntityType + public override ExportEntityType EntityType { get { return ExportEntityType.Customer; } } - public string FileExtension + public override string FileExtension { get { return "XLSX"; } } - public void Execute(IExportExecuteContext context) + public override void Execute(IExportExecuteContext context) { var invariantCulture = CultureInfo.InvariantCulture; var path = context.FilePath; @@ -214,10 +209,5 @@ public void Execute(IExportExecuteContext context) xlPackage.Save(); } } - - public void OnExecuted(IExportExecuteContext context) - { - // nothing to do - } } } diff --git a/src/Libraries/SmartStore.Services/DataExchange/Providers/CustomerXmlExportProvider.cs b/src/Libraries/SmartStore.Services/DataExchange/Providers/CustomerXmlExportProvider.cs index b88d3d8cd3..93d9c4462b 100644 --- a/src/Libraries/SmartStore.Services/DataExchange/Providers/CustomerXmlExportProvider.cs +++ b/src/Libraries/SmartStore.Services/DataExchange/Providers/CustomerXmlExportProvider.cs @@ -16,29 +16,24 @@ namespace SmartStore.Services.DataExchange.Providers [SystemName("Exports.SmartStoreCustomerXml")] [FriendlyName("SmartStore XML customer export")] [IsHidden(true)] - public class CustomerXmlExportProvider : IExportProvider + public class CustomerXmlExportProvider : ExportProviderBase { public static string SystemName { get { return "Exports.SmartStoreCustomerXml"; } } - public ExportConfigurationInfo ConfigurationInfo - { - get { return null; } - } - - public ExportEntityType EntityType + public override ExportEntityType EntityType { get { return ExportEntityType.Customer; } } - public string FileExtension + public override string FileExtension { get { return "XML"; } } - public void Execute(IExportExecuteContext context) + public override void Execute(IExportExecuteContext context) { var settings = new XmlWriterSettings { @@ -87,10 +82,5 @@ public void Execute(IExportExecuteContext context) writer.WriteEndDocument(); } } - - public void OnExecuted(IExportExecuteContext context) - { - // nothing to do - } } } diff --git a/src/Libraries/SmartStore.Services/DataExchange/Providers/ManufacturerXmlExportProvider.cs b/src/Libraries/SmartStore.Services/DataExchange/Providers/ManufacturerXmlExportProvider.cs index edc60a007d..8d26a9ab4e 100644 --- a/src/Libraries/SmartStore.Services/DataExchange/Providers/ManufacturerXmlExportProvider.cs +++ b/src/Libraries/SmartStore.Services/DataExchange/Providers/ManufacturerXmlExportProvider.cs @@ -16,29 +16,24 @@ namespace SmartStore.Services.DataExchange.Providers [SystemName("Exports.SmartStoreManufacturerXml")] [FriendlyName("SmartStore XML manufacturer export")] [IsHidden(true)] - public class ManufacturerXmlExportProvider : IExportProvider + public class ManufacturerXmlExportProvider : ExportProviderBase { public static string SystemName { get { return "Exports.SmartStoreManufacturerXml"; } } - public ExportConfigurationInfo ConfigurationInfo - { - get { return null; } - } - - public ExportEntityType EntityType + public override ExportEntityType EntityType { get { return ExportEntityType.Manufacturer; } } - public string FileExtension + public override string FileExtension { get { return "XML"; } } - public void Execute(IExportExecuteContext context) + public override void Execute(IExportExecuteContext context) { var settings = new XmlWriterSettings { @@ -104,10 +99,5 @@ public void Execute(IExportExecuteContext context) writer.WriteEndDocument(); } } - - public void OnExecuted(IExportExecuteContext context) - { - // nothing to do - } } } diff --git a/src/Libraries/SmartStore.Services/DataExchange/Providers/OrderXlsxExportProvider.cs b/src/Libraries/SmartStore.Services/DataExchange/Providers/OrderXlsxExportProvider.cs index 9f468e071f..ae6ce4271d 100644 --- a/src/Libraries/SmartStore.Services/DataExchange/Providers/OrderXlsxExportProvider.cs +++ b/src/Libraries/SmartStore.Services/DataExchange/Providers/OrderXlsxExportProvider.cs @@ -15,7 +15,7 @@ namespace SmartStore.Services.DataExchange.Providers [SystemName("Exports.SmartStoreOrderXlsx")] [FriendlyName("SmartStore Excel order export")] [IsHidden(true)] - public class OrderXlsxExportProvider : IExportProvider + public class OrderXlsxExportProvider : ExportProviderBase { private string[] Properties { @@ -96,22 +96,17 @@ public static string SystemName get { return "Exports.SmartStoreOrderXlsx"; } } - public ExportConfigurationInfo ConfigurationInfo - { - get { return null; } - } - - public ExportEntityType EntityType + public override ExportEntityType EntityType { get { return ExportEntityType.Order; } } - public string FileExtension + public override string FileExtension { get { return "XLSX"; } } - public void Execute(IExportExecuteContext context) + public override void Execute(IExportExecuteContext context) { var path = context.FilePath; @@ -250,10 +245,5 @@ public void Execute(IExportExecuteContext context) xlPackage.Save(); } } - - public void OnExecuted(IExportExecuteContext context) - { - // nothing to do - } } } diff --git a/src/Libraries/SmartStore.Services/DataExchange/Providers/OrderXmlExportProvider.cs b/src/Libraries/SmartStore.Services/DataExchange/Providers/OrderXmlExportProvider.cs index a21a94d2f9..15d347847f 100644 --- a/src/Libraries/SmartStore.Services/DataExchange/Providers/OrderXmlExportProvider.cs +++ b/src/Libraries/SmartStore.Services/DataExchange/Providers/OrderXmlExportProvider.cs @@ -16,29 +16,24 @@ namespace SmartStore.Services.DataExchange.Providers [SystemName("Exports.SmartStoreOrderXml")] [FriendlyName("SmartStore XML order export")] [IsHidden(true)] - public class OrderXmlExportProvider : IExportProvider + public class OrderXmlExportProvider : ExportProviderBase { public static string SystemName { get { return "Exports.SmartStoreOrderXml"; } } - public ExportConfigurationInfo ConfigurationInfo - { - get { return null; } - } - - public ExportEntityType EntityType + public override ExportEntityType EntityType { get { return ExportEntityType.Order; } } - public string FileExtension + public override string FileExtension { get { return "XML"; } } - public void Execute(IExportExecuteContext context) + public override void Execute(IExportExecuteContext context) { var settings = new XmlWriterSettings { @@ -260,10 +255,5 @@ public void Execute(IExportExecuteContext context) writer.WriteEndDocument(); } } - - public void OnExecuted(IExportExecuteContext context) - { - // nothing to do - } } } diff --git a/src/Libraries/SmartStore.Services/DataExchange/Providers/ProductXlsxExportProvider.cs b/src/Libraries/SmartStore.Services/DataExchange/Providers/ProductXlsxExportProvider.cs index a433bf5c8d..3da13558c0 100644 --- a/src/Libraries/SmartStore.Services/DataExchange/Providers/ProductXlsxExportProvider.cs +++ b/src/Libraries/SmartStore.Services/DataExchange/Providers/ProductXlsxExportProvider.cs @@ -22,7 +22,7 @@ namespace SmartStore.Services.DataExchange.Providers [SystemName("Exports.SmartStoreProductXlsx")] [FriendlyName("SmartStore Excel product export")] [IsHidden(true)] - public class ProductXlsxExportProvider : IExportProvider + public class ProductXlsxExportProvider : ExportProviderBase { private readonly ILanguageService _languageService; private readonly IProductService _productService; @@ -165,22 +165,17 @@ public static string SystemName get { return "Exports.SmartStoreProductXlsx"; } } - public ExportConfigurationInfo ConfigurationInfo - { - get { return null; } - } - - public ExportEntityType EntityType + public override ExportEntityType EntityType { get { return ExportEntityType.Product; } } - public string FileExtension + public override string FileExtension { get { return "XLSX"; } } - public void Execute(IExportExecuteContext context) + public override void Execute(IExportExecuteContext context) { var path = context.FilePath; @@ -414,10 +409,5 @@ public void Execute(IExportExecuteContext context) // EPPLus had serious memory leak problems in V3. We enforce the garbage collector to release unused memory, it's not perfect, but better than nothing. GC.Collect(); } - - public void OnExecuted(IExportExecuteContext context) - { - // nothing to do - } } } diff --git a/src/Libraries/SmartStore.Services/DataExchange/Providers/ProductXmlExportProvider.cs b/src/Libraries/SmartStore.Services/DataExchange/Providers/ProductXmlExportProvider.cs index a0cc291bf1..e4154f4804 100644 --- a/src/Libraries/SmartStore.Services/DataExchange/Providers/ProductXmlExportProvider.cs +++ b/src/Libraries/SmartStore.Services/DataExchange/Providers/ProductXmlExportProvider.cs @@ -16,29 +16,24 @@ namespace SmartStore.Services.DataExchange.Providers [SystemName("Exports.SmartStoreProductXml")] [FriendlyName("SmartStore XML product export")] [IsHidden(true)] - public class ProductXmlExportProvider : IExportProvider + public class ProductXmlExportProvider : ExportProviderBase { public static string SystemName { get { return "Exports.SmartStoreProductXml"; } } - public ExportConfigurationInfo ConfigurationInfo - { - get { return null; } - } - - public ExportEntityType EntityType + public override ExportEntityType EntityType { get { return ExportEntityType.Product; } } - public string FileExtension + public override string FileExtension { get { return "XML"; } } - public void Execute(IExportExecuteContext context) + public override void Execute(IExportExecuteContext context) { var settings = new XmlWriterSettings { @@ -87,10 +82,5 @@ public void Execute(IExportExecuteContext context) writer.WriteEndDocument(); } } - - public void OnExecuted(IExportExecuteContext context) - { - // nothing to do - } } } diff --git a/src/Libraries/SmartStore.Services/DataExchange/Providers/SubscriberCsvExportProvider.cs b/src/Libraries/SmartStore.Services/DataExchange/Providers/SubscriberCsvExportProvider.cs index 2ca56f48f8..2a7e299b51 100644 --- a/src/Libraries/SmartStore.Services/DataExchange/Providers/SubscriberCsvExportProvider.cs +++ b/src/Libraries/SmartStore.Services/DataExchange/Providers/SubscriberCsvExportProvider.cs @@ -13,29 +13,24 @@ namespace SmartStore.Services.DataExchange.Providers [SystemName("Exports.SmartStoreNewsSubscriptionCsv")] [FriendlyName("SmartStore CSV newsletter subscription export")] [IsHidden(true)] - public class SubscriberCsvExportProvider : IExportProvider + public class SubscriberCsvExportProvider : ExportProviderBase { public static string SystemName { get { return "Exports.SmartStoreNewsSubscriptionCsv"; } } - public ExportConfigurationInfo ConfigurationInfo - { - get { return null; } - } - - public ExportEntityType EntityType + public override ExportEntityType EntityType { get { return ExportEntityType.NewsLetterSubscription; } } - public string FileExtension + public override string FileExtension { get { return "CSV"; } } - public void Execute(IExportExecuteContext context) + public override void Execute(IExportExecuteContext context) { var path = context.FilePath; @@ -73,10 +68,5 @@ public void Execute(IExportExecuteContext context) } } } - - public void OnExecuted(IExportExecuteContext context) - { - // nothing to do - } } } diff --git a/src/Libraries/SmartStore.Services/SmartStore.Services.csproj b/src/Libraries/SmartStore.Services/SmartStore.Services.csproj index f63d565765..7b4dc44e1e 100644 --- a/src/Libraries/SmartStore.Services/SmartStore.Services.csproj +++ b/src/Libraries/SmartStore.Services/SmartStore.Services.csproj @@ -171,6 +171,7 @@ + diff --git a/src/Plugins/SmartStore.GoogleMerchantCenter/Providers/GmcXmlExportProvider.cs b/src/Plugins/SmartStore.GoogleMerchantCenter/Providers/GmcXmlExportProvider.cs index 3f1dac0bd2..b1a68d4591 100644 --- a/src/Plugins/SmartStore.GoogleMerchantCenter/Providers/GmcXmlExportProvider.cs +++ b/src/Plugins/SmartStore.GoogleMerchantCenter/Providers/GmcXmlExportProvider.cs @@ -28,7 +28,7 @@ namespace SmartStore.GoogleMerchantCenter.Providers ExportFeatures.OffersBrandFallback, ExportFeatures.CanIncludeMainPicture, ExportFeatures.UsesSpecialPrice)] - public class GmcXmlExportProvider : IExportProvider + public class GmcXmlExportProvider : ExportProviderBase { private const string _googleNamespace = "http://base.google.com/ns/1.0"; @@ -132,7 +132,7 @@ public static string Unspecified get { return "__nospec__"; } } - public ExportConfigurationInfo ConfigurationInfo + public override ExportConfigurationInfo ConfigurationInfo { get { @@ -150,17 +150,12 @@ public ExportConfigurationInfo ConfigurationInfo } } - public ExportEntityType EntityType - { - get { return ExportEntityType.Product; } - } - - public string FileExtension + public override string FileExtension { get { return "XML"; } } - public void Execute(IExportExecuteContext context) + public override void Execute(IExportExecuteContext context) { var settings = new XmlWriterSettings { @@ -400,10 +395,5 @@ public void Execute(IExportExecuteContext context) writer.WriteEndDocument(); } } - - public void OnExecuted(IExportExecuteContext context) - { - // nothing to do - } } } \ No newline at end of file From 2289b5c30629e9b4363644042cdfbe3780f09b2b Mon Sep 17 00:00:00 2001 From: Murat Cakir Date: Sun, 8 Nov 2015 03:19:21 +0100 Subject: [PATCH 016/707] (Perf) Faster reflection with new FastProperty helper class (makes Fasterflect obsolete soon) --- .../ComponentModel/HybridExpando.cs | 72 +-- .../SmartStore.Core/Plugins/PluginManager.cs | 1 - .../SmartStore.Core/SmartStore.Core.csproj | 1 + .../Utilities/Reflection/FastProperty.cs | 553 ++++++++++++++++++ .../Configuration/SettingService.cs | 11 +- .../DependencyRegistrar.cs | 38 +- 6 files changed, 609 insertions(+), 67 deletions(-) create mode 100644 src/Libraries/SmartStore.Core/Utilities/Reflection/FastProperty.cs diff --git a/src/Libraries/SmartStore.Core/ComponentModel/HybridExpando.cs b/src/Libraries/SmartStore.Core/ComponentModel/HybridExpando.cs index 6697e19d0c..eebf907175 100644 --- a/src/Libraries/SmartStore.Core/ComponentModel/HybridExpando.cs +++ b/src/Libraries/SmartStore.Core/ComponentModel/HybridExpando.cs @@ -37,6 +37,7 @@ using System.Dynamic; using System.Reflection; using System.Collections; +using SmartStore.Utilities.Reflection; namespace SmartStore.ComponentModel { @@ -71,8 +72,6 @@ public class HybridExpando : DynamicObject, IDictionary /// private Type _instanceType; - private IList _instancePropertyInfos; - /// /// String Dictionary that contains the extra dynamic values /// stored on this object/instance @@ -116,16 +115,6 @@ protected object WrappedObject get { return _instance; } } - IList InstancePropertyInfos - { - get - { - if (_instancePropertyInfos == null && _instance != null) - _instancePropertyInfos = Fasterflect.PropertyExtensions.Properties(_instanceType, Fasterflect.Flags.InstancePublic); - return _instancePropertyInfos; - } - } - public override IEnumerable GetDynamicMemberNames() { foreach (var prop in this.GetProperties(false)) @@ -238,25 +227,15 @@ public override bool TryInvokeMember(InvokeMemberBinder binder, object[] args, o /// protected bool GetProperty(object instance, string name, out object result) { - var pi = GetPropertyInfo(name); - if (pi != null) - { - result = Fasterflect.PropertyExtensions.GetPropertyValue(instance ?? this, pi.Name); - return true; - } + var fastProp = _instanceType != null ? FastProperty.GetProperty(_instanceType, name, true) : null; + if (fastProp != null) + { + result = fastProp.GetValue(instance ?? this); + return true; + } - result = null; + result = null; return false; - } - - /// - /// Gets a PropertyInfo instance from the wrapped object - /// - /// Property name - protected PropertyInfo GetPropertyInfo(string name) - { - var pi = Fasterflect.PropertyExtensions.Property(_instanceType, name, Fasterflect.Flags.InstancePublic); - return pi; } /// @@ -268,13 +247,14 @@ protected PropertyInfo GetPropertyInfo(string name) /// protected bool SetProperty(object instance, string name, object value) { - var pi = GetPropertyInfo(name); - if (pi != null) - { - Fasterflect.PropertyInfoExtensions.Set(pi, instance ?? this, value); - return true; + var fastProp = _instanceType != null ? FastProperty.GetProperty(_instanceType, name, true) : null; + if (fastProp != null) + { + fastProp.SetValue(instance ?? this, value); + return true; } - return false; + + return false; } /// @@ -288,10 +268,10 @@ protected bool SetProperty(object instance, string name, object value) protected bool InvokeMethod(object instance, string name, object[] args, out object result) { // Look at the instanceType - var mi = Fasterflect.MethodExtensions.Method(_instanceType, name, Fasterflect.Flags.InstancePublic); + var mi = _instanceType != null ? _instanceType.GetMethod(name, BindingFlags.Instance | BindingFlags.Public) : null; if (mi != null) { - result = Fasterflect.MethodInfoExtensions.Call(mi, instance ?? this, args); + result = mi.Invoke(instance ?? this, args); return true; } @@ -352,11 +332,11 @@ public IEnumerable> GetProperties(bool includeInsta if (includeInstanceProperties && _instance != null) { - foreach (var prop in this.InstancePropertyInfos) + foreach (var prop in FastProperty.GetProperties(_instance).Values) { if (!this.Properties.ContainsKey(prop.Name)) { - yield return new KeyValuePair(prop.Name, prop.GetValue(_instance, null)); + yield return new KeyValuePair(prop.Name, prop.GetValue(_instance)); } } } @@ -390,11 +370,7 @@ public bool Contains(string propertyName, bool includeInstanceProperties = false if (includeInstanceProperties && _instance != null) { - foreach (var prop in this.InstancePropertyInfos) - { - if (prop.Name == propertyName) - return true; - } + return FastProperty.GetProperties(_instance).ContainsKey(propertyName); } return false; @@ -422,7 +398,13 @@ int ICollection>.Count { get { - return Properties.Count + InstancePropertyInfos.Count; + var count = Properties.Count; + if (_instanceType != null) + { + count += FastProperty.GetProperties(_instanceType).Count; + } + + return count; } } diff --git a/src/Libraries/SmartStore.Core/Plugins/PluginManager.cs b/src/Libraries/SmartStore.Core/Plugins/PluginManager.cs index dfa85d8ef7..fa6e5e7aa5 100644 --- a/src/Libraries/SmartStore.Core/Plugins/PluginManager.cs +++ b/src/Libraries/SmartStore.Core/Plugins/PluginManager.cs @@ -178,7 +178,6 @@ public static void Initialize() } IncompatiblePlugins = incompatiblePlugins.AsReadOnly(); - } } diff --git a/src/Libraries/SmartStore.Core/SmartStore.Core.csproj b/src/Libraries/SmartStore.Core/SmartStore.Core.csproj index b23a0d7b0f..7d39d16e05 100644 --- a/src/Libraries/SmartStore.Core/SmartStore.Core.csproj +++ b/src/Libraries/SmartStore.Core/SmartStore.Core.csproj @@ -578,6 +578,7 @@ + diff --git a/src/Libraries/SmartStore.Core/Utilities/Reflection/FastProperty.cs b/src/Libraries/SmartStore.Core/Utilities/Reflection/FastProperty.cs new file mode 100644 index 0000000000..27498b5576 --- /dev/null +++ b/src/Libraries/SmartStore.Core/Utilities/Reflection/FastProperty.cs @@ -0,0 +1,553 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; +using System.Reflection; + +namespace SmartStore.Utilities.Reflection +{ + + public class FastProperty + { + // Delegate type for a by-ref property getter + private delegate TValue ByRefFunc(ref TDeclaringType arg); + + private static readonly MethodInfo CallPropertyGetterOpenGenericMethod = typeof(FastProperty).GetTypeInfo().GetDeclaredMethod(nameof(CallPropertyGetter)); + private static readonly MethodInfo CallPropertyGetterByReferenceOpenGenericMethod = typeof(FastProperty).GetTypeInfo().GetDeclaredMethod(nameof(CallPropertyGetterByReference)); + private static readonly MethodInfo CallNullSafePropertyGetterOpenGenericMethod = typeof(FastProperty).GetTypeInfo().GetDeclaredMethod(nameof(CallNullSafePropertyGetter)); + private static readonly MethodInfo CallNullSafePropertyGetterByReferenceOpenGenericMethod = typeof(FastProperty).GetTypeInfo().GetDeclaredMethod(nameof(CallNullSafePropertyGetterByReference)); + private static readonly MethodInfo CallPropertySetterOpenGenericMethod = typeof(FastProperty).GetTypeInfo().GetDeclaredMethod(nameof(CallPropertySetter)); + + private static readonly ConcurrentDictionary SinglePropertiesCache = new ConcurrentDictionary(); + + // Using an array rather than IEnumerable, as target will be called on the hot path numerous times. + private static readonly ConcurrentDictionary> PropertiesCache = new ConcurrentDictionary>(); + private static readonly ConcurrentDictionary> VisiblePropertiesCache = new ConcurrentDictionary>(); + + private Action _valueSetter; + + /// + /// Initializes a fast . + /// This constructor does not cache the helper. For caching, use . + /// + public FastProperty(PropertyInfo property) + { + if (property == null) + { + throw new ArgumentNullException(nameof(property)); + } + + Property = property; + Name = property.Name; + ValueGetter = MakeFastPropertyGetter(property); + } + + /// + /// Gets the backing . + /// + public PropertyInfo Property { get; } + + /// + /// Gets (or sets in derived types) the property name. + /// + public virtual string Name { get; protected set; } + + /// + /// Gets the property value getter. + /// + public Func ValueGetter { get; } + + /// + /// Gets the property value setter. + /// + public Action ValueSetter + { + get + { + if (_valueSetter == null) + { + // We'll allow safe races here. + _valueSetter = MakeFastPropertySetter(Property); + } + + return _valueSetter; + } + } + + /// + /// Returns the property value for the specified . + /// + /// The object whose property value will be returned. + /// The property value. + public object GetValue(object instance) + { + return ValueGetter(instance); + } + + /// + /// Sets the property value for the specified . + /// + /// The object whose property value will be set. + /// The property value. + public void SetValue(object instance, object value) + { + ValueSetter(instance, value); + } + + /// + /// Creates and caches fast property helpers that expose getters for every public get property on the + /// underlying type. + /// + /// the instance to extract property accessors for. + /// a cached array of all public property getters from the underlying type of target instance. + /// + public static IReadOnlyDictionary GetProperties(object instance) + { + return GetProperties(instance.GetType()); + } + + /// + /// Creates and caches fast property helpers that expose getters for every public get property on the + /// specified type. + /// + /// the type to extract property accessors for. + /// a cached array of all public property getters from the type of target instance. + /// + public static IReadOnlyDictionary GetProperties(Type type) + { + return (IReadOnlyDictionary)GetProperties(type, CreateInstance, PropertiesCache); + } + + /// + /// + /// Creates and caches fast property helpers that expose getters for every non-hidden get property + /// on the specified type. + /// + /// + /// excludes properties defined on base types that have been + /// hidden by definitions using the new keyword. + /// + /// + /// The instance to extract property accessors for. + /// + /// A cached array of all public property getters from the instance's type. + /// + public static IReadOnlyDictionary GetVisibleProperties(object instance) + { + return (IReadOnlyDictionary)GetVisibleProperties(instance.GetType(), CreateInstance, PropertiesCache, VisiblePropertiesCache); + } + + /// + /// + /// Creates and caches fast property helpers that expose getters for every non-hidden get property + /// on the specified type. + /// + /// + /// excludes properties defined on base types that have been + /// hidden by definitions using the new keyword. + /// + /// + /// The type to extract property accessors for. + /// + /// A cached array of all public property getters from the type. + /// + public static IReadOnlyDictionary GetVisibleProperties(Type type) + { + return (IReadOnlyDictionary)GetVisibleProperties(type, CreateInstance, PropertiesCache, VisiblePropertiesCache); + } + + public static FastProperty GetProperty(Type type, string propertyName, bool cacheAllProperties = false) + { + FastProperty fastProperty = null; + IDictionary allProperties; + + if (cacheAllProperties) + { + allProperties = (IDictionary)GetProperties(type); + allProperties.TryGetValue(propertyName, out fastProperty); + return fastProperty; + } + + if (PropertiesCache.TryGetValue(type, out allProperties)) + { + allProperties.TryGetValue(propertyName, out fastProperty); + return fastProperty; + } + + var key = new PropertyKey(type, propertyName); + if (!SinglePropertiesCache.TryGetValue(key, out fastProperty)) + { + var pi = GetPropertyCandidates(type).Where(p => p.Name.Equals(propertyName, StringComparison.OrdinalIgnoreCase)).FirstOrDefault(); + //var pi = type.GetProperty(propertyName, BindingFlags.Public | BindingFlags.Instance | BindingFlags.IgnoreCase); + if (pi != null) + { + fastProperty = CreateInstance(pi); + SinglePropertiesCache.TryAdd(key, fastProperty); + } + } + + return fastProperty; + } + + /// + /// Creates a single fast property getter. The result is not cached. + /// + /// propertyInfo to extract the getter for. + /// a fast getter. + /// + /// This method is more memory efficient than a dynamically compiled lambda, and about the + /// same speed. + /// + public static Func MakeFastPropertyGetter(PropertyInfo propertyInfo) + { + Debug.Assert(propertyInfo != null); + + return MakeFastPropertyGetter( + propertyInfo, + CallPropertyGetterOpenGenericMethod, + CallPropertyGetterByReferenceOpenGenericMethod); + } + + /// + /// Creates a single fast property getter which is safe for a null input object. The result is not cached. + /// + /// propertyInfo to extract the getter for. + /// a fast getter. + /// + /// This method is more memory efficient than a dynamically compiled lambda, and about the + /// same speed. + /// + public static Func MakeNullSafeFastPropertyGetter(PropertyInfo propertyInfo) + { + Debug.Assert(propertyInfo != null); + + return MakeFastPropertyGetter( + propertyInfo, + CallNullSafePropertyGetterOpenGenericMethod, + CallNullSafePropertyGetterByReferenceOpenGenericMethod); + } + + private static Func MakeFastPropertyGetter( + PropertyInfo propertyInfo, + MethodInfo propertyGetterWrapperMethod, + MethodInfo propertyGetterByRefWrapperMethod) + { + Debug.Assert(propertyInfo != null); + + // Must be a generic method with a Func<,> parameter + Debug.Assert(propertyGetterWrapperMethod != null); + Debug.Assert(propertyGetterWrapperMethod.IsGenericMethodDefinition); + Debug.Assert(propertyGetterWrapperMethod.GetParameters().Length == 2); + + // Must be a generic method with a ByRefFunc<,> parameter + Debug.Assert(propertyGetterByRefWrapperMethod != null); + Debug.Assert(propertyGetterByRefWrapperMethod.IsGenericMethodDefinition); + Debug.Assert(propertyGetterByRefWrapperMethod.GetParameters().Length == 2); + + var getMethod = propertyInfo.GetMethod; + Debug.Assert(getMethod != null); + Debug.Assert(!getMethod.IsStatic); + Debug.Assert(getMethod.GetParameters().Length == 0); + + // Instance methods in the CLR can be turned into static methods where the first parameter + // is open over "target". This parameter is always passed by reference, so we have a code + // path for value types and a code path for reference types. + if (getMethod.DeclaringType.GetTypeInfo().IsValueType) + { + // Create a delegate (ref TDeclaringType) -> TValue + return MakeFastPropertyGetter( + typeof(ByRefFunc<,>), + getMethod, + propertyGetterByRefWrapperMethod); + } + else + { + // Create a delegate TDeclaringType -> TValue + return MakeFastPropertyGetter( + typeof(Func<,>), + getMethod, + propertyGetterWrapperMethod); + } + } + + private static Func MakeFastPropertyGetter( + Type openGenericDelegateType, + MethodInfo propertyGetMethod, + MethodInfo openGenericWrapperMethod) + { + var typeInput = propertyGetMethod.DeclaringType; + var typeOutput = propertyGetMethod.ReturnType; + + var delegateType = openGenericDelegateType.MakeGenericType(typeInput, typeOutput); + var propertyGetterDelegate = propertyGetMethod.CreateDelegate(delegateType); + + var wrapperDelegateMethod = openGenericWrapperMethod.MakeGenericMethod(typeInput, typeOutput); + var accessorDelegate = wrapperDelegateMethod.CreateDelegate( + typeof(Func), + propertyGetterDelegate); + + return (Func)accessorDelegate; + } + + /// + /// Creates a single fast property setter for reference types. The result is not cached. + /// + /// propertyInfo to extract the setter for. + /// a fast getter. + /// + /// This method is more memory efficient than a dynamically compiled lambda, and about the + /// same speed. This only works for reference types. + /// + public static Action MakeFastPropertySetter(PropertyInfo propertyInfo) + { + Debug.Assert(propertyInfo != null); + Debug.Assert(!propertyInfo.DeclaringType.GetTypeInfo().IsValueType); + + var setMethod = propertyInfo.SetMethod; + Debug.Assert(setMethod != null); + Debug.Assert(!setMethod.IsStatic); + Debug.Assert(setMethod.ReturnType == typeof(void)); + var parameters = setMethod.GetParameters(); + Debug.Assert(parameters.Length == 1); + + // Instance methods in the CLR can be turned into static methods where the first parameter + // is open over "target". This parameter is always passed by reference, so we have a code + // path for value types and a code path for reference types. + var typeInput = setMethod.DeclaringType; + var parameterType = parameters[0].ParameterType; + + // Create a delegate TDeclaringType -> { TDeclaringType.Property = TValue; } + var propertySetterAsAction = + setMethod.CreateDelegate(typeof(Action<,>).MakeGenericType(typeInput, parameterType)); + var callPropertySetterClosedGenericMethod = + CallPropertySetterOpenGenericMethod.MakeGenericMethod(typeInput, parameterType); + var callPropertySetterDelegate = + callPropertySetterClosedGenericMethod.CreateDelegate( + typeof(Action), propertySetterAsAction); + + return (Action)callPropertySetterDelegate; + } + + /// + /// Given an object, adds each instance property with a public get method as a key and its + /// associated value to a dictionary. + /// + /// If the object is already an instance, then a copy + /// is returned. + /// + /// + /// The implementation of PropertyHelper will cache the property accessors per-type. This is + /// faster when the the same type is used multiple times with ObjectToDictionary. + /// + public static IDictionary ObjectToDictionary(object value) + { + var dictionary = value as IDictionary; + if (dictionary != null) + { + return new Dictionary(dictionary, StringComparer.OrdinalIgnoreCase); + } + + dictionary = new Dictionary(StringComparer.OrdinalIgnoreCase); + + if (value != null) + { + foreach (var helper in GetProperties(value).Values) + { + dictionary[helper.Name] = helper.GetValue(value); + } + } + + return dictionary; + } + + private static FastProperty CreateInstance(PropertyInfo property) + { + return new FastProperty(property); + } + + // Called via reflection + private static object CallPropertyGetter( + Func getter, + object target) + { + return getter((TDeclaringType)target); + } + + // Called via reflection + private static object CallPropertyGetterByReference( + ByRefFunc getter, + object target) + { + var unboxed = (TDeclaringType)target; + return getter(ref unboxed); + } + + // Called via reflection + private static object CallNullSafePropertyGetter( + Func getter, + object target) + { + if (target == null) + { + return null; + } + + return getter((TDeclaringType)target); + } + + // Called via reflection + private static object CallNullSafePropertyGetterByReference( + ByRefFunc getter, + object target) + { + if (target == null) + { + return null; + } + + var unboxed = (TDeclaringType)target; + return getter(ref unboxed); + } + + private static void CallPropertySetter( + Action setter, + object target, + object value) + { + setter((TDeclaringType)target, (TValue)value); + } + + protected static IDictionary GetVisibleProperties( + Type type, + Func createPropertyHelper, + ConcurrentDictionary> allPropertiesCache, + ConcurrentDictionary> visiblePropertiesCache) + { + IDictionary result; + if (visiblePropertiesCache.TryGetValue(type, out result)) + { + return result; + } + + // The simple and common case, this is normal POCO object - no need to allocate. + var allPropertiesDefinedOnType = true; + var allProperties = GetProperties(type, createPropertyHelper, allPropertiesCache); + foreach (var propertyHelper in allProperties.Values) + { + if (propertyHelper.Property.DeclaringType != type) + { + allPropertiesDefinedOnType = false; + break; + } + } + + if (allPropertiesDefinedOnType) + { + result = allProperties; + visiblePropertiesCache.TryAdd(type, result); + return result; + } + + // There's some inherited properties here, so we need to check for hiding via 'new'. + var filteredProperties = new List(allProperties.Count); + foreach (var propertyHelper in allProperties.Values) + { + var declaringType = propertyHelper.Property.DeclaringType; + if (declaringType == type) + { + filteredProperties.Add(propertyHelper); + continue; + } + + // If this property was declared on a base type then look for the definition closest to the + // the type to see if we should include it. + var ignoreProperty = false; + + // Walk up the hierarchy until we find the type that actally declares this + // PropertyInfo. + var currentTypeInfo = type.GetTypeInfo(); + var declaringTypeInfo = declaringType.GetTypeInfo(); + while (currentTypeInfo != null && currentTypeInfo != declaringTypeInfo) + { + // We've found a 'more proximal' public definition + var declaredProperty = currentTypeInfo.GetDeclaredProperty(propertyHelper.Name); + if (declaredProperty != null) + { + ignoreProperty = true; + break; + } + + currentTypeInfo = currentTypeInfo.BaseType?.GetTypeInfo(); + } + + if (!ignoreProperty) + { + filteredProperties.Add(propertyHelper); + } + } + + result = filteredProperties.ToDictionary(x => x.Name, StringComparer.OrdinalIgnoreCase); + visiblePropertiesCache.TryAdd(type, result); + return result; + } + + protected static IDictionary GetProperties( + Type type, + Func createPropertyHelper, + ConcurrentDictionary> cache) + { + // Unwrap nullable types. This means Nullable.Value and Nullable.HasValue will not be + // part of the sequence of properties returned by this method. + type = Nullable.GetUnderlyingType(type) ?? type; + + IDictionary fastProperties; + if (!cache.TryGetValue(type, out fastProperties)) + { + var candidates = GetPropertyCandidates(type); + fastProperties = candidates.Select(p => createPropertyHelper(p)).ToDictionary(x => x.Name, StringComparer.OrdinalIgnoreCase); + cache.TryAdd(type, fastProperties); + } + + return fastProperties; + } + + private static IEnumerable GetPropertyCandidates(Type type) + { + // We avoid loading indexed properties using the Where statement. + var properties = type.GetRuntimeProperties().Where(IsCandidateProperty); + + var typeInfo = type.GetTypeInfo(); + if (typeInfo.IsInterface) + { + // Reflection does not return information about inherited properties on the interface itself. + properties = properties.Concat(typeInfo.ImplementedInterfaces.SelectMany( + interfaceType => interfaceType.GetRuntimeProperties().Where(IsCandidateProperty))); + } + + return properties; + } + + // Indexed properties are not useful (or valid) for grabbing properties off an object. + private static bool IsCandidateProperty(PropertyInfo property) + { + return property.GetIndexParameters().Length == 0 && + property.GetMethod != null && + property.GetMethod.IsPublic && + !property.GetMethod.IsStatic; + } + + class PropertyKey : Tuple + { + public PropertyKey(Type type, string propertyName) + : base(type, propertyName) + { + } + public Type Type { get { return base.Item1; } } + public string PropertyName { get { return base.Item2; } } + } + } +} \ No newline at end of file diff --git a/src/Libraries/SmartStore.Services/Configuration/SettingService.cs b/src/Libraries/SmartStore.Services/Configuration/SettingService.cs index 9bdcecbfcb..c439ee40b5 100644 --- a/src/Libraries/SmartStore.Services/Configuration/SettingService.cs +++ b/src/Libraries/SmartStore.Services/Configuration/SettingService.cs @@ -15,6 +15,7 @@ using SmartStore.Core.Plugins; using System.ComponentModel; using SmartStore.Utilities; +using SmartStore.Utilities.Reflection; namespace SmartStore.Services.Configuration { @@ -303,10 +304,12 @@ public virtual bool SettingExists(T settings, var settings = Activator.CreateInstance(); - foreach (var prop in typeof(T).GetProperties()) + foreach (var fastProp in FastProperty.GetProperties(typeof(T)).Values) { + var prop = fastProp.Property; + // get properties we can read and write to - if (!prop.CanRead || !prop.CanWrite) + if (!prop.CanWrite) continue; var key = typeof(T).Name + "." + prop.Name; @@ -330,7 +333,7 @@ public virtual bool SettingExists(T settings, if (list != null) { - prop.SetValue(settings, list, null); + fastProp.SetValue(settings, list); } } @@ -348,7 +351,7 @@ public virtual bool SettingExists(T settings, object value = converter.ConvertFromInvariantString(setting); //set property - prop.SetValue(settings, value, null); + fastProp.SetValue(settings, value); } return settings; diff --git a/src/Presentation/SmartStore.Web.Framework/DependencyRegistrar.cs b/src/Presentation/SmartStore.Web.Framework/DependencyRegistrar.cs index 1daa71bd03..3820f326d8 100644 --- a/src/Presentation/SmartStore.Web.Framework/DependencyRegistrar.cs +++ b/src/Presentation/SmartStore.Web.Framework/DependencyRegistrar.cs @@ -75,6 +75,7 @@ using SmartStore.Web.Framework.WebApi.Configuration; using Module = Autofac.Module; using SmartStore.Core.Domain.DataExchange; +using SmartStore.Utilities.Reflection; namespace SmartStore.Web.Framework { @@ -327,12 +328,14 @@ protected override void AttachToComponentRegistration(IComponentRegistry compone if (querySettingsProperty == null) return; + var fastProperty = new FastProperty(querySettingsProperty); + registration.Activated += (sender, e) => { if (DataSettings.DatabaseIsInstalled()) { var querySettings = e.Context.Resolve(); - querySettingsProperty.SetValue(e.Instance, querySettings, null); + fastProperty.SetValue(e.Instance, querySettings); } }; } @@ -390,18 +393,17 @@ private IEnumerable> BuildLoggerInjectors(Type }) .Where(x => x.PropertyType == typeof(ILogger)) // must be a logger .Where(x => x.IndexParameters.Count() == 0) // must not be an indexer - .Where(x => x.Accessors.Length != 1 || x.Accessors[0].ReturnType == typeof(void)); //must have get/set, or only set + .Where(x => x.Accessors.Length != 1 || x.Accessors[0].ReturnType == typeof(void)) //must have get/set, or only set + .Select(x => new FastProperty(x.PropertyInfo)); // Return an array of actions that resolve a logger and assign the property - foreach (var entry in loggerProperties) + foreach (var prop in loggerProperties) { - var propertyInfo = entry.PropertyInfo; - yield return (ctx, instance) => { string component = componentType.ToString(); var logger = ctx.Resolve(); - propertyInfo.SetValue(instance, logger, null); + prop.SetValue(instance, logger); }; } } @@ -433,12 +435,14 @@ protected override void AttachToComponentRegistration(IComponentRegistry compone if (userProperty == null) return; + var fastProperty = new FastProperty(userProperty); + registration.Activated += (sender, e) => { if (DataSettings.DatabaseIsInstalled()) { Localizer localizer = e.Context.Resolve().Get; - userProperty.SetValue(e.Instance, localizer, null); + fastProperty.SetValue(e.Instance, localizer); } }; } @@ -1016,16 +1020,16 @@ public IEnumerable RegistrationsFor( var ts = service as TypedService; if (ts != null && typeof(ISettings).IsAssignableFrom(ts.ServiceType)) { - //var buildMethod = BuildMethod.MakeGenericMethod(ts.ServiceType); - //yield return (IComponentRegistration)buildMethod.Invoke(null, null); - - // Perf with Fasterflect - yield return (IComponentRegistration)Fasterflect.TryInvokeWithValuesExtensions.TryCallMethodWithValues( - typeof(SettingsSource), - null, - "BuildRegistration", - new Type[] { ts.ServiceType }, - BindingFlags.Static | BindingFlags.NonPublic); + var buildMethod = BuildMethod.MakeGenericMethod(ts.ServiceType); + yield return (IComponentRegistration)buildMethod.Invoke(null, null); + + //// Perf with Fasterflect + //yield return (IComponentRegistration)Fasterflect.TryInvokeWithValuesExtensions.TryCallMethodWithValues( + // typeof(SettingsSource), + // null, + // "BuildRegistration", + // new Type[] { ts.ServiceType }, + // BindingFlags.Static | BindingFlags.NonPublic); } } From e910adace963cef2360e75a6afd79f170186de7b Mon Sep 17 00:00:00 2001 From: Murat Cakir Date: Sun, 8 Nov 2015 04:43:14 +0100 Subject: [PATCH 017/707] (Perf) Replaced Fasterflect with custom reflection utilities (much faster & less mem usage) --- .../ComponentModel/SerializationUtils.cs | 9 +- .../Extensions/DictionaryExtensions.cs | 3 +- .../Extensions/TypeExtensions.cs | 58 ------------ .../Infrastructure/ComparableObject.cs | 7 +- .../Infrastructure/DateRange.cs | 70 --------------- .../SmartStore.Core/Infrastructure/Error.cs | 2 - .../Infrastructure/ValueObject.cs | 90 ------------------- .../SmartStore.Core/SmartStore.Core.csproj | 7 +- .../Utilities/CollectionHelper.cs | 21 +---- .../Utilities/DictionaryConverter.cs | 48 +++++----- .../Utilities/Reflection/FastProperty.cs | 4 +- .../SmartStore.Core/Utilities/TypeHelper.cs | 11 --- src/Libraries/SmartStore.Core/packages.config | 1 - src/Libraries/SmartStore.Data/app.config | 12 +-- .../Configuration/SettingService.cs | 17 ++-- .../ExportImport/DataSegmenter.cs | 17 +++- .../Localization/LocalizationExtentions.cs | 11 ++- .../SmartStore.Services.csproj | 4 - .../SmartStore.Services/packages.config | 1 - src/Plugins/SmartStore.Clickatell/web.config | 2 +- src/Plugins/SmartStore.DevTools/Web.config | 2 +- .../SmartStore.DiscountRules/web.config | 2 +- .../SmartStore.FacebookAuth/web.config | 2 +- .../SmartStore.GoogleAnalytics/web.config | 2 +- .../web.config | 2 +- .../SmartStore.OfflinePayment/web.config | 2 +- src/Plugins/SmartStore.Shipping/web.config | 2 +- .../SmartStore.ShippingByWeight/web.config | 2 +- src/Plugins/SmartStore.Tax/web.config | 2 +- src/Plugins/SmartStore.WebApi/web.config | 2 +- .../Settings/StoreDependingSettingHelper.cs | 10 +-- .../SmartStore.Web.Framework.csproj | 4 - .../UI/Components/ComponentBuilder.cs | 2 +- .../WebApi/WebApiEntityController.cs | 19 ++-- .../SmartStore.Web.Framework/packages.config | 1 - .../SmartStore.Web/Administration/Web.config | 2 +- src/Tools/SmartStore.Packager/App.config | 18 ++-- 37 files changed, 113 insertions(+), 358 deletions(-) delete mode 100644 src/Libraries/SmartStore.Core/Infrastructure/DateRange.cs delete mode 100644 src/Libraries/SmartStore.Core/Infrastructure/ValueObject.cs diff --git a/src/Libraries/SmartStore.Core/ComponentModel/SerializationUtils.cs b/src/Libraries/SmartStore.Core/ComponentModel/SerializationUtils.cs index 263e516ef5..26d6f8b079 100644 --- a/src/Libraries/SmartStore.Core/ComponentModel/SerializationUtils.cs +++ b/src/Libraries/SmartStore.Core/ComponentModel/SerializationUtils.cs @@ -35,7 +35,6 @@ using System.IO; using System.Text; //using System.Reflection; -using Fasterflect; using System.Xml; using System.Xml.Serialization; @@ -419,17 +418,17 @@ public static object DeSerializeObject(byte[] buffer, Type objectType, bool thro /// public static string ObjectToString(object instance, string separator, ObjectToStringTypes type) { - var fi = instance.GetType().Fields(); + var fi = instance.GetType().GetFields(); string output = string.Empty; if (type == ObjectToStringTypes.Properties || type == ObjectToStringTypes.PropertiesAndFields) { - foreach (var property in instance.GetType().Properties()) + foreach (var property in instance.GetType().GetProperties()) { try { - output += property.Name + ":" + instance.GetPropertyValue(property.Name).ToString() + separator; + output += property.Name + ":" + property.GetValue(instance, null).ToString() + separator; } catch { @@ -444,7 +443,7 @@ public static string ObjectToString(object instance, string separator, ObjectToS { try { - output = output + field.Name + ": " + instance.GetFieldValue(field.Name).ToString() + separator; + output = output + field.Name + ": " + field.GetValue(instance).ToString() + separator; } catch { diff --git a/src/Libraries/SmartStore.Core/Extensions/DictionaryExtensions.cs b/src/Libraries/SmartStore.Core/Extensions/DictionaryExtensions.cs index 8cfb8c1142..d0dde45343 100644 --- a/src/Libraries/SmartStore.Core/Extensions/DictionaryExtensions.cs +++ b/src/Libraries/SmartStore.Core/Extensions/DictionaryExtensions.cs @@ -5,6 +5,7 @@ using System.Web.Routing; using System.Globalization; using System.Dynamic; +using SmartStore.Utilities; namespace SmartStore { @@ -34,7 +35,7 @@ public static void Merge(this IDictionary instance, string key, public static void Merge(this IDictionary instance, object values, bool replaceExisting = true) { - instance.Merge(new RouteValueDictionary(values), replaceExisting); + instance.Merge(CollectionHelper.ObjectToDictionary(values), replaceExisting); } public static void Merge(this IDictionary instance, IDictionary from, bool replaceExisting = true) diff --git a/src/Libraries/SmartStore.Core/Extensions/TypeExtensions.cs b/src/Libraries/SmartStore.Core/Extensions/TypeExtensions.cs index d2ca8d9df9..007022ae53 100644 --- a/src/Libraries/SmartStore.Core/Extensions/TypeExtensions.cs +++ b/src/Libraries/SmartStore.Core/Extensions/TypeExtensions.cs @@ -4,7 +4,6 @@ using System.Reflection; using System.Collections; using System.Diagnostics; -using Fasterflect; namespace SmartStore { @@ -393,63 +392,6 @@ public static bool IsGenericDictionary(this Type type) // return false; //} - /// - /// Gets the member's value on the object. - /// - /// The member. - /// The target object. - /// The member's value on the object. - public static object GetValue(this MemberInfo member, object target) - { - Guard.ArgumentNotNull(member, "member"); - Guard.ArgumentNotNull(target, "target"); - - var type = target.GetType(); - - switch (member.MemberType) - { - case MemberTypes.Field: - return target.GetFieldValue(member.Name); - //return ((FieldInfo)member).GetValue(target); - case MemberTypes.Property: - return target.GetPropertyValue(member.Name); - default: - throw new ArgumentException("MemberInfo '{0}' is not of type FieldInfo or PropertyInfo".FormatInvariant(member.Name), "member"); - } - } - - /// - /// Sets the member's value on the target object. - /// - /// The member. - /// The target. - /// The value. - public static void SetValue(this MemberInfo member, object target, object value) - { - Guard.ArgumentNotNull(member, "member"); - Guard.ArgumentNotNull(target, "target"); - - switch (member.MemberType) - { - case MemberTypes.Field: - target.SetFieldValue(member.Name, value); - break; - //return ((FieldInfo)member).GetValue(target); - case MemberTypes.Property: - try - { - target.SetPropertyValue(member.Name, value); - } - catch (TargetParameterCountException e) - { - throw new ArgumentException("PropertyInfo '{0}' has index parameters".FormatInvariant(member.Name), "member", e); - } - break; - default: - throw new ArgumentException("MemberInfo '{0}' is not of type FieldInfo or PropertyInfo".FormatInvariant(member.Name), "member"); - } - } - /// /// Gets the underlying type of a type. /// diff --git a/src/Libraries/SmartStore.Core/Infrastructure/ComparableObject.cs b/src/Libraries/SmartStore.Core/Infrastructure/ComparableObject.cs index 7a0c3d9dbb..32b4a6a1e2 100644 --- a/src/Libraries/SmartStore.Core/Infrastructure/ComparableObject.cs +++ b/src/Libraries/SmartStore.Core/Infrastructure/ComparableObject.cs @@ -4,7 +4,6 @@ using System.Linq.Expressions; using System.Reflection; using System.ComponentModel; -using Fasterflect; namespace SmartStore { @@ -67,7 +66,7 @@ public override int GetHashCode() foreach (var pi in signatureProperties) { - object value = this.GetPropertyValue(pi.Name); // pi.GetValue(this); + object value = pi.GetValue(this); if (value != null) hashCode = (hashCode * HashMultiplier) ^ value.GetHashCode(); @@ -102,8 +101,8 @@ protected virtual bool HasSameSignatureAs(ComparableObject compareTo) foreach (var pi in signatureProperties) { - object thisValue = this.GetPropertyValue(pi.Name); - object thatValue = compareTo.GetPropertyValue(pi.Name); + object thisValue = pi.GetValue(this); + object thatValue = pi.GetValue(compareTo); if (thisValue == null && thatValue == null) continue; diff --git a/src/Libraries/SmartStore.Core/Infrastructure/DateRange.cs b/src/Libraries/SmartStore.Core/Infrastructure/DateRange.cs deleted file mode 100644 index bb331223be..0000000000 --- a/src/Libraries/SmartStore.Core/Infrastructure/DateRange.cs +++ /dev/null @@ -1,70 +0,0 @@ -using System; -using System.Collections.Generic; - -namespace SmartStore -{ - - public class DateRange : ValueObject, ICloneable - { - - public DateRange() - { - } - - public DateRange(DateTime to) - : this(default(DateTime), to) - { - } - - public DateRange(DateTime from, DateTime to) - { - DateFrom = from; - DateTo = to; - } - - [ObjectSignature] - public DateTime? DateFrom { get; set; } - - [ObjectSignature] - public DateTime? DateTo { get; set; } - - public bool IsDefined - { - get { return DateFrom.HasValue || DateTo.HasValue; } - } - - //public override int GetHashCode() - //{ - // return SystemUtil.GetHashCode(this.DateFrom, this.DateTo); - //} - - //public override bool Equals(object obj) - //{ - // if (ReferenceEquals(null, obj)) return false; - // if (ReferenceEquals(this, obj)) return true; - - // DateRange other = (DateRange)obj; - // return this.DateFrom.Equals(other.DateFrom) && this.DateTo.Equals(other.DateTo); - //} - - #region ICloneable Members - - public DateRange Clone() - { - return new DateRange() - { - DateFrom = this.DateFrom, - DateTo = this.DateTo - }; - } - - object ICloneable.Clone() - { - return this.Clone(); - } - - #endregion - - } - -} diff --git a/src/Libraries/SmartStore.Core/Infrastructure/Error.cs b/src/Libraries/SmartStore.Core/Infrastructure/Error.cs index d8752d8169..a83cc11464 100644 --- a/src/Libraries/SmartStore.Core/Infrastructure/Error.cs +++ b/src/Libraries/SmartStore.Core/Infrastructure/Error.cs @@ -2,8 +2,6 @@ using System.Globalization; using System.Diagnostics; -using Fasterflect; - namespace SmartStore { public static class Error diff --git a/src/Libraries/SmartStore.Core/Infrastructure/ValueObject.cs b/src/Libraries/SmartStore.Core/Infrastructure/ValueObject.cs deleted file mode 100644 index 066c47f810..0000000000 --- a/src/Libraries/SmartStore.Core/Infrastructure/ValueObject.cs +++ /dev/null @@ -1,90 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Reflection; -using Fasterflect; - -namespace SmartStore -{ - - /// - /// Base class for complex value objects, which do not have - /// identifiers. - /// - /// Type of the entity, which is the value obect. - public abstract class ValueObject : ComparableObject> - where T : ValueObject - { - - /// - /// Registers all properties of the subclass as signature properties. - /// - protected void RegisterProperties() - { - RegisterProperties((pd) => true); - } - - /// - /// Registers any properties of the subclass matching - /// the given as signature properties. - /// - protected void RegisterProperties(Func filter) - { - foreach (var pi in this.GetType().GetProperties(BindingFlags.Instance | BindingFlags.Public)) - { - if (filter(pi)) - RegisterSignatureProperty(pi); - } - } - - public override bool Equals(object obj) - { - return base.Equals(obj); - } - - public override int GetHashCode() - { - return base.GetHashCode(); - } - - public override string ToString() - { - var sb = new StringBuilder(); - var properties = GetSignatureProperties(); - int propsCount = properties.Count(); - - int i = 1; - - foreach (var pi in properties) - { - object value = this.GetPropertyValue(pi.Name); - if (value == null) - continue; - - sb.Append(pi.Name + ": " + value.ToString()); - if (i < propsCount) - sb.Append(", "); - - i++; - } - - return sb.ToString(); - } - - public static bool operator ==(ValueObject x, ValueObject y) - { - if ((object)x == null) - return (object)y == null; - - return x.Equals(y); - } - - public static bool operator !=(ValueObject x, ValueObject y) - { - return !(x == y); - } - - } - -} diff --git a/src/Libraries/SmartStore.Core/SmartStore.Core.csproj b/src/Libraries/SmartStore.Core/SmartStore.Core.csproj index 7d39d16e05..8dc531e3be 100644 --- a/src/Libraries/SmartStore.Core/SmartStore.Core.csproj +++ b/src/Libraries/SmartStore.Core/SmartStore.Core.csproj @@ -77,10 +77,6 @@ False ..\..\packages\EntityFramework.6.1.3\lib\net45\EntityFramework.SqlServer.dll - - False - ..\..\packages\fasterflect.2.1.3\lib\net40\Fasterflect.dll - True ..\..\packages\Microsoft.Web.Infrastructure.1.0.0.0\lib\net40\Microsoft.Web.Infrastructure.dll @@ -441,7 +437,6 @@ - @@ -451,7 +446,6 @@ - @@ -599,6 +593,7 @@ + diff --git a/src/Libraries/SmartStore.Core/Utilities/CollectionHelper.cs b/src/Libraries/SmartStore.Core/Utilities/CollectionHelper.cs index 2497ef9349..f5dcfae895 100644 --- a/src/Libraries/SmartStore.Core/Utilities/CollectionHelper.cs +++ b/src/Libraries/SmartStore.Core/Utilities/CollectionHelper.cs @@ -6,10 +6,7 @@ using System.Text; using System.Collections; using System.Globalization; -using System.Collections.Specialized; -using System.ComponentModel; - -using Fasterflect; +using SmartStore.Utilities.Reflection; namespace SmartStore.Utilities { @@ -221,24 +218,12 @@ public static IDictionary ObjectToDictionary(object obj) Type t = obj.GetType(); - return t.GetProperties(BindingFlags.Instance | BindingFlags.Public) + return FastProperty.GetProperties(t).Values .ToDictionary(k => k.Name.Replace("_", "-"), - v => obj.GetPropertyValue(v.Name), + v => v.GetValue(obj), StringComparer.OrdinalIgnoreCase); } - public static NameValueCollection ObjectToNameValueCollection(object obj) - { - var result = new NameValueCollection(StringComparer.OrdinalIgnoreCase); - foreach (PropertyDescriptor descriptor in TypeDescriptor.GetProperties(obj)) - { - object value = descriptor.GetValue(obj); - result.Add(descriptor.Name, value.ToString()); - } - - return result; - } - /// /// Converts the type to an /// compatible object. diff --git a/src/Libraries/SmartStore.Core/Utilities/DictionaryConverter.cs b/src/Libraries/SmartStore.Core/Utilities/DictionaryConverter.cs index bcb4706ad6..34f4e74782 100644 --- a/src/Libraries/SmartStore.Core/Utilities/DictionaryConverter.cs +++ b/src/Libraries/SmartStore.Core/Utilities/DictionaryConverter.cs @@ -1,12 +1,11 @@ using System; using System.Collections.Generic; using System.Linq; -using System.ComponentModel; using System.Text; using System.Collections; using System.Reflection; using System.Runtime.Serialization; -using Fasterflect; +using SmartStore.Utilities.Reflection; namespace SmartStore.Utilities { @@ -93,7 +92,7 @@ public static object CreateAndPopulate(Type targetType, IDictionary targetType); - var target = targetType.CreateInstance(); //Activator.CreateInstance(targetType); + var target = Activator.CreateInstance(targetType); Populate(source, target, out problems); @@ -141,15 +140,14 @@ public static void Populate(IDictionary source, object target, o if (source != null) { - // TODO: Metadaten aus einem TypeCache ziehen zwecks Performance! - foreach (var pi in t.GetProperties(BindingFlags.Instance | BindingFlags.Public)) + foreach (var fastProp in FastProperty.GetProperties(t).Values) { - object value; + var pi = fastProp.Property; if (!pi.PropertyType.IsPredefinedSimpleType() && source.TryGetValue(pi.Name, out value) && value is IDictionary) { - var nestedValue = target.GetPropertyValue(pi.Name); + var nestedValue = fastProp.GetValue(target); ICollection nestedProblems; populated = populated.Concat(new object[] { target }).ToArray(); @@ -159,17 +157,17 @@ public static void Populate(IDictionary source, object target, o { problems.AddRange(nestedProblems); } - WriteToProperty(target, pi, nestedValue, problems); + WriteToProperty(target, fastProp, nestedValue, problems); } else if (pi.PropertyType.IsArray && !source.ContainsKey(pi.Name)) { - WriteToProperty(target, pi, RetrieveArrayValues(pi, source, problems), problems); + WriteToProperty(target, fastProp, RetrieveArrayValues(pi, source, problems), problems); } else { if (source.TryGetValue(pi.Name, out value)) { - WriteToProperty(target, pi, value, problems); + WriteToProperty(target, fastProp, value, problems); } } } @@ -182,21 +180,19 @@ private static object RetrieveArrayValues(PropertyInfo arrayProp, IDictionary).MakeGenericType(elemType)); - var elements = (IList)typeof(List<>).MakeGenericType(elemType).CreateInstance(); + var elements = (IList)Activator.CreateInstance(typeof(List<>).MakeGenericType(elemType)); - // TODO: Metadaten aus einem TypeCache ziehen zwecks Performance! - var properties = elemType.GetProperties(BindingFlags.Public | BindingFlags.Instance); + var properties = FastProperty.GetProperties(elemType); while (anyValuesFound) { object curElement = null; anyValuesFound = false; // false until proven otherwise - foreach (var pi in properties) + foreach (var prop in properties.Values) { //var key = string.Format("_{0}{1}_{2}", idx, arrayProp.Name, pd.Name); - var key = string.Format("{0}[{1}].{2}", arrayProp.Name, idx, pi.Name); + var key = string.Format("{0}[{1}].{2}", arrayProp.Name, idx, prop.Name); object value; if (source.TryGetValue(key, out value)) @@ -205,11 +201,11 @@ private static object RetrieveArrayValues(PropertyInfo arrayProp, IDictionary problems) + private static void SetPropFromValue(object value, object item, FastProperty prop, ICollection problems) { - WriteToProperty(item, pi, value, problems); + WriteToProperty(item, prop, value, problems); } - private static void WriteToProperty(object item, PropertyInfo pi, object value, ICollection problems) + private static void WriteToProperty(object item, FastProperty prop, object value, ICollection problems) { - if (!pi.CanWrite) + var pi = prop.Property; + + if (!pi.CanWrite) return; try @@ -246,8 +244,7 @@ private static void WriteToProperty(object item, PropertyInfo pi, object value, if (pi.PropertyType.IsAssignableFrom(value.GetType())) { - //pi.SetValue(item, value); - item.SetPropertyValue(pi.Name, value); + prop.SetValue(item, value); return; } @@ -256,8 +253,7 @@ private static void WriteToProperty(object item, PropertyInfo pi, object value, destType = pi.PropertyType.GetGenericArguments()[0]; } - //pi.SetValue(item, value.Convert(destType)); - item.SetPropertyValue(pi.Name, value.Convert(destType)); + prop.SetValue(item, value.Convert(destType)); } } catch (Exception ex) diff --git a/src/Libraries/SmartStore.Core/Utilities/Reflection/FastProperty.cs b/src/Libraries/SmartStore.Core/Utilities/Reflection/FastProperty.cs index 27498b5576..e72bbafcd9 100644 --- a/src/Libraries/SmartStore.Core/Utilities/Reflection/FastProperty.cs +++ b/src/Libraries/SmartStore.Core/Utilities/Reflection/FastProperty.cs @@ -355,9 +355,9 @@ public static IDictionary ObjectToDictionary(object value) if (value != null) { - foreach (var helper in GetProperties(value).Values) + foreach (var prop in GetProperties(value).Values) { - dictionary[helper.Name] = helper.GetValue(value); + dictionary[prop.Name] = prop.GetValue(value); } } diff --git a/src/Libraries/SmartStore.Core/Utilities/TypeHelper.cs b/src/Libraries/SmartStore.Core/Utilities/TypeHelper.cs index 34dbf27b18..482b1ed9bd 100644 --- a/src/Libraries/SmartStore.Core/Utilities/TypeHelper.cs +++ b/src/Libraries/SmartStore.Core/Utilities/TypeHelper.cs @@ -6,7 +6,6 @@ using System.Linq; using System.Globalization; using System.IO; -using Fasterflect; namespace SmartStore.Utilities { @@ -332,16 +331,6 @@ public static void RegisterTypeConverter() where TC : TypeConverter TypeDescriptor.AddAttributes(typeof(T), new TypeConverterAttribute(typeof(TC))); } - public static T CreateInstance(params object[] parameters) where T : class - { - return (T)typeof(T).CreateInstance(parameters); - } - - public static object CreateInstance(Type type, params object[] parameters) - { - return type.CreateInstance(parameters); - } - } } \ No newline at end of file diff --git a/src/Libraries/SmartStore.Core/packages.config b/src/Libraries/SmartStore.Core/packages.config index 923c1183a2..78f9872f99 100644 --- a/src/Libraries/SmartStore.Core/packages.config +++ b/src/Libraries/SmartStore.Core/packages.config @@ -3,7 +3,6 @@ - diff --git a/src/Libraries/SmartStore.Data/app.config b/src/Libraries/SmartStore.Data/app.config index 4f592fbcd8..7808ca6f28 100644 --- a/src/Libraries/SmartStore.Data/app.config +++ b/src/Libraries/SmartStore.Data/app.config @@ -1,15 +1,15 @@ - + - - + + - - + + - + diff --git a/src/Libraries/SmartStore.Services/Configuration/SettingService.cs b/src/Libraries/SmartStore.Services/Configuration/SettingService.cs index c439ee40b5..ae83128abb 100644 --- a/src/Libraries/SmartStore.Services/Configuration/SettingService.cs +++ b/src/Libraries/SmartStore.Services/Configuration/SettingService.cs @@ -9,7 +9,7 @@ using SmartStore.Core.Domain.Configuration; using SmartStore.Core.Infrastructure; using SmartStore.Core.Events; -using Fasterflect; +//using Fasterflect; using System.Linq.Expressions; using System.Reflection; using SmartStore.Core.Plugins; @@ -413,18 +413,20 @@ public virtual void SetSetting(string key, T value, int storeId = 0, bool cle /* We do not clear cache after each setting update. * This behavior can increase performance because cached settings will not be cleared * and loaded from database after each update */ - foreach (var prop in typeof(T).GetProperties()) + foreach (var prop in FastProperty.GetProperties(typeof(T)).Values) { + var pi = prop.Property; + // get properties we can read and write to - if (!prop.CanRead || !prop.CanWrite) + if (!pi.CanRead || !pi.CanWrite) continue; - if (!CommonHelper.GetTypeConverter(prop.PropertyType).CanConvertFrom(typeof(string))) + if (!CommonHelper.GetTypeConverter(pi.PropertyType).CanConvertFrom(typeof(string))) continue; string key = typeof(T).Name + "." + prop.Name; //Duck typing is not supported in C#. That's why we're using dynamic type - dynamic value = settings.TryGetPropertyValue(prop.Name); + dynamic value = prop.GetValue(settings); SetSetting(key, value ?? "", storeId, false); } @@ -462,8 +464,9 @@ public virtual void SaveSetting(T settings, } string key = typeof(T).Name + "." + propInfo.Name; - //Duck typing is not supported in C#. That's why we're using dynamic type - dynamic value = settings.TryGetPropertyValue(propInfo.Name); + // Duck typing is not supported in C#. That's why we're using dynamic type + var fastProp = FastProperty.GetProperty(settings.GetType(), propInfo.Name, true); + dynamic value = fastProp.GetValue(settings); SetSetting(key, value ?? "", storeId, false); } diff --git a/src/Libraries/SmartStore.Services/ExportImport/DataSegmenter.cs b/src/Libraries/SmartStore.Services/ExportImport/DataSegmenter.cs index 303f12a2c5..6bb3693cd1 100644 --- a/src/Libraries/SmartStore.Services/ExportImport/DataSegmenter.cs +++ b/src/Libraries/SmartStore.Services/ExportImport/DataSegmenter.cs @@ -5,10 +5,10 @@ using System.Linq.Expressions; using System.Reflection; using System.Text; -using Fasterflect; using OfficeOpenXml; using SmartStore.Core; using SmartStore.Core.Data; +using SmartStore.Utilities.Reflection; namespace SmartStore.Services.ExportImport { @@ -277,6 +277,12 @@ public int Position get { return _position; } } + public object Fastproperty + { + get; + private set; + } + public TProp GetValue(string columnName) { object value; @@ -298,6 +304,8 @@ public TProp GetValue(string columnName) try { + var fastProp = FastProperty.GetProperty(typeof(T), propName, true); + object value; if (this.TryGetValue(propName, out value)) { @@ -319,7 +327,9 @@ public TProp GetValue(string columnName) converted = value.Convert(); } } - return target.TrySetPropertyValue(propName, converted); + + fastProp.SetValue(target, converted); + return true; } else { @@ -328,7 +338,8 @@ public TProp GetValue(string columnName) { // ...but the entity is new. In this case // set the default value if given. - return target.TrySetPropertyValue(propName, defaultValue); + fastProp.SetValue(target, defaultValue); + return true; } } } diff --git a/src/Libraries/SmartStore.Services/Localization/LocalizationExtentions.cs b/src/Libraries/SmartStore.Services/Localization/LocalizationExtentions.cs index b73e7660ed..0256ef1ac8 100644 --- a/src/Libraries/SmartStore.Services/Localization/LocalizationExtentions.cs +++ b/src/Libraries/SmartStore.Services/Localization/LocalizationExtentions.cs @@ -5,12 +5,13 @@ using SmartStore.Core.Domain.Localization; using SmartStore.Core.Infrastructure; using SmartStore.Core.Plugins; -using Fasterflect; +//using Fasterflect; using System.Xml; using SmartStore.Core.Data; using SmartStore.Utilities; using System.Collections.Concurrent; using SmartStore.Core.ComponentModel; +using SmartStore.Utilities.Reflection; namespace SmartStore.Services.Localization { @@ -324,7 +325,13 @@ public static string GetLocalizedValue(this PluginDescriptor descriptor, ILocali string result = localizationService.GetResource(resourceName, languageId, false, "", true); if (String.IsNullOrEmpty(result) && returnDefaultValue) - result = descriptor.TryGetPropertyValue(propertyName) as string; + { + var fastProp = FastProperty.GetProperty(descriptor.GetType(), propertyName); + if (fastProp != null) + { + result = fastProp.GetValue(descriptor) as string; + } + } return result; } diff --git a/src/Libraries/SmartStore.Services/SmartStore.Services.csproj b/src/Libraries/SmartStore.Services/SmartStore.Services.csproj index f63d565765..76cfeb1040 100644 --- a/src/Libraries/SmartStore.Services/SmartStore.Services.csproj +++ b/src/Libraries/SmartStore.Services/SmartStore.Services.csproj @@ -80,10 +80,6 @@ False ..\..\packages\EPPlus.4.0.3\lib\net20\EPPlus.dll - - False - ..\..\packages\fasterflect.2.1.3\lib\net40\Fasterflect.dll - False ..\..\packages\ImageResizer.3.4.2\lib\ImageResizer.dll diff --git a/src/Libraries/SmartStore.Services/packages.config b/src/Libraries/SmartStore.Services/packages.config index 2419041a2c..2efca85a84 100644 --- a/src/Libraries/SmartStore.Services/packages.config +++ b/src/Libraries/SmartStore.Services/packages.config @@ -4,7 +4,6 @@ - diff --git a/src/Plugins/SmartStore.Clickatell/web.config b/src/Plugins/SmartStore.Clickatell/web.config index 46b8ba77d4..deaeafe833 100644 --- a/src/Plugins/SmartStore.Clickatell/web.config +++ b/src/Plugins/SmartStore.Clickatell/web.config @@ -106,7 +106,7 @@ - + diff --git a/src/Plugins/SmartStore.DevTools/Web.config b/src/Plugins/SmartStore.DevTools/Web.config index e0593e522a..58d0f26ce4 100644 --- a/src/Plugins/SmartStore.DevTools/Web.config +++ b/src/Plugins/SmartStore.DevTools/Web.config @@ -114,7 +114,7 @@ - + diff --git a/src/Plugins/SmartStore.DiscountRules/web.config b/src/Plugins/SmartStore.DiscountRules/web.config index 46b8ba77d4..deaeafe833 100644 --- a/src/Plugins/SmartStore.DiscountRules/web.config +++ b/src/Plugins/SmartStore.DiscountRules/web.config @@ -106,7 +106,7 @@ - + diff --git a/src/Plugins/SmartStore.FacebookAuth/web.config b/src/Plugins/SmartStore.FacebookAuth/web.config index 10ad5c862a..b294e19325 100644 --- a/src/Plugins/SmartStore.FacebookAuth/web.config +++ b/src/Plugins/SmartStore.FacebookAuth/web.config @@ -110,7 +110,7 @@ - + diff --git a/src/Plugins/SmartStore.GoogleAnalytics/web.config b/src/Plugins/SmartStore.GoogleAnalytics/web.config index ad003b3e26..d4330046b2 100644 --- a/src/Plugins/SmartStore.GoogleAnalytics/web.config +++ b/src/Plugins/SmartStore.GoogleAnalytics/web.config @@ -105,7 +105,7 @@ - + diff --git a/src/Plugins/SmartStore.GoogleMerchantCenter/web.config b/src/Plugins/SmartStore.GoogleMerchantCenter/web.config index 46b8ba77d4..deaeafe833 100644 --- a/src/Plugins/SmartStore.GoogleMerchantCenter/web.config +++ b/src/Plugins/SmartStore.GoogleMerchantCenter/web.config @@ -106,7 +106,7 @@ - + diff --git a/src/Plugins/SmartStore.OfflinePayment/web.config b/src/Plugins/SmartStore.OfflinePayment/web.config index 46b8ba77d4..deaeafe833 100644 --- a/src/Plugins/SmartStore.OfflinePayment/web.config +++ b/src/Plugins/SmartStore.OfflinePayment/web.config @@ -106,7 +106,7 @@ - + diff --git a/src/Plugins/SmartStore.Shipping/web.config b/src/Plugins/SmartStore.Shipping/web.config index ad003b3e26..d4330046b2 100644 --- a/src/Plugins/SmartStore.Shipping/web.config +++ b/src/Plugins/SmartStore.Shipping/web.config @@ -105,7 +105,7 @@ - + diff --git a/src/Plugins/SmartStore.ShippingByWeight/web.config b/src/Plugins/SmartStore.ShippingByWeight/web.config index ad003b3e26..d4330046b2 100644 --- a/src/Plugins/SmartStore.ShippingByWeight/web.config +++ b/src/Plugins/SmartStore.ShippingByWeight/web.config @@ -105,7 +105,7 @@ - + diff --git a/src/Plugins/SmartStore.Tax/web.config b/src/Plugins/SmartStore.Tax/web.config index 46b8ba77d4..deaeafe833 100644 --- a/src/Plugins/SmartStore.Tax/web.config +++ b/src/Plugins/SmartStore.Tax/web.config @@ -106,7 +106,7 @@ - + diff --git a/src/Plugins/SmartStore.WebApi/web.config b/src/Plugins/SmartStore.WebApi/web.config index 0219bc2ade..8c7ae2efce 100644 --- a/src/Plugins/SmartStore.WebApi/web.config +++ b/src/Plugins/SmartStore.WebApi/web.config @@ -78,7 +78,7 @@ - + diff --git a/src/Presentation/SmartStore.Web.Framework/Settings/StoreDependingSettingHelper.cs b/src/Presentation/SmartStore.Web.Framework/Settings/StoreDependingSettingHelper.cs index 802fea0798..7f0f2e0096 100644 --- a/src/Presentation/SmartStore.Web.Framework/Settings/StoreDependingSettingHelper.cs +++ b/src/Presentation/SmartStore.Web.Framework/Settings/StoreDependingSettingHelper.cs @@ -2,11 +2,11 @@ using System.Collections.Generic; using System.Linq; using System.Web.Mvc; -using Fasterflect; using SmartStore.Core.Infrastructure; using SmartStore.Services.Configuration; using SmartStore.Services.Localization; using SmartStore.Web.Framework.Localization; +using SmartStore.Utilities.Reflection; namespace SmartStore.Web.Framework.Settings { @@ -139,7 +139,7 @@ public void GetOverrideKeysLocalized(object settings, object model, int storeId, public void UpdateSettings(object settings, FormCollection form, int storeId, ISettingService settingService) { var settingName = settings.GetType().Name; - var properties = settings.GetType().GetProperties(); + var properties = FastProperty.GetProperties(settings.GetType()).Values; foreach (var prop in properties) { @@ -148,7 +148,7 @@ public void UpdateSettings(object settings, FormCollection form, int storeId, IS if (storeId == 0 || IsOverrideChecked(key, form)) { - dynamic value = settings.TryGetPropertyValue(name); + dynamic value = prop.GetValue(settings); settingService.SetSetting(key, value == null ? "" : value, storeId, false); } else if (storeId > 0) @@ -161,7 +161,7 @@ public void UpdateSettings(object settings, FormCollection form, int storeId, IS public void UpdateLocalizedSettings(object settings, FormCollection form, int storeId, ISettingService settingService, ILocalizedModelLocal localized) { var settingName = settings.GetType().Name; - var properties = localized.GetType().GetProperties(); + var properties = FastProperty.GetProperties(localized.GetType()).Values; foreach (var prop in properties) { @@ -170,7 +170,7 @@ public void UpdateLocalizedSettings(object settings, FormCollection form, int st if (storeId == 0 || IsOverrideChecked(key, form)) { - dynamic value = settings.TryGetPropertyValue(name); + dynamic value = prop.GetValue(settings); settingService.SetSetting(key, value == null ? "" : value, storeId, false); } else if (storeId > 0) diff --git a/src/Presentation/SmartStore.Web.Framework/SmartStore.Web.Framework.csproj b/src/Presentation/SmartStore.Web.Framework/SmartStore.Web.Framework.csproj index dba5ac1aaf..b70e4658a1 100644 --- a/src/Presentation/SmartStore.Web.Framework/SmartStore.Web.Framework.csproj +++ b/src/Presentation/SmartStore.Web.Framework/SmartStore.Web.Framework.csproj @@ -101,10 +101,6 @@ False ..\..\packages\EntityFramework.6.1.3\lib\net45\EntityFramework.SqlServer.dll - - False - ..\..\packages\fasterflect.2.1.3\lib\net40\Fasterflect.dll - False ..\..\packages\FluentValidation.5.0.0.1\lib\Net40\FluentValidation.dll diff --git a/src/Presentation/SmartStore.Web.Framework/UI/Components/ComponentBuilder.cs b/src/Presentation/SmartStore.Web.Framework/UI/Components/ComponentBuilder.cs index e315ebacd9..b45a50dfae 100644 --- a/src/Presentation/SmartStore.Web.Framework/UI/Components/ComponentBuilder.cs +++ b/src/Presentation/SmartStore.Web.Framework/UI/Components/ComponentBuilder.cs @@ -88,7 +88,7 @@ public TBuilder WithRenderer(Type rendererType) { Guard.ArgumentNotNull(() => rendererType); Guard.Implements>(rendererType); - var renderer = TypeHelper.CreateInstance(rendererType) as ComponentRenderer; + var renderer = Activator.CreateInstance(rendererType) as ComponentRenderer; if (renderer != null) { this.Renderer = renderer; diff --git a/src/Presentation/SmartStore.Web.Framework/WebApi/WebApiEntityController.cs b/src/Presentation/SmartStore.Web.Framework/WebApi/WebApiEntityController.cs index 4354426a9f..3f48b374d2 100644 --- a/src/Presentation/SmartStore.Web.Framework/WebApi/WebApiEntityController.cs +++ b/src/Presentation/SmartStore.Web.Framework/WebApi/WebApiEntityController.cs @@ -16,6 +16,7 @@ using SmartStore.Services.Directory; using SmartStore.Services.Localization; using System.Collections.Generic; +using SmartStore.Utilities.Reflection; namespace SmartStore.Web.Framework.WebApi { @@ -77,7 +78,7 @@ protected virtual internal HttpResponseMessage UnmappedGetProperty(ODataPath oda if (entity == null) return Request.CreateErrorResponse(HttpStatusCode.NotFound, WebApiGlobal.Error.EntityNotFound.FormatInvariant(key)); - PropertyInfo pi = null; + FastProperty prop = null; string propertyName = null; var lastSegment = odataPath.Segments.Last(); var propertySegment = (lastSegment as PropertyAccessPathSegment); @@ -88,14 +89,14 @@ protected virtual internal HttpResponseMessage UnmappedGetProperty(ODataPath oda propertyName = propertySegment.PropertyName; if (propertyName.HasValue()) - pi = entity.GetType().GetProperty(propertyName); + prop = FastProperty.GetProperty(entity.GetType(), propertyName); - if (pi == null) + if (prop == null) return UnmappedGetProperty(entity, propertyName ?? ""); - var propertyValue = pi.GetValue(entity, null); + var propertyValue = prop.GetValue(entity); - return Request.CreateResponse(HttpStatusCode.OK, pi.PropertyType, propertyValue); + return Request.CreateResponse(HttpStatusCode.OK, prop.Property.PropertyType, propertyValue); } protected virtual internal HttpResponseMessage UnmappedGetProperty(TEntity entity, string propertyName) @@ -465,17 +466,17 @@ protected internal virtual TEntity FulfillPropertiesOn(TEntity entity) if (propertyName.HasValue() && queryValue.HasValue()) { - var pi = entity.GetType().GetProperty(propertyName); - if (pi != null) + var prop = FastProperty.GetProperty(entity.GetType(), propertyName); + if (prop != null) { - var propertyValue = pi.GetValue(entity, null); + var propertyValue = prop.GetValue(entity); if (propertyValue == null) { object value = FulfillPropertyOn(entity, propertyName, queryValue); if (value != null) // there's no requirement to set a property value of null { - pi.SetValue(entity, value); + prop.SetValue(entity, value); } } } diff --git a/src/Presentation/SmartStore.Web.Framework/packages.config b/src/Presentation/SmartStore.Web.Framework/packages.config index 2f40cf1830..1688ceb9e7 100644 --- a/src/Presentation/SmartStore.Web.Framework/packages.config +++ b/src/Presentation/SmartStore.Web.Framework/packages.config @@ -9,7 +9,6 @@ - diff --git a/src/Presentation/SmartStore.Web/Administration/Web.config b/src/Presentation/SmartStore.Web/Administration/Web.config index 7d3a217dd0..82ce6dbca5 100644 --- a/src/Presentation/SmartStore.Web/Administration/Web.config +++ b/src/Presentation/SmartStore.Web/Administration/Web.config @@ -100,7 +100,7 @@ - + diff --git a/src/Tools/SmartStore.Packager/App.config b/src/Tools/SmartStore.Packager/App.config index 30622f85af..59552e8d6b 100644 --- a/src/Tools/SmartStore.Packager/App.config +++ b/src/Tools/SmartStore.Packager/App.config @@ -1,32 +1,32 @@ - + -
+
- + - + - + - - + + - - + + From adbce646e1586e37330c0e0178b23c9b7605e1a1 Mon Sep 17 00:00:00 2001 From: Marcus Gesing Date: Sun, 8 Nov 2015 11:40:45 +0100 Subject: [PATCH 018/707] ExportXmlHelper creates own XmlWriter --- .../ExportTask/ExportProfileTask.cs | 2 + .../DataExchange/ExportXmlHelper.cs | 39 ++- .../Providers/CategoryXmlExportProvider.cs | 49 +-- .../Providers/CustomerXmlExportProvider.cs | 27 +- .../ManufacturerXmlExportProvider.cs | 49 +-- .../Providers/OrderXmlExportProvider.cs | 308 +++++++++--------- .../Providers/ProductXmlExportProvider.cs | 27 +- .../Controllers/ExportController.cs | 3 +- 8 files changed, 238 insertions(+), 266 deletions(-) diff --git a/src/Libraries/SmartStore.Services/DataExchange/ExportTask/ExportProfileTask.cs b/src/Libraries/SmartStore.Services/DataExchange/ExportTask/ExportProfileTask.cs index 86c909fc27..1a52e264ea 100644 --- a/src/Libraries/SmartStore.Services/DataExchange/ExportTask/ExportProfileTask.cs +++ b/src/Libraries/SmartStore.Services/DataExchange/ExportTask/ExportProfileTask.cs @@ -132,6 +132,8 @@ private void InitDependencies(TaskExecutionContext context) _urlRecordService = context.Resolve>(); _genericAttributeService = context.Resolve>(); _subscriptionRepository = context.Resolve>>(); + + T = NullLocalizer.Instance; } public Localizer T { get; set; } diff --git a/src/Libraries/SmartStore.Services/DataExchange/ExportXmlHelper.cs b/src/Libraries/SmartStore.Services/DataExchange/ExportXmlHelper.cs index 8191f0d76e..e5837578d6 100644 --- a/src/Libraries/SmartStore.Services/DataExchange/ExportXmlHelper.cs +++ b/src/Libraries/SmartStore.Services/DataExchange/ExportXmlHelper.cs @@ -1,20 +1,53 @@ using System; using System.Globalization; +using System.IO; +using System.Text; using System.Xml; using SmartStore.Core.Domain.Catalog; using SmartStore.Core.Domain.DataExchange; namespace SmartStore.Services.DataExchange { - public class ExportXmlHelper + public class ExportXmlHelper : IDisposable { private XmlWriter _writer; private CultureInfo _culture; + private bool _doNotDispose; - public ExportXmlHelper(XmlWriter writer, CultureInfo culture) + public ExportXmlHelper(XmlWriter writer, bool doNotDispose = false, CultureInfo culture = null) { _writer = writer; - _culture = culture; + _doNotDispose = doNotDispose; + _culture = (culture == null ? CultureInfo.InvariantCulture : culture); + } + public ExportXmlHelper(Stream stream, XmlWriterSettings settings = null, CultureInfo culture = null) + { + if (settings == null) + { + settings = new XmlWriterSettings + { + Encoding = Encoding.UTF8, + CheckCharacters = false, + Indent = true, + IndentChars = "\t" + }; + } + + _writer = XmlWriter.Create(stream, settings); + _culture = (culture == null ? CultureInfo.InvariantCulture : culture); + } + + public XmlWriter Writer + { + get { return _writer; } + } + + public void Dispose() + { + if (_writer != null && !_doNotDispose) + { + _writer.Dispose(); + } } public void WriteLocalized(dynamic parentNode) diff --git a/src/Libraries/SmartStore.Services/DataExchange/Providers/CategoryXmlExportProvider.cs b/src/Libraries/SmartStore.Services/DataExchange/Providers/CategoryXmlExportProvider.cs index e473a28ad2..2b74231730 100644 --- a/src/Libraries/SmartStore.Services/DataExchange/Providers/CategoryXmlExportProvider.cs +++ b/src/Libraries/SmartStore.Services/DataExchange/Providers/CategoryXmlExportProvider.cs @@ -1,8 +1,5 @@ using System; -using System.Globalization; using System.IO; -using System.Text; -using System.Xml; using SmartStore.Core; using SmartStore.Core.Domain.DataExchange; using SmartStore.Core.Logging; @@ -35,26 +32,16 @@ public override string FileExtension public override void Execute(IExportExecuteContext context) { - var settings = new XmlWriterSettings - { - Encoding = Encoding.UTF8, - CheckCharacters = false, - Indent = true, - IndentChars = "\t" - }; - var path = context.FilePath; context.Log.Information("Creating file " + path); using (var stream = new FileStream(path, FileMode.Create, FileAccess.Write, FileShare.ReadWrite)) - using (var writer = XmlWriter.Create(stream, settings)) + using (var helper = new ExportXmlHelper(stream)) { - var xmlHelper = new ExportXmlHelper(writer, CultureInfo.InvariantCulture); - - writer.WriteStartDocument(); - writer.WriteStartElement("Categories"); - writer.WriteAttributeString("Version", SmartStoreVersion.CurrentVersion); + helper.Writer.WriteStartDocument(); + helper.Writer.WriteStartElement("Categories"); + helper.Writer.WriteAttributeString("Version", SmartStoreVersion.CurrentVersion); while (context.Abort == ExportAbortion.None && context.Segmenter.ReadNextSegment()) { @@ -65,24 +52,24 @@ public override void Execute(IExportExecuteContext context) if (context.Abort != ExportAbortion.None) break; - writer.WriteStartElement("Category"); + helper.Writer.WriteStartElement("Category"); try { - xmlHelper.WriteCategory(category, null); + helper.WriteCategory(category, null); - writer.WriteStartElement("ProductCategories"); + helper.Writer.WriteStartElement("ProductCategories"); foreach (dynamic productCategory in category.ProductCategories) { - writer.WriteStartElement("ProductCategory"); - writer.Write("Id", ((int)productCategory.Id).ToString()); - writer.Write("ProductId", ((int)productCategory.ProductId).ToString()); - writer.Write("DisplayOrder", ((int)productCategory.DisplayOrder).ToString()); - writer.Write("IsFeaturedProduct", ((bool)productCategory.IsFeaturedProduct).ToString()); - writer.Write("CategoryId", ((int)productCategory.CategoryId).ToString()); - writer.WriteEndElement(); // ProductCategory + helper.Writer.WriteStartElement("ProductCategory"); + helper.Writer.Write("Id", ((int)productCategory.Id).ToString()); + helper.Writer.Write("ProductId", ((int)productCategory.ProductId).ToString()); + helper.Writer.Write("DisplayOrder", ((int)productCategory.DisplayOrder).ToString()); + helper.Writer.Write("IsFeaturedProduct", ((bool)productCategory.IsFeaturedProduct).ToString()); + helper.Writer.Write("CategoryId", ((int)productCategory.CategoryId).ToString()); + helper.Writer.WriteEndElement(); // ProductCategory } - writer.WriteEndElement(); // ProductCategories + helper.Writer.WriteEndElement(); // ProductCategories ++context.RecordsSucceeded; } @@ -91,12 +78,12 @@ public override void Execute(IExportExecuteContext context) context.RecordException(exc, (int)category.Id); } - writer.WriteEndElement(); // Category + helper.Writer.WriteEndElement(); // Category } } - writer.WriteEndElement(); // Categories - writer.WriteEndDocument(); + helper.Writer.WriteEndElement(); // Categories + helper.Writer.WriteEndDocument(); } } } diff --git a/src/Libraries/SmartStore.Services/DataExchange/Providers/CustomerXmlExportProvider.cs b/src/Libraries/SmartStore.Services/DataExchange/Providers/CustomerXmlExportProvider.cs index 93d9c4462b..4103b412a5 100644 --- a/src/Libraries/SmartStore.Services/DataExchange/Providers/CustomerXmlExportProvider.cs +++ b/src/Libraries/SmartStore.Services/DataExchange/Providers/CustomerXmlExportProvider.cs @@ -1,8 +1,5 @@ using System; -using System.Globalization; using System.IO; -using System.Text; -using System.Xml; using SmartStore.Core; using SmartStore.Core.Domain.DataExchange; using SmartStore.Core.Logging; @@ -35,26 +32,16 @@ public override string FileExtension public override void Execute(IExportExecuteContext context) { - var settings = new XmlWriterSettings - { - Encoding = Encoding.UTF8, - CheckCharacters = false, - Indent = true, - IndentChars = "\t" - }; - var path = context.FilePath; context.Log.Information("Creating file " + path); using (var stream = new FileStream(path, FileMode.Create, FileAccess.Write, FileShare.ReadWrite)) - using (var writer = XmlWriter.Create(stream, settings)) + using (var helper = new ExportXmlHelper(stream)) { - var xmlHelper = new ExportXmlHelper(writer, CultureInfo.InvariantCulture); - - writer.WriteStartDocument(); - writer.WriteStartElement("Customers"); - writer.WriteAttributeString("Version", SmartStoreVersion.CurrentVersion); + helper.Writer.WriteStartDocument(); + helper.Writer.WriteStartElement("Customers"); + helper.Writer.WriteAttributeString("Version", SmartStoreVersion.CurrentVersion); while (context.Abort == ExportAbortion.None && context.Segmenter.ReadNextSegment()) { @@ -67,7 +54,7 @@ public override void Execute(IExportExecuteContext context) try { - xmlHelper.WriteCustomer(customer, "Customer"); + helper.WriteCustomer(customer, "Customer"); ++context.RecordsSucceeded; } @@ -78,8 +65,8 @@ public override void Execute(IExportExecuteContext context) } } - writer.WriteEndElement(); // Customers - writer.WriteEndDocument(); + helper.Writer.WriteEndElement(); // Customers + helper.Writer.WriteEndDocument(); } } } diff --git a/src/Libraries/SmartStore.Services/DataExchange/Providers/ManufacturerXmlExportProvider.cs b/src/Libraries/SmartStore.Services/DataExchange/Providers/ManufacturerXmlExportProvider.cs index 8d26a9ab4e..3c5d6afa53 100644 --- a/src/Libraries/SmartStore.Services/DataExchange/Providers/ManufacturerXmlExportProvider.cs +++ b/src/Libraries/SmartStore.Services/DataExchange/Providers/ManufacturerXmlExportProvider.cs @@ -1,8 +1,5 @@ using System; -using System.Globalization; using System.IO; -using System.Text; -using System.Xml; using SmartStore.Core; using SmartStore.Core.Domain.DataExchange; using SmartStore.Core.Logging; @@ -35,26 +32,16 @@ public override string FileExtension public override void Execute(IExportExecuteContext context) { - var settings = new XmlWriterSettings - { - Encoding = Encoding.UTF8, - CheckCharacters = false, - Indent = true, - IndentChars = "\t" - }; - var path = context.FilePath; context.Log.Information("Creating file " + path); using (var stream = new FileStream(path, FileMode.Create, FileAccess.Write, FileShare.ReadWrite)) - using (var writer = XmlWriter.Create(stream, settings)) + using (var helper = new ExportXmlHelper(stream)) { - var xmlHelper = new ExportXmlHelper(writer, CultureInfo.InvariantCulture); - - writer.WriteStartDocument(); - writer.WriteStartElement("Manufacturers"); - writer.WriteAttributeString("Version", SmartStoreVersion.CurrentVersion); + helper.Writer.WriteStartDocument(); + helper.Writer.WriteStartElement("Manufacturers"); + helper.Writer.WriteAttributeString("Version", SmartStoreVersion.CurrentVersion); while (context.Abort == ExportAbortion.None && context.Segmenter.ReadNextSegment()) { @@ -65,24 +52,24 @@ public override void Execute(IExportExecuteContext context) if (context.Abort != ExportAbortion.None) break; - writer.WriteStartElement("Manufacturer"); + helper.Writer.WriteStartElement("Manufacturer"); try { - xmlHelper.WriteManufacturer(manufacturer, null); + helper.WriteManufacturer(manufacturer, null); - writer.WriteStartElement("ProductManufacturers"); + helper.Writer.WriteStartElement("ProductManufacturers"); foreach (dynamic productManu in manufacturer.ProductManufacturers) { - writer.WriteStartElement("ProductManufacturer"); - writer.Write("Id", ((int)productManu.Id).ToString()); - writer.Write("ProductId", ((int)productManu.ProductId).ToString()); - writer.Write("DisplayOrder", ((int)productManu.DisplayOrder).ToString()); - writer.Write("IsFeaturedProduct", ((bool)productManu.IsFeaturedProduct).ToString()); - writer.Write("ManufacturerId", ((int)productManu.ManufacturerId).ToString()); - writer.WriteEndElement(); // ProductManufacturer + helper.Writer.WriteStartElement("ProductManufacturer"); + helper.Writer.Write("Id", ((int)productManu.Id).ToString()); + helper.Writer.Write("ProductId", ((int)productManu.ProductId).ToString()); + helper.Writer.Write("DisplayOrder", ((int)productManu.DisplayOrder).ToString()); + helper.Writer.Write("IsFeaturedProduct", ((bool)productManu.IsFeaturedProduct).ToString()); + helper.Writer.Write("ManufacturerId", ((int)productManu.ManufacturerId).ToString()); + helper.Writer.WriteEndElement(); // ProductManufacturer } - writer.WriteEndElement(); // ProductManufacturers + helper.Writer.WriteEndElement(); // ProductManufacturers ++context.RecordsSucceeded; } @@ -91,12 +78,12 @@ public override void Execute(IExportExecuteContext context) context.RecordException(exc, (int)manufacturer.Id); } - writer.WriteEndElement(); // Manufacturer + helper.Writer.WriteEndElement(); // Manufacturer } } - writer.WriteEndElement(); // Manufacturers - writer.WriteEndDocument(); + helper.Writer.WriteEndElement(); // Manufacturers + helper.Writer.WriteEndDocument(); } } } diff --git a/src/Libraries/SmartStore.Services/DataExchange/Providers/OrderXmlExportProvider.cs b/src/Libraries/SmartStore.Services/DataExchange/Providers/OrderXmlExportProvider.cs index 15d347847f..470155603a 100644 --- a/src/Libraries/SmartStore.Services/DataExchange/Providers/OrderXmlExportProvider.cs +++ b/src/Libraries/SmartStore.Services/DataExchange/Providers/OrderXmlExportProvider.cs @@ -1,8 +1,6 @@ using System; using System.Globalization; using System.IO; -using System.Text; -using System.Xml; using SmartStore.Core; using SmartStore.Core.Domain.DataExchange; using SmartStore.Core.Logging; @@ -35,27 +33,17 @@ public override string FileExtension public override void Execute(IExportExecuteContext context) { - var settings = new XmlWriterSettings - { - Encoding = Encoding.UTF8, - CheckCharacters = false, - Indent = true, - IndentChars = "\t" - }; - var path = context.FilePath; var invariantCulture = CultureInfo.InvariantCulture; context.Log.Information("Creating file " + path); using (var stream = new FileStream(path, FileMode.Create, FileAccess.Write, FileShare.ReadWrite)) - using (var writer = XmlWriter.Create(stream, settings)) + using (var helper = new ExportXmlHelper(stream)) { - var xmlHelper = new ExportXmlHelper(writer, invariantCulture); - - writer.WriteStartDocument(); - writer.WriteStartElement("Orders"); - writer.WriteAttributeString("Version", SmartStoreVersion.CurrentVersion); + helper.Writer.WriteStartDocument(); + helper.Writer.WriteStartElement("Orders"); + helper.Writer.WriteAttributeString("Version", SmartStoreVersion.CurrentVersion); while (context.Abort == ExportAbortion.None && context.Segmenter.ReadNextSegment()) { @@ -66,7 +54,7 @@ public override void Execute(IExportExecuteContext context) if (context.Abort != ExportAbortion.None) break; - writer.WriteStartElement("Order"); + helper.Writer.WriteStartElement("Order"); try { @@ -75,170 +63,170 @@ public override void Execute(IExportExecuteContext context) DateTime? paidDateUtc = order.PaidDateUtc; int? rewardPointsRemaining = order.RewardPointsRemaining; - writer.Write("Id", ((int)order.Id).ToString()); - writer.Write("OrderNumber", (string)order.OrderNumber); - writer.Write("OrderGuid", ((Guid)order.OrderGuid).ToString()); - writer.Write("StoreId", ((int)order.StoreId).ToString()); - writer.Write("CustomerId", ((int)order.CustomerId).ToString()); - writer.Write("BillingAddressId", ((int)order.BillingAddressId).ToString()); - writer.Write("ShippingAddressId", shippingAddressId.HasValue ? shippingAddressId.Value.ToString() : ""); - writer.Write("OrderStatusId", ((int)order.OrderStatusId).ToString()); - writer.Write("ShippingStatusId", ((int)order.ShippingStatusId).ToString()); - writer.Write("PaymentStatusId", ((int)order.PaymentStatusId).ToString()); - writer.Write("PaymentMethodSystemName", (string)order.PaymentMethodSystemName); - writer.Write("CustomerCurrencyCode", (string)order.CustomerCurrencyCode); - writer.Write("CurrencyRate", ((decimal)order.CurrencyRate).ToString(invariantCulture)); - writer.Write("CustomerTaxDisplayTypeId", ((int)order.CustomerTaxDisplayTypeId).ToString()); - writer.Write("VatNumber", (string)order.VatNumber); - writer.Write("OrderSubtotalInclTax", ((decimal)order.OrderSubtotalInclTax).ToString(invariantCulture)); - writer.Write("OrderSubtotalExclTax", ((decimal)order.OrderSubtotalExclTax).ToString(invariantCulture)); - writer.Write("OrderSubTotalDiscountInclTax", ((decimal)order.OrderSubTotalDiscountInclTax).ToString(invariantCulture)); - writer.Write("OrderSubTotalDiscountExclTax", ((decimal)order.OrderSubTotalDiscountExclTax).ToString(invariantCulture)); - writer.Write("OrderShippingInclTax", ((decimal)order.OrderShippingInclTax).ToString(invariantCulture)); - writer.Write("OrderShippingExclTax", ((decimal)order.OrderShippingExclTax).ToString(invariantCulture)); - writer.Write("OrderShippingTaxRate", ((decimal)order.OrderShippingTaxRate).ToString(invariantCulture)); - writer.Write("PaymentMethodAdditionalFeeInclTax", ((decimal)order.PaymentMethodAdditionalFeeInclTax).ToString(invariantCulture)); - writer.Write("PaymentMethodAdditionalFeeExclTax", ((decimal)order.PaymentMethodAdditionalFeeExclTax).ToString(invariantCulture)); - writer.Write("PaymentMethodAdditionalFeeTaxRate", ((decimal)order.PaymentMethodAdditionalFeeTaxRate).ToString(invariantCulture)); - writer.Write("TaxRates", (string)order.TaxRates); - writer.Write("OrderTax", ((decimal)order.OrderTax).ToString(invariantCulture)); - writer.Write("OrderDiscount", ((decimal)order.OrderDiscount).ToString(invariantCulture)); - writer.Write("OrderTotal", ((decimal)order.OrderTotal).ToString(invariantCulture)); - writer.Write("RefundedAmount", ((decimal)order.RefundedAmount).ToString(invariantCulture)); - writer.Write("RewardPointsWereAdded", ((bool)order.RewardPointsWereAdded).ToString()); - writer.Write("CheckoutAttributeDescription", (string)order.CheckoutAttributeDescription); - writer.Write("CheckoutAttributesXml", (string)order.CheckoutAttributesXml); - writer.Write("CustomerLanguageId", ((int)order.CustomerLanguageId).ToString()); - writer.Write("AffiliateId", ((int)order.AffiliateId).ToString()); - writer.Write("CustomerIp", (string)order.CustomerIp); - writer.Write("AllowStoringCreditCardNumber", ((bool)order.AllowStoringCreditCardNumber).ToString()); - writer.Write("CardType", (string)order.CardType); - writer.Write("CardName", (string)order.CardName); - writer.Write("CardNumber", (string)order.CardNumber); - writer.Write("MaskedCreditCardNumber", (string)order.MaskedCreditCardNumber); - writer.Write("CardCvv2", (string)order.CardCvv2); - writer.Write("CardExpirationMonth", (string)order.CardExpirationMonth); - writer.Write("CardExpirationYear", (string)order.CardExpirationYear); - writer.Write("AllowStoringDirectDebit", ((bool)order.AllowStoringDirectDebit).ToString()); - writer.Write("DirectDebitAccountHolder", (string)order.DirectDebitAccountHolder); - writer.Write("DirectDebitAccountNumber", (string)order.DirectDebitAccountNumber); - writer.Write("DirectDebitBankCode", (string)order.DirectDebitBankCode); - writer.Write("DirectDebitBankName", (string)order.DirectDebitBankName); - writer.Write("DirectDebitBIC", (string)order.DirectDebitBIC); - writer.Write("DirectDebitCountry", (string)order.DirectDebitCountry); - writer.Write("DirectDebitIban", (string)order.DirectDebitIban); - writer.Write("CustomerOrderComment", (string)order.CustomerOrderComment); - writer.Write("AuthorizationTransactionId", (string)order.AuthorizationTransactionId); - writer.Write("AuthorizationTransactionCode", (string)order.AuthorizationTransactionCode); - writer.Write("AuthorizationTransactionResult", (string)order.AuthorizationTransactionResult); - writer.Write("CaptureTransactionId", (string)order.CaptureTransactionId); - writer.Write("CaptureTransactionResult", (string)order.CaptureTransactionResult); - writer.Write("SubscriptionTransactionId", (string)order.SubscriptionTransactionId); - writer.Write("PurchaseOrderNumber", (string)order.PurchaseOrderNumber); - writer.Write("PaidDateUtc", paidDateUtc.HasValue ? paidDateUtc.Value.ToString(invariantCulture) : ""); - writer.Write("ShippingMethod", (string)order.ShippingMethod); - writer.Write("ShippingRateComputationMethodSystemName", (string)order.ShippingRateComputationMethodSystemName); - writer.Write("Deleted", ((bool)order.Deleted).ToString()); - writer.Write("CreatedOnUtc", ((DateTime)order.CreatedOnUtc).ToString(invariantCulture)); - writer.Write("UpdatedOnUtc", ((DateTime)order.UpdatedOnUtc).ToString(invariantCulture)); - writer.Write("RewardPointsRemaining", rewardPointsRemaining.HasValue ? rewardPointsRemaining.Value.ToString() : ""); - writer.Write("HasNewPaymentNotification", ((bool)order.HasNewPaymentNotification).ToString()); - writer.Write("OrderStatus", (string)order.OrderStatus); - writer.Write("PaymentStatus", (string)order.PaymentStatus); - writer.Write("ShippingStatus", (string)order.ShippingStatus); - - xmlHelper.WriteCustomer(order.Customer, "Customer"); - - xmlHelper.WriteAddress(order.BillingAddress, "BillingAddress"); - xmlHelper.WriteAddress(order.ShippingAddress, "ShippingAddress"); + helper.Writer.Write("Id", ((int)order.Id).ToString()); + helper.Writer.Write("OrderNumber", (string)order.OrderNumber); + helper.Writer.Write("OrderGuid", ((Guid)order.OrderGuid).ToString()); + helper.Writer.Write("StoreId", ((int)order.StoreId).ToString()); + helper.Writer.Write("CustomerId", ((int)order.CustomerId).ToString()); + helper.Writer.Write("BillingAddressId", ((int)order.BillingAddressId).ToString()); + helper.Writer.Write("ShippingAddressId", shippingAddressId.HasValue ? shippingAddressId.Value.ToString() : ""); + helper.Writer.Write("OrderStatusId", ((int)order.OrderStatusId).ToString()); + helper.Writer.Write("ShippingStatusId", ((int)order.ShippingStatusId).ToString()); + helper.Writer.Write("PaymentStatusId", ((int)order.PaymentStatusId).ToString()); + helper.Writer.Write("PaymentMethodSystemName", (string)order.PaymentMethodSystemName); + helper.Writer.Write("CustomerCurrencyCode", (string)order.CustomerCurrencyCode); + helper.Writer.Write("CurrencyRate", ((decimal)order.CurrencyRate).ToString(invariantCulture)); + helper.Writer.Write("CustomerTaxDisplayTypeId", ((int)order.CustomerTaxDisplayTypeId).ToString()); + helper.Writer.Write("VatNumber", (string)order.VatNumber); + helper.Writer.Write("OrderSubtotalInclTax", ((decimal)order.OrderSubtotalInclTax).ToString(invariantCulture)); + helper.Writer.Write("OrderSubtotalExclTax", ((decimal)order.OrderSubtotalExclTax).ToString(invariantCulture)); + helper.Writer.Write("OrderSubTotalDiscountInclTax", ((decimal)order.OrderSubTotalDiscountInclTax).ToString(invariantCulture)); + helper.Writer.Write("OrderSubTotalDiscountExclTax", ((decimal)order.OrderSubTotalDiscountExclTax).ToString(invariantCulture)); + helper.Writer.Write("OrderShippingInclTax", ((decimal)order.OrderShippingInclTax).ToString(invariantCulture)); + helper.Writer.Write("OrderShippingExclTax", ((decimal)order.OrderShippingExclTax).ToString(invariantCulture)); + helper.Writer.Write("OrderShippingTaxRate", ((decimal)order.OrderShippingTaxRate).ToString(invariantCulture)); + helper.Writer.Write("PaymentMethodAdditionalFeeInclTax", ((decimal)order.PaymentMethodAdditionalFeeInclTax).ToString(invariantCulture)); + helper.Writer.Write("PaymentMethodAdditionalFeeExclTax", ((decimal)order.PaymentMethodAdditionalFeeExclTax).ToString(invariantCulture)); + helper.Writer.Write("PaymentMethodAdditionalFeeTaxRate", ((decimal)order.PaymentMethodAdditionalFeeTaxRate).ToString(invariantCulture)); + helper.Writer.Write("TaxRates", (string)order.TaxRates); + helper.Writer.Write("OrderTax", ((decimal)order.OrderTax).ToString(invariantCulture)); + helper.Writer.Write("OrderDiscount", ((decimal)order.OrderDiscount).ToString(invariantCulture)); + helper.Writer.Write("OrderTotal", ((decimal)order.OrderTotal).ToString(invariantCulture)); + helper.Writer.Write("RefundedAmount", ((decimal)order.RefundedAmount).ToString(invariantCulture)); + helper.Writer.Write("RewardPointsWereAdded", ((bool)order.RewardPointsWereAdded).ToString()); + helper.Writer.Write("CheckoutAttributeDescription", (string)order.CheckoutAttributeDescription); + helper.Writer.Write("CheckoutAttributesXml", (string)order.CheckoutAttributesXml); + helper.Writer.Write("CustomerLanguageId", ((int)order.CustomerLanguageId).ToString()); + helper.Writer.Write("AffiliateId", ((int)order.AffiliateId).ToString()); + helper.Writer.Write("CustomerIp", (string)order.CustomerIp); + helper.Writer.Write("AllowStoringCreditCardNumber", ((bool)order.AllowStoringCreditCardNumber).ToString()); + helper.Writer.Write("CardType", (string)order.CardType); + helper.Writer.Write("CardName", (string)order.CardName); + helper.Writer.Write("CardNumber", (string)order.CardNumber); + helper.Writer.Write("MaskedCreditCardNumber", (string)order.MaskedCreditCardNumber); + helper.Writer.Write("CardCvv2", (string)order.CardCvv2); + helper.Writer.Write("CardExpirationMonth", (string)order.CardExpirationMonth); + helper.Writer.Write("CardExpirationYear", (string)order.CardExpirationYear); + helper.Writer.Write("AllowStoringDirectDebit", ((bool)order.AllowStoringDirectDebit).ToString()); + helper.Writer.Write("DirectDebitAccountHolder", (string)order.DirectDebitAccountHolder); + helper.Writer.Write("DirectDebitAccountNumber", (string)order.DirectDebitAccountNumber); + helper.Writer.Write("DirectDebitBankCode", (string)order.DirectDebitBankCode); + helper.Writer.Write("DirectDebitBankName", (string)order.DirectDebitBankName); + helper.Writer.Write("DirectDebitBIC", (string)order.DirectDebitBIC); + helper.Writer.Write("DirectDebitCountry", (string)order.DirectDebitCountry); + helper.Writer.Write("DirectDebitIban", (string)order.DirectDebitIban); + helper.Writer.Write("CustomerOrderComment", (string)order.CustomerOrderComment); + helper.Writer.Write("AuthorizationTransactionId", (string)order.AuthorizationTransactionId); + helper.Writer.Write("AuthorizationTransactionCode", (string)order.AuthorizationTransactionCode); + helper.Writer.Write("AuthorizationTransactionResult", (string)order.AuthorizationTransactionResult); + helper.Writer.Write("CaptureTransactionId", (string)order.CaptureTransactionId); + helper.Writer.Write("CaptureTransactionResult", (string)order.CaptureTransactionResult); + helper.Writer.Write("SubscriptionTransactionId", (string)order.SubscriptionTransactionId); + helper.Writer.Write("PurchaseOrderNumber", (string)order.PurchaseOrderNumber); + helper.Writer.Write("PaidDateUtc", paidDateUtc.HasValue ? paidDateUtc.Value.ToString(invariantCulture) : ""); + helper.Writer.Write("ShippingMethod", (string)order.ShippingMethod); + helper.Writer.Write("ShippingRateComputationMethodSystemName", (string)order.ShippingRateComputationMethodSystemName); + helper.Writer.Write("Deleted", ((bool)order.Deleted).ToString()); + helper.Writer.Write("CreatedOnUtc", ((DateTime)order.CreatedOnUtc).ToString(invariantCulture)); + helper.Writer.Write("UpdatedOnUtc", ((DateTime)order.UpdatedOnUtc).ToString(invariantCulture)); + helper.Writer.Write("RewardPointsRemaining", rewardPointsRemaining.HasValue ? rewardPointsRemaining.Value.ToString() : ""); + helper.Writer.Write("HasNewPaymentNotification", ((bool)order.HasNewPaymentNotification).ToString()); + helper.Writer.Write("OrderStatus", (string)order.OrderStatus); + helper.Writer.Write("PaymentStatus", (string)order.PaymentStatus); + helper.Writer.Write("ShippingStatus", (string)order.ShippingStatus); + + helper.WriteCustomer(order.Customer, "Customer"); + + helper.WriteAddress(order.BillingAddress, "BillingAddress"); + helper.WriteAddress(order.ShippingAddress, "ShippingAddress"); if (store != null) { - writer.WriteStartElement("Store"); - writer.Write("Id", ((int)store.Id).ToString()); - writer.Write("Name", (string)store.Name); - writer.Write("Url", (string)store.Url); - writer.Write("SslEnabled", ((bool)store.SslEnabled).ToString()); - writer.Write("SecureUrl", (string)store.SecureUrl); - writer.Write("Hosts", (string)store.Hosts); - writer.Write("LogoPictureId", ((int)store.LogoPictureId).ToString()); - writer.Write("DisplayOrder", ((int)store.DisplayOrder).ToString()); - writer.Write("HtmlBodyId", (string)store.HtmlBodyId); - writer.Write("ContentDeliveryNetwork", (string)store.ContentDeliveryNetwork); - writer.Write("PrimaryStoreCurrencyId", ((int)store.PrimaryStoreCurrencyId).ToString()); - writer.Write("PrimaryExchangeRateCurrencyId", ((int)store.PrimaryExchangeRateCurrencyId).ToString()); - - xmlHelper.WriteCurrency(store.PrimaryStoreCurrency, "PrimaryStoreCurrency"); - xmlHelper.WriteCurrency(store.PrimaryExchangeRateCurrency, "PrimaryExchangeRateCurrency"); - - writer.WriteEndElement(); // Store + helper.Writer.WriteStartElement("Store"); + helper.Writer.Write("Id", ((int)store.Id).ToString()); + helper.Writer.Write("Name", (string)store.Name); + helper.Writer.Write("Url", (string)store.Url); + helper.Writer.Write("SslEnabled", ((bool)store.SslEnabled).ToString()); + helper.Writer.Write("SecureUrl", (string)store.SecureUrl); + helper.Writer.Write("Hosts", (string)store.Hosts); + helper.Writer.Write("LogoPictureId", ((int)store.LogoPictureId).ToString()); + helper.Writer.Write("DisplayOrder", ((int)store.DisplayOrder).ToString()); + helper.Writer.Write("HtmlBodyId", (string)store.HtmlBodyId); + helper.Writer.Write("ContentDeliveryNetwork", (string)store.ContentDeliveryNetwork); + helper.Writer.Write("PrimaryStoreCurrencyId", ((int)store.PrimaryStoreCurrencyId).ToString()); + helper.Writer.Write("PrimaryExchangeRateCurrencyId", ((int)store.PrimaryExchangeRateCurrencyId).ToString()); + + helper.WriteCurrency(store.PrimaryStoreCurrency, "PrimaryStoreCurrency"); + helper.WriteCurrency(store.PrimaryExchangeRateCurrency, "PrimaryExchangeRateCurrency"); + + helper.Writer.WriteEndElement(); // Store } - writer.WriteStartElement("OrderItems"); + helper.Writer.WriteStartElement("OrderItems"); foreach (dynamic orderItem in order.OrderItems) { int? licenseDownloadId = orderItem.LicenseDownloadId; decimal? itemWeight = orderItem.ItemWeight; - writer.WriteStartElement("OrderItem"); - writer.Write("Id", ((int)orderItem.Id).ToString()); - writer.Write("OrderItemGuid", ((Guid)orderItem.OrderItemGuid).ToString()); - writer.Write("OrderId", ((int)orderItem.OrderId).ToString()); - writer.Write("ProductId", ((int)orderItem.ProductId).ToString()); - writer.Write("Quantity", ((int)orderItem.Quantity).ToString()); - writer.Write("UnitPriceInclTax", ((decimal)orderItem.UnitPriceInclTax).ToString(invariantCulture)); - writer.Write("UnitPriceExclTax", ((decimal)orderItem.UnitPriceExclTax).ToString(invariantCulture)); - writer.Write("PriceInclTax", ((decimal)orderItem.PriceInclTax).ToString(invariantCulture)); - writer.Write("PriceExclTax", ((decimal)orderItem.PriceExclTax).ToString(invariantCulture)); - writer.Write("TaxRate", ((decimal)orderItem.TaxRate).ToString(invariantCulture)); - writer.Write("DiscountAmountInclTax", ((decimal)orderItem.DiscountAmountInclTax).ToString(invariantCulture)); - writer.Write("DiscountAmountExclTax", ((decimal)orderItem.DiscountAmountExclTax).ToString(invariantCulture)); - writer.Write("AttributeDescription", (string)orderItem.AttributeDescription); - writer.Write("AttributesXml", (string)orderItem.AttributesXml); - writer.Write("DownloadCount", ((int)orderItem.DownloadCount).ToString()); - writer.Write("IsDownloadActivated", ((bool)orderItem.IsDownloadActivated).ToString()); - writer.Write("LicenseDownloadId", licenseDownloadId.HasValue ? licenseDownloadId.Value.ToString() : ""); - writer.Write("ItemWeight", itemWeight.HasValue ? itemWeight.Value.ToString(invariantCulture) : ""); - writer.Write("BundleData", (string)orderItem.BundleData); - writer.Write("ProductCost", ((decimal)orderItem.ProductCost).ToString(invariantCulture)); - - xmlHelper.WriteProduct(orderItem.Product, "Product"); - - writer.WriteEndElement(); // OrderItem + helper.Writer.WriteStartElement("OrderItem"); + helper.Writer.Write("Id", ((int)orderItem.Id).ToString()); + helper.Writer.Write("OrderItemGuid", ((Guid)orderItem.OrderItemGuid).ToString()); + helper.Writer.Write("OrderId", ((int)orderItem.OrderId).ToString()); + helper.Writer.Write("ProductId", ((int)orderItem.ProductId).ToString()); + helper.Writer.Write("Quantity", ((int)orderItem.Quantity).ToString()); + helper.Writer.Write("UnitPriceInclTax", ((decimal)orderItem.UnitPriceInclTax).ToString(invariantCulture)); + helper.Writer.Write("UnitPriceExclTax", ((decimal)orderItem.UnitPriceExclTax).ToString(invariantCulture)); + helper.Writer.Write("PriceInclTax", ((decimal)orderItem.PriceInclTax).ToString(invariantCulture)); + helper.Writer.Write("PriceExclTax", ((decimal)orderItem.PriceExclTax).ToString(invariantCulture)); + helper.Writer.Write("TaxRate", ((decimal)orderItem.TaxRate).ToString(invariantCulture)); + helper.Writer.Write("DiscountAmountInclTax", ((decimal)orderItem.DiscountAmountInclTax).ToString(invariantCulture)); + helper.Writer.Write("DiscountAmountExclTax", ((decimal)orderItem.DiscountAmountExclTax).ToString(invariantCulture)); + helper.Writer.Write("AttributeDescription", (string)orderItem.AttributeDescription); + helper.Writer.Write("AttributesXml", (string)orderItem.AttributesXml); + helper.Writer.Write("DownloadCount", ((int)orderItem.DownloadCount).ToString()); + helper.Writer.Write("IsDownloadActivated", ((bool)orderItem.IsDownloadActivated).ToString()); + helper.Writer.Write("LicenseDownloadId", licenseDownloadId.HasValue ? licenseDownloadId.Value.ToString() : ""); + helper.Writer.Write("ItemWeight", itemWeight.HasValue ? itemWeight.Value.ToString(invariantCulture) : ""); + helper.Writer.Write("BundleData", (string)orderItem.BundleData); + helper.Writer.Write("ProductCost", ((decimal)orderItem.ProductCost).ToString(invariantCulture)); + + helper.WriteProduct(orderItem.Product, "Product"); + + helper.Writer.WriteEndElement(); // OrderItem } - writer.WriteEndElement(); // OrderItems + helper.Writer.WriteEndElement(); // OrderItems - writer.WriteStartElement("Shipments"); + helper.Writer.WriteStartElement("Shipments"); foreach (dynamic shipment in order.Shipments) { decimal? totalWeight = shipment.TotalWeight; DateTime? shippedDateUtc = shipment.ShippedDateUtc; DateTime? deliveryDateUtc = shipment.DeliveryDateUtc; - writer.WriteStartElement("Shipment"); - writer.Write("Id", ((int)shipment.Id).ToString()); - writer.Write("OrderId", ((int)shipment.OrderId).ToString()); - writer.Write("TrackingNumber", (string)shipment.TrackingNumber); - writer.Write("TotalWeight", totalWeight.HasValue ? totalWeight.Value.ToString(invariantCulture) : ""); - writer.Write("ShippedDateUtc", shippedDateUtc.HasValue ? shippedDateUtc.Value.ToString(invariantCulture) : ""); - writer.Write("DeliveryDateUtc", deliveryDateUtc.HasValue ? deliveryDateUtc.Value.ToString(invariantCulture) : ""); - writer.Write("CreatedOnUtc", ((DateTime)shipment.CreatedOnUtc).ToString(invariantCulture)); + helper.Writer.WriteStartElement("Shipment"); + helper.Writer.Write("Id", ((int)shipment.Id).ToString()); + helper.Writer.Write("OrderId", ((int)shipment.OrderId).ToString()); + helper.Writer.Write("TrackingNumber", (string)shipment.TrackingNumber); + helper.Writer.Write("TotalWeight", totalWeight.HasValue ? totalWeight.Value.ToString(invariantCulture) : ""); + helper.Writer.Write("ShippedDateUtc", shippedDateUtc.HasValue ? shippedDateUtc.Value.ToString(invariantCulture) : ""); + helper.Writer.Write("DeliveryDateUtc", deliveryDateUtc.HasValue ? deliveryDateUtc.Value.ToString(invariantCulture) : ""); + helper.Writer.Write("CreatedOnUtc", ((DateTime)shipment.CreatedOnUtc).ToString(invariantCulture)); - writer.WriteStartElement("ShipmentItems"); + helper.Writer.WriteStartElement("ShipmentItems"); foreach (dynamic shipmentItem in shipment.ShipmentItems) { - writer.WriteStartElement("ShipmentItem"); - writer.Write("Id", ((int)shipmentItem.Id).ToString()); - writer.Write("ShipmentId", ((int)shipmentItem.ShipmentId).ToString()); - writer.Write("OrderItemId", ((int)shipmentItem.OrderItemId).ToString()); - writer.Write("Quantity", ((int)shipmentItem.Quantity).ToString()); - writer.WriteEndElement(); // ShipmentItem + helper.Writer.WriteStartElement("ShipmentItem"); + helper.Writer.Write("Id", ((int)shipmentItem.Id).ToString()); + helper.Writer.Write("ShipmentId", ((int)shipmentItem.ShipmentId).ToString()); + helper.Writer.Write("OrderItemId", ((int)shipmentItem.OrderItemId).ToString()); + helper.Writer.Write("Quantity", ((int)shipmentItem.Quantity).ToString()); + helper.Writer.WriteEndElement(); // ShipmentItem } - writer.WriteEndElement(); // ShipmentItems + helper.Writer.WriteEndElement(); // ShipmentItems - writer.WriteEndElement(); // Shipment + helper.Writer.WriteEndElement(); // Shipment } - writer.WriteEndElement(); // Shipments + helper.Writer.WriteEndElement(); // Shipments ++context.RecordsSucceeded; } @@ -247,12 +235,12 @@ public override void Execute(IExportExecuteContext context) context.RecordException(exc, (int)order.Id); } - writer.WriteEndElement(); // Order + helper.Writer.WriteEndElement(); // Order } } - writer.WriteEndElement(); // Orders - writer.WriteEndDocument(); + helper.Writer.WriteEndElement(); // Orders + helper.Writer.WriteEndDocument(); } } } diff --git a/src/Libraries/SmartStore.Services/DataExchange/Providers/ProductXmlExportProvider.cs b/src/Libraries/SmartStore.Services/DataExchange/Providers/ProductXmlExportProvider.cs index e4154f4804..a3480bdb3a 100644 --- a/src/Libraries/SmartStore.Services/DataExchange/Providers/ProductXmlExportProvider.cs +++ b/src/Libraries/SmartStore.Services/DataExchange/Providers/ProductXmlExportProvider.cs @@ -1,8 +1,5 @@ using System; -using System.Globalization; using System.IO; -using System.Text; -using System.Xml; using SmartStore.Core; using SmartStore.Core.Domain.DataExchange; using SmartStore.Core.Logging; @@ -35,26 +32,16 @@ public override string FileExtension public override void Execute(IExportExecuteContext context) { - var settings = new XmlWriterSettings - { - Encoding = Encoding.UTF8, - CheckCharacters = false, - Indent = true, - IndentChars = "\t" - }; - var path = context.FilePath; context.Log.Information("Creating file " + path); using (var stream = new FileStream(path, FileMode.Create, FileAccess.Write, FileShare.ReadWrite)) - using (var writer = XmlWriter.Create(stream, settings)) + using (var helper = new ExportXmlHelper(stream)) { - var xmlHelper = new ExportXmlHelper(writer, CultureInfo.InvariantCulture); - - writer.WriteStartDocument(); - writer.WriteStartElement("Products"); - writer.WriteAttributeString("Version", SmartStoreVersion.CurrentVersion); + helper.Writer.WriteStartDocument(); + helper.Writer.WriteStartElement("Products"); + helper.Writer.WriteAttributeString("Version", SmartStoreVersion.CurrentVersion); while (context.Abort == ExportAbortion.None && context.Segmenter.ReadNextSegment()) { @@ -67,7 +54,7 @@ public override void Execute(IExportExecuteContext context) try { - xmlHelper.WriteProduct(product, "Product"); + helper.WriteProduct(product, "Product"); ++context.RecordsSucceeded; } @@ -78,8 +65,8 @@ public override void Execute(IExportExecuteContext context) } } - writer.WriteEndElement(); // Products - writer.WriteEndDocument(); + helper.Writer.WriteEndElement(); // Products + helper.Writer.WriteEndDocument(); } } } diff --git a/src/Presentation/SmartStore.Web/Administration/Controllers/ExportController.cs b/src/Presentation/SmartStore.Web/Administration/Controllers/ExportController.cs index 984f3641a1..29c4c040b9 100644 --- a/src/Presentation/SmartStore.Web/Administration/Controllers/ExportController.cs +++ b/src/Presentation/SmartStore.Web/Administration/Controllers/ExportController.cs @@ -3,6 +3,7 @@ using System.IO; using System.Linq; using System.Net.Mime; +using System.Text; using System.Web; using System.Web.Mvc; using Autofac; @@ -878,7 +879,7 @@ public ActionResult DownloadLogFile(int id) var path = profile.GetExportLogFilePath(); var stream = new FileStream(path, FileMode.Open); - var result = new FileStreamResult(stream, MediaTypeNames.Text.Plain); + var result = new FileStreamResult(stream, "text/plain; charset=utf-8"); result.FileDownloadName = profile.Name.ToValidFileName() + "-log.txt"; return result; From 451dd5e9460a20fc8e9e010bcf9bce4a510748a2 Mon Sep 17 00:00:00 2001 From: Marcus Gesing Date: Sun, 8 Nov 2015 18:58:53 +0100 Subject: [PATCH 019/707] Export framework rather than provider should create export data files --- .../Extensions/XmlWriterExtensions.cs | 10 -- .../DataExchange/ExportExecuteContext.cs | 54 ++++++-- .../ExportTask/ExportProfileTask.cs | 122 +++++++++++++----- .../DataExchange/ExportXmlHelper.cs | 16 ++- .../Providers/CategoryXmlExportProvider.cs | 9 +- .../Providers/CustomerXlsxExportProvider.cs | 8 +- .../Providers/CustomerXmlExportProvider.cs | 9 +- .../ManufacturerXmlExportProvider.cs | 9 +- .../Providers/OrderXlsxExportProvider.cs | 9 +- .../Providers/OrderXmlExportProvider.cs | 8 +- .../Providers/ProductXlsxExportProvider.cs | 9 +- .../Providers/ProductXmlExportProvider.cs | 9 +- .../Providers/SubscriberCsvExportProvider.cs | 8 +- .../Providers/GmcXmlExportProvider.cs | 14 +- 14 files changed, 153 insertions(+), 141 deletions(-) diff --git a/src/Libraries/SmartStore.Core/Extensions/XmlWriterExtensions.cs b/src/Libraries/SmartStore.Core/Extensions/XmlWriterExtensions.cs index 5ead943146..ca4e1c2c71 100644 --- a/src/Libraries/SmartStore.Core/Extensions/XmlWriterExtensions.cs +++ b/src/Libraries/SmartStore.Core/Extensions/XmlWriterExtensions.cs @@ -21,16 +21,6 @@ public static void WriteCData(this XmlWriter writer, string name, string value, } } - public static void WriteNode(this XmlWriter writer, string name, Action content) - { - if (name.HasValue() && content != null) - { - writer.WriteStartElement(name); - content(); - writer.WriteEndElement(); - } - } - /// /// Created a simple or CData node element /// diff --git a/src/Libraries/SmartStore.Services/DataExchange/ExportExecuteContext.cs b/src/Libraries/SmartStore.Services/DataExchange/ExportExecuteContext.cs index 17ae53a8bf..d4a6286570 100644 --- a/src/Libraries/SmartStore.Services/DataExchange/ExportExecuteContext.cs +++ b/src/Libraries/SmartStore.Services/DataExchange/ExportExecuteContext.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.IO; using System.Threading; using SmartStore.Core.Domain.DataExchange; using SmartStore.Core.Logging; @@ -50,14 +51,25 @@ public interface IExportExecuteContext /// - /// The maximum allowed file name length + /// Identifier of current data stream. Can be null. /// - int MaxFileNameLength { get; } + string DataStreamId { get; set; } /// - /// The path of the export content folder + /// Stream used to write data to /// - string Folder { get; } + Stream DataStream { get; } + + /// + /// List with extra data streams required by provider + /// + List ExtraDataStreams { get; set; } + + + /// + /// The maximum allowed file name length + /// + int MaxFileNameLength { get; } /// /// The name of the current export file @@ -65,9 +77,9 @@ public interface IExportExecuteContext string FileName { get; } /// - /// The path of the current export file + /// The path of the export content folder /// - string FilePath { get; } + string Folder { get; } /// @@ -114,6 +126,25 @@ public interface IExportExecuteContext } + public class ExportExtraStreams + { + /// + /// Your Id to identify this stream within a list of streams + /// + public string Id { get; set; } + + /// + /// Stream used to write data to + /// + public Stream DataStream { get; internal set; } + + /// + /// The name of the file to be created + /// + public string FileName { get; set; } + } + + public class ExportExecuteContext : IExportExecuteContext { private DataExportResult _result; @@ -125,7 +156,7 @@ internal ExportExecuteContext(DataExportResult result, CancellationToken cancell _result = result; _cancellation = cancellation; Folder = folder; - + ExtraDataStreams = new List(); CustomProperties = new Dictionary(); } @@ -159,12 +190,13 @@ public bool IsMaxFailures get { return RecordsFailed > 11; } } - public int MaxFileNameLength { get; internal set; } + public string DataStreamId { get; set; } + public Stream DataStream { get; internal set; } + public List ExtraDataStreams { get; set; } - public string Folder { get; private set; } + public int MaxFileNameLength { get; internal set; } public string FileName { get; internal set; } - public string FileExtension { get; internal set; } - public string FilePath { get; internal set; } + public string Folder { get; private set; } public bool HasPublicDeployment { get; internal set; } public string PublicFolderPath { get; internal set; } diff --git a/src/Libraries/SmartStore.Services/DataExchange/ExportTask/ExportProfileTask.cs b/src/Libraries/SmartStore.Services/DataExchange/ExportTask/ExportProfileTask.cs index 1a52e264ea..8218acffb0 100644 --- a/src/Libraries/SmartStore.Services/DataExchange/ExportTask/ExportProfileTask.cs +++ b/src/Libraries/SmartStore.Services/DataExchange/ExportTask/ExportProfileTask.cs @@ -133,7 +133,7 @@ private void InitDependencies(TaskExecutionContext context) _genericAttributeService = context.Resolve>(); _subscriptionRepository = context.Resolve>>(); - T = NullLocalizer.Instance; + T = NullLocalizer.Instance; // TODO: resolve } public Localizer T { get; set; } @@ -316,6 +316,61 @@ private IExportDataSegmenterProvider CreateSegmenter(ExportProfileTaskContext ct return ctx.ExecuteContext.Segmenter as IExportDataSegmenterProvider; } + private bool CallProvider(ExportProfileTaskContext ctx, string streamId, string method, string path) + { + if (method != "Execute" && method != "OnExecuted") + throw new SmartException("Unknown export method {0}".FormatInvariant(method.NaIfEmpty())); + + try + { + ctx.ExecuteContext.DataStreamId = streamId; + + using (ctx.ExecuteContext.DataStream = new MemoryStream()) + { + if (method == "Execute") + { + ctx.Provider.Value.Execute(ctx.ExecuteContext); + } + else if (method == "OnExecuted") + { + ctx.Provider.Value.OnExecuted(ctx.ExecuteContext); + } + + if (ctx.IsFileBasedExport && path.HasValue()) + { + if (!ctx.ExecuteContext.DataStream.CanSeek) + ctx.Log.Warning("Data stream seems to be closed!"); + + ctx.ExecuteContext.DataStream.Seek(0, SeekOrigin.Begin); + + using (_rwLock.GetWriteLock()) + using (var fileStream = new FileStream(path, FileMode.Create, FileAccess.Write, FileShare.ReadWrite)) + { + ctx.Log.Information("Creating file " + path); + + ctx.ExecuteContext.DataStream.CopyTo(fileStream); + } + } + } + } + catch (Exception exc) + { + ctx.ExecuteContext.Abort = ExportAbortion.Hard; + ctx.Log.Error("The provider failed at the {0} method: {1}".FormatInvariant(method, exc.ToAllMessages()), exc); + ctx.Result.LastError = exc.ToString(); + } + finally + { + if (ctx.ExecuteContext.DataStream != null) + { + ctx.ExecuteContext.DataStream.Dispose(); + ctx.ExecuteContext.DataStream = null; + } + } + + return (ctx.ExecuteContext.Abort != ExportAbortion.Hard); + } + private void PrepareProductDescription(ExportProfileTaskContext ctx, dynamic expando, Product product) { try @@ -2465,12 +2520,12 @@ private void ExportCoreInner(ExportProfileTaskContext ctx, Store store) ctx.ExecuteContext.MaxFileNameLength = _dataExchangeSettings.Value.MaxFileNameLength; - ctx.ExecuteContext.FileExtension = (ctx.Provider.Value.FileExtension.HasValue() ? ctx.Provider.Value.FileExtension.ToLower().EnsureStartsWith(".") : ""); - ctx.ExecuteContext.HasPublicDeployment = ctx.Profile.Deployments.Any(x => x.IsPublic && x.DeploymentType == ExportDeploymentType.FileSystem); ctx.ExecuteContext.PublicFolderPath = (ctx.ExecuteContext.HasPublicDeployment ? Path.Combine(HttpRuntime.AppDomainAppPath, PublicFolder) : null); + var fileExtension = (ctx.Provider.Value.FileExtension.HasValue() ? ctx.Provider.Value.FileExtension.ToLower().EnsureStartsWith(".") : ""); + using (var segmenter = CreateSegmenter(ctx)) { @@ -2489,42 +2544,32 @@ private void ExportCoreInner(ExportProfileTaskContext ctx, Store store) segmenter.RecordPerSegmentCount = 0; ctx.ExecuteContext.RecordsSucceeded = 0; - try + string path = null; + + if (ctx.IsFileBasedExport) { - if (ctx.IsFileBasedExport) - { - var resolvedPattern = ctx.Profile.ResolveFileNamePattern(ctx.Store, ++fileIndex, ctx.ExecuteContext.MaxFileNameLength); + var resolvedPattern = ctx.Profile.ResolveFileNamePattern(ctx.Store, ++fileIndex, ctx.ExecuteContext.MaxFileNameLength); - ctx.ExecuteContext.FileName = resolvedPattern + ctx.ExecuteContext.FileExtension; - ctx.ExecuteContext.FilePath = Path.Combine(ctx.ExecuteContext.Folder, ctx.ExecuteContext.FileName); + ctx.ExecuteContext.FileName = resolvedPattern + fileExtension; + path = Path.Combine(ctx.ExecuteContext.Folder, ctx.ExecuteContext.FileName); - if (ctx.ExecuteContext.HasPublicDeployment) - ctx.ExecuteContext.PublicFileUrl = ctx.Store.Url.EnsureEndsWith("/") + PublicFolder.EnsureEndsWith("/") + ctx.ExecuteContext.FileName; + if (ctx.ExecuteContext.HasPublicDeployment) + ctx.ExecuteContext.PublicFileUrl = ctx.Store.Url.EnsureEndsWith("/") + PublicFolder.EnsureEndsWith("/") + ctx.ExecuteContext.FileName; + } - ctx.Provider.Value.Execute(ctx.ExecuteContext); + if (CallProvider(ctx, null, "Execute", path)) + { + ctx.Log.Information("Provider reports {0} successful exported record(s)".FormatInvariant(ctx.ExecuteContext.RecordsSucceeded)); - // create info for deployment list in profile edit - if (File.Exists(ctx.ExecuteContext.FilePath)) - { - ctx.Result.Files.Add(new DataExportResult.ExportFileInfo - { - StoreId = ctx.Store.Id, - FileName = ctx.ExecuteContext.FileName - }); - } - } - else + // create info for deployment list in profile edit + if (ctx.IsFileBasedExport) { - ctx.Provider.Value.Execute(ctx.ExecuteContext); + ctx.Result.Files.Add(new DataExportResult.ExportFileInfo + { + StoreId = ctx.Store.Id, + FileName = ctx.ExecuteContext.FileName + }); } - - ctx.Log.Information("Provider reports {0} successful exported record(s)".FormatInvariant(ctx.ExecuteContext.RecordsSucceeded)); - } - catch (Exception exc) - { - ctx.ExecuteContext.Abort = ExportAbortion.Hard; - ctx.Log.Error("The provider failed to execute the export: " + exc.ToAllMessages(), exc); - ctx.Result.LastError = exc.ToString(); } if (ctx.ExecuteContext.IsMaxFailures) @@ -2536,7 +2581,17 @@ private void ExportCoreInner(ExportProfileTaskContext ctx, Store store) if (ctx.ExecuteContext.Abort != ExportAbortion.Hard) { - ctx.Provider.Value.OnExecuted(ctx.ExecuteContext); + if (ctx.ExecuteContext.ExtraDataStreams.Count == 0) + ctx.ExecuteContext.ExtraDataStreams.Add(new ExportExtraStreams()); + + ctx.ExecuteContext.ExtraDataStreams.ForEach(x => + { + var path = (x.FileName.HasValue() ? Path.Combine(ctx.ExecuteContext.Folder, x.FileName) : null); + + CallProvider(ctx, x.Id, "OnExecuted", path); + }); + + ctx.ExecuteContext.ExtraDataStreams.Clear(); } } } @@ -2550,7 +2605,6 @@ private void ExportCoreOuter(ExportProfileTaskContext ctx) FileSystemHelper.ClearDirectory(ctx.FolderContent, false); FileSystemHelper.Delete(ctx.ZipPath); - using (_rwLock.GetWriteLock()) using (var logger = new TraceLogger(ctx.LogPath)) { try diff --git a/src/Libraries/SmartStore.Services/DataExchange/ExportXmlHelper.cs b/src/Libraries/SmartStore.Services/DataExchange/ExportXmlHelper.cs index e5837578d6..d58c724eac 100644 --- a/src/Libraries/SmartStore.Services/DataExchange/ExportXmlHelper.cs +++ b/src/Libraries/SmartStore.Services/DataExchange/ExportXmlHelper.cs @@ -24,7 +24,18 @@ public ExportXmlHelper(Stream stream, XmlWriterSettings settings = null, Culture { if (settings == null) { - settings = new XmlWriterSettings + settings = DefaultSettings; + } + + _writer = XmlWriter.Create(stream, settings); + _culture = (culture == null ? CultureInfo.InvariantCulture : culture); + } + + public static XmlWriterSettings DefaultSettings + { + get + { + return new XmlWriterSettings { Encoding = Encoding.UTF8, CheckCharacters = false, @@ -32,9 +43,6 @@ public ExportXmlHelper(Stream stream, XmlWriterSettings settings = null, Culture IndentChars = "\t" }; } - - _writer = XmlWriter.Create(stream, settings); - _culture = (culture == null ? CultureInfo.InvariantCulture : culture); } public XmlWriter Writer diff --git a/src/Libraries/SmartStore.Services/DataExchange/Providers/CategoryXmlExportProvider.cs b/src/Libraries/SmartStore.Services/DataExchange/Providers/CategoryXmlExportProvider.cs index 2b74231730..1aecac8667 100644 --- a/src/Libraries/SmartStore.Services/DataExchange/Providers/CategoryXmlExportProvider.cs +++ b/src/Libraries/SmartStore.Services/DataExchange/Providers/CategoryXmlExportProvider.cs @@ -1,8 +1,6 @@ using System; -using System.IO; using SmartStore.Core; using SmartStore.Core.Domain.DataExchange; -using SmartStore.Core.Logging; using SmartStore.Core.Plugins; namespace SmartStore.Services.DataExchange.Providers @@ -32,12 +30,7 @@ public override string FileExtension public override void Execute(IExportExecuteContext context) { - var path = context.FilePath; - - context.Log.Information("Creating file " + path); - - using (var stream = new FileStream(path, FileMode.Create, FileAccess.Write, FileShare.ReadWrite)) - using (var helper = new ExportXmlHelper(stream)) + using (var helper = new ExportXmlHelper(context.DataStream)) { helper.Writer.WriteStartDocument(); helper.Writer.WriteStartElement("Categories"); diff --git a/src/Libraries/SmartStore.Services/DataExchange/Providers/CustomerXlsxExportProvider.cs b/src/Libraries/SmartStore.Services/DataExchange/Providers/CustomerXlsxExportProvider.cs index 4ab09bd5c5..72bda50969 100644 --- a/src/Libraries/SmartStore.Services/DataExchange/Providers/CustomerXlsxExportProvider.cs +++ b/src/Libraries/SmartStore.Services/DataExchange/Providers/CustomerXlsxExportProvider.cs @@ -1,12 +1,10 @@ using System; using System.Drawing; using System.Globalization; -using System.IO; using OfficeOpenXml; using OfficeOpenXml.Style; using SmartStore.Core.Domain.Customers; using SmartStore.Core.Domain.DataExchange; -using SmartStore.Core.Logging; using SmartStore.Core.Plugins; using SmartStore.Services.Customers; @@ -110,12 +108,8 @@ public override string FileExtension public override void Execute(IExportExecuteContext context) { var invariantCulture = CultureInfo.InvariantCulture; - var path = context.FilePath; - context.Log.Information("Creating file " + path); - - using (var stream = new FileStream(path, FileMode.Create, FileAccess.Write, FileShare.ReadWrite)) - using (var xlPackage = new ExcelPackage(stream)) + using (var xlPackage = new ExcelPackage(context.DataStream)) { // uncomment this line if you want the XML written out to the outputDir //xlPackage.DebugMode = true; diff --git a/src/Libraries/SmartStore.Services/DataExchange/Providers/CustomerXmlExportProvider.cs b/src/Libraries/SmartStore.Services/DataExchange/Providers/CustomerXmlExportProvider.cs index 4103b412a5..4963380787 100644 --- a/src/Libraries/SmartStore.Services/DataExchange/Providers/CustomerXmlExportProvider.cs +++ b/src/Libraries/SmartStore.Services/DataExchange/Providers/CustomerXmlExportProvider.cs @@ -1,8 +1,6 @@ using System; -using System.IO; using SmartStore.Core; using SmartStore.Core.Domain.DataExchange; -using SmartStore.Core.Logging; using SmartStore.Core.Plugins; namespace SmartStore.Services.DataExchange.Providers @@ -32,12 +30,7 @@ public override string FileExtension public override void Execute(IExportExecuteContext context) { - var path = context.FilePath; - - context.Log.Information("Creating file " + path); - - using (var stream = new FileStream(path, FileMode.Create, FileAccess.Write, FileShare.ReadWrite)) - using (var helper = new ExportXmlHelper(stream)) + using (var helper = new ExportXmlHelper(context.DataStream)) { helper.Writer.WriteStartDocument(); helper.Writer.WriteStartElement("Customers"); diff --git a/src/Libraries/SmartStore.Services/DataExchange/Providers/ManufacturerXmlExportProvider.cs b/src/Libraries/SmartStore.Services/DataExchange/Providers/ManufacturerXmlExportProvider.cs index 3c5d6afa53..af672aeed8 100644 --- a/src/Libraries/SmartStore.Services/DataExchange/Providers/ManufacturerXmlExportProvider.cs +++ b/src/Libraries/SmartStore.Services/DataExchange/Providers/ManufacturerXmlExportProvider.cs @@ -1,8 +1,6 @@ using System; -using System.IO; using SmartStore.Core; using SmartStore.Core.Domain.DataExchange; -using SmartStore.Core.Logging; using SmartStore.Core.Plugins; namespace SmartStore.Services.DataExchange.Providers @@ -32,12 +30,7 @@ public override string FileExtension public override void Execute(IExportExecuteContext context) { - var path = context.FilePath; - - context.Log.Information("Creating file " + path); - - using (var stream = new FileStream(path, FileMode.Create, FileAccess.Write, FileShare.ReadWrite)) - using (var helper = new ExportXmlHelper(stream)) + using (var helper = new ExportXmlHelper(context.DataStream)) { helper.Writer.WriteStartDocument(); helper.Writer.WriteStartElement("Manufacturers"); diff --git a/src/Libraries/SmartStore.Services/DataExchange/Providers/OrderXlsxExportProvider.cs b/src/Libraries/SmartStore.Services/DataExchange/Providers/OrderXlsxExportProvider.cs index ae6ce4271d..0520409914 100644 --- a/src/Libraries/SmartStore.Services/DataExchange/Providers/OrderXlsxExportProvider.cs +++ b/src/Libraries/SmartStore.Services/DataExchange/Providers/OrderXlsxExportProvider.cs @@ -1,10 +1,8 @@ using System; using System.Drawing; -using System.IO; using OfficeOpenXml; using OfficeOpenXml.Style; using SmartStore.Core.Domain.DataExchange; -using SmartStore.Core.Logging; using SmartStore.Core.Plugins; namespace SmartStore.Services.DataExchange.Providers @@ -108,12 +106,7 @@ public override string FileExtension public override void Execute(IExportExecuteContext context) { - var path = context.FilePath; - - context.Log.Information("Creating file " + path); - - using (var stream = new FileStream(path, FileMode.Create, FileAccess.Write, FileShare.ReadWrite)) - using (var xlPackage = new ExcelPackage(stream)) + using (var xlPackage = new ExcelPackage(context.DataStream)) { // uncomment this line if you want the XML written out to the outputDir //xlPackage.DebugMode = true; diff --git a/src/Libraries/SmartStore.Services/DataExchange/Providers/OrderXmlExportProvider.cs b/src/Libraries/SmartStore.Services/DataExchange/Providers/OrderXmlExportProvider.cs index 470155603a..366dcd15d0 100644 --- a/src/Libraries/SmartStore.Services/DataExchange/Providers/OrderXmlExportProvider.cs +++ b/src/Libraries/SmartStore.Services/DataExchange/Providers/OrderXmlExportProvider.cs @@ -1,9 +1,7 @@ using System; using System.Globalization; -using System.IO; using SmartStore.Core; using SmartStore.Core.Domain.DataExchange; -using SmartStore.Core.Logging; using SmartStore.Core.Plugins; namespace SmartStore.Services.DataExchange.Providers @@ -33,13 +31,9 @@ public override string FileExtension public override void Execute(IExportExecuteContext context) { - var path = context.FilePath; var invariantCulture = CultureInfo.InvariantCulture; - context.Log.Information("Creating file " + path); - - using (var stream = new FileStream(path, FileMode.Create, FileAccess.Write, FileShare.ReadWrite)) - using (var helper = new ExportXmlHelper(stream)) + using (var helper = new ExportXmlHelper(context.DataStream)) { helper.Writer.WriteStartDocument(); helper.Writer.WriteStartElement("Orders"); diff --git a/src/Libraries/SmartStore.Services/DataExchange/Providers/ProductXlsxExportProvider.cs b/src/Libraries/SmartStore.Services/DataExchange/Providers/ProductXlsxExportProvider.cs index 3da13558c0..d2e877b7f8 100644 --- a/src/Libraries/SmartStore.Services/DataExchange/Providers/ProductXlsxExportProvider.cs +++ b/src/Libraries/SmartStore.Services/DataExchange/Providers/ProductXlsxExportProvider.cs @@ -1,14 +1,12 @@ using System; using System.Collections.Generic; using System.Drawing; -using System.IO; using System.Linq; using OfficeOpenXml; using OfficeOpenXml.Style; using SmartStore.Core.Domain.Catalog; using SmartStore.Core.Domain.DataExchange; using SmartStore.Core.Domain.Localization; -using SmartStore.Core.Logging; using SmartStore.Core.Plugins; using SmartStore.Services.Catalog; using SmartStore.Services.Localization; @@ -177,12 +175,7 @@ public override string FileExtension public override void Execute(IExportExecuteContext context) { - var path = context.FilePath; - - context.Log.Information("Creating file " + path); - - using (var stream = new FileStream(path, FileMode.Create, FileAccess.Write, FileShare.ReadWrite)) - using (var xlPackage = new ExcelPackage(stream)) + using (var xlPackage = new ExcelPackage(context.DataStream)) { // uncomment this line if you want the XML written out to the outputDir //xlPackage.DebugMode = true; diff --git a/src/Libraries/SmartStore.Services/DataExchange/Providers/ProductXmlExportProvider.cs b/src/Libraries/SmartStore.Services/DataExchange/Providers/ProductXmlExportProvider.cs index a3480bdb3a..63d5dc4122 100644 --- a/src/Libraries/SmartStore.Services/DataExchange/Providers/ProductXmlExportProvider.cs +++ b/src/Libraries/SmartStore.Services/DataExchange/Providers/ProductXmlExportProvider.cs @@ -1,8 +1,6 @@ using System; -using System.IO; using SmartStore.Core; using SmartStore.Core.Domain.DataExchange; -using SmartStore.Core.Logging; using SmartStore.Core.Plugins; namespace SmartStore.Services.DataExchange.Providers @@ -32,12 +30,7 @@ public override string FileExtension public override void Execute(IExportExecuteContext context) { - var path = context.FilePath; - - context.Log.Information("Creating file " + path); - - using (var stream = new FileStream(path, FileMode.Create, FileAccess.Write, FileShare.ReadWrite)) - using (var helper = new ExportXmlHelper(stream)) + using (var helper = new ExportXmlHelper(context.DataStream)) { helper.Writer.WriteStartDocument(); helper.Writer.WriteStartElement("Products"); diff --git a/src/Libraries/SmartStore.Services/DataExchange/Providers/SubscriberCsvExportProvider.cs b/src/Libraries/SmartStore.Services/DataExchange/Providers/SubscriberCsvExportProvider.cs index 2a7e299b51..be904fa6c7 100644 --- a/src/Libraries/SmartStore.Services/DataExchange/Providers/SubscriberCsvExportProvider.cs +++ b/src/Libraries/SmartStore.Services/DataExchange/Providers/SubscriberCsvExportProvider.cs @@ -2,7 +2,6 @@ using System.IO; using System.Text; using SmartStore.Core.Domain.DataExchange; -using SmartStore.Core.Logging; using SmartStore.Core.Plugins; namespace SmartStore.Services.DataExchange.Providers @@ -32,12 +31,7 @@ public override string FileExtension public override void Execute(IExportExecuteContext context) { - var path = context.FilePath; - - context.Log.Information("Creating file " + path); - - using (var stream = new FileStream(path, FileMode.Create, FileAccess.Write, FileShare.ReadWrite)) - using (var writer = new StreamWriter(stream, Encoding.UTF8)) + using (var writer = new StreamWriter(context.DataStream, Encoding.UTF8, 1024, true)) { while (context.Abort == ExportAbortion.None && context.Segmenter.ReadNextSegment()) { diff --git a/src/Plugins/SmartStore.GoogleMerchantCenter/Providers/GmcXmlExportProvider.cs b/src/Plugins/SmartStore.GoogleMerchantCenter/Providers/GmcXmlExportProvider.cs index b1a68d4591..a58b4b98b8 100644 --- a/src/Plugins/SmartStore.GoogleMerchantCenter/Providers/GmcXmlExportProvider.cs +++ b/src/Plugins/SmartStore.GoogleMerchantCenter/Providers/GmcXmlExportProvider.cs @@ -1,7 +1,5 @@ using System; -using System.IO; using System.Linq; -using System.Text; using System.Xml; using SmartStore.Core.Domain.Catalog; using SmartStore.Core.Domain.DataExchange; @@ -157,13 +155,6 @@ public override string FileExtension public override void Execute(IExportExecuteContext context) { - var settings = new XmlWriterSettings - { - Encoding = Encoding.UTF8, - CheckCharacters = false - }; - - var path = context.FilePath; dynamic currency = context.Currency; string measureWeightSystemKey = ""; @@ -174,10 +165,7 @@ public override void Execute(IExportExecuteContext context) var config = (context.ConfigurationData as ProfileConfigurationModel) ?? new ProfileConfigurationModel(); - context.Log.Information("Creating file " + path); - - using (var stream = new FileStream(path, FileMode.Create, FileAccess.Write, FileShare.ReadWrite)) - using (var writer = XmlWriter.Create(stream, settings)) + using (var writer = XmlWriter.Create(context.DataStream, ExportXmlHelper.DefaultSettings)) { writer.WriteStartDocument(); writer.WriteStartElement("rss"); From 738052a5be9af329f02181d7d2d9fdbd3839ce76 Mon Sep 17 00:00:00 2001 From: Marcus Gesing Date: Sun, 8 Nov 2015 19:47:39 +0100 Subject: [PATCH 020/707] ExportFeature becomes an enum of flags --- .../Domain/DataExchange/ExportEnums.cs | 32 +++++++++++-------- .../Plugins/Providers/ProviderMetadata.cs | 4 +-- .../DataExchange/ExportExtensions.cs | 16 ---------- .../DataExchange/ExportFeaturesAttribute.cs | 7 +--- .../DataExchange/ExportProfileService.cs | 4 +-- .../ExportTask/ExportProfileTask.cs | 18 +++++------ .../ExportTask/ExportProfileTaskContext.cs | 9 ++---- .../Providers/GmcXmlExportProvider.cs | 18 +++++------ .../DependencyRegistrar.cs | 8 ++--- .../Controllers/ExportController.cs | 2 +- .../Models/DataExchange/ExportProfileModel.cs | 2 +- .../Views/Export/_Tab.Projection.cshtml | 14 ++++---- 12 files changed, 56 insertions(+), 78 deletions(-) diff --git a/src/Libraries/SmartStore.Core/Domain/DataExchange/ExportEnums.cs b/src/Libraries/SmartStore.Core/Domain/DataExchange/ExportEnums.cs index b7f041fed5..90cb107353 100644 --- a/src/Libraries/SmartStore.Core/Domain/DataExchange/ExportEnums.cs +++ b/src/Libraries/SmartStore.Core/Domain/DataExchange/ExportEnums.cs @@ -1,4 +1,5 @@  +using System; namespace SmartStore.Core.Domain.DataExchange { /// @@ -59,64 +60,67 @@ public enum ExportAttributeValueMerging } /// - /// Controls data processing and projection items supported by export provider + /// Controls data processing and projection items supported by an export provider /// - public enum ExportFeatures + [Flags] + public enum ExportFeature { + None = 0, + /// /// Whether to automatically create a file based public deployment when an export profile is created /// - CreatesInitialPublicDeployment = 0, + CreatesInitialPublicDeployment = 1, /// /// Whether to offer option to include\exclude grouped products /// - CanOmitGroupedProducts, + CanOmitGroupedProducts = 1 << 2, /// /// Whether to offer option to export attribute combinations as products /// - CanProjectAttributeCombinations, + CanProjectAttributeCombinations = 1 << 3, /// /// Whether to offer further options to manipulate the product description /// - CanProjectDescription, + CanProjectDescription = 1 << 4, /// /// Whether to offer option to enter a brand fallback /// - OffersBrandFallback, + OffersBrandFallback = 1 << 5, /// /// Whether to offer option to set a picture size and to get the URL of the main image /// - CanIncludeMainPicture, + CanIncludeMainPicture = 1 << 6, /// /// Whether to use SKU as manufacturer part number if MPN is empty /// - UsesSkuAsMpnFallback, - + UsesSkuAsMpnFallback = 1 << 7, + /// /// Whether to offer option to enter a shipping time fallback /// - OffersShippingTimeFallback, + OffersShippingTimeFallback = 1 << 8, /// /// Whether to offer option to enter a shipping costs fallback and a free shipping threshold /// - OffersShippingCostsFallback, + OffersShippingCostsFallback = 1 << 9, /// /// Whether to get the calculated old product price /// - UsesOldPrice, + UsesOldPrice = 1 << 10, /// /// Whether to get the calculated special and regular price (ignoring special offers) /// - UsesSpecialPrice + UsesSpecialPrice = 1 << 11 } /// diff --git a/src/Libraries/SmartStore.Core/Plugins/Providers/ProviderMetadata.cs b/src/Libraries/SmartStore.Core/Plugins/Providers/ProviderMetadata.cs index 31d98942d4..05ef601ecc 100644 --- a/src/Libraries/SmartStore.Core/Plugins/Providers/ProviderMetadata.cs +++ b/src/Libraries/SmartStore.Core/Plugins/Providers/ProviderMetadata.cs @@ -74,9 +74,9 @@ public class ProviderMetadata public bool IsHidden { get; set; } /// - /// Gets or sets an array of values that reflects what export data processing is supported by a provider + /// Gets or sets flags that reflects what features of export data processing is supported by a provider /// - public ExportFeatures[] ExportSupport { get; set; } + public ExportFeature ExportFeature { get; set; } /// /// Gets or sets an array of widget system names, which depend on the current provider diff --git a/src/Libraries/SmartStore.Services/DataExchange/ExportExtensions.cs b/src/Libraries/SmartStore.Services/DataExchange/ExportExtensions.cs index ae5b8ff6ce..a7a8e5c5b9 100644 --- a/src/Libraries/SmartStore.Services/DataExchange/ExportExtensions.cs +++ b/src/Libraries/SmartStore.Services/DataExchange/ExportExtensions.cs @@ -1,10 +1,8 @@ using System; using System.IO; -using System.Linq; using System.Web; using System.Web.Caching; using SmartStore.Core.Domain; -using SmartStore.Core.Domain.DataExchange; using SmartStore.Core.Domain.Stores; using SmartStore.Core.Plugins; using SmartStore.Services.Localization; @@ -24,20 +22,6 @@ public static bool IsValid(this Provider provider) return provider != null; } - /// - /// Returns a value indicating whether the export provider supports a projection type - /// - /// Export provider - /// The feature to check - /// true provider supports type, false provider does not support type. - public static bool Supports(this Provider provider, ExportFeatures feature) - { - if (provider != null) - return provider.Metadata.ExportSupport.Contains(feature); - - return false; - } - /// /// Gets the localized friendly name or the system name as fallback /// diff --git a/src/Libraries/SmartStore.Services/DataExchange/ExportFeaturesAttribute.cs b/src/Libraries/SmartStore.Services/DataExchange/ExportFeaturesAttribute.cs index d29f5641d3..7f803715f4 100644 --- a/src/Libraries/SmartStore.Services/DataExchange/ExportFeaturesAttribute.cs +++ b/src/Libraries/SmartStore.Services/DataExchange/ExportFeaturesAttribute.cs @@ -10,11 +10,6 @@ namespace SmartStore.Services.DataExchange [AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = false)] public sealed class ExportFeaturesAttribute : Attribute { - public ExportFeaturesAttribute(params ExportFeatures[] features) - { - Features = features; - } - - public ExportFeatures[] Features { get; set; } + public ExportFeature Features { get; set; } } } diff --git a/src/Libraries/SmartStore.Services/DataExchange/ExportProfileService.cs b/src/Libraries/SmartStore.Services/DataExchange/ExportProfileService.cs index dac3287770..95302de285 100644 --- a/src/Libraries/SmartStore.Services/DataExchange/ExportProfileService.cs +++ b/src/Libraries/SmartStore.Services/DataExchange/ExportProfileService.cs @@ -116,7 +116,7 @@ public virtual ExportProfile InsertExportProfile(Provider provi RemoveCriticalCharacters = true, CriticalCharacters = "¼,½,¾", PriceType = PriceDisplayType.PreSelectedPrice, - NoGroupedProducts = (provider.Supports(ExportFeatures.CanOmitGroupedProducts) ? true : false) + NoGroupedProducts = (provider.Metadata.ExportFeature.HasFlag(ExportFeature.CanOmitGroupedProducts) ? true : false) }; var filter = new ExportFilter @@ -150,7 +150,7 @@ public virtual ExportProfile InsertExportProfile(Provider provi { if (cloneProfile == null) { - if (provider.Supports(ExportFeatures.CreatesInitialPublicDeployment)) + if (provider.Metadata.ExportFeature.HasFlag(ExportFeature.CreatesInitialPublicDeployment)) { profile.Deployments.Add(new ExportDeployment { diff --git a/src/Libraries/SmartStore.Services/DataExchange/ExportTask/ExportProfileTask.cs b/src/Libraries/SmartStore.Services/DataExchange/ExportTask/ExportProfileTask.cs index 8218acffb0..b796715059 100644 --- a/src/Libraries/SmartStore.Services/DataExchange/ExportTask/ExportProfileTask.cs +++ b/src/Libraries/SmartStore.Services/DataExchange/ExportTask/ExportProfileTask.cs @@ -1539,7 +1539,7 @@ private List ConvertToExpando(ExportProfileTaskContext ctx, Product pro var productTemplate = ctx.ProductTemplates.FirstOrDefault(x => x.Key == product.ProductTemplateId); var pictureSize = _mediaSettings.Value.ProductDetailsPictureSize; - if (ctx.SupportedFeatures[ExportFeatures.CanIncludeMainPicture] && ctx.Projection.PictureSize > 0) + if (ctx.Supports(ExportFeature.CanIncludeMainPicture) && ctx.Projection.PictureSize > 0) pictureSize = ctx.Projection.PictureSize; var perfLoadId = (ctx.IsPreview ? 0 : product.Id); // perf preview (it's a compromise) @@ -1745,12 +1745,12 @@ private List ConvertToExpando(ExportProfileTaskContext ctx, Product pro #region more attribute controlled data - if (ctx.Supports(ExportFeatures.CanProjectDescription)) + if (ctx.Supports(ExportFeature.CanProjectDescription)) { PrepareProductDescription(ctx, expando, product); } - if (ctx.Supports(ExportFeatures.OffersBrandFallback)) + if (ctx.Supports(ExportFeature.OffersBrandFallback)) { string brand = null; var productManus = ctx.ProductExportContext.ProductManufacturers.Load(perfLoadId); @@ -1764,7 +1764,7 @@ private List ConvertToExpando(ExportProfileTaskContext ctx, Product pro expando._Brand = brand; } - if (ctx.Supports(ExportFeatures.CanIncludeMainPicture)) + if (ctx.Supports(ExportFeature.CanIncludeMainPicture)) { if (productPictures != null && productPictures.Any()) expando._MainPictureUrl = _pictureService.Value.GetPictureUrl(productPictures.First().Picture, ctx.Projection.PictureSize, storeLocation: ctx.Store.Url); @@ -1806,18 +1806,18 @@ private List ConvertToExpando(ExportProfileTaskContext ctx, Product pro // navigation properties GetDeliveryTimeAndQuantityUnit(ctx, exp, product.DeliveryTimeId, product.QuantityUnitId); - if (ctx.Supports(ExportFeatures.UsesSkuAsMpnFallback) && product.ManufacturerPartNumber.IsEmpty()) + if (ctx.Supports(ExportFeature.UsesSkuAsMpnFallback) && product.ManufacturerPartNumber.IsEmpty()) { exp.ManufacturerPartNumber = product.Sku; } - if (ctx.Supports(ExportFeatures.OffersShippingTimeFallback)) + if (ctx.Supports(ExportFeature.OffersShippingTimeFallback)) { dynamic deliveryTime = exp.DeliveryTime; exp._ShippingTime = (deliveryTime == null ? ctx.Projection.ShippingTime : deliveryTime.Name); } - if (ctx.Supports(ExportFeatures.OffersShippingCostsFallback)) + if (ctx.Supports(ExportFeature.OffersShippingCostsFallback)) { exp._FreeShippingThreshold = ctx.Projection.FreeShippingThreshold; @@ -1827,7 +1827,7 @@ private List ConvertToExpando(ExportProfileTaskContext ctx, Product pro exp._ShippingCosts = ctx.Projection.ShippingCosts; } - if (ctx.Supports(ExportFeatures.UsesOldPrice)) + if (ctx.Supports(ExportFeature.UsesOldPrice)) { if (product.OldPrice != decimal.Zero && product.OldPrice != (decimal)exp.Price && !(product.ProductType == ProductType.BundledProduct && product.BundlePerItemPricing)) { @@ -1847,7 +1847,7 @@ private List ConvertToExpando(ExportProfileTaskContext ctx, Product pro } } - if (ctx.Supports(ExportFeatures.UsesSpecialPrice)) + if (ctx.Supports(ExportFeature.UsesSpecialPrice)) { exp._SpecialPrice = null; exp._RegularPrice = null; // price if a special price would not exist diff --git a/src/Libraries/SmartStore.Services/DataExchange/ExportTask/ExportProfileTaskContext.cs b/src/Libraries/SmartStore.Services/DataExchange/ExportTask/ExportProfileTaskContext.cs index 8c1286b5d6..ae14972e42 100644 --- a/src/Libraries/SmartStore.Services/DataExchange/ExportTask/ExportProfileTaskContext.cs +++ b/src/Libraries/SmartStore.Services/DataExchange/ExportTask/ExportProfileTaskContext.cs @@ -41,10 +41,6 @@ public ExportProfileTaskContext( EntityIdsSelected = selectedIds.SplitSafe(",").Select(x => x.ToInt()).ToList(); PreviewData = previewData; - SupportedFeatures = Enum.GetValues(typeof(ExportFeatures)) - .Cast() - .ToDictionary(x => x, x => Provider.Supports(x)); - FolderContent = FileSystemHelper.TempDir(@"Profile\Export\{0}\Content".FormatInvariant(profile.FolderName)); FolderRoot = System.IO.Directory.GetParent(FolderContent).FullName; @@ -84,10 +80,9 @@ public bool IsPreview public ExportProfile Profile { get; private set; } public Provider Provider { get; private set; } - public Dictionary SupportedFeatures { get; private set; } - public bool Supports(ExportFeatures feature) + public bool Supports(ExportFeature feature) { - return (!IsPreview && SupportedFeatures[feature]); + return (!IsPreview && Provider.Metadata.ExportFeature.HasFlag(feature)); } public ExportFilter Filter { get; private set; } diff --git a/src/Plugins/SmartStore.GoogleMerchantCenter/Providers/GmcXmlExportProvider.cs b/src/Plugins/SmartStore.GoogleMerchantCenter/Providers/GmcXmlExportProvider.cs index a58b4b98b8..852f8eb430 100644 --- a/src/Plugins/SmartStore.GoogleMerchantCenter/Providers/GmcXmlExportProvider.cs +++ b/src/Plugins/SmartStore.GoogleMerchantCenter/Providers/GmcXmlExportProvider.cs @@ -17,15 +17,15 @@ namespace SmartStore.GoogleMerchantCenter.Providers [SystemName("Feeds.GoogleMerchantCenterProductXml")] [FriendlyName("Google Merchant Center XML product feed")] [DisplayOrder(1)] - [ExportFeatures( - ExportFeatures.CreatesInitialPublicDeployment, - ExportFeatures.CanOmitGroupedProducts, - ExportFeatures.CanProjectAttributeCombinations, - ExportFeatures.CanProjectDescription, - ExportFeatures.UsesSkuAsMpnFallback, - ExportFeatures.OffersBrandFallback, - ExportFeatures.CanIncludeMainPicture, - ExportFeatures.UsesSpecialPrice)] + [ExportFeatures(Features = + ExportFeature.CreatesInitialPublicDeployment | + ExportFeature.CanOmitGroupedProducts | + ExportFeature.CanProjectAttributeCombinations | + ExportFeature.CanProjectDescription | + ExportFeature.UsesSkuAsMpnFallback | + ExportFeature.OffersBrandFallback | + ExportFeature.CanIncludeMainPicture | + ExportFeature.UsesSpecialPrice)] public class GmcXmlExportProvider : ExportProviderBase { private const string _googleNamespace = "http://base.google.com/ns/1.0"; diff --git a/src/Presentation/SmartStore.Web.Framework/DependencyRegistrar.cs b/src/Presentation/SmartStore.Web.Framework/DependencyRegistrar.cs index 1daa71bd03..2b11924761 100644 --- a/src/Presentation/SmartStore.Web.Framework/DependencyRegistrar.cs +++ b/src/Presentation/SmartStore.Web.Framework/DependencyRegistrar.cs @@ -768,7 +768,7 @@ protected override void Load(ContainerBuilder builder) var isConfigurable = typeof(IConfigurable).IsAssignableFrom(type); var isEditable = typeof(IUserEditable).IsAssignableFrom(type); var isHidden = GetIsHidden(type); - var exportSupport = GetExportFeatures(type); + var exportFeature = GetExportFeature(type); var registration = builder.RegisterType(type).Named(systemName).InstancePerRequest().PropertiesAutowired(PropertyWiringOptions.None); registration.WithMetadata(m => @@ -785,7 +785,7 @@ protected override void Load(ContainerBuilder builder) m.For(em => em.IsConfigurable, isConfigurable); m.For(em => em.IsEditable, isEditable); m.For(em => em.IsHidden, isHidden); - m.For(em => em.ExportSupport, exportSupport); + m.For(em => em.ExportFeature, exportFeature); }); // register specific provider type @@ -863,7 +863,7 @@ private bool GetIsHidden(Type type) return false; } - private ExportFeatures[] GetExportFeatures(Type type) + private ExportFeature GetExportFeature(Type type) { var attr = type.GetAttribute(false); @@ -872,7 +872,7 @@ private ExportFeatures[] GetExportFeatures(Type type) return attr.Features; } - return new ExportFeatures[0]; + return ExportFeature.None; } private Tuple GetFriendlyName(Type type, PluginDescriptor descriptor) diff --git a/src/Presentation/SmartStore.Web/Administration/Controllers/ExportController.cs b/src/Presentation/SmartStore.Web/Administration/Controllers/ExportController.cs index 29c4c040b9..8690b4507c 100644 --- a/src/Presentation/SmartStore.Web/Administration/Controllers/ExportController.cs +++ b/src/Presentation/SmartStore.Web/Administration/Controllers/ExportController.cs @@ -279,7 +279,7 @@ private void PrepareProfileModelForEdit(ExportProfileModel model, ExportProfile if (provider != null) { - model.Provider.Supporting = provider.Metadata.ExportSupport; + model.Provider.Feature = provider.Metadata.ExportFeature; if (model.Provider.EntityType == ExportEntityType.Product) { diff --git a/src/Presentation/SmartStore.Web/Administration/Models/DataExchange/ExportProfileModel.cs b/src/Presentation/SmartStore.Web/Administration/Models/DataExchange/ExportProfileModel.cs index 3ebf4350d9..ee44a44113 100644 --- a/src/Presentation/SmartStore.Web/Administration/Models/DataExchange/ExportProfileModel.cs +++ b/src/Presentation/SmartStore.Web/Administration/Models/DataExchange/ExportProfileModel.cs @@ -94,7 +94,7 @@ public class ProviderModel public Type ConfigDataType { get; set; } public object ConfigData { get; set; } - public ExportFeatures[] Supporting { get; set; } + public ExportFeature Feature { get; set; } [SmartResourceDisplayName("Common.Image")] public string ThumbnailUrl { get; set; } diff --git a/src/Presentation/SmartStore.Web/Administration/Views/Export/_Tab.Projection.cshtml b/src/Presentation/SmartStore.Web/Administration/Views/Export/_Tab.Projection.cshtml index 4815fba951..3d02c0a230 100644 --- a/src/Presentation/SmartStore.Web/Administration/Views/Export/_Tab.Projection.cshtml +++ b/src/Presentation/SmartStore.Web/Administration/Views/Export/_Tab.Projection.cshtml @@ -42,7 +42,7 @@ @if (Model.Provider.EntityType == ExportEntityType.Product) { - if (Model.Provider.Supporting.Contains(ExportFeatures.CanProjectAttributeCombinations)) + if (Model.Provider.Feature.HasFlag(ExportFeature.CanProjectAttributeCombinations)) {
@@ -71,7 +71,7 @@
@@ -110,7 +110,7 @@
@@ -123,7 +123,7 @@
@@ -145,7 +145,7 @@
@@ -158,7 +158,7 @@
@@ -171,7 +171,7 @@
From 6d1e4ad7a7e7f9e1c6cb5723b7c1d292c1e231ad Mon Sep 17 00:00:00 2001 From: Marcus Gesing Date: Mon, 9 Nov 2015 11:01:35 +0100 Subject: [PATCH 021/707] Fixed issues due to incomplete renaming --- .../FeedGoogleMerchantCenter/Configure.cshtml | 2 +- .../ProfileConfiguration.cshtml | 14 ++++++++------ 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/src/Plugins/SmartStore.GoogleMerchantCenter/Views/FeedGoogleMerchantCenter/Configure.cshtml b/src/Plugins/SmartStore.GoogleMerchantCenter/Views/FeedGoogleMerchantCenter/Configure.cshtml index 8d01b7baeb..6312648112 100644 --- a/src/Plugins/SmartStore.GoogleMerchantCenter/Views/FeedGoogleMerchantCenter/Configure.cshtml +++ b/src/Plugins/SmartStore.GoogleMerchantCenter/Views/FeedGoogleMerchantCenter/Configure.cshtml @@ -22,7 +22,7 @@ @Html.Raw(@T("Plugins.Feed.Froogle.AdminInstruction"))
- @Html.Action("InfoProfile", "Export", new { systemName = ProductExportXmlProvider.SystemName, returnUrl = Request.RawUrl, area = "admin" }) + @Html.Action("InfoProfile", "Export", new { systemName = GmcXmlExportProvider.SystemName, returnUrl = Request.RawUrl, area = "admin" })
diff --git a/src/Plugins/SmartStore.GoogleMerchantCenter/Views/FeedGoogleMerchantCenter/ProfileConfiguration.cshtml b/src/Plugins/SmartStore.GoogleMerchantCenter/Views/FeedGoogleMerchantCenter/ProfileConfiguration.cshtml index 57b1c7b693..edf7fecb7e 100644 --- a/src/Plugins/SmartStore.GoogleMerchantCenter/Views/FeedGoogleMerchantCenter/ProfileConfiguration.cshtml +++ b/src/Plugins/SmartStore.GoogleMerchantCenter/Views/FeedGoogleMerchantCenter/ProfileConfiguration.cshtml @@ -39,9 +39,10 @@ @Html.SmartLabelFor(m => m.Condition)
- @Html.DropDownList("Condition", new List { + @Html.DropDownList("Condition", new List + { new SelectListItem { Text = T("Common.Auto"), Value = "" }, - new SelectListItem { Text = T("Common.Unspecified"), Value = ProductExportXmlProvider.Unspecified }, + new SelectListItem { Text = T("Common.Unspecified"), Value = GmcXmlExportProvider.Unspecified }, new SelectListItem { Text = T("Plugins.Feed.Froogle.ConditionNew"), Value = "new" }, new SelectListItem { Text = T("Plugins.Feed.Froogle.ConditionUsed"), Value = "used" }, new SelectListItem { Text = T("Plugins.Feed.Froogle.ConditionRefurbished"), Value = "refurbished" } @@ -54,9 +55,10 @@ @Html.SmartLabelFor(m => m.Availability) - @Html.DropDownList("Availability", new List { + @Html.DropDownList("Availability", new List + { new SelectListItem { Text = T("Common.Auto"), Value = "" }, - new SelectListItem { Text = T("Common.Unspecified"), Value = ProductExportXmlProvider.Unspecified }, + new SelectListItem { Text = T("Common.Unspecified"), Value = GmcXmlExportProvider.Unspecified }, new SelectListItem { Text = T("Plugins.Feed.Froogle.AvailabilityInStock"), Value = "in stock" }, new SelectListItem { Text = T("Plugins.Feed.Froogle.AvailabilityOutOfStock"), Value = "out of stock" }, new SelectListItem { Text = T("Plugins.Feed.Froogle.AvailabilityPreorder"), Value = "preorder" } @@ -71,7 +73,7 @@ @Html.DropDownList("Gender", new List { new SelectListItem { Text = T("Common.Auto"), Value = "" }, - new SelectListItem { Text = T("Common.Unspecified"), Value = ProductExportXmlProvider.Unspecified }, + new SelectListItem { Text = T("Common.Unspecified"), Value = GmcXmlExportProvider.Unspecified }, new SelectListItem { Text = T("Plugins.Feed.Froogle.GenderMale"), Value = "male" }, new SelectListItem { Text = T("Plugins.Feed.Froogle.GenderFemale"), Value = "female" }, new SelectListItem { Text = T("Plugins.Feed.Froogle.GenderUnisex"), Value = "unisex" } @@ -86,7 +88,7 @@ @Html.DropDownList("AgeGroup", new List { new SelectListItem { Text = T("Common.Auto"), Value = "" }, - new SelectListItem { Text = T("Common.Unspecified"), Value = ProductExportXmlProvider.Unspecified }, + new SelectListItem { Text = T("Common.Unspecified"), Value = GmcXmlExportProvider.Unspecified }, new SelectListItem { Text = T("Plugins.Feed.Froogle.AgeGroupAdult"), Value = "adult" }, new SelectListItem { Text = T("Plugins.Feed.Froogle.AgeGroupKids"), Value = "kids" } }) From d75613c885bf853b4e647b0e3f9ce8cf1aaad01d Mon Sep 17 00:00:00 2001 From: Marcus Gesing Date: Mon, 9 Nov 2015 12:50:37 +0100 Subject: [PATCH 022/707] Improved pattern resolving of export file names --- .../201509021536425_ExportFramework1.cs | 4 +- .../201509150931528_ExportFramework2.cs | 5 ++ .../DataExchange/ExportExtensions.cs | 33 ++++++--- .../DataExchange/ExportProfileService.cs | 2 +- .../Controllers/ExportController.cs | 1 + .../Models/DataExchange/ExportProfileModel.cs | 1 + .../Views/Export/_Tab.Deployment.cshtml | 70 ++++++++++++++++++- 7 files changed, 103 insertions(+), 13 deletions(-) diff --git a/src/Libraries/SmartStore.Data/Migrations/201509021536425_ExportFramework1.cs b/src/Libraries/SmartStore.Data/Migrations/201509021536425_ExportFramework1.cs index d8e9b8ab9d..ed09b5e8d3 100644 --- a/src/Libraries/SmartStore.Data/Migrations/201509021536425_ExportFramework1.cs +++ b/src/Libraries/SmartStore.Data/Migrations/201509021536425_ExportFramework1.cs @@ -100,8 +100,8 @@ public void MigrateLocaleResources(LocaleResourcesBuilder builder) "Legt den Namen des Ordners fest, in den die Daten exportiert werden."); builder.AddOrUpdate("Admin.DataExchange.Export.FolderAndFileName.Validate", - "Please enter a valid folder and file name. Example for file names: %Misc.FileNumber%-%ExportProfile.Id%-gmc-%Store.Name%", - "Bitte einen gltigen Ordner- und Dateinamen eingeben. Beispiel fr Dateinamen: %Misc.FileNumber%-%ExportProfile.Id%-gmc-%Store.Name%"); + "Please enter a valid folder and file name. Example for file names: %File.Index%-%Profile.Id%-gmc-%Store.Name%", + "Bitte einen gltigen Ordner- und Dateinamen eingeben. Beispiel fr Dateinamen: %File.Index%-%Profile.Id%-gmc-%Store.Name%"); builder.AddOrUpdate("Admin.DataExchange.Export.Deployment.CreateZip", diff --git a/src/Libraries/SmartStore.Data/Migrations/201509150931528_ExportFramework2.cs b/src/Libraries/SmartStore.Data/Migrations/201509150931528_ExportFramework2.cs index 174f2d1f44..ccc5a52b37 100644 --- a/src/Libraries/SmartStore.Data/Migrations/201509150931528_ExportFramework2.cs +++ b/src/Libraries/SmartStore.Data/Migrations/201509150931528_ExportFramework2.cs @@ -41,6 +41,7 @@ public void MigrateLocaleResources(LocaleResourcesBuilder builder) builder.AddOrUpdate("Common.ShowAll", "Show all", "Alle anzeigen"); builder.AddOrUpdate("Admin.Common.Selected", "Selected", "Ausgewhlte"); builder.AddOrUpdate("Admin.Common.Entity", "Entity", "Entitt"); + builder.AddOrUpdate("Admin.Common.Placeholder", "Placeholder", "Platzhalter"); builder.AddOrUpdate("Admin.Common.FilesDeleted", @@ -108,6 +109,10 @@ public void MigrateLocaleResources(LocaleResourcesBuilder builder) "Pro Sprache darf nur ein aktiver SEO Name festgelegt werden."); + builder.AddOrUpdate("Admin.DataExchange.Export.FileNamePatternDescriptions", + "ID of export profil;Folder name of export profil;SEO name of export profil;Store ID;SEO name of store;One based file index;Random number;UTC timestamp", + "ID des Exportprofils;Ordername des Exportprofils;SEO Name des Exportprofils;Shop ID;SEO Name des Shops;Mit 1 beginnender Dateiindex;Zufallszahl;UTC Zeitstempel"); + builder.AddOrUpdate("Admin.DataExchange.Export.NotPreviewCompatible", "This option is not taken into account in the preview.", "Diese Option wird in der Vorschau nicht bercksichtigt."); diff --git a/src/Libraries/SmartStore.Services/DataExchange/ExportExtensions.cs b/src/Libraries/SmartStore.Services/DataExchange/ExportExtensions.cs index a7a8e5c5b9..8a0cdc959d 100644 --- a/src/Libraries/SmartStore.Services/DataExchange/ExportExtensions.cs +++ b/src/Libraries/SmartStore.Services/DataExchange/ExportExtensions.cs @@ -1,5 +1,7 @@ using System; +using System.Globalization; using System.IO; +using System.Text; using System.Web; using System.Web.Caching; using SmartStore.Core.Domain; @@ -64,18 +66,31 @@ public static string GetExportLogFilePath(this ExportProfile profile) /// /// Export profile /// Store - /// File number + /// One based file index /// The maximum length of the file name /// Resolved file name pattern - public static string ResolveFileNamePattern(this ExportProfile profile, Store store, int fileNumber, int maxFileNameLength) + public static string ResolveFileNamePattern(this ExportProfile profile, Store store, int fileIndex, int maxFileNameLength) { - var result = profile.FileNamePattern - .Replace("%ExportProfile.Id%", profile.Id.ToString()) - .Replace("%ExportProfile.SeoName%", SeoHelper.GetSeName(profile.Name, true, false).Replace("/", "").Replace("-", "")) - .Replace("%ExportProfile.FolderName%", profile.FolderName) - .Replace("%Store.Id%", store.Id.ToString()) - .Replace("%Store.SeoName%", profile.PerStore ? SeoHelper.GetSeName(store.Name, true, false) : "allstores") - .Replace("%Misc.FileNumber%", fileNumber.ToString("D4")) + var sb = new StringBuilder(profile.FileNamePattern); + + sb.Replace("%Profile.Id%", profile.Id.ToString()); + sb.Replace("%Profile.FolderName%", profile.FolderName); + sb.Replace("%Store.Id%", store.Id.ToString()); + sb.Replace("%File.Index%", fileIndex.ToString("D4")); + + if (profile.FileNamePattern.Contains("%Profile.SeoName%")) + sb.Replace("%Profile.SeoName%", SeoHelper.GetSeName(profile.Name, true, false).Replace("/", "").Replace("-", "")); + + if (profile.FileNamePattern.Contains("%Store.SeoName%")) + sb.Replace("%Store.SeoName%", profile.PerStore ? SeoHelper.GetSeName(store.Name, true, false) : "allstores"); + + if (profile.FileNamePattern.Contains("%Random.Number%")) + sb.Replace("%Random.Number%", CommonHelper.GenerateRandomInteger().ToString()); + + if (profile.FileNamePattern.Contains("%Timestamp%")) + sb.Replace("%Timestamp%", DateTime.UtcNow.ToString("s", CultureInfo.InvariantCulture)); + + var result = sb.ToString() .ToValidFileName("") .Truncate(maxFileNameLength); diff --git a/src/Libraries/SmartStore.Services/DataExchange/ExportProfileService.cs b/src/Libraries/SmartStore.Services/DataExchange/ExportProfileService.cs index 95302de285..465b97a3c2 100644 --- a/src/Libraries/SmartStore.Services/DataExchange/ExportProfileService.cs +++ b/src/Libraries/SmartStore.Services/DataExchange/ExportProfileService.cs @@ -18,7 +18,7 @@ namespace SmartStore.Services.DataExchange { public partial class ExportProfileService : IExportProfileService { - private const string _defaultFileNamePattern = "%Store.Id%-%ExportProfile.Id%-%Misc.FileNumber%-%ExportProfile.SeoName%"; + private const string _defaultFileNamePattern = "%Store.Id%-%Profile.Id%-%File.Index%-%Profile.SeoName%"; private readonly IRepository _exportProfileRepository; private readonly IRepository _exportDeploymentRepository; diff --git a/src/Presentation/SmartStore.Web/Administration/Controllers/ExportController.cs b/src/Presentation/SmartStore.Web/Administration/Controllers/ExportController.cs index 8690b4507c..0aa83791c2 100644 --- a/src/Presentation/SmartStore.Web/Administration/Controllers/ExportController.cs +++ b/src/Presentation/SmartStore.Web/Administration/Controllers/ExportController.cs @@ -113,6 +113,7 @@ private void PrepareProfileModel(ExportProfileModel model, ExportProfile profile model.IsTaskEnabled = profile.ScheduleTask.Enabled; model.LogFileExists = System.IO.File.Exists(profile.GetExportLogFilePath()); model.HasActiveProvider = (provider != null); + model.FileNamePatternDescriptions = T("Admin.DataExchange.Export.FileNamePatternDescriptions").Text.SplitSafe(";"); model.Provider = new ExportProfileModel.ProviderModel(); model.Provider.ThumbnailUrl = GetThumbnailUrl(provider); diff --git a/src/Presentation/SmartStore.Web/Administration/Models/DataExchange/ExportProfileModel.cs b/src/Presentation/SmartStore.Web/Administration/Models/DataExchange/ExportProfileModel.cs index ee44a44113..a863d55d3f 100644 --- a/src/Presentation/SmartStore.Web/Administration/Models/DataExchange/ExportProfileModel.cs +++ b/src/Presentation/SmartStore.Web/Administration/Models/DataExchange/ExportProfileModel.cs @@ -19,6 +19,7 @@ public partial class ExportProfileModel : EntityModelBase public string UnspecifiedString { get; set; } public bool LogFileExists { get; set; } public bool HasActiveProvider { get; set; } + public string[] FileNamePatternDescriptions { get; set; } [SmartResourceDisplayName("Admin.DataExchange.Export.Name")] public string Name { get; set; } diff --git a/src/Presentation/SmartStore.Web/Administration/Views/Export/_Tab.Deployment.cshtml b/src/Presentation/SmartStore.Web/Administration/Views/Export/_Tab.Deployment.cshtml index 3e8d295898..17bfd46a84 100644 --- a/src/Presentation/SmartStore.Web/Administration/Views/Export/_Tab.Deployment.cshtml +++ b/src/Presentation/SmartStore.Web/Administration/Views/Export/_Tab.Deployment.cshtml @@ -23,6 +23,16 @@ @Html.TextBoxFor(x => x.FileNamePattern, new { @class = "input-large" }) @Html.ValidationMessageFor(x => x.FileNamePattern) + +
+
+ @T("Admin.Common.Show")... +
+ @FileNamePatternDescription() +
+
+ +
@@ -71,7 +71,7 @@
@@ -110,7 +110,7 @@
@@ -123,7 +123,7 @@
@@ -145,7 +145,7 @@
@@ -158,7 +158,7 @@
@@ -171,7 +171,7 @@
From c951a1d29ae8f9521365078a6b98dd073dbc0f86 Mon Sep 17 00:00:00 2001 From: Marcus Gesing Date: Wed, 11 Nov 2015 12:55:53 +0100 Subject: [PATCH 037/707] Further IDataExporter implementation --- .../DataExchange/IDataExporter.cs | 29 +- .../DataExchange/Internal/DataExportTask.cs | 12 +- .../DataExchange/Internal/DataExporter.cs | 917 +++++++++++++++++- .../Internal/DataExporterContext.cs | 218 +++++ .../Internal/DynamicEntityHelper.cs | 130 +-- .../SmartStore.Services.csproj | 1 + 6 files changed, 1191 insertions(+), 116 deletions(-) create mode 100644 src/Libraries/SmartStore.Services/DataExchange/Internal/DataExporterContext.cs diff --git a/src/Libraries/SmartStore.Services/DataExchange/IDataExporter.cs b/src/Libraries/SmartStore.Services/DataExchange/IDataExporter.cs index 82820238d8..4a96e5c515 100644 --- a/src/Libraries/SmartStore.Services/DataExchange/IDataExporter.cs +++ b/src/Libraries/SmartStore.Services/DataExchange/IDataExporter.cs @@ -6,7 +6,8 @@ namespace SmartStore.Services.DataExchange { - public delegate void ProgressSetter(int value, int maximum, string message); + public delegate void ProgressValueSetter(int value, int maximum, string message); + public delegate void ProgressMessageSetter(string message); public interface IDataExporter { @@ -23,24 +24,31 @@ public interface IDataExporter public class DataExportRequest { - private readonly static ProgressSetter _voidProgressSetter = DataExportRequest.SetProgress; + private readonly static ProgressValueSetter _voidProgressValueSetter = DataExportRequest.SetProgress; + private readonly static ProgressMessageSetter _voidProgressMessageSetter = DataExportRequest.SetProgress; - public DataExportRequest(ExportProfile profile) + public DataExportRequest(ExportProfile profile, Provider provider) { Guard.ArgumentNotNull(() => profile); + Guard.ArgumentNotNull(() => provider); - CustomData = new Dictionary(StringComparer.OrdinalIgnoreCase); - ProgressSetter = _voidProgressSetter; Profile = profile; - } + Provider = provider; + + ProgressValueSetter = _voidProgressValueSetter; + ProgressMessageSetter = _voidProgressMessageSetter; + + CustomData = new Dictionary(StringComparer.OrdinalIgnoreCase); + } public ExportProfile Profile { get; private set; } - public Provider Provider { get; set; } + public Provider Provider { get; private set; } public IEnumerable EntitiesToExport { get; set; } - public ProgressSetter ProgressSetter { get; set; } + public ProgressValueSetter ProgressValueSetter { get; set; } + public ProgressMessageSetter ProgressMessageSetter { get; set; } public IDictionary CustomData { get; private set; } @@ -49,5 +57,10 @@ private static void SetProgress(int val, int max, string msg) { // do nothing } + + private static void SetProgress(string msg) + { + // do nothing + } } } diff --git a/src/Libraries/SmartStore.Services/DataExchange/Internal/DataExportTask.cs b/src/Libraries/SmartStore.Services/DataExchange/Internal/DataExportTask.cs index ea3c676587..b1e3d31f54 100644 --- a/src/Libraries/SmartStore.Services/DataExchange/Internal/DataExportTask.cs +++ b/src/Libraries/SmartStore.Services/DataExchange/Internal/DataExportTask.cs @@ -37,10 +37,16 @@ public void Execute(TaskExecutionContext ctx) throw new SmartException(T("Admin.Common.ProviderNotLoaded", profile.ProviderSystemName.NaIfEmpty())); // build export request - var request = new DataExportRequest(profile); - request.ProgressSetter = delegate(int val, int max, string msg) + var request = new DataExportRequest(profile, provider); + + request.ProgressValueSetter = delegate(int val, int max, string msg) + { + ctx.SetProgress(val, max, msg, true); + }; + + request.ProgressMessageSetter = delegate(string msg) { - ctx.SetProgress(val, max, msg); + ctx.SetProgress(null, msg, true); }; if (selectedEntityIds.HasValue()) diff --git a/src/Libraries/SmartStore.Services/DataExchange/Internal/DataExporter.cs b/src/Libraries/SmartStore.Services/DataExchange/Internal/DataExporter.cs index c0c44e0304..391b210db6 100644 --- a/src/Libraries/SmartStore.Services/DataExchange/Internal/DataExporter.cs +++ b/src/Libraries/SmartStore.Services/DataExchange/Internal/DataExporter.cs @@ -1,21 +1,38 @@ using System; using System.Collections.Generic; +using System.IO; +using System.IO.Compression; using System.Linq; +using System.Text; using System.Threading; using System.Web; +using SmartStore.Core; +using SmartStore.Core.Data; using SmartStore.Core.Domain.Catalog; +using SmartStore.Core.Domain.Customers; using SmartStore.Core.Domain.DataExchange; using SmartStore.Core.Domain.Media; using SmartStore.Core.Domain.Messages; +using SmartStore.Core.Domain.Orders; +using SmartStore.Core.Domain.Stores; +using SmartStore.Core.Email; using SmartStore.Core.Localization; +using SmartStore.Core.Logging; using SmartStore.Services.Catalog; +using SmartStore.Services.Common; +using SmartStore.Services.Customers; using SmartStore.Services.Directory; using SmartStore.Services.Helpers; using SmartStore.Services.Localization; using SmartStore.Services.Media; +using SmartStore.Services.Messages; +using SmartStore.Services.Orders; using SmartStore.Services.Seo; +using SmartStore.Services.Shipping; using SmartStore.Services.Tasks; using SmartStore.Services.Tax; +using SmartStore.Utilities; +using SmartStore.Utilities.Threading; namespace SmartStore.Services.DataExchange.Internal { @@ -23,57 +40,121 @@ public partial class DataExporter : IDataExporter { private static readonly ReaderWriterLockSlim _rwLock = new ReaderWriterLockSlim(); + #region Dependencies + private readonly ICommonServices _services; - private readonly IUrlRecordService _urlRecordService; - private readonly ILocalizedEntityService _localizedEntityService; - private readonly IPictureService _pictureService; - private readonly IPriceCalculationService _priceCalculationService; - private readonly ICurrencyService _currencyService; - private readonly ITaxService _taxService; - private readonly IPriceFormatter _priceFormatter; - private readonly ICategoryService _categoryService; - private readonly IProductAttributeParser _productAttributeParser; - private readonly IProductService _productService; - private readonly IDateTimeHelper _dateTimeHelper; - - private MediaSettings _mediaSettings; + private readonly Lazy _priceFormatter; + private readonly Lazy _dateTimeHelper; + private readonly Lazy _exportProfileService; + private readonly Lazy _localizedEntityService; + private readonly Lazy _languageService; + private readonly Lazy _urlRecordService; + private readonly Lazy _pictureService; + private readonly Lazy _priceCalculationService; + private readonly Lazy _currencyService; + private readonly Lazy _taxService; + private readonly Lazy _categoryService; + private readonly Lazy _productAttributeParser; + private readonly Lazy _productAttributeService; + private readonly Lazy _productTemplateService; + private readonly Lazy _productService; + private readonly Lazy _orderService; + private readonly Lazy _manufacturerService; + private readonly Lazy _customerService; + private readonly Lazy _addressService; + private readonly Lazy _countryService; + private readonly Lazy _shipmentService; + private readonly Lazy _genericAttributeService; + private readonly Lazy _emailAccountService; + private readonly Lazy _emailSender; + private readonly Lazy _deliveryTimeService; + private readonly Lazy _quantityUnitService; + + private readonly Lazy>_customerRepository; + private readonly Lazy> _subscriptionRepository; + + private Lazy _dataExchangeSettings; + private Lazy _mediaSettings; public DataExporter( ICommonServices services, - IUrlRecordService urlRecordService, - ILocalizedEntityService localizedEntityService, - IPictureService pictureService, - IPriceCalculationService priceCalculationService, - ICurrencyService currencyService, - ITaxService taxService, - IPriceFormatter priceFormatter, - ICategoryService categoryService, - IProductAttributeParser productAttributeParser, - IProductService productService, - IDateTimeHelper dateTimeHelper, - MediaSettings mediaSettings) + Lazy priceFormatter, + Lazy dateTimeHelper, + Lazy exportProfileService, + Lazy localizedEntityService, + Lazy languageService, + Lazy urlRecordService, + Lazy pictureService, + Lazy priceCalculationService, + Lazy currencyService, + Lazy taxService, + Lazy categoryService, + Lazy productAttributeParser, + Lazy productAttributeService, + Lazy productTemplateService, + Lazy productService, + Lazy orderService, + Lazy manufacturerService, + Lazy customerService, + Lazy addressService, + Lazy countryService, + Lazy shipmentService, + Lazy genericAttributeService, + Lazy emailAccountService, + Lazy emailSender, + Lazy deliveryTimeService, + Lazy quantityUnitService, + Lazy> customerRepository, + Lazy> subscriptionRepository, + Lazy dataExchangeSettings, + Lazy mediaSettings) { + _priceFormatter = priceFormatter; + _dateTimeHelper = dateTimeHelper; _services = services; - _urlRecordService = urlRecordService; + _exportProfileService = exportProfileService; _localizedEntityService = localizedEntityService; + _languageService = languageService; + _urlRecordService = urlRecordService; _pictureService = pictureService; _priceCalculationService = priceCalculationService; _currencyService = currencyService; _taxService = taxService; - _priceFormatter = priceFormatter; _categoryService = categoryService; _productAttributeParser = productAttributeParser; + _productAttributeService = productAttributeService; + _productTemplateService = productTemplateService; _productService = productService; - _dateTimeHelper = dateTimeHelper; + _orderService = orderService; + _manufacturerService = manufacturerService; + _customerService = customerService; + _addressService = addressService; + _countryService = countryService; + _shipmentService = shipmentService; + _genericAttributeService = genericAttributeService; + _emailAccountService = emailAccountService; + _emailSender = emailSender; + _deliveryTimeService = deliveryTimeService; + _quantityUnitService = quantityUnitService; + _customerRepository = customerRepository; + _subscriptionRepository = subscriptionRepository; + + _dataExchangeSettings = dataExchangeSettings; _mediaSettings = mediaSettings; + + T = NullLocalizer.Instance; } + public Localizer T { get; set; } + + #endregion + #region Utilities - private void SetProgress(DataExportTaskContext ctx, int loadedRecords) + private void SetProgress(DataExporterContext ctx, int loadedRecords) { - if (!ctx.IsPreview && ctx.TaskContext.ScheduleTask != null && loadedRecords > 0) + if (!ctx.IsPreview && loadedRecords > 0) { int totalRecords = ctx.RecordsPerStore.Sum(x => x.Value); @@ -84,23 +165,219 @@ private void SetProgress(DataExportTaskContext ctx, int loadedRecords) var msg = ctx.ProgressInfo.FormatInvariant(ctx.RecordCount, totalRecords); - ctx.TaskContext.SetProgress(ctx.RecordCount, totalRecords, msg, true); + ctx.Request.ProgressValueSetter.Invoke(ctx.RecordCount, totalRecords, msg); + } + } + + private void SetProgress(DataExporterContext ctx, string message) + { + if (!ctx.IsPreview && message.HasValue()) + { + ctx.Request.ProgressMessageSetter.Invoke(message); } } - private void SetProgress(DataExportTaskContext ctx, string message) + private IExportDataSegmenterProvider CreateSegmenter(DataExporterContext ctx, int pageIndex = 0) { - if (!ctx.IsPreview && ctx.TaskContext.ScheduleTask != null && message.HasValue()) + var offset = ctx.Profile.Offset + (pageIndex * PageSize); + + var limit = (ctx.IsPreview ? PageSize : ctx.Profile.Limit); + + var recordsPerSegment = (ctx.IsPreview ? 0 : ctx.Profile.BatchSize); + + var totalCount = ctx.Profile.Offset + ctx.RecordsPerStore.First(x => x.Key == ctx.Store.Id).Value; + + switch (ctx.Provider.Value.EntityType) { - ctx.TaskContext.SetProgress(null, message, true); + case ExportEntityType.Product: + ctx.ExecuteContext.Segmenter = new ExportDataSegmenter + ( + skip => GetProducts(ctx, skip), + entities => + { + // load data behind navigation properties for current queue in one go + ctx.ProductExportContext = new ProductExportContext(entities, + x => _productAttributeService.Value.GetProductVariantAttributesByProductIds(x, null), + x => _productAttributeService.Value.GetProductVariantAttributeCombinations(x), + x => _productService.Value.GetTierPricesByProductIds(x, (ctx.Projection.CurrencyId ?? 0) != 0 ? ctx.ContextCustomer : null, ctx.Store.Id), + x => _categoryService.Value.GetProductCategoriesByProductIds(x), + x => _manufacturerService.Value.GetProductManufacturersByProductIds(x), + x => _productService.Value.GetProductPicturesByProductIds(x), + x => _productService.Value.GetProductTagsByProductIds(x), + x => _productService.Value.GetAppliedDiscountsByProductIds(x), + x => _productService.Value.GetProductSpecificationAttributesByProductIds(x), + x => _productService.Value.GetBundleItemsByProductIds(x, true) + ); + }, + entity => Convert(ctx, entity), + offset, PageSize, limit, recordsPerSegment, totalCount + ); + break; + + case ExportEntityType.Order: + ctx.ExecuteContext.Segmenter = new ExportDataSegmenter + ( + skip => GetOrders(ctx, skip), + entities => + { + ctx.OrderExportContext = new OrderExportContext(entities, + x => _customerService.Value.GetCustomersByIds(x), + x => _customerService.Value.GetRewardPointsHistoriesByCustomerIds(x), + x => _addressService.Value.GetAddressByIds(x), + x => _orderService.Value.GetOrderItemsByOrderIds(x), + x => _shipmentService.Value.GetShipmentsByOrderIds(x) + ); + }, + entity => Convert(ctx, entity), + offset, PageSize, limit, recordsPerSegment, totalCount + ); + break; + + case ExportEntityType.Manufacturer: + ctx.ExecuteContext.Segmenter = new ExportDataSegmenter + ( + skip => GetManufacturers(ctx, skip), + entities => + { + ctx.ManufacturerExportContext = new ManufacturerExportContext(entities, + x => _manufacturerService.Value.GetProductManufacturersByManufacturerIds(x), + x => _pictureService.Value.GetPicturesByIds(x) + ); + }, + entity => Convert(ctx, entity), + offset, PageSize, limit, recordsPerSegment, totalCount + ); + break; + + case ExportEntityType.Category: + ctx.ExecuteContext.Segmenter = new ExportDataSegmenter + ( + skip => GetCategories(ctx, skip), + entities => + { + ctx.CategoryExportContext = new CategoryExportContext(entities, + x => _categoryService.Value.GetProductCategoriesByCategoryIds(x), + x => _pictureService.Value.GetPicturesByIds(x) + ); + }, + entity => Convert(ctx, entity), + offset, PageSize, limit, recordsPerSegment, totalCount + ); + break; + + case ExportEntityType.Customer: + ctx.ExecuteContext.Segmenter = new ExportDataSegmenter + ( + skip => GetCustomers(ctx, skip), + entities => + { + ctx.CustomerExportContext = new CustomerExportContext(entities, + x => _genericAttributeService.Value.GetAttributesForEntity(x, "Customer") + ); + }, + entity => Convert(ctx, entity), + offset, PageSize, limit, recordsPerSegment, totalCount + ); + break; + + case ExportEntityType.NewsLetterSubscription: + ctx.ExecuteContext.Segmenter = new ExportDataSegmenter + ( + skip => GetNewsLetterSubscriptions(ctx, skip), + null, + entity => Convert(ctx, entity), + offset, PageSize, limit, recordsPerSegment, totalCount + ); + break; + + default: + ctx.ExecuteContext.Segmenter = null; + break; } + + return ctx.ExecuteContext.Segmenter as IExportDataSegmenterProvider; + } + + private bool CallProvider(DataExporterContext ctx, string streamId, string method, string path) + { + if (method != "Execute" && method != "OnExecuted") + throw new SmartException("Unknown export method {0}".FormatInvariant(method.NaIfEmpty())); + + try + { + ctx.ExecuteContext.DataStreamId = streamId; + + using (ctx.ExecuteContext.DataStream = new MemoryStream()) + { + if (method == "Execute") + { + ctx.Provider.Value.Execute(ctx.ExecuteContext); + } + else if (method == "OnExecuted") + { + ctx.Provider.Value.OnExecuted(ctx.ExecuteContext); + } + + if (ctx.IsFileBasedExport && path.HasValue()) + { + if (!ctx.ExecuteContext.DataStream.CanSeek) + ctx.Log.Warning("Data stream seems to be closed!"); + + ctx.ExecuteContext.DataStream.Seek(0, SeekOrigin.Begin); + + using (_rwLock.GetWriteLock()) + using (var fileStream = new FileStream(path, FileMode.Create, FileAccess.Write, FileShare.ReadWrite)) + { + ctx.Log.Information("Creating file " + path); + + ctx.ExecuteContext.DataStream.CopyTo(fileStream); + } + } + } + } + catch (Exception exc) + { + ctx.ExecuteContext.Abort = ExportAbortion.Hard; + ctx.Log.Error("The provider failed at the {0} method: {1}".FormatInvariant(method, exc.ToAllMessages()), exc); + ctx.Result.LastError = exc.ToString(); + } + finally + { + if (ctx.ExecuteContext.DataStream != null) + { + ctx.ExecuteContext.DataStream.Dispose(); + ctx.ExecuteContext.DataStream = null; + } + } + + return (ctx.ExecuteContext.Abort != ExportAbortion.Hard); + } + + private void SendCompletionEmail(DataExporterContext ctx) + { + var emailAccount = _emailAccountService.Value.GetEmailAccountById(ctx.Profile.EmailAccountId); + var smtpContext = new SmtpContext(emailAccount); + var message = new EmailMessage(); + + var storeInfo = "{0} ({1})".FormatInvariant(ctx.Store.Name, ctx.Store.Url); + + message.To.AddRange(ctx.Profile.CompletedEmailAddresses.SplitSafe(",").Where(x => x.IsEmail()).Select(x => new EmailAddress(x))); + message.From = new EmailAddress(emailAccount.Email, emailAccount.DisplayName); + + message.Subject = _services.Localization.GetResource("Admin.DataExchange.Export.CompletedEmail.Subject", ctx.Projection.LanguageId ?? 0) + .FormatInvariant(ctx.Profile.Name); + + message.Body = _services.Localization.GetResource("Admin.DataExchange.Export.CompletedEmail.Body", ctx.Projection.LanguageId ?? 0) + .FormatInvariant(storeInfo); + + _emailSender.Value.SendEmail(smtpContext, message); } #endregion #region Getting data - private IQueryable GetProductQuery(DataExportTaskContext ctx, int skip, int take) + private IQueryable GetProductQuery(DataExporterContext ctx, int skip, int take) { IQueryable query = null; @@ -134,12 +411,12 @@ private IQueryable GetProductQuery(DataExportTaskContext ctx, int skip, searchContext.CategoryIds = ctx.Filter.CategoryIds.ToList(); if (ctx.Filter.CreatedFrom.HasValue) - searchContext.CreatedFromUtc = _dateTimeHelper.ConvertToUtcTime(ctx.Filter.CreatedFrom.Value, _dateTimeHelper.CurrentTimeZone); + searchContext.CreatedFromUtc = _dateTimeHelper.Value.ConvertToUtcTime(ctx.Filter.CreatedFrom.Value, _dateTimeHelper.Value.CurrentTimeZone); if (ctx.Filter.CreatedTo.HasValue) - searchContext.CreatedToUtc = _dateTimeHelper.ConvertToUtcTime(ctx.Filter.CreatedTo.Value, _dateTimeHelper.CurrentTimeZone); + searchContext.CreatedToUtc = _dateTimeHelper.Value.ConvertToUtcTime(ctx.Filter.CreatedTo.Value, _dateTimeHelper.Value.CurrentTimeZone); - query = _productService.PrepareProductSearchQuery(searchContext); + query = _productService.Value.PrepareProductSearchQuery(searchContext); query = query.OrderByDescending(x => x.CreatedOnUtc); } @@ -157,7 +434,7 @@ private IQueryable GetProductQuery(DataExportTaskContext ctx, int skip, return query; } - private List GetProducts(DataExportTaskContext ctx, int skip) + private List GetProducts(DataExporterContext ctx, int skip) { var result = new List(); @@ -182,7 +459,7 @@ private List GetProducts(DataExportTaskContext ctx, int skip) ParentGroupedProductId = product.Id }; - foreach (var associatedProduct in _productService.SearchProducts(associatedSearchContext)) + foreach (var associatedProduct in _productService.Value.SearchProducts(associatedSearchContext)) { result.Add(associatedProduct); } @@ -205,8 +482,568 @@ private List GetProducts(DataExportTaskContext ctx, int skip) return result; } + private IQueryable GetOrderQuery(DataExporterContext ctx, int skip, int take) + { + var query = _orderService.Value.GetOrders( + ctx.Profile.PerStore ? ctx.Store.Id : ctx.Filter.StoreId, + ctx.Projection.CustomerId ?? 0, + ctx.Filter.CreatedFrom.HasValue ? (DateTime?)_dateTimeHelper.Value.ConvertToUtcTime(ctx.Filter.CreatedFrom.Value, _dateTimeHelper.Value.CurrentTimeZone) : null, + ctx.Filter.CreatedTo.HasValue ? (DateTime?)_dateTimeHelper.Value.ConvertToUtcTime(ctx.Filter.CreatedTo.Value, _dateTimeHelper.Value.CurrentTimeZone) : null, + ctx.Filter.OrderStatusIds, + ctx.Filter.PaymentStatusIds, + ctx.Filter.ShippingStatusIds, + null, + null, + null); + + if (ctx.EntityIdsSelected.Count > 0) + query = query.Where(x => ctx.EntityIdsSelected.Contains(x.Id)); + + query = query.OrderByDescending(x => x.CreatedOnUtc); + + if (skip > 0) + query = query.Skip(skip); + + if (take != int.MaxValue) + query = query.Take(take); + + return query; + } + + private List GetOrders(DataExporterContext ctx, int skip) + { + var orders = GetOrderQuery(ctx, skip, PageSize).ToList(); + + if (ctx.Projection.OrderStatusChange != ExportOrderStatusChange.None) + { + ctx.EntityIdsLoaded = ctx.EntityIdsLoaded + .Union(orders.Select(x => x.Id)) + .Distinct() + .ToList(); + } + + try + { + SetProgress(ctx, orders.Count); + + _services.DbContext.DetachEntities(orders); + } + catch { } + + return orders; + } + + private IQueryable GetManufacturerQuery(DataExporterContext ctx, int skip, int take) + { + var showHidden = !ctx.Filter.IsPublished.HasValue; + var storeId = (ctx.Profile.PerStore ? ctx.Store.Id : ctx.Filter.StoreId); + + var query = _manufacturerService.Value.GetManufacturers(showHidden, storeId); + + query = query.OrderBy(x => x.DisplayOrder); + + if (skip > 0) + query = query.Skip(skip); + + if (take != int.MaxValue) + query = query.Take(take); + + return query; + } + + private List GetManufacturers(DataExporterContext ctx, int skip) + { + var manus = GetManufacturerQuery(ctx, skip, PageSize).ToList(); + + try + { + SetProgress(ctx, manus.Count); + + _services.DbContext.DetachEntities(manus); + } + catch { } + + return manus; + } + + private IQueryable GetCategoryQuery(DataExporterContext ctx, int skip, int take) + { + var showHidden = !ctx.Filter.IsPublished.HasValue; + var storeId = (ctx.Profile.PerStore ? ctx.Store.Id : ctx.Filter.StoreId); + + var query = _categoryService.Value.GetCategories(null, showHidden, null, true, storeId); + + query = query + .OrderBy(x => x.ParentCategoryId) + .ThenBy(x => x.DisplayOrder); + + if (skip > 0) + query = query.Skip(skip); + + if (take != int.MaxValue) + query = query.Take(take); + + return query; + } + + private List GetCategories(DataExporterContext ctx, int skip) + { + var categories = GetCategoryQuery(ctx, skip, PageSize).ToList(); + + try + { + SetProgress(ctx, categories.Count); + + _services.DbContext.DetachEntities(categories); + } + catch { } + + return categories; + } + + private IQueryable GetCustomerQuery(DataExporterContext ctx, int skip, int take) + { + var query = _customerRepository.Value.TableUntracked + .Expand(x => x.BillingAddress) + .Expand(x => x.ShippingAddress) + .Expand(x => x.Addresses.Select(y => y.Country)) + .Expand(x => x.Addresses.Select(y => y.StateProvince)) + .Expand(x => x.CustomerRoles) + .Where(x => !x.Deleted); + + if (ctx.EntityIdsSelected.Count > 0) + { + query = query.Where(x => ctx.EntityIdsSelected.Contains(x.Id)); + } + + query = query.OrderByDescending(x => x.CreatedOnUtc); + + if (skip > 0) + query = query.Skip(skip); + + if (take != int.MaxValue) + query = query.Take(take); + + return query; + } + + private List GetCustomers(DataExporterContext ctx, int skip) + { + var customers = GetCustomerQuery(ctx, skip, PageSize).ToList(); + + try + { + SetProgress(ctx, customers.Count); + + _services.DbContext.DetachEntities(customers); + } + catch { } + + return customers; + } + + private IQueryable GetNewsLetterSubscriptionQuery(DataExporterContext ctx, int skip, int take) + { + var storeId = (ctx.Profile.PerStore ? ctx.Store.Id : ctx.Filter.StoreId); + + var query = _subscriptionRepository.Value.TableUntracked; + + if (storeId > 0) + { + query = query.Where(x => x.StoreId == storeId); + } + + query = query + .OrderBy(x => x.StoreId) + .ThenBy(x => x.Email); + + if (skip > 0) + query = query.Skip(skip); + + if (take != int.MaxValue) + query = query.Take(take); + + return query; + } + + private List GetNewsLetterSubscriptions(DataExporterContext ctx, int skip) + { + var subscriptions = GetNewsLetterSubscriptionQuery(ctx, skip, PageSize).ToList(); + + try + { + SetProgress(ctx, subscriptions.Count); + + _services.DbContext.DetachEntities(subscriptions); + } + catch { } + + return subscriptions; + } + #endregion + private List Init(DataExporterContext ctx, int? totalRecords = null) + { + // Init base things that are even required for preview. Init all other things (regular export) in ExportCoreOuter. + List result = null; + + if (ctx.Projection.CurrencyId.HasValue) + ctx.ContextCurrency = _currencyService.Value.GetCurrencyById(ctx.Projection.CurrencyId.Value); + else + ctx.ContextCurrency = _services.WorkContext.WorkingCurrency; + + if (ctx.Projection.CustomerId.HasValue) + ctx.ContextCustomer = _customerService.Value.GetCustomerById(ctx.Projection.CustomerId.Value); + else + ctx.ContextCustomer = _services.WorkContext.CurrentCustomer; + + if (ctx.Projection.LanguageId.HasValue) + ctx.ContextLanguage = _languageService.Value.GetLanguageById(ctx.Projection.LanguageId.Value); + else + ctx.ContextLanguage = _services.WorkContext.WorkingLanguage; + + ctx.Stores = _services.StoreService.GetAllStores().ToDictionary(x => x.Id, x => x); + ctx.Languages = _languageService.Value.GetAllLanguages(true).ToDictionary(x => x.Id, x => x); + + if (!ctx.IsPreview && ctx.Profile.PerStore) + { + result = new List(ctx.Stores.Values.Where(x => x.Id == ctx.Filter.StoreId || ctx.Filter.StoreId == 0)); + } + else + { + int? storeId = (ctx.Filter.StoreId == 0 ? ctx.Projection.StoreId : ctx.Filter.StoreId); + + ctx.Store = ctx.Stores.Values.FirstOrDefault(x => x.Id == (storeId ?? _services.StoreContext.CurrentStore.Id)); + + result = new List { ctx.Store }; + } + + // get total records for progress + foreach (var store in result) + { + ctx.Store = store; + + int totalCount = 0; + + if (totalRecords.HasValue) + { + totalCount = totalRecords.Value; // speed up preview by not counting total at each page + } + else + { + switch (ctx.Provider.Value.EntityType) + { + case ExportEntityType.Product: + totalCount = GetProductQuery(ctx, ctx.Profile.Offset, int.MaxValue).Count(); + break; + case ExportEntityType.Order: + totalCount = GetOrderQuery(ctx, ctx.Profile.Offset, int.MaxValue).Count(); + break; + case ExportEntityType.Manufacturer: + totalCount = GetManufacturerQuery(ctx, ctx.Profile.Offset, int.MaxValue).Count(); + break; + case ExportEntityType.Category: + totalCount = GetCategoryQuery(ctx, ctx.Profile.Offset, int.MaxValue).Count(); + break; + case ExportEntityType.Customer: + totalCount = GetCustomerQuery(ctx, ctx.Profile.Offset, int.MaxValue).Count(); + break; + case ExportEntityType.NewsLetterSubscription: + totalCount = GetNewsLetterSubscriptionQuery(ctx, ctx.Profile.Offset, int.MaxValue).Count(); + break; + } + } + + ctx.RecordsPerStore.Add(store.Id, totalCount); + } + + return result; + } + + private void ExportCoreInner(DataExporterContext ctx, Store store) + { + if (ctx.ExecuteContext.Abort != ExportAbortion.None) + return; + + int fileIndex = 0; + + ctx.Store = store; + + { + var logHead = new StringBuilder(); + logHead.AppendLine(); + logHead.AppendLine(new string('-', 40)); + logHead.AppendLine("SmartStore.NET:\t\tv." + SmartStoreVersion.CurrentFullVersion); + logHead.Append("Export profile:\t\t" + ctx.Profile.Name); + logHead.AppendLine(ctx.Profile.Id == 0 ? " (volatile)" : " (Id {0})".FormatInvariant(ctx.Profile.Id)); + + logHead.AppendLine("Export provider:\t{0} ({1})".FormatInvariant(ctx.Provider.Metadata.FriendlyName, ctx.Profile.ProviderSystemName)); + + var plugin = ctx.Provider.Metadata.PluginDescriptor; + logHead.Append("Plugin:\t\t\t\t"); + logHead.AppendLine(plugin == null ? "".NaIfEmpty() : "{0} ({1}) v.{2}".FormatInvariant(plugin.FriendlyName, plugin.SystemName, plugin.Version.ToString())); + + logHead.AppendLine("Entity:\t\t\t\t" + ctx.Provider.Value.EntityType.ToString()); + + var storeInfo = (ctx.Profile.PerStore ? "{0} (Id {1})".FormatInvariant(ctx.Store.Name, ctx.Store.Id) : "All stores"); + logHead.Append("Store:\t\t\t\t" + storeInfo); + + ctx.Log.Information(logHead.ToString()); + } + + ctx.ExecuteContext.Store = ToDynamic(ctx, ctx.Store); + + ctx.ExecuteContext.MaxFileNameLength = _dataExchangeSettings.Value.MaxFileNameLength; + + ctx.ExecuteContext.HasPublicDeployment = ctx.Profile.Deployments.Any(x => x.IsPublic && x.DeploymentType == ExportDeploymentType.FileSystem); + + ctx.ExecuteContext.PublicFolderPath = (ctx.ExecuteContext.HasPublicDeployment ? Path.Combine(HttpRuntime.AppDomainAppPath, PublicFolder) : null); + + var fileExtension = (ctx.Provider.Value.FileExtension.HasValue() ? ctx.Provider.Value.FileExtension.ToLower().EnsureStartsWith(".") : ""); + + + using (var segmenter = CreateSegmenter(ctx)) + { + if (segmenter == null) + { + throw new SmartException("Unsupported entity type '{0}'".FormatInvariant(ctx.Provider.Value.EntityType.ToString())); + } + + if (segmenter.TotalRecords <= 0) + { + ctx.Log.Information("There are no records to export"); + } + + while (ctx.ExecuteContext.Abort == ExportAbortion.None && segmenter.HasData) + { + segmenter.RecordPerSegmentCount = 0; + ctx.ExecuteContext.RecordsSucceeded = 0; + + string path = null; + + if (ctx.IsFileBasedExport) + { + var resolvedPattern = ctx.Profile.ResolveFileNamePattern(ctx.Store, ++fileIndex, ctx.ExecuteContext.MaxFileNameLength); + + ctx.ExecuteContext.FileName = resolvedPattern + fileExtension; + path = Path.Combine(ctx.ExecuteContext.Folder, ctx.ExecuteContext.FileName); + + if (ctx.ExecuteContext.HasPublicDeployment) + ctx.ExecuteContext.PublicFileUrl = ctx.Store.Url.EnsureEndsWith("/") + PublicFolder.EnsureEndsWith("/") + ctx.ExecuteContext.FileName; + } + + if (CallProvider(ctx, null, "Execute", path)) + { + ctx.Log.Information("Provider reports {0} successful exported record(s)".FormatInvariant(ctx.ExecuteContext.RecordsSucceeded)); + + // create info for deployment list in profile edit + if (ctx.IsFileBasedExport) + { + ctx.Result.Files.Add(new DataExportResult.ExportFileInfo + { + StoreId = ctx.Store.Id, + FileName = ctx.ExecuteContext.FileName + }); + } + } + + if (ctx.ExecuteContext.IsMaxFailures) + ctx.Log.Warning("Export aborted. The maximum number of failures has been reached"); + + if (ctx.CancellationToken.IsCancellationRequested) + ctx.Log.Warning("Export aborted. A cancellation has been requested"); + } + + if (ctx.ExecuteContext.Abort != ExportAbortion.Hard) + { + // always call OnExecuted + if (ctx.ExecuteContext.ExtraDataStreams.Count == 0) + ctx.ExecuteContext.ExtraDataStreams.Add(new ExportExtraStreams()); + + ctx.ExecuteContext.ExtraDataStreams.ForEach(x => + { + var path = (x.FileName.HasValue() ? Path.Combine(ctx.ExecuteContext.Folder, x.FileName) : null); + + CallProvider(ctx, x.Id, "OnExecuted", path); + }); + + ctx.ExecuteContext.ExtraDataStreams.Clear(); + } + } + } + + private void ExportCoreOuter(DataExporterContext ctx) + { + if (ctx.Profile == null || !ctx.Profile.Enabled) + return; + + FileSystemHelper.Delete(ctx.LogPath); + FileSystemHelper.ClearDirectory(ctx.FolderContent, false); + FileSystemHelper.Delete(ctx.ZipPath); + + using (var logger = new TraceLogger(ctx.LogPath)) + { + try + { + if (!ctx.Provider.IsValid()) + { + throw new SmartException("Export aborted because the export provider is not valid"); + } + + ctx.Log = logger; + ctx.ExecuteContext.Log = logger; + ctx.ProgressInfo = T("Admin.DataExchange.Export.ProgressInfo"); + + if (ctx.Profile.ProviderConfigData.HasValue()) + { + var configInfo = ctx.Provider.Value.ConfigurationInfo; + if (configInfo != null) + { + ctx.ExecuteContext.ConfigurationData = XmlHelper.Deserialize(ctx.Profile.ProviderConfigData, configInfo.ModelType); + } + } + + // TODO: lazyLoading: false. It requires IDbContextExtensions::Load/QueryFor for properties internally mapped by EF + using (var scope = new DbContextScope(_services.DbContext, autoDetectChanges: false, proxyCreation: false, validateOnSave: false, forceNoTracking: true)) + { + ctx.DeliveryTimes = _deliveryTimeService.Value.GetAllDeliveryTimes().ToDictionary(x => x.Id); + ctx.QuantityUnits = _quantityUnitService.Value.GetAllQuantityUnits().ToDictionary(x => x.Id); + ctx.ProductTemplates = _productTemplateService.Value.GetAllProductTemplates().ToDictionary(x => x.Id); + + if (ctx.Provider.Value.EntityType == ExportEntityType.Product) + { + var allCategories = _categoryService.Value.GetAllCategories(showHidden: true, applyNavigationFilters: false); + ctx.Categories = allCategories.ToDictionary(x => x.Id); + } + + if (ctx.Provider.Value.EntityType == ExportEntityType.Order) + { + ctx.Countries = _countryService.Value.GetAllCountries(true).ToDictionary(x => x.Id, x => x); + } + + if (ctx.Provider.Value.EntityType == ExportEntityType.Customer) + { + var subscriptionEmails = _subscriptionRepository.Value.TableUntracked + .Where(x => x.Active) + .Select(x => x.Email) + .Distinct() + .ToList(); + + ctx.NewsletterSubscriptions = new HashSet(subscriptionEmails, StringComparer.OrdinalIgnoreCase); + } + + var stores = Init(ctx); + + ctx.ExecuteContext.Language = ToDynamic(ctx, ctx.ContextLanguage); + ctx.ExecuteContext.Customer = ToDynamic(ctx, ctx.ContextCustomer); + ctx.ExecuteContext.Currency = ToDynamic(ctx, ctx.ContextCurrency); + + stores.ForEach(x => ExportCoreInner(ctx, x)); + } + + if (!ctx.IsPreview && ctx.ExecuteContext.Abort != ExportAbortion.Hard) + { + if (ctx.IsFileBasedExport) + { + if (ctx.Profile.CreateZipArchive || ctx.Profile.Deployments.Any(x => x.Enabled && x.CreateZip)) + { + ZipFile.CreateFromDirectory(ctx.FolderContent, ctx.ZipPath, CompressionLevel.Fastest, true); + } + + SetProgress(ctx, T("Common.Deployment")); + + // TODO: deployment + //foreach (var deployment in ctx.Profile.Deployments.OrderBy(x => x.DeploymentTypeId).Where(x => x.Enabled)) + //{ + // try + // { + // switch (deployment.DeploymentType) + // { + // case ExportDeploymentType.FileSystem: + // DeployFileSystem(ctx, deployment); + // break; + // case ExportDeploymentType.Email: + // DeployEmail(ctx, deployment); + // break; + // case ExportDeploymentType.Http: + // DeployHttp(ctx, deployment); + // break; + // case ExportDeploymentType.Ftp: + // DeployFtp(ctx, deployment); + // break; + // } + // } + // catch (Exception exc) + // { + // logger.Error("Deployment \"{0}\" of type {1} failed: {2}".FormatInvariant( + // deployment.Name, deployment.DeploymentType.ToString(), exc.Message), exc); + // } + //} + } + + if (ctx.Profile.EmailAccountId != 0 && ctx.Profile.CompletedEmailAddresses.HasValue()) + { + SendCompletionEmail(ctx); + } + } + } + catch (Exception exc) + { + logger.Error(exc); + ctx.Result.LastError = exc.ToString(); + } + finally + { + try + { + if (!ctx.IsPreview && ctx.Profile.Id != 0) + { + ctx.Profile.ResultInfo = XmlHelper.Serialize(ctx.Result); + + _exportProfileService.Value.UpdateExportProfile(ctx.Profile); + } + } + catch { } + + try + { + if (ctx.IsFileBasedExport && ctx.ExecuteContext.Abort != ExportAbortion.Hard && ctx.Profile.Cleanup) + { + FileSystemHelper.ClearDirectory(ctx.FolderContent, false); + } + } + catch { } + + try + { + ctx.NewsletterSubscriptions.Clear(); + ctx.ProductTemplates.Clear(); + ctx.Countries.Clear(); + ctx.Stores.Clear(); + ctx.QuantityUnits.Clear(); + ctx.DeliveryTimes.Clear(); + ctx.CategoryPathes.Clear(); + ctx.Categories.Clear(); + ctx.EntityIdsSelected.Clear(); + ctx.ProductExportContext = null; + ctx.OrderExportContext = null; + ctx.ManufacturerExportContext = null; + ctx.CategoryExportContext = null; + ctx.CustomerExportContext = null; + + ctx.ExecuteContext.CustomProperties.Clear(); + ctx.ExecuteContext.Log = null; + ctx.Log = null; + } + catch { } + } + } + + if (ctx.IsPreview || ctx.ExecuteContext.Abort == ExportAbortion.Hard) + return; + } + /// /// The name of the public export folder /// diff --git a/src/Libraries/SmartStore.Services/DataExchange/Internal/DataExporterContext.cs b/src/Libraries/SmartStore.Services/DataExchange/Internal/DataExporterContext.cs new file mode 100644 index 0000000000..cb95e67f23 --- /dev/null +++ b/src/Libraries/SmartStore.Services/DataExchange/Internal/DataExporterContext.cs @@ -0,0 +1,218 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Threading; +using SmartStore.Core; +using SmartStore.Core.Domain; +using SmartStore.Core.Domain.Catalog; +using SmartStore.Core.Domain.Customers; +using SmartStore.Core.Domain.DataExchange; +using SmartStore.Core.Domain.Directory; +using SmartStore.Core.Domain.Localization; +using SmartStore.Core.Domain.Stores; +using SmartStore.Core.Logging; +using SmartStore.Core.Plugins; +using SmartStore.Utilities; + +namespace SmartStore.Services.DataExchange.Internal +{ + internal class DataExporterContext + { + private ProductExportContext _productExportContext; + private OrderExportContext _orderExportContext; + private ManufacturerExportContext _manufacturerExportContext; + private CategoryExportContext _categoryExportContext; + private CustomerExportContext _customerExportContext; + + public DataExporterContext( + DataExportRequest request, + CancellationToken cancellationToken, + ExportProfile profile, + Provider provider, + string selectedIds = null, + Action previewData = null) + { + Request = request; + CancellationToken = cancellationToken; + Profile = profile; + Provider = provider; + Filter = XmlHelper.Deserialize(profile.Filtering); + Projection = XmlHelper.Deserialize(profile.Projection); + EntityIdsSelected = selectedIds.SplitSafe(",").Select(x => x.ToInt()).ToList(); + PreviewData = previewData; + + FolderContent = FileSystemHelper.TempDir(@"Profile\Export\{0}\Content".FormatInvariant(profile.FolderName)); + FolderRoot = System.IO.Directory.GetParent(FolderContent).FullName; + + Categories = new Dictionary(); + CategoryPathes = new Dictionary(); + Countries = new Dictionary(); + ProductTemplates = new Dictionary(); + NewsletterSubscriptions = new HashSet(); + + RecordsPerStore = new Dictionary(); + EntityIdsLoaded = new List(); + + Result = new DataExportResult + { + FileFolder = (IsFileBasedExport ? FolderContent : null) + }; + + ExecuteContext = new ExportExecuteContext(Result, CancellationToken, FolderContent); + ExecuteContext.Projection = XmlHelper.Deserialize(profile.Projection); + } + + public List EntityIdsSelected { get; private set; } + public List EntityIdsLoaded { get; set; } + + public int RecordCount { get; set; } + public Dictionary RecordsPerStore { get; set; } + public string ProgressInfo { get; set; } + public IQueryable QueryProducts { get; set; } + + public Action PreviewData { get; private set; } + public bool IsPreview + { + get { return PreviewData != null; } + } + + public DataExportRequest Request { get; private set; } + public CancellationToken CancellationToken { get; private set; } + public ExportProfile Profile { get; private set; } + public Provider Provider { get; private set; } + + public bool Supports(ExportFeatures feature) + { + return (!IsPreview && Provider.Metadata.ExportFeatures.HasFlag(feature)); + } + + public ExportFilter Filter { get; private set; } + public ExportProjection Projection { get; private set; } + public Currency ContextCurrency { get; set; } + public Customer ContextCustomer { get; set; } + public Language ContextLanguage { get; set; } + + public TraceLogger Log { get; set; } + public Store Store { get; set; } + + public string FolderRoot { get; private set; } + public string FolderContent { get; private set; } + public string ZipName + { + get { return Profile.FolderName + ".zip"; } + } + public string ZipPath + { + get { return Path.Combine(FolderRoot, ZipName); } + } + public string LogPath + { + get { return Path.Combine(FolderRoot, "log.txt"); } + } + + public bool IsFileBasedExport + { + get { return Provider == null || Provider.Value == null || Provider.Value.FileExtension.HasValue(); } + } + public string[] GetDeploymentFiles(ExportDeployment deployment) + { + if (!IsFileBasedExport) + return new string[0]; + + if (deployment.CreateZip) + return new string[] { ZipPath }; + + return System.IO.Directory.GetFiles(FolderContent, "*.*", SearchOption.AllDirectories); + } + + // data loaded once per export + public Dictionary Categories { get; set; } + public Dictionary CategoryPathes { get; set; } + public Dictionary DeliveryTimes { get; set; } + public Dictionary QuantityUnits { get; set; } + public Dictionary Stores { get; set; } + public Dictionary Languages { get; set; } + public Dictionary Countries { get; set; } + public Dictionary ProductTemplates { get; set; } + public HashSet NewsletterSubscriptions { get; set; } + + // data loaded once per page + public ProductExportContext ProductExportContext + { + get + { + return _productExportContext; + } + set + { + if (_productExportContext != null) + _productExportContext.Clear(); + + _productExportContext = value; + } + } + + public OrderExportContext OrderExportContext + { + get + { + return _orderExportContext; + } + set + { + if (_orderExportContext != null) + _orderExportContext.Clear(); + + _orderExportContext = value; + } + } + + public ManufacturerExportContext ManufacturerExportContext + { + get + { + return _manufacturerExportContext; + } + set + { + if (_manufacturerExportContext != null) + _manufacturerExportContext.Clear(); + + _manufacturerExportContext = value; + } + } + + public CategoryExportContext CategoryExportContext + { + get + { + return _categoryExportContext; + } + set + { + if (_categoryExportContext != null) + _categoryExportContext.Clear(); + + _categoryExportContext = value; + } + } + public CustomerExportContext CustomerExportContext + { + get + { + return _customerExportContext; + } + set + { + if (_customerExportContext != null) + _customerExportContext.Clear(); + + _customerExportContext = value; + } + } + + public ExportExecuteContext ExecuteContext { get; set; } + public DataExportResult Result { get; set; } + } +} diff --git a/src/Libraries/SmartStore.Services/DataExchange/Internal/DynamicEntityHelper.cs b/src/Libraries/SmartStore.Services/DataExchange/Internal/DynamicEntityHelper.cs index c1ebf6a7a5..e3de6b5e56 100644 --- a/src/Libraries/SmartStore.Services/DataExchange/Internal/DynamicEntityHelper.cs +++ b/src/Libraries/SmartStore.Services/DataExchange/Internal/DynamicEntityHelper.cs @@ -28,7 +28,7 @@ namespace SmartStore.Services.DataExchange.Internal { public partial class DataExporter { - private void PrepareProductDescription(DataExportTaskContext ctx, dynamic dynObject, Product product) + private void PrepareProductDescription(DataExporterContext ctx, dynamic dynObject, Product product) { try { @@ -118,25 +118,25 @@ private void PrepareProductDescription(DataExportTaskContext ctx, dynamic dynObj catch { } } - private decimal? ConvertPrice(DataExportTaskContext ctx, Product product, decimal? price) + private decimal? ConvertPrice(DataExporterContext ctx, Product product, decimal? price) { if (price.HasValue) { if (ctx.Projection.ConvertNetToGrossPrices) { decimal taxRate; - price = _taxService.GetProductPrice(product, price.Value, true, ctx.ContextCustomer, out taxRate); + price = _taxService.Value.GetProductPrice(product, price.Value, true, ctx.ContextCustomer, out taxRate); } if (price != decimal.Zero) { - price = _currencyService.ConvertFromPrimaryStoreCurrency(price.Value, ctx.ContextCurrency, ctx.Store); + price = _currencyService.Value.ConvertFromPrimaryStoreCurrency(price.Value, ctx.ContextCurrency, ctx.Store); } } return price; } - private decimal CalculatePrice(DataExportTaskContext ctx, Product product, bool forAttributeCombination) + private decimal CalculatePrice(DataExporterContext ctx, Product product, bool forAttributeCombination) { decimal price = product.Price; @@ -148,22 +148,22 @@ private decimal CalculatePrice(DataExportTaskContext ctx, Product product, bool if (ctx.Projection.PriceType.Value == PriceDisplayType.LowestPrice) { bool displayFromMessage; - price = _priceCalculationService.GetLowestPrice(product, priceCalculationContext, out displayFromMessage); + price = _priceCalculationService.Value.GetLowestPrice(product, priceCalculationContext, out displayFromMessage); } else if (ctx.Projection.PriceType.Value == PriceDisplayType.PreSelectedPrice) { - price = _priceCalculationService.GetPreselectedPrice(product, priceCalculationContext); + price = _priceCalculationService.Value.GetPreselectedPrice(product, priceCalculationContext); } else if (ctx.Projection.PriceType.Value == PriceDisplayType.PriceWithoutDiscountsAndAttributes) { - price = _priceCalculationService.GetFinalPrice(product, null, ctx.ContextCustomer, decimal.Zero, false, 1, null, priceCalculationContext); + price = _priceCalculationService.Value.GetFinalPrice(product, null, ctx.ContextCustomer, decimal.Zero, false, 1, null, priceCalculationContext); } } return ConvertPrice(ctx, product, price) ?? price; } - private void MergeWithCombination(DataExportTaskContext ctx, dynamic dynObject, Product product, + private void MergeWithCombination(DataExporterContext ctx, dynamic dynObject, Product product, ICollection productAttributes, ProductVariantAttributeCombination combination) { product.MergeWithCombination(combination); @@ -172,13 +172,13 @@ private void MergeWithCombination(DataExportTaskContext ctx, dynamic dynObject, if (combination != null && ctx.Projection.AttributeCombinationValueMerging == ExportAttributeValueMerging.AppendAllValuesToName) { - var values = _productAttributeParser.ParseProductVariantAttributeValues(combination.AttributesXml, productAttributes, ctx.Projection.LanguageId ?? 0); + var values = _productAttributeParser.Value.ParseProductVariantAttributeValues(combination.AttributesXml, productAttributes, ctx.Projection.LanguageId ?? 0); dynObject.Name = ((string)dynObject.Name).Grow(string.Join(", ", values), " "); } - dynObject._BasePriceInfo = product.GetBasePriceInfo(_services.Localization, _priceFormatter, _currencyService, _taxService, - _priceCalculationService, ctx.ContextCurrency, decimal.Zero, true); + dynObject._BasePriceInfo = product.GetBasePriceInfo(_services.Localization, _priceFormatter.Value, _currencyService.Value, _taxService.Value, + _priceCalculationService.Value, ctx.ContextCurrency, decimal.Zero, true); // navigation properties ToDeliveryTime(ctx, dynObject, product.DeliveryTimeId); @@ -212,7 +212,7 @@ private void MergeWithCombination(DataExportTaskContext ctx, dynamic dynObject, if (ctx.Projection.ConvertNetToGrossPrices) { decimal taxRate; - dynObject._OldPrice = _taxService.GetProductPrice(product, product.OldPrice, true, ctx.ContextCustomer, out taxRate); + dynObject._OldPrice = _taxService.Value.GetProductPrice(product, product.OldPrice, true, ctx.ContextCustomer, out taxRate); } else { @@ -232,7 +232,7 @@ private void MergeWithCombination(DataExportTaskContext ctx, dynamic dynObject, if (!(product.ProductType == ProductType.BundledProduct && product.BundlePerItemPricing)) { - var specialPrice = _priceCalculationService.GetSpecialPrice(product); + var specialPrice = _priceCalculationService.Value.GetSpecialPrice(product); dynObject._SpecialPrice = ConvertPrice(ctx, product, specialPrice); @@ -248,7 +248,7 @@ private void MergeWithCombination(DataExportTaskContext ctx, dynamic dynObject, } - private List GetLocalized(DataExportTaskContext ctx, T entity, params Expression>[] keySelectors) + private List GetLocalized(DataExporterContext ctx, T entity, params Expression>[] keySelectors) where T : BaseEntity, ILocalizedEntity { if (ctx.Languages.Count <= 1) @@ -266,7 +266,7 @@ private List GetLocalized(DataExportTaskContext ctx, T entity, param // add SeName if (isSlugSupported) { - var value = _urlRecordService.GetActiveSlug(entity.Id, localeKeyGroup, language.Value.Id); + var value = _urlRecordService.Value.GetActiveSlug(entity.Id, localeKeyGroup, language.Value.Id); if (value.HasValue()) { dynamic exp = new HybridExpando(); @@ -283,7 +283,7 @@ private List GetLocalized(DataExportTaskContext ctx, T entity, param var member = keySelector.Body as MemberExpression; var propInfo = member.Member as PropertyInfo; string localeKey = propInfo.Name; - var value = _localizedEntityService.GetLocalizedValue(language.Value.Id, entity.Id, localeKeyGroup, localeKey); + var value = _localizedEntityService.Value.GetLocalizedValue(language.Value.Id, entity.Id, localeKeyGroup, localeKey); // we better not export empty values. the risk is to high that they are imported and unnecessary fill databases. if (value.HasValue()) @@ -301,7 +301,7 @@ private List GetLocalized(DataExportTaskContext ctx, T entity, param return (localized.Count == 0 ? null : localized); } - private dynamic ToDynamic(DataExportTaskContext ctx, Currency currency) + private dynamic ToDynamic(DataExporterContext ctx, Currency currency) { if (currency == null) return null; @@ -314,7 +314,7 @@ private dynamic ToDynamic(DataExportTaskContext ctx, Currency currency) return result; } - private dynamic ToDynamic(DataExportTaskContext ctx, Language language) + private dynamic ToDynamic(DataExporterContext ctx, Language language) { if (language == null) return null; @@ -323,7 +323,7 @@ private dynamic ToDynamic(DataExportTaskContext ctx, Language language) return result; } - private dynamic ToDynamic(DataExportTaskContext ctx, Country country) + private dynamic ToDynamic(DataExporterContext ctx, Country country) { if (country == null) return null; @@ -336,7 +336,7 @@ private dynamic ToDynamic(DataExportTaskContext ctx, Country country) return result; } - private dynamic ToDynamic(DataExportTaskContext ctx, Address address) + private dynamic ToDynamic(DataExporterContext ctx, Address address) { if (address == null) return null; @@ -362,7 +362,7 @@ private dynamic ToDynamic(DataExportTaskContext ctx, Address address) return result; } - private dynamic ToDynamic(DataExportTaskContext ctx, RewardPointsHistory points) + private dynamic ToDynamic(DataExporterContext ctx, RewardPointsHistory points) { if (points == null) return null; @@ -372,7 +372,7 @@ private dynamic ToDynamic(DataExportTaskContext ctx, RewardPointsHistory points) return result; } - private dynamic ToDynamic(DataExportTaskContext ctx, Customer customer) + private dynamic ToDynamic(DataExporterContext ctx, Customer customer) { if (customer == null) return null; @@ -393,7 +393,7 @@ private dynamic ToDynamic(DataExportTaskContext ctx, Customer customer) return result; } - private dynamic ToDynamic(DataExportTaskContext ctx, Store store) + private dynamic ToDynamic(DataExporterContext ctx, Store store) { if (store == null) return null; @@ -406,7 +406,7 @@ private dynamic ToDynamic(DataExportTaskContext ctx, Store store) return result; } - private dynamic ToDynamic(DataExportTaskContext ctx, DeliveryTime deliveryTime) + private dynamic ToDynamic(DataExporterContext ctx, DeliveryTime deliveryTime) { if (deliveryTime == null) return null; @@ -419,7 +419,7 @@ private dynamic ToDynamic(DataExportTaskContext ctx, DeliveryTime deliveryTime) return result; } - private void ToDeliveryTime(DataExportTaskContext ctx, dynamic parent, int? deliveryTimeId) + private void ToDeliveryTime(DataExporterContext ctx, dynamic parent, int? deliveryTimeId) { if (ctx.DeliveryTimes != null) { @@ -430,7 +430,7 @@ private void ToDeliveryTime(DataExportTaskContext ctx, dynamic parent, int? deli } } - private dynamic ToDynamic(DataExportTaskContext ctx, QuantityUnit quantityUnit) + private dynamic ToDynamic(DataExporterContext ctx, QuantityUnit quantityUnit) { if (quantityUnit == null) return null; @@ -447,7 +447,7 @@ private dynamic ToDynamic(DataExportTaskContext ctx, QuantityUnit quantityUnit) return result; } - private void ToQuantityUnit(DataExportTaskContext ctx, dynamic parent, int? quantityUnitId) + private void ToQuantityUnit(DataExporterContext ctx, dynamic parent, int? quantityUnitId) { if (ctx.QuantityUnits != null) { @@ -458,26 +458,26 @@ private void ToQuantityUnit(DataExportTaskContext ctx, dynamic parent, int? quan } } - private dynamic ToDynamic(DataExportTaskContext ctx, Picture picture, int thumbPictureSize, int detailsPictureSize) + private dynamic ToDynamic(DataExporterContext ctx, Picture picture, int thumbPictureSize, int detailsPictureSize) { if (picture == null) return null; dynamic result = new DynamicEntity(picture); - result._ThumbImageUrl = _pictureService.GetPictureUrl(picture, thumbPictureSize, false, ctx.Store.Url); - result._ImageUrl = _pictureService.GetPictureUrl(picture, detailsPictureSize, false, ctx.Store.Url); - result._FullSizeImageUrl = _pictureService.GetPictureUrl(picture, 0, false, ctx.Store.Url); + result._ThumbImageUrl = _pictureService.Value.GetPictureUrl(picture, thumbPictureSize, false, ctx.Store.Url); + result._ImageUrl = _pictureService.Value.GetPictureUrl(picture, detailsPictureSize, false, ctx.Store.Url); + result._FullSizeImageUrl = _pictureService.Value.GetPictureUrl(picture, 0, false, ctx.Store.Url); - var relativeUrl = _pictureService.GetPictureUrl(picture); + var relativeUrl = _pictureService.Value.GetPictureUrl(picture); result._FileName = relativeUrl.Substring(relativeUrl.LastIndexOf("/") + 1); - result._ThumbLocalPath = _pictureService.GetThumbLocalPath(picture); + result._ThumbLocalPath = _pictureService.Value.GetThumbLocalPath(picture); return result; } - private dynamic ToDynamic(DataExportTaskContext ctx, ProductVariantAttribute pva) + private dynamic ToDynamic(DataExporterContext ctx, ProductVariantAttribute pva) { if (pva == null) return null; @@ -511,7 +511,7 @@ private dynamic ToDynamic(DataExportTaskContext ctx, ProductVariantAttribute pva return result; } - private dynamic ToDynamic(DataExportTaskContext ctx, ProductVariantAttributeCombination pvac) + private dynamic ToDynamic(DataExporterContext ctx, ProductVariantAttributeCombination pvac) { if (pvac == null) return null; @@ -524,7 +524,7 @@ private dynamic ToDynamic(DataExportTaskContext ctx, ProductVariantAttributeComb return result; } - private dynamic ToDynamic(DataExportTaskContext ctx, Manufacturer manufacturer) + private dynamic ToDynamic(DataExporterContext ctx, Manufacturer manufacturer) { if (manufacturer == null) return null; @@ -550,7 +550,7 @@ private dynamic ToDynamic(DataExportTaskContext ctx, Manufacturer manufacturer) return result; } - private dynamic ToDynamic(DataExportTaskContext ctx, Category category) + private dynamic ToDynamic(DataExporterContext ctx, Category category) { if (category == null) return null; @@ -580,7 +580,7 @@ private dynamic ToDynamic(DataExportTaskContext ctx, Category category) return result; } - private dynamic ToDynamic(DataExportTaskContext ctx, Product product) + private dynamic ToDynamic(DataExporterContext ctx, Product product) { if (product == null) return null; @@ -619,7 +619,7 @@ private dynamic ToDynamic(DataExportTaskContext ctx, Product product) return result; } - private dynamic ToDynamic(DataExportTaskContext ctx, Order order) + private dynamic ToDynamic(DataExporterContext ctx, Order order) { if (order == null) return null; @@ -642,7 +642,7 @@ private dynamic ToDynamic(DataExportTaskContext ctx, Order order) return result; } - private dynamic ToDynamic(DataExportTaskContext ctx, OrderItem orderItem) + private dynamic ToDynamic(DataExporterContext ctx, OrderItem orderItem) { if (orderItem == null) return null; @@ -654,7 +654,7 @@ private dynamic ToDynamic(DataExportTaskContext ctx, OrderItem orderItem) return result; } - private dynamic ToDynamic(DataExportTaskContext ctx, Shipment shipment) + private dynamic ToDynamic(DataExporterContext ctx, Shipment shipment) { if (shipment == null) return null; @@ -673,7 +673,7 @@ private dynamic ToDynamic(DataExportTaskContext ctx, Shipment shipment) return result; } - private dynamic ToDynamic(DataExportTaskContext ctx, Discount discount) + private dynamic ToDynamic(DataExporterContext ctx, Discount discount) { if (discount == null) return null; @@ -683,7 +683,7 @@ private dynamic ToDynamic(DataExportTaskContext ctx, Discount discount) return result; } - private dynamic ToDynamic(DataExportTaskContext ctx, ProductSpecificationAttribute psa) + private dynamic ToDynamic(DataExporterContext ctx, ProductSpecificationAttribute psa) { if (psa == null) return null; @@ -709,7 +709,7 @@ private dynamic ToDynamic(DataExportTaskContext ctx, ProductSpecificationAttribu return result; } - private dynamic ToDynamic(DataExportTaskContext ctx, GenericAttribute genericAttribute) + private dynamic ToDynamic(DataExporterContext ctx, GenericAttribute genericAttribute) { if (genericAttribute == null) return null; @@ -719,7 +719,7 @@ private dynamic ToDynamic(DataExportTaskContext ctx, GenericAttribute genericAtt return result; } - private dynamic ToDynamic(DataExportTaskContext ctx, NewsLetterSubscription subscription) + private dynamic ToDynamic(DataExporterContext ctx, NewsLetterSubscription subscription) { if (subscription == null) return null; @@ -730,13 +730,13 @@ private dynamic ToDynamic(DataExportTaskContext ctx, NewsLetterSubscription subs } - private List Convert(DataExportTaskContext ctx, Product product) + private List Convert(DataExporterContext ctx, Product product) { var result = new List(); var languageId = (ctx.Projection.LanguageId ?? 0); var productTemplate = ctx.ProductTemplates.FirstOrDefault(x => x.Key == product.ProductTemplateId); - var pictureSize = _mediaSettings.ProductDetailsPictureSize; + var pictureSize = _mediaSettings.Value.ProductDetailsPictureSize; if (ctx.Supports(ExportFeatures.CanIncludeMainPicture) && ctx.Projection.PictureSize > 0) pictureSize = ctx.Projection.PictureSize; @@ -762,12 +762,12 @@ private List Convert(DataExportTaskContext ctx, Product product) if (ctx.Categories.Count > 0 && ctx.CategoryPathes.Count > 0) { - dynObject._CategoryPath = _categoryService.GetCategoryPath( + dynObject._CategoryPath = _categoryService.Value.GetCategoryPath( product, null, x => ctx.CategoryPathes.ContainsKey(x) ? ctx.CategoryPathes[x] : null, (id, value) => ctx.CategoryPathes[id] = value, - x => ctx.Categories.ContainsKey(x) ? ctx.Categories[x] : _categoryService.GetCategoryById(x), + x => ctx.Categories.ContainsKey(x) ? ctx.Categories[x] : _categoryService.Value.GetCategoryById(x), productCategories.OrderBy(x => x.DisplayOrder).FirstOrDefault() ); } @@ -782,7 +782,7 @@ private List Convert(DataExportTaskContext ctx, Product product) { dynamic dyn = new DynamicEntity(x); - dyn.Picture = ToDynamic(ctx, x.Picture, _mediaSettings.ProductThumbPictureSize, pictureSize); + dyn.Picture = ToDynamic(ctx, x.Picture, _mediaSettings.Value.ProductThumbPictureSize, pictureSize); return dyn; }) @@ -797,7 +797,7 @@ private List Convert(DataExportTaskContext ctx, Product product) dyn.Manufacturer = ToDynamic(ctx, x.Manufacturer); if (x.Manufacturer != null && x.Manufacturer.PictureId.HasValue) - dyn.Manufacturer.Picture = ToDynamic(ctx, x.Manufacturer.Picture, _mediaSettings.ManufacturerThumbPictureSize, _mediaSettings.ManufacturerThumbPictureSize); + dyn.Manufacturer.Picture = ToDynamic(ctx, x.Manufacturer.Picture, _mediaSettings.Value.ManufacturerThumbPictureSize, _mediaSettings.Value.ManufacturerThumbPictureSize); else dyn.Manufacturer.Picture = null; @@ -814,7 +814,7 @@ private List Convert(DataExportTaskContext ctx, Product product) dyn.Category = ToDynamic(ctx, x.Category); if (x.Category != null && x.Category.PictureId.HasValue) - dyn.Category.Picture = ToDynamic(ctx, x.Category.Picture, _mediaSettings.CategoryThumbPictureSize, _mediaSettings.CategoryThumbPictureSize); + dyn.Category.Picture = ToDynamic(ctx, x.Category.Picture, _mediaSettings.Value.CategoryThumbPictureSize, _mediaSettings.Value.CategoryThumbPictureSize); if (dynObject._CategoryName == null) dynObject._CategoryName = (string)dyn.Category.Name; @@ -839,7 +839,7 @@ private List Convert(DataExportTaskContext ctx, Product product) var assignedPicture = productPictures.FirstOrDefault(y => y.PictureId == pictureId); if (assignedPicture != null && assignedPicture.Picture != null) { - assignedPictures.Add(ToDynamic(ctx, assignedPicture.Picture, _mediaSettings.ProductThumbPictureSize, pictureSize)); + assignedPictures.Add(ToDynamic(ctx, assignedPicture.Picture, _mediaSettings.Value.ProductThumbPictureSize, pictureSize)); } } @@ -934,9 +934,9 @@ private List Convert(DataExportTaskContext ctx, Product product) if (ctx.Supports(ExportFeatures.CanIncludeMainPicture)) { if (productPictures != null && productPictures.Any()) - dynObject._MainPictureUrl = _pictureService.GetPictureUrl(productPictures.First().Picture, ctx.Projection.PictureSize, storeLocation: ctx.Store.Url); + dynObject._MainPictureUrl = _pictureService.Value.GetPictureUrl(productPictures.First().Picture, ctx.Projection.PictureSize, storeLocation: ctx.Store.Url); else - dynObject._MainPictureUrl = _pictureService.GetDefaultPictureUrl(ctx.Projection.PictureSize, storeLocation: ctx.Store.Url); + dynObject._MainPictureUrl = _pictureService.Value.GetDefaultPictureUrl(ctx.Projection.PictureSize, storeLocation: ctx.Store.Url); } #endregion @@ -975,7 +975,7 @@ private List Convert(DataExportTaskContext ctx, Product product) return result; } - private List Convert(DataExportTaskContext ctx, Order order) + private List Convert(DataExporterContext ctx, Order order) { var result = new List(); @@ -1025,8 +1025,8 @@ private List Convert(DataExportTaskContext ctx, Order order) dyn.Product._ProductTemplateViewPath = (productTemplate.Value == null ? "" : productTemplate.Value.ViewPath); - dyn.Product._BasePriceInfo = e.Product.GetBasePriceInfo(_services.Localization, _priceFormatter, _currencyService, _taxService, - _priceCalculationService, ctx.ContextCurrency, decimal.Zero, true); + dyn.Product._BasePriceInfo = e.Product.GetBasePriceInfo(_services.Localization, _priceFormatter.Value, _currencyService.Value, _taxService.Value, + _priceCalculationService.Value, ctx.ContextCurrency, decimal.Zero, true); ToDeliveryTime(ctx, dyn.Product, e.Product.DeliveryTimeId); ToQuantityUnit(ctx, dyn.Product, e.Product.QuantityUnitId); @@ -1044,7 +1044,7 @@ private List Convert(DataExportTaskContext ctx, Order order) return result; } - private List Convert(DataExportTaskContext ctx, Manufacturer manufacturer) + private List Convert(DataExporterContext ctx, Manufacturer manufacturer) { var result = new List(); @@ -1057,7 +1057,7 @@ private List Convert(DataExportTaskContext ctx, Manufacturer manufactur var pictures = ctx.ManufacturerExportContext.Pictures.Load(manufacturer.PictureId.Value); if (pictures.Count > 0) - dynObject.Picture = ToDynamic(ctx, pictures.First(), _mediaSettings.ManufacturerThumbPictureSize, _mediaSettings.ManufacturerThumbPictureSize); + dynObject.Picture = ToDynamic(ctx, pictures.First(), _mediaSettings.Value.ManufacturerThumbPictureSize, _mediaSettings.Value.ManufacturerThumbPictureSize); } dynObject.ProductManufacturers = productManufacturers @@ -1075,7 +1075,7 @@ private List Convert(DataExportTaskContext ctx, Manufacturer manufactur return result; } - private List Convert(DataExportTaskContext ctx, Category category) + private List Convert(DataExporterContext ctx, Category category) { var result = new List(); @@ -1088,7 +1088,7 @@ private List Convert(DataExportTaskContext ctx, Category category) var pictures = ctx.CategoryExportContext.Pictures.Load(category.PictureId.Value); if (pictures.Count > 0) - dynObject.Picture = ToDynamic(ctx, pictures.First(), _mediaSettings.CategoryThumbPictureSize, _mediaSettings.CategoryThumbPictureSize); + dynObject.Picture = ToDynamic(ctx, pictures.First(), _mediaSettings.Value.CategoryThumbPictureSize, _mediaSettings.Value.CategoryThumbPictureSize); } dynObject.ProductCategories = productCategories @@ -1106,7 +1106,7 @@ private List Convert(DataExportTaskContext ctx, Category category) return result; } - private List Convert(DataExportTaskContext ctx, Customer customer) + private List Convert(DataExporterContext ctx, Customer customer) { var result = new List(); @@ -1142,7 +1142,7 @@ private List Convert(DataExportTaskContext ctx, Customer customer) return result; } - private List Convert(DataExportTaskContext ctx, NewsLetterSubscription subscription) + private List Convert(DataExporterContext ctx, NewsLetterSubscription subscription) { var result = new List(); diff --git a/src/Libraries/SmartStore.Services/SmartStore.Services.csproj b/src/Libraries/SmartStore.Services/SmartStore.Services.csproj index 0e67aca232..83fe5c10e4 100644 --- a/src/Libraries/SmartStore.Services/SmartStore.Services.csproj +++ b/src/Libraries/SmartStore.Services/SmartStore.Services.csproj @@ -169,6 +169,7 @@ + From bca184d4728c09f28e475242bd2b251e6d9c66ca Mon Sep 17 00:00:00 2001 From: Marcus Gesing Date: Wed, 11 Nov 2015 14:40:04 +0100 Subject: [PATCH 038/707] Further IDataExporter implementation --- .../DataExchange/Internal/DataExporter.cs | 184 ++++++++++++------ .../Internal/DataExporterContext.cs | 35 ++-- 2 files changed, 140 insertions(+), 79 deletions(-) diff --git a/src/Libraries/SmartStore.Services/DataExchange/Internal/DataExporter.cs b/src/Libraries/SmartStore.Services/DataExchange/Internal/DataExporter.cs index 391b210db6..37d64d5fbb 100644 --- a/src/Libraries/SmartStore.Services/DataExchange/Internal/DataExporter.cs +++ b/src/Libraries/SmartStore.Services/DataExchange/Internal/DataExporter.cs @@ -29,7 +29,6 @@ using SmartStore.Services.Orders; using SmartStore.Services.Seo; using SmartStore.Services.Shipping; -using SmartStore.Services.Tasks; using SmartStore.Services.Tax; using SmartStore.Utilities; using SmartStore.Utilities.Threading; @@ -158,8 +157,8 @@ private void SetProgress(DataExporterContext ctx, int loadedRecords) { int totalRecords = ctx.RecordsPerStore.Sum(x => x.Value); - if (ctx.Profile.Limit > 0 && totalRecords > ctx.Profile.Limit) - totalRecords = ctx.Profile.Limit; + if (ctx.Request.Profile.Limit > 0 && totalRecords > ctx.Request.Profile.Limit) + totalRecords = ctx.Request.Profile.Limit; ctx.RecordCount = Math.Min(ctx.RecordCount + loadedRecords, totalRecords); @@ -179,15 +178,15 @@ private void SetProgress(DataExporterContext ctx, string message) private IExportDataSegmenterProvider CreateSegmenter(DataExporterContext ctx, int pageIndex = 0) { - var offset = ctx.Profile.Offset + (pageIndex * PageSize); + var offset = ctx.Request.Profile.Offset + (pageIndex * PageSize); - var limit = (ctx.IsPreview ? PageSize : ctx.Profile.Limit); + var limit = (ctx.IsPreview ? PageSize : ctx.Request.Profile.Limit); - var recordsPerSegment = (ctx.IsPreview ? 0 : ctx.Profile.BatchSize); + var recordsPerSegment = (ctx.IsPreview ? 0 : ctx.Request.Profile.BatchSize); - var totalCount = ctx.Profile.Offset + ctx.RecordsPerStore.First(x => x.Key == ctx.Store.Id).Value; + var totalCount = ctx.Request.Profile.Offset + ctx.RecordsPerStore.First(x => x.Key == ctx.Store.Id).Value; - switch (ctx.Provider.Value.EntityType) + switch (ctx.Request.Provider.Value.EntityType) { case ExportEntityType.Product: ctx.ExecuteContext.Segmenter = new ExportDataSegmenter @@ -311,11 +310,11 @@ private bool CallProvider(DataExporterContext ctx, string streamId, string metho { if (method == "Execute") { - ctx.Provider.Value.Execute(ctx.ExecuteContext); + ctx.Request.Provider.Value.Execute(ctx.ExecuteContext); } else if (method == "OnExecuted") { - ctx.Provider.Value.OnExecuted(ctx.ExecuteContext); + ctx.Request.Provider.Value.OnExecuted(ctx.ExecuteContext); } if (ctx.IsFileBasedExport && path.HasValue()) @@ -355,17 +354,17 @@ private bool CallProvider(DataExporterContext ctx, string streamId, string metho private void SendCompletionEmail(DataExporterContext ctx) { - var emailAccount = _emailAccountService.Value.GetEmailAccountById(ctx.Profile.EmailAccountId); + var emailAccount = _emailAccountService.Value.GetEmailAccountById(ctx.Request.Profile.EmailAccountId); var smtpContext = new SmtpContext(emailAccount); var message = new EmailMessage(); var storeInfo = "{0} ({1})".FormatInvariant(ctx.Store.Name, ctx.Store.Url); - message.To.AddRange(ctx.Profile.CompletedEmailAddresses.SplitSafe(",").Where(x => x.IsEmail()).Select(x => new EmailAddress(x))); + message.To.AddRange(ctx.Request.Profile.CompletedEmailAddresses.SplitSafe(",").Where(x => x.IsEmail()).Select(x => new EmailAddress(x))); message.From = new EmailAddress(emailAccount.Email, emailAccount.DisplayName); message.Subject = _services.Localization.GetResource("Admin.DataExchange.Export.CompletedEmail.Subject", ctx.Projection.LanguageId ?? 0) - .FormatInvariant(ctx.Profile.Name); + .FormatInvariant(ctx.Request.Profile.Name); message.Body = _services.Localization.GetResource("Admin.DataExchange.Export.CompletedEmail.Body", ctx.Projection.LanguageId ?? 0) .FormatInvariant(storeInfo); @@ -387,7 +386,7 @@ private IQueryable GetProductQuery(DataExporterContext ctx, int skip, i { OrderBy = ProductSortingEnum.CreatedOn, ProductIds = ctx.EntityIdsSelected, - StoreId = (ctx.Profile.PerStore ? ctx.Store.Id : ctx.Filter.StoreId), + StoreId = (ctx.Request.Profile.PerStore ? ctx.Store.Id : ctx.Filter.StoreId), VisibleIndividuallyOnly = true, PriceMin = ctx.Filter.PriceMinimum, PriceMax = ctx.Filter.PriceMaximum, @@ -454,7 +453,7 @@ private List GetProducts(DataExporterContext ctx, int skip) { OrderBy = ProductSortingEnum.CreatedOn, PageSize = int.MaxValue, - StoreId = (ctx.Profile.PerStore ? ctx.Store.Id : ctx.Filter.StoreId), + StoreId = (ctx.Request.Profile.PerStore ? ctx.Store.Id : ctx.Filter.StoreId), VisibleIndividuallyOnly = false, ParentGroupedProductId = product.Id }; @@ -485,7 +484,7 @@ private List GetProducts(DataExporterContext ctx, int skip) private IQueryable GetOrderQuery(DataExporterContext ctx, int skip, int take) { var query = _orderService.Value.GetOrders( - ctx.Profile.PerStore ? ctx.Store.Id : ctx.Filter.StoreId, + ctx.Request.Profile.PerStore ? ctx.Store.Id : ctx.Filter.StoreId, ctx.Projection.CustomerId ?? 0, ctx.Filter.CreatedFrom.HasValue ? (DateTime?)_dateTimeHelper.Value.ConvertToUtcTime(ctx.Filter.CreatedFrom.Value, _dateTimeHelper.Value.CurrentTimeZone) : null, ctx.Filter.CreatedTo.HasValue ? (DateTime?)_dateTimeHelper.Value.ConvertToUtcTime(ctx.Filter.CreatedTo.Value, _dateTimeHelper.Value.CurrentTimeZone) : null, @@ -536,7 +535,7 @@ private List GetOrders(DataExporterContext ctx, int skip) private IQueryable GetManufacturerQuery(DataExporterContext ctx, int skip, int take) { var showHidden = !ctx.Filter.IsPublished.HasValue; - var storeId = (ctx.Profile.PerStore ? ctx.Store.Id : ctx.Filter.StoreId); + var storeId = (ctx.Request.Profile.PerStore ? ctx.Store.Id : ctx.Filter.StoreId); var query = _manufacturerService.Value.GetManufacturers(showHidden, storeId); @@ -569,7 +568,7 @@ private List GetManufacturers(DataExporterContext ctx, int skip) private IQueryable GetCategoryQuery(DataExporterContext ctx, int skip, int take) { var showHidden = !ctx.Filter.IsPublished.HasValue; - var storeId = (ctx.Profile.PerStore ? ctx.Store.Id : ctx.Filter.StoreId); + var storeId = (ctx.Request.Profile.PerStore ? ctx.Store.Id : ctx.Filter.StoreId); var query = _categoryService.Value.GetCategories(null, showHidden, null, true, storeId); @@ -644,7 +643,7 @@ private List GetCustomers(DataExporterContext ctx, int skip) private IQueryable GetNewsLetterSubscriptionQuery(DataExporterContext ctx, int skip, int take) { - var storeId = (ctx.Profile.PerStore ? ctx.Store.Id : ctx.Filter.StoreId); + var storeId = (ctx.Request.Profile.PerStore ? ctx.Store.Id : ctx.Filter.StoreId); var query = _subscriptionRepository.Value.TableUntracked; @@ -706,7 +705,7 @@ private List Init(DataExporterContext ctx, int? totalRecords = null) ctx.Stores = _services.StoreService.GetAllStores().ToDictionary(x => x.Id, x => x); ctx.Languages = _languageService.Value.GetAllLanguages(true).ToDictionary(x => x.Id, x => x); - if (!ctx.IsPreview && ctx.Profile.PerStore) + if (!ctx.IsPreview && ctx.Request.Profile.PerStore) { result = new List(ctx.Stores.Values.Where(x => x.Id == ctx.Filter.StoreId || ctx.Filter.StoreId == 0)); } @@ -732,25 +731,25 @@ private List Init(DataExporterContext ctx, int? totalRecords = null) } else { - switch (ctx.Provider.Value.EntityType) + switch (ctx.Request.Provider.Value.EntityType) { case ExportEntityType.Product: - totalCount = GetProductQuery(ctx, ctx.Profile.Offset, int.MaxValue).Count(); + totalCount = GetProductQuery(ctx, ctx.Request.Profile.Offset, int.MaxValue).Count(); break; case ExportEntityType.Order: - totalCount = GetOrderQuery(ctx, ctx.Profile.Offset, int.MaxValue).Count(); + totalCount = GetOrderQuery(ctx, ctx.Request.Profile.Offset, int.MaxValue).Count(); break; case ExportEntityType.Manufacturer: - totalCount = GetManufacturerQuery(ctx, ctx.Profile.Offset, int.MaxValue).Count(); + totalCount = GetManufacturerQuery(ctx, ctx.Request.Profile.Offset, int.MaxValue).Count(); break; case ExportEntityType.Category: - totalCount = GetCategoryQuery(ctx, ctx.Profile.Offset, int.MaxValue).Count(); + totalCount = GetCategoryQuery(ctx, ctx.Request.Profile.Offset, int.MaxValue).Count(); break; case ExportEntityType.Customer: - totalCount = GetCustomerQuery(ctx, ctx.Profile.Offset, int.MaxValue).Count(); + totalCount = GetCustomerQuery(ctx, ctx.Request.Profile.Offset, int.MaxValue).Count(); break; case ExportEntityType.NewsLetterSubscription: - totalCount = GetNewsLetterSubscriptionQuery(ctx, ctx.Profile.Offset, int.MaxValue).Count(); + totalCount = GetNewsLetterSubscriptionQuery(ctx, ctx.Request.Profile.Offset, int.MaxValue).Count(); break; } } @@ -775,18 +774,18 @@ private void ExportCoreInner(DataExporterContext ctx, Store store) logHead.AppendLine(); logHead.AppendLine(new string('-', 40)); logHead.AppendLine("SmartStore.NET:\t\tv." + SmartStoreVersion.CurrentFullVersion); - logHead.Append("Export profile:\t\t" + ctx.Profile.Name); - logHead.AppendLine(ctx.Profile.Id == 0 ? " (volatile)" : " (Id {0})".FormatInvariant(ctx.Profile.Id)); + logHead.Append("Export profile:\t\t" + ctx.Request.Profile.Name); + logHead.AppendLine(ctx.Request.Profile.Id == 0 ? " (volatile)" : " (Id {0})".FormatInvariant(ctx.Request.Profile.Id)); - logHead.AppendLine("Export provider:\t{0} ({1})".FormatInvariant(ctx.Provider.Metadata.FriendlyName, ctx.Profile.ProviderSystemName)); + logHead.AppendLine("Export provider:\t{0} ({1})".FormatInvariant(ctx.Request.Provider.Metadata.FriendlyName, ctx.Request.Profile.ProviderSystemName)); - var plugin = ctx.Provider.Metadata.PluginDescriptor; + var plugin = ctx.Request.Provider.Metadata.PluginDescriptor; logHead.Append("Plugin:\t\t\t\t"); logHead.AppendLine(plugin == null ? "".NaIfEmpty() : "{0} ({1}) v.{2}".FormatInvariant(plugin.FriendlyName, plugin.SystemName, plugin.Version.ToString())); - logHead.AppendLine("Entity:\t\t\t\t" + ctx.Provider.Value.EntityType.ToString()); + logHead.AppendLine("Entity:\t\t\t\t" + ctx.Request.Provider.Value.EntityType.ToString()); - var storeInfo = (ctx.Profile.PerStore ? "{0} (Id {1})".FormatInvariant(ctx.Store.Name, ctx.Store.Id) : "All stores"); + var storeInfo = (ctx.Request.Profile.PerStore ? "{0} (Id {1})".FormatInvariant(ctx.Store.Name, ctx.Store.Id) : "All stores"); logHead.Append("Store:\t\t\t\t" + storeInfo); ctx.Log.Information(logHead.ToString()); @@ -796,18 +795,18 @@ private void ExportCoreInner(DataExporterContext ctx, Store store) ctx.ExecuteContext.MaxFileNameLength = _dataExchangeSettings.Value.MaxFileNameLength; - ctx.ExecuteContext.HasPublicDeployment = ctx.Profile.Deployments.Any(x => x.IsPublic && x.DeploymentType == ExportDeploymentType.FileSystem); + ctx.ExecuteContext.HasPublicDeployment = ctx.Request.Profile.Deployments.Any(x => x.IsPublic && x.DeploymentType == ExportDeploymentType.FileSystem); ctx.ExecuteContext.PublicFolderPath = (ctx.ExecuteContext.HasPublicDeployment ? Path.Combine(HttpRuntime.AppDomainAppPath, PublicFolder) : null); - var fileExtension = (ctx.Provider.Value.FileExtension.HasValue() ? ctx.Provider.Value.FileExtension.ToLower().EnsureStartsWith(".") : ""); + var fileExtension = (ctx.Request.Provider.Value.FileExtension.HasValue() ? ctx.Request.Provider.Value.FileExtension.ToLower().EnsureStartsWith(".") : ""); using (var segmenter = CreateSegmenter(ctx)) { if (segmenter == null) { - throw new SmartException("Unsupported entity type '{0}'".FormatInvariant(ctx.Provider.Value.EntityType.ToString())); + throw new SmartException("Unsupported entity type '{0}'".FormatInvariant(ctx.Request.Provider.Value.EntityType.ToString())); } if (segmenter.TotalRecords <= 0) @@ -824,7 +823,7 @@ private void ExportCoreInner(DataExporterContext ctx, Store store) if (ctx.IsFileBasedExport) { - var resolvedPattern = ctx.Profile.ResolveFileNamePattern(ctx.Store, ++fileIndex, ctx.ExecuteContext.MaxFileNameLength); + var resolvedPattern = ctx.Request.Profile.ResolveFileNamePattern(ctx.Store, ++fileIndex, ctx.ExecuteContext.MaxFileNameLength); ctx.ExecuteContext.FileName = resolvedPattern + fileExtension; path = Path.Combine(ctx.ExecuteContext.Folder, ctx.ExecuteContext.FileName); @@ -875,7 +874,7 @@ private void ExportCoreInner(DataExporterContext ctx, Store store) private void ExportCoreOuter(DataExporterContext ctx) { - if (ctx.Profile == null || !ctx.Profile.Enabled) + if (ctx.Request.Profile == null || !ctx.Request.Profile.Enabled) return; FileSystemHelper.Delete(ctx.LogPath); @@ -886,7 +885,7 @@ private void ExportCoreOuter(DataExporterContext ctx) { try { - if (!ctx.Provider.IsValid()) + if (!ctx.Request.Provider.IsValid()) { throw new SmartException("Export aborted because the export provider is not valid"); } @@ -895,12 +894,12 @@ private void ExportCoreOuter(DataExporterContext ctx) ctx.ExecuteContext.Log = logger; ctx.ProgressInfo = T("Admin.DataExchange.Export.ProgressInfo"); - if (ctx.Profile.ProviderConfigData.HasValue()) + if (ctx.Request.Profile.ProviderConfigData.HasValue()) { - var configInfo = ctx.Provider.Value.ConfigurationInfo; + var configInfo = ctx.Request.Provider.Value.ConfigurationInfo; if (configInfo != null) { - ctx.ExecuteContext.ConfigurationData = XmlHelper.Deserialize(ctx.Profile.ProviderConfigData, configInfo.ModelType); + ctx.ExecuteContext.ConfigurationData = XmlHelper.Deserialize(ctx.Request.Profile.ProviderConfigData, configInfo.ModelType); } } @@ -911,18 +910,18 @@ private void ExportCoreOuter(DataExporterContext ctx) ctx.QuantityUnits = _quantityUnitService.Value.GetAllQuantityUnits().ToDictionary(x => x.Id); ctx.ProductTemplates = _productTemplateService.Value.GetAllProductTemplates().ToDictionary(x => x.Id); - if (ctx.Provider.Value.EntityType == ExportEntityType.Product) + if (ctx.Request.Provider.Value.EntityType == ExportEntityType.Product) { var allCategories = _categoryService.Value.GetAllCategories(showHidden: true, applyNavigationFilters: false); ctx.Categories = allCategories.ToDictionary(x => x.Id); } - if (ctx.Provider.Value.EntityType == ExportEntityType.Order) + if (ctx.Request.Provider.Value.EntityType == ExportEntityType.Order) { ctx.Countries = _countryService.Value.GetAllCountries(true).ToDictionary(x => x.Id, x => x); } - if (ctx.Provider.Value.EntityType == ExportEntityType.Customer) + if (ctx.Request.Provider.Value.EntityType == ExportEntityType.Customer) { var subscriptionEmails = _subscriptionRepository.Value.TableUntracked .Where(x => x.Active) @@ -946,7 +945,7 @@ private void ExportCoreOuter(DataExporterContext ctx) { if (ctx.IsFileBasedExport) { - if (ctx.Profile.CreateZipArchive || ctx.Profile.Deployments.Any(x => x.Enabled && x.CreateZip)) + if (ctx.Request.Profile.CreateZipArchive || ctx.Request.Profile.Deployments.Any(x => x.Enabled && x.CreateZip)) { ZipFile.CreateFromDirectory(ctx.FolderContent, ctx.ZipPath, CompressionLevel.Fastest, true); } @@ -954,7 +953,7 @@ private void ExportCoreOuter(DataExporterContext ctx) SetProgress(ctx, T("Common.Deployment")); // TODO: deployment - //foreach (var deployment in ctx.Profile.Deployments.OrderBy(x => x.DeploymentTypeId).Where(x => x.Enabled)) + //foreach (var deployment in ctx.Request.Profile.Deployments.OrderBy(x => x.DeploymentTypeId).Where(x => x.Enabled)) //{ // try // { @@ -982,7 +981,7 @@ private void ExportCoreOuter(DataExporterContext ctx) //} } - if (ctx.Profile.EmailAccountId != 0 && ctx.Profile.CompletedEmailAddresses.HasValue()) + if (ctx.Request.Profile.EmailAccountId != 0 && ctx.Request.Profile.CompletedEmailAddresses.HasValue()) { SendCompletionEmail(ctx); } @@ -997,18 +996,18 @@ private void ExportCoreOuter(DataExporterContext ctx) { try { - if (!ctx.IsPreview && ctx.Profile.Id != 0) + if (!ctx.IsPreview && ctx.Request.Profile.Id != 0) { - ctx.Profile.ResultInfo = XmlHelper.Serialize(ctx.Result); + ctx.Request.Profile.ResultInfo = XmlHelper.Serialize(ctx.Result); - _exportProfileService.Value.UpdateExportProfile(ctx.Profile); + _exportProfileService.Value.UpdateExportProfile(ctx.Request.Profile); } } catch { } try { - if (ctx.IsFileBasedExport && ctx.ExecuteContext.Abort != ExportAbortion.Hard && ctx.Profile.Cleanup) + if (ctx.IsFileBasedExport && ctx.ExecuteContext.Abort != ExportAbortion.Hard && ctx.Request.Profile.Cleanup) { FileSystemHelper.ClearDirectory(ctx.FolderContent, false); } @@ -1059,17 +1058,92 @@ public static int PageSize public DataExportResult Export(DataExportRequest request, CancellationToken cancellationToken) { - return null; + var ctx = new DataExporterContext(request, cancellationToken); + + ExportCoreOuter(ctx); + + if (ctx.Result != null && ctx.Result.Succeeded && ctx.Result.Files.Count > 0) + { + string prefix = null; + string suffix = null; + var extension = Path.GetExtension(ctx.Result.Files.First().FileName); + var selectedEntityCount = (request.EntitiesToExport == null ? 0 : request.EntitiesToExport.Count()); + + if (request.Provider.Value.EntityType == ExportEntityType.Product) + prefix = T("Admin.Catalog.Products"); + else if (request.Provider.Value.EntityType == ExportEntityType.Order) + prefix = T("Admin.Orders"); + else if (request.Provider.Value.EntityType == ExportEntityType.Category) + prefix = T("Admin.Catalog.Categories"); + else if (request.Provider.Value.EntityType == ExportEntityType.Manufacturer) + prefix = T("Admin.Catalog.Manufacturers"); + else if (request.Provider.Value.EntityType == ExportEntityType.Customer) + prefix = T("Admin.Customers"); + else if (request.Provider.Value.EntityType == ExportEntityType.NewsLetterSubscription) + prefix = T("Admin.Promotions.NewsLetterSubscriptions"); + else + prefix = request.Provider.Value.EntityType.ToString(); + + if (selectedEntityCount == 0) + suffix = T("Common.All"); + else + suffix = (selectedEntityCount == 1 ? request.EntitiesToExport.First().ToString() : T("Admin.Common.Selected").Text); + + ctx.Result.DownloadFileName = string.Concat(prefix, "-", suffix).ToLower().ToValidFileName() + extension; + } + + return ctx.Result; } public IList Preview(DataExportRequest request) { - return null; + var pageIndex = (request.CustomData.ContainsKey("PageIndex") ? (int)request.CustomData["PageIndex"] : 0); + var totalRecords = (request.CustomData.ContainsKey("TotalRecords") ? (int)request.CustomData["TotalRecords"] : 0); + + var result = new List(); + var cancellation = new CancellationTokenSource(TimeSpan.FromMinutes(5.0)); + + var ctx = new DataExporterContext(request, cancellation.Token, null, true); + + var unused = Init(ctx, totalRecords); + + using (var segmenter = CreateSegmenter(ctx, pageIndex)) + { + if (segmenter == null) + { + throw new SmartException("Unsupported entity type '{0}'".FormatInvariant(ctx.Request.Provider.Value.EntityType.ToString())); + } + + while (segmenter.HasData) + { + segmenter.RecordPerSegmentCount = 0; + + while (segmenter.ReadNextSegment()) + { + result.AddRange(segmenter.CurrentSegment); + } + } + } + + if (ctx.Result.LastError.HasValue()) + { + _services.Notifier.Error(ctx.Result.LastError); + } + + return result; } public long GetDataCount(DataExportRequest request) { - return 0; + var cancellation = new CancellationTokenSource(TimeSpan.FromMinutes(5.0)); + + var ctx = new DataExporterContext(request, cancellation.Token, null, true); + + var unused = Init(ctx); + + var totalCount = ctx.RecordsPerStore.First().Value; + + return totalCount; } } } diff --git a/src/Libraries/SmartStore.Services/DataExchange/Internal/DataExporterContext.cs b/src/Libraries/SmartStore.Services/DataExchange/Internal/DataExporterContext.cs index cb95e67f23..2ae610ca6d 100644 --- a/src/Libraries/SmartStore.Services/DataExchange/Internal/DataExporterContext.cs +++ b/src/Libraries/SmartStore.Services/DataExchange/Internal/DataExporterContext.cs @@ -1,5 +1,4 @@ -using System; -using System.Collections.Generic; +using System.Collections.Generic; using System.IO; using System.Linq; using System.Threading; @@ -12,7 +11,6 @@ using SmartStore.Core.Domain.Localization; using SmartStore.Core.Domain.Stores; using SmartStore.Core.Logging; -using SmartStore.Core.Plugins; using SmartStore.Utilities; namespace SmartStore.Services.DataExchange.Internal @@ -28,21 +26,17 @@ internal class DataExporterContext public DataExporterContext( DataExportRequest request, CancellationToken cancellationToken, - ExportProfile profile, - Provider provider, string selectedIds = null, - Action previewData = null) + bool isPreview = false) { Request = request; CancellationToken = cancellationToken; - Profile = profile; - Provider = provider; - Filter = XmlHelper.Deserialize(profile.Filtering); - Projection = XmlHelper.Deserialize(profile.Projection); + Filter = XmlHelper.Deserialize(request.Profile.Filtering); + Projection = XmlHelper.Deserialize(request.Profile.Projection); EntityIdsSelected = selectedIds.SplitSafe(",").Select(x => x.ToInt()).ToList(); - PreviewData = previewData; + IsPreview = isPreview; - FolderContent = FileSystemHelper.TempDir(@"Profile\Export\{0}\Content".FormatInvariant(profile.FolderName)); + FolderContent = FileSystemHelper.TempDir(@"Profile\Export\{0}\Content".FormatInvariant(request.Profile.FolderName)); FolderRoot = System.IO.Directory.GetParent(FolderContent).FullName; Categories = new Dictionary(); @@ -60,7 +54,7 @@ public DataExporterContext( }; ExecuteContext = new ExportExecuteContext(Result, CancellationToken, FolderContent); - ExecuteContext.Projection = XmlHelper.Deserialize(profile.Projection); + ExecuteContext.Projection = XmlHelper.Deserialize(request.Profile.Projection); } public List EntityIdsSelected { get; private set; } @@ -71,20 +65,13 @@ public DataExporterContext( public string ProgressInfo { get; set; } public IQueryable QueryProducts { get; set; } - public Action PreviewData { get; private set; } - public bool IsPreview - { - get { return PreviewData != null; } - } - public DataExportRequest Request { get; private set; } public CancellationToken CancellationToken { get; private set; } - public ExportProfile Profile { get; private set; } - public Provider Provider { get; private set; } + public bool IsPreview { get; private set; } public bool Supports(ExportFeatures feature) { - return (!IsPreview && Provider.Metadata.ExportFeatures.HasFlag(feature)); + return (!IsPreview && Request.Provider.Metadata.ExportFeatures.HasFlag(feature)); } public ExportFilter Filter { get; private set; } @@ -100,7 +87,7 @@ public bool Supports(ExportFeatures feature) public string FolderContent { get; private set; } public string ZipName { - get { return Profile.FolderName + ".zip"; } + get { return Request.Profile.FolderName + ".zip"; } } public string ZipPath { @@ -113,7 +100,7 @@ public string LogPath public bool IsFileBasedExport { - get { return Provider == null || Provider.Value == null || Provider.Value.FileExtension.HasValue(); } + get { return Request.Provider == null || Request.Provider.Value == null || Request.Provider.Value.FileExtension.HasValue(); } } public string[] GetDeploymentFiles(ExportDeployment deployment) { From fadd6dda9cf31a871c27289ef1f2b78951c6076a Mon Sep 17 00:00:00 2001 From: Marcus Gesing Date: Wed, 11 Nov 2015 17:26:08 +0100 Subject: [PATCH 039/707] ExportController using DataExporter --- .../DataExchange/ExportProfileService.cs | 3 +- .../DataExchange/IDataExporter.cs | 5 +- .../DataExchange/Internal/DataExportTask.cs | 1 + .../DataExchange/Internal/DataExporter.cs | 13 +-- .../DependencyRegistrar.cs | 4 +- .../Controllers/ExportController.cs | 87 ++++++++++--------- 6 files changed, 61 insertions(+), 52 deletions(-) diff --git a/src/Libraries/SmartStore.Services/DataExchange/ExportProfileService.cs b/src/Libraries/SmartStore.Services/DataExchange/ExportProfileService.cs index 1651171aa2..414e5c073a 100644 --- a/src/Libraries/SmartStore.Services/DataExchange/ExportProfileService.cs +++ b/src/Libraries/SmartStore.Services/DataExchange/ExportProfileService.cs @@ -10,6 +10,7 @@ using SmartStore.Core.Events; using SmartStore.Core.Plugins; using SmartStore.Services.DataExchange.ExportTask; +using SmartStore.Services.DataExchange.Internal; using SmartStore.Services.Localization; using SmartStore.Services.Tasks; using SmartStore.Utilities; @@ -91,7 +92,7 @@ public virtual ExportProfile InsertExportProfile(Provider provi task = new ScheduleTask { CronExpression = "0 */6 * * *", // every six hours - Type = (new ExportProfileTask()).GetType().AssemblyQualifiedNameWithoutVersion(), + Type = typeof(DataExportTask).AssemblyQualifiedNameWithoutVersion(), Enabled = false, StopOnError = false, IsHidden = true diff --git a/src/Libraries/SmartStore.Services/DataExchange/IDataExporter.cs b/src/Libraries/SmartStore.Services/DataExchange/IDataExporter.cs index 4a96e5c515..843a15351e 100644 --- a/src/Libraries/SmartStore.Services/DataExchange/IDataExporter.cs +++ b/src/Libraries/SmartStore.Services/DataExchange/IDataExporter.cs @@ -13,12 +13,9 @@ public interface IDataExporter { DataExportResult Export(DataExportRequest request, CancellationToken cancellationToken); - // Handle model conversion for grid in backend's controller IList Preview(DataExportRequest request); - // useful for decision making whether export should - // be processed sync or async - long GetDataCount(DataExportRequest request); + int GetDataCount(DataExportRequest request); } diff --git a/src/Libraries/SmartStore.Services/DataExchange/Internal/DataExportTask.cs b/src/Libraries/SmartStore.Services/DataExchange/Internal/DataExportTask.cs index b1e3d31f54..33b2eb1e2a 100644 --- a/src/Libraries/SmartStore.Services/DataExchange/Internal/DataExportTask.cs +++ b/src/Libraries/SmartStore.Services/DataExchange/Internal/DataExportTask.cs @@ -4,6 +4,7 @@ namespace SmartStore.Services.DataExchange.Internal { + // note: namespace persisted in ScheduleTask.Type public partial class DataExportTask : ITask { private readonly IDataExporter _exporter; diff --git a/src/Libraries/SmartStore.Services/DataExchange/Internal/DataExporter.cs b/src/Libraries/SmartStore.Services/DataExchange/Internal/DataExporter.cs index 37d64d5fbb..faccb9748f 100644 --- a/src/Libraries/SmartStore.Services/DataExchange/Internal/DataExporter.cs +++ b/src/Libraries/SmartStore.Services/DataExchange/Internal/DataExporter.cs @@ -903,8 +903,9 @@ private void ExportCoreOuter(DataExporterContext ctx) } } - // TODO: lazyLoading: false. It requires IDbContextExtensions::Load/QueryFor for properties internally mapped by EF - using (var scope = new DbContextScope(_services.DbContext, autoDetectChanges: false, proxyCreation: false, validateOnSave: false, forceNoTracking: true)) + // TODO: lazyLoading: false, proxyCreation: false possible? how to identify all properties of all data levels of all entities + // that require manual resolving for now and for future? fragile, susceptible to faults (e.g. price calculation)... + using (var scope = new DbContextScope(_services.DbContext, autoDetectChanges: false, proxyCreation: true, validateOnSave: false, forceNoTracking: true)) { ctx.DeliveryTimes = _deliveryTimeService.Value.GetAllDeliveryTimes().ToDictionary(x => x.Id); ctx.QuantityUnits = _quantityUnitService.Value.GetAllQuantityUnits().ToDictionary(x => x.Id); @@ -1100,7 +1101,7 @@ public IList Preview(DataExportRequest request) var pageIndex = (request.CustomData.ContainsKey("PageIndex") ? (int)request.CustomData["PageIndex"] : 0); var totalRecords = (request.CustomData.ContainsKey("TotalRecords") ? (int)request.CustomData["TotalRecords"] : 0); - var result = new List(); + var resultData = new List(); var cancellation = new CancellationTokenSource(TimeSpan.FromMinutes(5.0)); var ctx = new DataExporterContext(request, cancellation.Token, null, true); @@ -1120,7 +1121,7 @@ public IList Preview(DataExportRequest request) while (segmenter.ReadNextSegment()) { - result.AddRange(segmenter.CurrentSegment); + resultData.AddRange(segmenter.CurrentSegment); } } } @@ -1130,10 +1131,10 @@ public IList Preview(DataExportRequest request) _services.Notifier.Error(ctx.Result.LastError); } - return result; + return resultData; } - public long GetDataCount(DataExportRequest request) + public int GetDataCount(DataExportRequest request) { var cancellation = new CancellationTokenSource(TimeSpan.FromMinutes(5.0)); diff --git a/src/Presentation/SmartStore.Web.Framework/DependencyRegistrar.cs b/src/Presentation/SmartStore.Web.Framework/DependencyRegistrar.cs index 7eea57921e..574f649606 100644 --- a/src/Presentation/SmartStore.Web.Framework/DependencyRegistrar.cs +++ b/src/Presentation/SmartStore.Web.Framework/DependencyRegistrar.cs @@ -76,6 +76,7 @@ using Module = Autofac.Module; using SmartStore.Core.Domain.DataExchange; using SmartStore.Utilities.Reflection; +using SmartStore.Services.DataExchange.Internal; namespace SmartStore.Web.Framework { @@ -223,8 +224,9 @@ public virtual void Register(ContainerBuilder builder, ITypeFinder typeFinder, b builder.RegisterType().As().InstancePerRequest(); builder.RegisterType().As().InstancePerRequest(); + builder.RegisterType().As().InstancePerRequest(); - builder.RegisterType().As().InstancePerRequest(); + builder.RegisterType().As().InstancePerRequest(); builder.RegisterType().As().InstancePerRequest(); builder.RegisterType().As().InstancePerRequest(); diff --git a/src/Presentation/SmartStore.Web/Administration/Controllers/ExportController.cs b/src/Presentation/SmartStore.Web/Administration/Controllers/ExportController.cs index e53c712192..55ac7330ac 100644 --- a/src/Presentation/SmartStore.Web/Administration/Controllers/ExportController.cs +++ b/src/Presentation/SmartStore.Web/Administration/Controllers/ExportController.cs @@ -2,11 +2,8 @@ using System.Collections.Generic; using System.IO; using System.Linq; -using System.Net.Mime; -using System.Text; using System.Web; using System.Web.Mvc; -using Autofac; using SmartStore.Admin.Extensions; using SmartStore.Admin.Models.DataExchange; using SmartStore.Core; @@ -21,12 +18,13 @@ using SmartStore.Services.Catalog; using SmartStore.Services.Customers; using SmartStore.Services.DataExchange; -using SmartStore.Services.DataExchange.ExportTask; +using SmartStore.Services.DataExchange.Internal; using SmartStore.Services.Directory; using SmartStore.Services.Helpers; using SmartStore.Services.Localization; using SmartStore.Services.Messages; using SmartStore.Services.Security; +using SmartStore.Services.Tasks; using SmartStore.Web.Framework; using SmartStore.Web.Framework.Controllers; using SmartStore.Web.Framework.Plugins; @@ -48,9 +46,10 @@ public class ExportController : AdminControllerBase private readonly ILanguageService _languageService; private readonly ICurrencyService _currencyService; private readonly IEmailAccountService _emailAccountService; - private readonly IComponentContext _componentContext; private readonly IDateTimeHelper _dateTimeHelper; private readonly DataExchangeSettings _dataExchangeSettings; + private readonly ITaskScheduler _taskScheduler; + private readonly IDataExporter _dataExporter; public ExportController( ICommonServices services, @@ -63,9 +62,10 @@ public ExportController( ILanguageService languageService, ICurrencyService currencyService, IEmailAccountService emailAccountService, - IComponentContext componentContext, IDateTimeHelper dateTimeHelper, - DataExchangeSettings dataExchangeSettings) + DataExchangeSettings dataExchangeSettings, + ITaskScheduler taskScheduler, + IDataExporter dataExporter) { _services = services; _exportService = exportService; @@ -77,9 +77,10 @@ public ExportController( _languageService = languageService; _currencyService = currencyService; _emailAccountService = emailAccountService; - _componentContext = componentContext; _dateTimeHelper = dateTimeHelper; _dataExchangeSettings = dataExchangeSettings; + _taskScheduler = taskScheduler; + _dataExporter = dataExporter; } #region Utilities @@ -245,7 +246,7 @@ private void PrepareProfileModelForEdit(ExportProfileModel model, ExportProfile { try { - var publicFolder = Path.Combine(HttpRuntime.AppDomainAppPath, ExportProfileTask.PublicFolder); + var publicFolder = Path.Combine(HttpRuntime.AppDomainAppPath, DataExporter.PublicFolder); var resultInfo = XmlHelper.Deserialize(profile.ResultInfo); if (resultInfo != null && resultInfo.Files != null) @@ -261,7 +262,7 @@ private void PrepareProfileModelForEdit(ExportProfileModel model, ExportProfile StoreId = store.Id, StoreName = store.Name, FileName = fileInfo.FileName, - FileUrl = string.Concat(store.Url.EnsureEndsWith("/"), ExportProfileTask.PublicFolder.EnsureEndsWith("/"), fileInfo.FileName) + FileUrl = string.Concat(store.Url.EnsureEndsWith("/"), DataExporter.PublicFolder.EnsureEndsWith("/"), fileInfo.FileName) }); } } @@ -722,15 +723,15 @@ public ActionResult Preview(int id) var provider = _exportService.LoadProvider(profile.ProviderSystemName); - var task = new ExportProfileTask(); - var totalRecords = task.GetRecordCount(profile, provider, _componentContext); + var request = new DataExportRequest(profile, provider); + var totalRecords = _dataExporter.GetDataCount(request); var model = new ExportPreviewModel { Id = profile.Id, Name = profile.Name, ThumbnailUrl = GetThumbnailUrl(provider), - GridPageSize = ExportProfileTask.PageSize, + GridPageSize = DataExporter.PageSize, EntityType = provider.Value.EntityType, TotalRecords = totalRecords, LogFileExists = System.IO.File.Exists(profile.GetExportLogFilePath()) @@ -751,25 +752,30 @@ public ActionResult PreviewList(GridCommand command, int id, int totalRecords) { var productModel = new List(); var orderModel = new List(); - var task = new ExportProfileTask(); - Action previewData = x => + var request = new DataExportRequest(profile, provider); + request.CustomData.Add("PageIndex", command.Page - 1); + request.CustomData.Add("TotalRecords", totalRecords); + + var data = _dataExporter.Preview(request); + + foreach (dynamic item in data) { if (provider.Value.EntityType == ExportEntityType.Product) { - var product = x.Entity as Product; + var product = item.Entity as Product; var pm = new ExportPreviewProductModel { - Id = x.Id, - ProductTypeId = x.ProductTypeId, + Id = product.Id, + ProductTypeId = product.ProductTypeId, ProductTypeName = product.GetProductTypeLabel(_services.Localization), ProductTypeLabelHint = product.ProductTypeLabelHint, - Name = x.Name, - Sku = x.Sku, - Price = x.Price, - Published = x.Published, - StockQuantity = x.StockQuantity, - AdminComment = x.AdminComment + Name = item.Name, + Sku = item.Sku, + Price = item.Price, + Published = product.Published, + StockQuantity = product.StockQuantity, + AdminComment = item.AdminComment }; productModel.Add(pm); @@ -778,23 +784,21 @@ public ActionResult PreviewList(GridCommand command, int id, int totalRecords) { var om = new ExportPreviewOrderModel { - Id = x.Id, - HasNewPaymentNotification = x.HasNewPaymentNotification, - OrderNumber = x.OrderNumber, - OrderStatus = x.OrderStatus, - PaymentStatus = x.PaymentStatus, - ShippingStatus = x.ShippingStatus, - CustomerEmail = x.Customer.Email, - StoreName = (x.Store == null ? "".NaIfEmpty() : x.Store.Name), - CreatedOn = _dateTimeHelper.ConvertToUserTime(x.CreatedOnUtc, DateTimeKind.Utc), - OrderTotal = x.OrderTotal + Id = item.Id, + HasNewPaymentNotification = item.HasNewPaymentNotification, + OrderNumber = item.OrderNumber, + OrderStatus = item.OrderStatus, + PaymentStatus = item.PaymentStatus, + ShippingStatus = item.ShippingStatus, + CustomerEmail = item.Customer.Email, + StoreName = (item.Store == null ? "".NaIfEmpty() : item.Store.Name), + CreatedOn = _dateTimeHelper.ConvertToUserTime(item.CreatedOnUtc, DateTimeKind.Utc), + OrderTotal = item.OrderTotal }; orderModel.Add(om); } - }; - - task.Preview(profile, provider, _componentContext, command.Page - 1, totalRecords, previewData); + } var normalizedTotal = totalRecords; @@ -831,12 +835,15 @@ public ActionResult Execute(int id, string selectedIds, bool exportAll) if (profile == null) return RedirectToAction("List"); + // TODO: profile.CacheSelectedEntityIds(selectedIds); - var returnUrl = Url.Action("List", "Export", new { area = "admin" }); + _taskScheduler.RunSingleTask(profile.SchedulingTaskId); - return RedirectToAction("RunJob", "ScheduleTask", new { area = "admin", id = profile.SchedulingTaskId, returnUrl = returnUrl }); - } + NotifyInfo(T("Admin.System.ScheduleTasks.RunNow.Progress")); + + return RedirectToAction("List"); + } [ChildActionOnly] public ActionResult InfoProfile(string systemName, string returnUrl) From b93c2ef966a51d88071244126eb4a3ff37c848ea Mon Sep 17 00:00:00 2001 From: Murat Cakir Date: Wed, 11 Nov 2015 17:44:44 +0100 Subject: [PATCH 040/707] Fix #808: Removed C# 6 features to remain compatible with Visual Studio 2013 --- .../Extensions/StringExtensions.cs | 2 +- .../Extensions/TypeExtensions.cs | 1 - .../Infrastructure/AppDomainTypeFinder.cs | 2 +- .../DependencyManagement/ContainerManager.cs | 70 +++++++--- .../Utilities/Reflection/FastActivator.cs | 127 +++++++++++++++++- .../Utilities/Reflection/FastProperty.cs | 49 +++---- .../SmartStore.Core.Tests/PerformanceTests.cs | 90 ++++++++----- .../Customer/RegisterValidatorTests.cs | 2 +- 8 files changed, 261 insertions(+), 82 deletions(-) diff --git a/src/Libraries/SmartStore.Core/Extensions/StringExtensions.cs b/src/Libraries/SmartStore.Core/Extensions/StringExtensions.cs index 1fca421bad..4a7f28e209 100644 --- a/src/Libraries/SmartStore.Core/Extensions/StringExtensions.cs +++ b/src/Libraries/SmartStore.Core/Extensions/StringExtensions.cs @@ -511,7 +511,7 @@ public static string EncodeJsString(this string value) [DebuggerStepThrough] public static string EncodeJsString(this string value, char delimiter, bool appendDelimiters) { - StringBuilder sb = new StringBuilder(value?.Length ?? 16); + StringBuilder sb = new StringBuilder(value != null ? value.Length : 16); using (StringWriter w = new StringWriter(sb, CultureInfo.InvariantCulture)) { EncodeJsString(w, value, delimiter, appendDelimiters); diff --git a/src/Libraries/SmartStore.Core/Extensions/TypeExtensions.cs b/src/Libraries/SmartStore.Core/Extensions/TypeExtensions.cs index 981d71d9f8..987938eab3 100644 --- a/src/Libraries/SmartStore.Core/Extensions/TypeExtensions.cs +++ b/src/Libraries/SmartStore.Core/Extensions/TypeExtensions.cs @@ -7,7 +7,6 @@ namespace SmartStore { - public static class TypeExtensions { private static Type[] s_predefinedTypes; diff --git a/src/Libraries/SmartStore.Core/Infrastructure/AppDomainTypeFinder.cs b/src/Libraries/SmartStore.Core/Infrastructure/AppDomainTypeFinder.cs index 8e2e1b1498..7c5169afac 100644 --- a/src/Libraries/SmartStore.Core/Infrastructure/AppDomainTypeFinder.cs +++ b/src/Libraries/SmartStore.Core/Infrastructure/AppDomainTypeFinder.cs @@ -21,7 +21,7 @@ public class AppDomainTypeFinder : ITypeFinder private static object s_lock = new object(); - private string _assemblySkipLoadingPattern = @"^System|^mscorlib|^Microsoft|^CppCodeProvider|^VJSharpCodeProvider|^WebDev|^Nuget|^Castle|^Iesi|^log4net|^Autofac|^AutoMapper|^EntityFramework|^EPPlus|^Fasterflect|^nunit|^TestDriven|^MbUnit|^Rhino|^QuickGraph|^TestFu|^Telerik|^Antlr3|^Recaptcha|^FluentValidation|^ImageResizer|^itextsharp|^MiniProfiler|^Newtonsoft|^Pandora|^WebGrease|^Noesis|^DotNetOpenAuth|^Facebook|^LinqToTwitter|^PerceptiveMCAPI|^CookComputing|^GCheckout|^Mono\.Math|^Org\.Mentalis|^App_Web|^BundleTransformer|^ClearScript|^JavaScriptEngineSwitcher|^MsieJavaScriptEngine|^Glimpse|^Ionic|^App_GlobalResources|^AjaxMin|^MaxMind|^NReco|^OffAmazonPayments|^UAParser"; + private string _assemblySkipLoadingPattern = @"^System|^mscorlib|^Microsoft|^CppCodeProvider|^VJSharpCodeProvider|^WebDev|^Nuget|^Castle|^Iesi|^log4net|^Autofac|^AutoMapper|^EntityFramework|^EPPlus|^nunit|^TestDriven|^MbUnit|^Rhino|^QuickGraph|^TestFu|^Telerik|^Antlr3|^Recaptcha|^FluentValidation|^ImageResizer|^itextsharp|^MiniProfiler|^Newtonsoft|^Pandora|^WebGrease|^Noesis|^DotNetOpenAuth|^Facebook|^LinqToTwitter|^PerceptiveMCAPI|^CookComputing|^GCheckout|^Mono\.Math|^Org\.Mentalis|^App_Web|^BundleTransformer|^ClearScript|^JavaScriptEngineSwitcher|^MsieJavaScriptEngine|^Glimpse|^Ionic|^App_GlobalResources|^AjaxMin|^MaxMind|^NReco|^OffAmazonPayments|^UAParser"; private string _assemblyRestrictToLoadingPattern = ".*"; private readonly IDictionary _assemblyMatchTable = new Dictionary(); diff --git a/src/Libraries/SmartStore.Core/Infrastructure/DependencyManagement/ContainerManager.cs b/src/Libraries/SmartStore.Core/Infrastructure/DependencyManagement/ContainerManager.cs index f1abc97e26..c8c8bca9b3 100644 --- a/src/Libraries/SmartStore.Core/Infrastructure/DependencyManagement/ContainerManager.cs +++ b/src/Libraries/SmartStore.Core/Infrastructure/DependencyManagement/ContainerManager.cs @@ -1,15 +1,19 @@ using System; +using System.Collections.Concurrent; using System.Collections.Generic; using System.Linq; +using System.Reflection; using Autofac; using Autofac.Builder; using SmartStore.Core.Caching; +using SmartStore.Utilities.Reflection; namespace SmartStore.Core.Infrastructure.DependencyManagement { public class ContainerManager { private readonly IContainer _container; + private readonly ConcurrentDictionary _cachedActivators = new ConcurrentDictionary(); public ContainerManager(IContainer container) { @@ -61,30 +65,60 @@ public T ResolveUnregistered(ILifetimeScope scope = null) where T : class public object ResolveUnregistered(Type type, ILifetimeScope scope = null) { - var constructors = type.GetConstructors(); + var constructors = type.GetConstructors(BindingFlags.Public | BindingFlags.Instance); foreach (var constructor in constructors) { - try - { - var parameters = constructor.GetParameters(); - var parameterInstances = new List(); - foreach (var parameter in parameters) - { - var service = Resolve(parameter.ParameterType, scope); - if (service == null) - throw new SmartException("Unkown dependency"); - parameterInstances.Add(service); - } - return Activator.CreateInstance(type, parameterInstances.ToArray()); - } - catch - { - - } + object instance; + if (TryInvokeConstructor(constructor, out instance, scope)) + { + return instance; + } } + throw new SmartException("No contructor was found that had all the dependencies satisfied."); } + private FastActivator GetActivatorForUnregisteredService(Type serviceType) + { + FastActivator activator; + if (!_cachedActivators.TryGetValue(serviceType, out activator)) + { + + } + + return activator; + } + + private bool TryInvokeConstructor(ConstructorInfo constructor, out object instance, ILifetimeScope scope = null) + { + instance = null; + + try + { + var parameters = constructor.GetParameters(); + var parameterInstances = new List(); + + foreach (var parameter in parameters) + { + var service = Resolve(parameter.ParameterType, scope); + if (service == null) + { + return false; + } + + parameterInstances.Add(service); + } + + instance = constructor.Invoke(parameterInstances.ToArray()); + + return instance != null; + } + catch + { + return false; + } + } + public bool TryResolve(Type serviceType, ILifetimeScope scope, out object instance) { return (scope ?? Scope()).TryResolve(serviceType, out instance); diff --git a/src/Libraries/SmartStore.Core/Utilities/Reflection/FastActivator.cs b/src/Libraries/SmartStore.Core/Utilities/Reflection/FastActivator.cs index 88de6542d6..970ddd6ec1 100644 --- a/src/Libraries/SmartStore.Core/Utilities/Reflection/FastActivator.cs +++ b/src/Libraries/SmartStore.Core/Utilities/Reflection/FastActivator.cs @@ -5,12 +5,13 @@ using System.Reflection; using System.Threading.Tasks; using System.Linq.Expressions; +using System.Collections.Concurrent; namespace SmartStore.Utilities.Reflection { public class FastActivator { - private Action _invoker; + private static readonly ConcurrentDictionary _activatorsCache = new ConcurrentDictionary(); public FastActivator(ConstructorInfo constructorInfo) { @@ -23,12 +24,12 @@ public FastActivator(ConstructorInfo constructorInfo) /// /// Gets the backing . /// - public ConstructorInfo Constructor { get; } + public ConstructorInfo Constructor { get; private set; } /// /// Gets the constructor invoker. /// - public Func Invoker { get; } + public Func Invoker { get; private set; } /// /// Creates an instance of the type using the specified parameters. @@ -70,5 +71,125 @@ public static Func MakeFastInvoker(ConstructorInfo constructor return lambda.Compile(); } + + #region Static + + /// + /// Creates and caches fast constructor invokers + /// + /// The type to extract fast constructor invokers for + /// A cached array of all public instance constructors from the given type. + /// The parameterless default constructor is always excluded from the list of activators + public static FastActivator[] GetActivators(Type type) + { + return GetActivatorsCore(type); + } + + private static FastActivator[] GetActivatorsCore(Type type) + { + FastActivator[] activators; + if (!_activatorsCache.TryGetValue(type, out activators)) + { + var candidates = GetCandidateConstructors(type); + activators = candidates.Select(c => new FastActivator(c)).ToArray(); + _activatorsCache.TryAdd(type, activators); + } + + return activators; + } + + /// + /// Creates an instance of the specified type using the constructor that best matches the specified parameters. + /// + /// The type of object to create. + /// + /// An array of arguments that match in number, order, and type the parameters of the constructor to invoke. + /// If args is an empty array or null, the constructor that takes no parameters (the default constructor) is invoked. + /// + /// A reference to the newly created object. + public static T CreateInstance(params object[] args) + { + return (T)CreateInstance(typeof(T), args); + } + + /// + /// Creates an instance of the specified type using the constructor that best matches the specified parameters. + /// + /// The type of object to create. + /// + /// An array of arguments that match in number, order, and type the parameters of the constructor to invoke. + /// If args is an empty array or null, the constructor that takes no parameters (the default constructor) is invoked. + /// + /// A reference to the newly created object. + public static object CreateInstance(Type type, params object[] args) + { + Guard.ArgumentNotNull(() => type); + + if (args == null || args.Length == 0) + { + // don't struggle with FastActivator: native reflection is really fast with default constructor! + return Activator.CreateInstance(type); + } + + var activators = GetActivatorsCore(type); + var matchingActivator = FindMatchingActivatorCore(activators, type, args); + + if (matchingActivator == null) + { + throw new ArgumentException("No matching contructor was found for the given arguments.", "args"); + } + + return matchingActivator.Activate(args); + } + + public static FastActivator FindMatchingActivator(Type type, params object[] args) + { + var activators = GetActivatorsCore(type); + var matchingActivator = FindMatchingActivatorCore(activators, type, args); + + return matchingActivator; + } + + private static FastActivator FindMatchingActivatorCore(FastActivator[] activators, Type type, object[] args) + { + if (activators.Length == 0) + { + return null; + } + + if (activators.Length == 1) + { + // this seems to be bad design, but it's on purpose for performance reasons. + // In nearly ALL cases there is only one constructor. + return activators[0]; + } + + var argTypes = args.Select(x => x.GetType()).ToArray(); + var constructor = type.GetConstructor(BindingFlags.Instance | BindingFlags.CreateInstance | BindingFlags.Public, null, argTypes, null); + + if (constructor != null) + { + var matchingActivator = activators.FirstOrDefault(a => a.Constructor == constructor); + return matchingActivator; + } + + return null; + } + + private static IEnumerable GetCandidateConstructors(Type type) + { + var constructors = type.GetConstructors(BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly); + return constructors.Where(c => c.GetParameters().Length > 0); + } + + private static void CheckIsValidType(Type type) + { + if (type.IsAbstract || type.IsInterface) + { + throw new ArgumentException("The type to create activators for must be concrete. Type: {0}".FormatInvariant(type.ToString()), "type"); + } + } + + #endregion } } diff --git a/src/Libraries/SmartStore.Core/Utilities/Reflection/FastProperty.cs b/src/Libraries/SmartStore.Core/Utilities/Reflection/FastProperty.cs index fd26b61225..65a726248f 100644 --- a/src/Libraries/SmartStore.Core/Utilities/Reflection/FastProperty.cs +++ b/src/Libraries/SmartStore.Core/Utilities/Reflection/FastProperty.cs @@ -16,17 +16,17 @@ public class FastProperty // Delegate type for a by-ref property getter private delegate TValue ByRefFunc(ref TDeclaringType arg); - private static readonly MethodInfo CallPropertyGetterOpenGenericMethod = typeof(FastProperty).GetTypeInfo().GetDeclaredMethod(nameof(CallPropertyGetter)); - private static readonly MethodInfo CallPropertyGetterByReferenceOpenGenericMethod = typeof(FastProperty).GetTypeInfo().GetDeclaredMethod(nameof(CallPropertyGetterByReference)); - private static readonly MethodInfo CallNullSafePropertyGetterOpenGenericMethod = typeof(FastProperty).GetTypeInfo().GetDeclaredMethod(nameof(CallNullSafePropertyGetter)); - private static readonly MethodInfo CallNullSafePropertyGetterByReferenceOpenGenericMethod = typeof(FastProperty).GetTypeInfo().GetDeclaredMethod(nameof(CallNullSafePropertyGetterByReference)); - private static readonly MethodInfo CallPropertySetterOpenGenericMethod = typeof(FastProperty).GetTypeInfo().GetDeclaredMethod(nameof(CallPropertySetter)); + private static readonly MethodInfo CallPropertyGetterOpenGenericMethod = typeof(FastProperty).GetTypeInfo().GetDeclaredMethod("CallPropertyGetter"); + private static readonly MethodInfo CallPropertyGetterByReferenceOpenGenericMethod = typeof(FastProperty).GetTypeInfo().GetDeclaredMethod("CallPropertyGetterByReference"); + private static readonly MethodInfo CallNullSafePropertyGetterOpenGenericMethod = typeof(FastProperty).GetTypeInfo().GetDeclaredMethod("CallNullSafePropertyGetter"); + private static readonly MethodInfo CallNullSafePropertyGetterByReferenceOpenGenericMethod = typeof(FastProperty).GetTypeInfo().GetDeclaredMethod("CallNullSafePropertyGetterByReference"); + private static readonly MethodInfo CallPropertySetterOpenGenericMethod = typeof(FastProperty).GetTypeInfo().GetDeclaredMethod("CallPropertySetter"); - private static readonly ConcurrentDictionary SinglePropertiesCache = new ConcurrentDictionary(); + private static readonly ConcurrentDictionary _singlePropertiesCache = new ConcurrentDictionary(); // Using an array rather than IEnumerable, as target will be called on the hot path numerous times. - private static readonly ConcurrentDictionary> PropertiesCache = new ConcurrentDictionary>(); - private static readonly ConcurrentDictionary> VisiblePropertiesCache = new ConcurrentDictionary>(); + private static readonly ConcurrentDictionary> _propertiesCache = new ConcurrentDictionary>(); + private static readonly ConcurrentDictionary> _visiblePropertiesCache = new ConcurrentDictionary>(); private Action _valueSetter; @@ -36,10 +36,7 @@ public class FastProperty /// public FastProperty(PropertyInfo property) { - if (property == null) - { - throw new ArgumentNullException(nameof(property)); - } + Guard.ArgumentNotNull(() => property); Property = property; Name = property.Name; @@ -49,7 +46,7 @@ public FastProperty(PropertyInfo property) /// /// Gets the backing . /// - public PropertyInfo Property { get; } + public PropertyInfo Property { get; private set; } /// /// Gets (or sets in derived types) the property name. @@ -59,7 +56,7 @@ public FastProperty(PropertyInfo property) /// /// Gets the property value getter. /// - public Func ValueGetter { get; } + public Func ValueGetter { get; private set; } /// /// Gets the property value setter. @@ -119,7 +116,7 @@ public static IReadOnlyDictionary GetProperties(object ins /// public static IReadOnlyDictionary GetProperties(Type type) { - return (IReadOnlyDictionary)GetProperties(type, CreateInstance, PropertiesCache); + return (IReadOnlyDictionary)GetProperties(type, CreateInstance, _propertiesCache); } /// @@ -138,7 +135,7 @@ public static IReadOnlyDictionary GetProperties(Type type) /// public static IReadOnlyDictionary GetVisibleProperties(object instance) { - return (IReadOnlyDictionary)GetVisibleProperties(instance.GetType(), CreateInstance, PropertiesCache, VisiblePropertiesCache); + return (IReadOnlyDictionary)GetVisibleProperties(instance.GetType(), CreateInstance, _propertiesCache, _visiblePropertiesCache); } /// @@ -157,7 +154,7 @@ public static IReadOnlyDictionary GetVisibleProperties(obj /// public static IReadOnlyDictionary GetVisibleProperties(Type type) { - return (IReadOnlyDictionary)GetVisibleProperties(type, CreateInstance, PropertiesCache, VisiblePropertiesCache); + return (IReadOnlyDictionary)GetVisibleProperties(type, CreateInstance, _propertiesCache, _visiblePropertiesCache); } public static FastProperty GetProperty(Type type, string propertyName, bool cacheAllProperties = false) @@ -172,21 +169,21 @@ public static FastProperty GetProperty(Type type, string propertyName, bool cach return fastProperty; } - if (PropertiesCache.TryGetValue(type, out allProperties)) + if (_propertiesCache.TryGetValue(type, out allProperties)) { allProperties.TryGetValue(propertyName, out fastProperty); return fastProperty; } var key = new PropertyKey(type, propertyName); - if (!SinglePropertiesCache.TryGetValue(key, out fastProperty)) + if (!_singlePropertiesCache.TryGetValue(key, out fastProperty)) { - var pi = GetPropertyCandidates(type).Where(p => p.Name.Equals(propertyName, StringComparison.OrdinalIgnoreCase)).FirstOrDefault(); + var pi = GetCandidateProperties(type).Where(p => p.Name.Equals(propertyName, StringComparison.OrdinalIgnoreCase)).FirstOrDefault(); //var pi = type.GetProperty(propertyName, BindingFlags.Public | BindingFlags.Instance | BindingFlags.IgnoreCase); if (pi != null) { fastProperty = CreateInstance(pi); - SinglePropertiesCache.TryAdd(key, fastProperty); + _singlePropertiesCache.TryAdd(key, fastProperty); } } @@ -483,7 +480,11 @@ protected static IDictionary GetVisibleProperties( break; } - currentTypeInfo = currentTypeInfo.BaseType?.GetTypeInfo(); + if (currentTypeInfo.BaseType != null) + { + currentTypeInfo = currentTypeInfo.BaseType.GetTypeInfo(); + } + } if (!ignoreProperty) @@ -509,7 +510,7 @@ protected static IDictionary GetProperties( IDictionary fastProperties; if (!cache.TryGetValue(type, out fastProperties)) { - var candidates = GetPropertyCandidates(type); + var candidates = GetCandidateProperties(type); fastProperties = candidates.Select(p => createPropertyHelper(p)).ToDictionary(x => x.Name, StringComparer.OrdinalIgnoreCase); cache.TryAdd(type, fastProperties); } @@ -517,7 +518,7 @@ protected static IDictionary GetProperties( return fastProperties; } - private static IEnumerable GetPropertyCandidates(Type type) + private static IEnumerable GetCandidateProperties(Type type) { // We avoid loading indexed properties using the Where statement. var properties = type.GetRuntimeProperties().Where(IsCandidateProperty); diff --git a/src/Tests/SmartStore.Core.Tests/PerformanceTests.cs b/src/Tests/SmartStore.Core.Tests/PerformanceTests.cs index ee3e85d923..e0b542d3be 100644 --- a/src/Tests/SmartStore.Core.Tests/PerformanceTests.cs +++ b/src/Tests/SmartStore.Core.Tests/PerformanceTests.cs @@ -1,36 +1,60 @@ -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.Reflection; -using NUnit.Framework; -using SmartStore.Core.Domain.Catalog; -using SmartStore.Tests; -using SmartStore.Utilities.Reflection; - -namespace SmartStore.Core.Tests -{ - [TestFixture] - public class PerformanceTests - { - [Test] - public void InstantiatePerfTest() - { - int cycles = 500000; - - Chronometer.Measure(cycles, "Create Product NATIVE", i => new Product()); - Chronometer.Measure(cycles, "Create Product Reflection", i => Activator.CreateInstance(typeof(Product))); - - var list = new List(); - - Chronometer.Measure(cycles, "Create List NATIVE", i => new List(list)); - Chronometer.Measure(cycles, "Create List Reflection", i => Activator.CreateInstance(typeof(List), list)); - - var ctor = typeof(List).GetConstructor(new Type[] { typeof(List) }); - var activator = new FastActivator(ctor); - Chronometer.Measure(cycles, "Create List FASTACTIVATOR", i => activator.Activate(list) ); - } - } -} +//using System; +//using System.Collections.Generic; +//using System.Diagnostics; +//using System.Reflection; +//using NUnit.Framework; +//using SmartStore.Core.Domain.Catalog; +//using SmartStore.Tests; +//using SmartStore.Utilities.Reflection; + +//namespace SmartStore.Core.Tests +//{ +// [TestFixture] +// public class PerformanceTests +// { +// [Test] +// public void InstantiatePerfTest() +// { +// int cycles = 500000; + +// Chronometer.Measure(cycles, "Create Product NATIVE", i => new Product()); +// Chronometer.Measure(cycles, "Create Product Reflection", i => Activator.CreateInstance(typeof(Product))); + +// var list = new List(); + +// Chronometer.Measure(cycles, "Create List NATIVE", i => new TestClass(list)); +// Chronometer.Measure(cycles, "Create List Reflection", i => Activator.CreateInstance(typeof(TestClass), list)); +// Chronometer.Measure(cycles, "Create List FASTACTIVATOR.CreateInstance()", i => FastActivator.CreateInstance(typeof(TestClass), list) ); + +// var ctor = typeof(TestClass).GetConstructor(new Type[] { typeof(List) }); +// //var activator = new FastActivator(ctor); +// var activator = FastActivator.FindMatchingActivator(typeof(TestClass), list); +// Chronometer.Measure(cycles, "Create List FASTACTIVATOR.Activate()", i => activator.Activate(list)); + +// Chronometer.Measure(cycles, "Create List CTOR.Invoke()", i => ctor.Invoke(new object[] { list })); +// } +// } + +// public class TestClass +// { +// //public TestClass() +// //{ +// //} +// public TestClass(IEnumerable param1) +// { +// } +// //public TestClass(int param1) +// //{ +// //} +// //public TestClass(IEnumerable param1, int param2) +// //{ +// //} +// //public TestClass(IEnumerable param1, int param2, string param3) +// //{ +// //} +// } + +//} diff --git a/src/Tests/SmartStore.Web.MVC.Tests/Public/Validators/Customer/RegisterValidatorTests.cs b/src/Tests/SmartStore.Web.MVC.Tests/Public/Validators/Customer/RegisterValidatorTests.cs index 8998a635ef..71787a6fae 100644 --- a/src/Tests/SmartStore.Web.MVC.Tests/Public/Validators/Customer/RegisterValidatorTests.cs +++ b/src/Tests/SmartStore.Web.MVC.Tests/Public/Validators/Customer/RegisterValidatorTests.cs @@ -12,7 +12,7 @@ public class RegisterValidatorTests : BaseValidatorTests { private RegisterValidator _validator; private CustomerSettings _customerSettings; - private TaxSettings _taxSettings; + private TaxSettings _taxSettings = new TaxSettings(); [SetUp] public new void Setup() From dd0162d9c9f389210522411cc33041c7e1dbb99e Mon Sep 17 00:00:00 2001 From: Murat Cakir Date: Wed, 11 Nov 2015 18:55:06 +0100 Subject: [PATCH 041/707] * (Perf) ContainerManager.ResolveUnregistered() now much faster * (Perf) FluentValidator instances are now request scoped, not transient --- .../DependencyManagement/ContainerManager.cs | 63 +++++----- .../Utilities/Reflection/FastActivator.cs | 40 +++--- .../Security/PermissionService.cs | 2 +- .../Validators/SmartValidatorFactory.cs | 27 +++-- .../SmartStore.Core.Tests/PerformanceTests.cs | 114 +++++++++--------- 5 files changed, 136 insertions(+), 110 deletions(-) diff --git a/src/Libraries/SmartStore.Core/Infrastructure/DependencyManagement/ContainerManager.cs b/src/Libraries/SmartStore.Core/Infrastructure/DependencyManagement/ContainerManager.cs index c8c8bca9b3..d0effe4bee 100644 --- a/src/Libraries/SmartStore.Core/Infrastructure/DependencyManagement/ContainerManager.cs +++ b/src/Libraries/SmartStore.Core/Infrastructure/DependencyManagement/ContainerManager.cs @@ -65,53 +65,60 @@ public T ResolveUnregistered(ILifetimeScope scope = null) where T : class public object ResolveUnregistered(Type type, ILifetimeScope scope = null) { - var constructors = type.GetConstructors(BindingFlags.Public | BindingFlags.Instance); - foreach (var constructor in constructors) - { - object instance; - if (TryInvokeConstructor(constructor, out instance, scope)) + FastActivator activator; + object[] parameterInstances = null; + + if (!_cachedActivators.TryGetValue(type, out activator)) + { + var constructors = type.GetConstructors(BindingFlags.Public | BindingFlags.CreateInstance | BindingFlags.Instance); + foreach (var constructor in constructors) { - return instance; + var parameterTypes = constructor.GetParameters().Select(p => p.ParameterType).ToArray(); + if (TryResolveAll(parameterTypes, out parameterInstances, scope)) + { + activator = new FastActivator(constructor); + _cachedActivators.TryAdd(type, activator); + break; + } } - } - - throw new SmartException("No contructor was found that had all the dependencies satisfied."); - } + } - private FastActivator GetActivatorForUnregisteredService(Type serviceType) - { - FastActivator activator; - if (!_cachedActivators.TryGetValue(serviceType, out activator)) + if (activator != null) { - + if (parameterInstances == null) + { + TryResolveAll(activator.ParameterTypes, out parameterInstances, scope); + } + if (parameterInstances != null) + { + return activator.Activate(parameterInstances); + } } - return activator; - } + throw new SmartException("No contructor was found that had all the dependencies satisfied."); + } - private bool TryInvokeConstructor(ConstructorInfo constructor, out object instance, ILifetimeScope scope = null) + private bool TryResolveAll(Type[] types, out object[] instances, ILifetimeScope scope = null) { - instance = null; + instances = null; try { - var parameters = constructor.GetParameters(); - var parameterInstances = new List(); - - foreach (var parameter in parameters) + var instances2 = new object[types.Length]; + + for (int i = 0; i < types.Length; i++) { - var service = Resolve(parameter.ParameterType, scope); + var service = Resolve(types[i], scope); if (service == null) { return false; } - parameterInstances.Add(service); + instances2[i] = service; } - instance = constructor.Invoke(parameterInstances.ToArray()); - - return instance != null; + instances = instances2; + return true; } catch { diff --git a/src/Libraries/SmartStore.Core/Utilities/Reflection/FastActivator.cs b/src/Libraries/SmartStore.Core/Utilities/Reflection/FastActivator.cs index 970ddd6ec1..3f95ddeee4 100644 --- a/src/Libraries/SmartStore.Core/Utilities/Reflection/FastActivator.cs +++ b/src/Libraries/SmartStore.Core/Utilities/Reflection/FastActivator.cs @@ -19,13 +19,19 @@ public FastActivator(ConstructorInfo constructorInfo) Constructor = constructorInfo; Invoker = MakeFastInvoker(constructorInfo); + ParameterTypes = constructorInfo.GetParameters().Select(p => p.ParameterType).ToArray(); } /// - /// Gets the backing . + /// Gets the backing . /// public ConstructorInfo Constructor { get; private set; } + /// + /// Gets the parameter types from the backing + /// + public Type[] ParameterTypes { get; private set; } + /// /// Gets the constructor invoker. /// @@ -47,27 +53,29 @@ public object Activate(params object[] parameters) /// a fast invoker. public static Func MakeFastInvoker(ConstructorInfo constructorInfo) { - // parameters to execute - var parametersParameter = Expression.Parameter(typeof(object[]), "parameters"); + var paramsInfo = constructorInfo.GetParameters(); - // build parameter list - var parameterExpressions = new List(); - var paramInfos = constructorInfo.GetParameters(); - for (int i = 0; i < paramInfos.Length; i++) + var parametersExpression = Expression.Parameter(typeof(object[]), "args"); + var argumentsExpression = new Expression[paramsInfo.Length]; + + for (int paramIndex = 0; paramIndex < paramsInfo.Length; paramIndex++) { - var valueObj = Expression.ArrayIndex(parametersParameter, Expression.Constant(i)); - var valueCast = Expression.Convert(valueObj, paramInfos[i].ParameterType); + var indexExpression = Expression.Constant(paramIndex); + var parameterType = paramsInfo[paramIndex].ParameterType; - parameterExpressions.Add(valueCast); - } + var parameterIndexExpression = Expression.ArrayIndex(parametersExpression, indexExpression); + var convertExpression = Expression.Convert(parameterIndexExpression, parameterType); + argumentsExpression[paramIndex] = convertExpression; - // new T((T0)parameters[0], (T1)parameters[1], ...) - var instanceCreate = Expression.New(constructorInfo, parameterExpressions); + if (!parameterType.GetTypeInfo().IsValueType) + continue; - // (object)new T((T0)parameters[0], (T1)parameters[1], ...) - var instanceCreateCast = Expression.Convert(instanceCreate, typeof(object)); + var nullConditionExpression = Expression.Equal(parameterIndexExpression, Expression.Constant(null)); + argumentsExpression[paramIndex] = Expression.Condition(nullConditionExpression, Expression.Default(parameterType), convertExpression); + } - var lambda = Expression.Lambda>(instanceCreateCast, parametersParameter); + var newExpression = Expression.New(constructorInfo, argumentsExpression); + var lambda = Expression.Lambda>(newExpression, parametersExpression); return lambda.Compile(); } diff --git a/src/Libraries/SmartStore.Services/Security/PermissionService.cs b/src/Libraries/SmartStore.Services/Security/PermissionService.cs index a4c8bd1803..3ea2815466 100644 --- a/src/Libraries/SmartStore.Services/Security/PermissionService.cs +++ b/src/Libraries/SmartStore.Services/Security/PermissionService.cs @@ -207,7 +207,7 @@ public virtual void InstallPermissions(IPermissionProvider permissionProvider) if (customerRole == null) { //new role (save it) - customerRole = new CustomerRole() + customerRole = new CustomerRole { Name = defaultPermission.CustomerRoleSystemName, Active = true, diff --git a/src/Presentation/SmartStore.Web.Framework/Validators/SmartValidatorFactory.cs b/src/Presentation/SmartStore.Web.Framework/Validators/SmartValidatorFactory.cs index fd72c748ed..7a1eea0a51 100644 --- a/src/Presentation/SmartStore.Web.Framework/Validators/SmartValidatorFactory.cs +++ b/src/Presentation/SmartStore.Web.Framework/Validators/SmartValidatorFactory.cs @@ -1,28 +1,39 @@ using System; using FluentValidation; using FluentValidation.Attributes; +using SmartStore.Core.Caching; using SmartStore.Core.Infrastructure; namespace SmartStore.Web.Framework.Validators { public class SmartValidatorFactory : AttributedValidatorFactory { - //private readonly InstanceCache _cache = new InstanceCache(); public override IValidator GetValidator(Type type) { if (type != null) { - var attribute = (ValidatorAttribute)Attribute.GetCustomAttribute(type, typeof(ValidatorAttribute)); + var attribute = (ValidatorAttribute)Attribute.GetCustomAttribute(type, typeof(ValidatorAttribute)); if ((attribute != null) && (attribute.ValidatorType != null)) { - //validators can depend on some customer specific settings (such as working language) - //that's why we do not cache validators - //var instance = _cache.GetOrCreateInstance(attribute.ValidatorType, - // x => EngineContext.Current.ContainerManager.ResolveUnregistered(x)); - var instance = EngineContext.Current.ContainerManager.ResolveUnregistered(attribute.ValidatorType); - return instance as IValidator; + var container = EngineContext.Current.ContainerManager; + + // Validators can depend on some scoped dependencies settings (such as working language), + // that's why we do not cache validators in a singleton cache. + var requestCache = container.Resolve(); + + string cacheKey = "FluentValidator.{0}".FormatInvariant(attribute.ValidatorType.ToString()); + var result = requestCache.Get(cacheKey, () => + { + System.Diagnostics.Debug.WriteLine("VAL: " + type.Name); + + var instance = EngineContext.Current.ContainerManager.ResolveUnregistered(attribute.ValidatorType); + return instance as IValidator; + }); + + return result; } } + return null; } diff --git a/src/Tests/SmartStore.Core.Tests/PerformanceTests.cs b/src/Tests/SmartStore.Core.Tests/PerformanceTests.cs index e0b542d3be..1f1330805e 100644 --- a/src/Tests/SmartStore.Core.Tests/PerformanceTests.cs +++ b/src/Tests/SmartStore.Core.Tests/PerformanceTests.cs @@ -1,60 +1,60 @@ -//using System; -//using System.Collections.Generic; -//using System.Diagnostics; -//using System.Reflection; -//using NUnit.Framework; -//using SmartStore.Core.Domain.Catalog; -//using SmartStore.Tests; -//using SmartStore.Utilities.Reflection; - -//namespace SmartStore.Core.Tests -//{ -// [TestFixture] -// public class PerformanceTests -// { -// [Test] -// public void InstantiatePerfTest() -// { -// int cycles = 500000; - -// Chronometer.Measure(cycles, "Create Product NATIVE", i => new Product()); -// Chronometer.Measure(cycles, "Create Product Reflection", i => Activator.CreateInstance(typeof(Product))); - -// var list = new List(); - -// Chronometer.Measure(cycles, "Create List NATIVE", i => new TestClass(list)); -// Chronometer.Measure(cycles, "Create List Reflection", i => Activator.CreateInstance(typeof(TestClass), list)); -// Chronometer.Measure(cycles, "Create List FASTACTIVATOR.CreateInstance()", i => FastActivator.CreateInstance(typeof(TestClass), list) ); - -// var ctor = typeof(TestClass).GetConstructor(new Type[] { typeof(List) }); -// //var activator = new FastActivator(ctor); -// var activator = FastActivator.FindMatchingActivator(typeof(TestClass), list); -// Chronometer.Measure(cycles, "Create List FASTACTIVATOR.Activate()", i => activator.Activate(list)); - -// Chronometer.Measure(cycles, "Create List CTOR.Invoke()", i => ctor.Invoke(new object[] { list })); -// } -// } - -// public class TestClass -// { -// //public TestClass() -// //{ -// //} -// public TestClass(IEnumerable param1) -// { -// } -// //public TestClass(int param1) -// //{ -// //} -// //public TestClass(IEnumerable param1, int param2) -// //{ -// //} -// //public TestClass(IEnumerable param1, int param2, string param3) -// //{ -// //} -// } - -//} +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Reflection; +using NUnit.Framework; +using SmartStore.Core.Domain.Catalog; +using SmartStore.Tests; +using SmartStore.Utilities.Reflection; + +namespace SmartStore.Core.Tests +{ + [TestFixture] + public class PerformanceTests + { + [Test] + public void InstantiatePerfTest() + { + int cycles = 500000; + + Chronometer.Measure(cycles, "Create Product NATIVE", i => new Product()); + Chronometer.Measure(cycles, "Create Product Reflection", i => Activator.CreateInstance(typeof(Product))); + + var list = new List(); + + Chronometer.Measure(cycles, "Create List NATIVE", i => new TestClass(list)); + Chronometer.Measure(cycles, "Create List Reflection", i => Activator.CreateInstance(typeof(TestClass), list)); + Chronometer.Measure(cycles, "Create List FASTACTIVATOR.CreateInstance()", i => FastActivator.CreateInstance(typeof(TestClass), list) ); + + var ctor = typeof(TestClass).GetConstructor(new Type[] { typeof(List) }); + //var activator = new FastActivator(ctor); + var activator = FastActivator.FindMatchingActivator(typeof(TestClass), list); + Chronometer.Measure(cycles, "Create List FASTACTIVATOR.Activate()", i => activator.Activate(list)); + + Chronometer.Measure(cycles, "Create List CTOR.Invoke()", i => ctor.Invoke(new object[] { list })); + } + } + + public class TestClass + { + public TestClass() + { + } + public TestClass(IEnumerable param1) + { + } + public TestClass(int param1) + { + } + public TestClass(IEnumerable param1, int param2) + { + } + public TestClass(IEnumerable param1, int param2, string param3) + { + } + } + +} From e178bf51efcb3636833c6e7376dbfb9068936bbe Mon Sep 17 00:00:00 2001 From: Marcus Gesing Date: Wed, 11 Nov 2015 19:51:50 +0100 Subject: [PATCH 042/707] Export of selected entities using task parameter instead of HTTP runtime cache --- .../Collections/Querystring.cs | 11 ++++---- .../201509150931528_ExportFramework2.cs | 4 +++ .../DataExchange/ExportExtensions.cs | 28 ------------------- .../ExportTask/ExportProfileTask.cs | 2 +- .../DataExchange/Internal/DataExportTask.cs | 11 ++------ .../DataExchange/Internal/DataExporter.cs | 12 ++++++-- .../Internal/DataExporterContext.cs | 3 +- .../Tasks/TaskScheduler.cs | 2 +- .../Controllers/ExportController.cs | 13 ++++++--- .../Administration/Views/Export/List.cshtml | 1 - .../Views/Export/Preview.cshtml | 8 ++++-- 11 files changed, 40 insertions(+), 55 deletions(-) diff --git a/src/Libraries/SmartStore.Core/Collections/Querystring.cs b/src/Libraries/SmartStore.Core/Collections/Querystring.cs index 76606ef24d..e430e4ccb2 100644 --- a/src/Libraries/SmartStore.Core/Collections/Querystring.cs +++ b/src/Libraries/SmartStore.Core/Collections/Querystring.cs @@ -45,22 +45,23 @@ public static string ExtractQuerystring(string s) /// /// the string to parse /// the QueryString object - public QueryString FillFromString(string s) + public QueryString FillFromString(string s, bool urlDecode = false) { base.Clear(); if (string.IsNullOrEmpty(s)) { return this; } + foreach (string keyValuePair in ExtractQuerystring(s).Split('&')) { if (string.IsNullOrEmpty(keyValuePair)) { continue; } + string[] split = keyValuePair.Split('='); - base.Add(split[0], - split.Length == 2 ? split[1] : ""); + base.Add(split[0], split.Length == 2 ? (urlDecode ? HttpUtility.UrlDecode(split[1]) : split[1]) : ""); } return this; } @@ -73,7 +74,7 @@ public QueryString FromCurrent() { if (HttpContext.Current != null) { - return FillFromString(HttpContext.Current.Request.QueryString.ToString()); + return FillFromString(HttpContext.Current.Request.QueryString.ToString(), true); } base.Clear(); return this; @@ -182,7 +183,7 @@ public override string ToString() { if (!string.IsNullOrEmpty(base.Keys[i])) { - foreach (string val in base[base.Keys[i]].Split(',')) + foreach (string val in base[base.Keys[i]].EmptyNull().Split(',')) { builder.Append((builder.Length == 0) ? "?" : "&").Append( HttpUtility.UrlEncode(base.Keys[i])).Append("=").Append(val); diff --git a/src/Libraries/SmartStore.Data/Migrations/201509150931528_ExportFramework2.cs b/src/Libraries/SmartStore.Data/Migrations/201509150931528_ExportFramework2.cs index 819cb147ae..b32ed81653 100644 --- a/src/Libraries/SmartStore.Data/Migrations/201509150931528_ExportFramework2.cs +++ b/src/Libraries/SmartStore.Data/Migrations/201509150931528_ExportFramework2.cs @@ -56,6 +56,10 @@ public void MigrateLocaleResources(LocaleResourcesBuilder builder) "Cannot load the provider {0}.", "Der Provider {0} konnte nicht geladen werden."); + builder.AddOrUpdate("Admin.Common.NoEntriesSelected", + "No entries have been selected.", + "Es wurden keine Eintrge ausgewhlt."); + builder.AddOrUpdate("ActivityLog.EditPaymentMethod", "Edited payment method '{0}' ({1})", "Zahlungsart '{0}' ({1}) bearbeitet"); diff --git a/src/Libraries/SmartStore.Services/DataExchange/ExportExtensions.cs b/src/Libraries/SmartStore.Services/DataExchange/ExportExtensions.cs index 8a0cdc959d..cf86f0d411 100644 --- a/src/Libraries/SmartStore.Services/DataExchange/ExportExtensions.cs +++ b/src/Libraries/SmartStore.Services/DataExchange/ExportExtensions.cs @@ -2,8 +2,6 @@ using System.Globalization; using System.IO; using System.Text; -using System.Web; -using System.Web.Caching; using SmartStore.Core.Domain; using SmartStore.Core.Domain.Stores; using SmartStore.Core.Plugins; @@ -96,31 +94,5 @@ public static string ResolveFileNamePattern(this ExportProfile profile, Store st return result; } - - /// - /// Gets the cache key for selected entity identifiers - /// - /// Export profile - /// Cache key for selected entity identifiers - public static string GetSelectedEntityIdsCacheKey(this ExportProfile profile) - { - // do not use profile.Id because it can be 0 - return "ExportProfile_SelectedEntityIds_" + profile.ProviderSystemName; - } - - /// - /// Caches selected entity identifiers to be considered during following export - /// - /// Export profile - /// Comma separated entity identifiers - public static void CacheSelectedEntityIds(this ExportProfile profile, string selectedIds) - { - var selectedIdsCacheKey = profile.GetSelectedEntityIdsCacheKey(); - - if (selectedIds.HasValue()) - HttpRuntime.Cache.Add(selectedIdsCacheKey, selectedIds, null, DateTime.UtcNow.AddMinutes(5), Cache.NoSlidingExpiration, CacheItemPriority.Normal, null); - else - HttpRuntime.Cache.Remove(selectedIdsCacheKey); - } } } diff --git a/src/Libraries/SmartStore.Services/DataExchange/ExportTask/ExportProfileTask.cs b/src/Libraries/SmartStore.Services/DataExchange/ExportTask/ExportProfileTask.cs index 3bc601bedf..95f276a993 100644 --- a/src/Libraries/SmartStore.Services/DataExchange/ExportTask/ExportProfileTask.cs +++ b/src/Libraries/SmartStore.Services/DataExchange/ExportTask/ExportProfileTask.cs @@ -2872,7 +2872,7 @@ public void Execute(TaskExecutionContext taskContext) var profileId = taskContext.ScheduleTask.Alias.ToInt(); var profile = _exportProfileService.Value.GetExportProfileById(profileId); - var selectedIdsCacheKey = profile.GetSelectedEntityIdsCacheKey(); + var selectedIdsCacheKey = "ExportProfile_SelectedEntityIds_" + profile.ProviderSystemName; var selectedEntityIds = HttpRuntime.Cache[selectedIdsCacheKey] as string; var provider = _exportProfileService.Value.LoadProvider(profile.ProviderSystemName); diff --git a/src/Libraries/SmartStore.Services/DataExchange/Internal/DataExportTask.cs b/src/Libraries/SmartStore.Services/DataExchange/Internal/DataExportTask.cs index 33b2eb1e2a..ab5d8e40c5 100644 --- a/src/Libraries/SmartStore.Services/DataExchange/Internal/DataExportTask.cs +++ b/src/Libraries/SmartStore.Services/DataExchange/Internal/DataExportTask.cs @@ -27,11 +27,6 @@ public void Execute(TaskExecutionContext ctx) var profileId = ctx.ScheduleTask.Alias.ToInt(); var profile = _exportProfileService.GetExportProfileById(profileId); - // TODO: find a better way to transmit selected entity ids (e.g. new TaskExecutionContext.Parameters property) - var selectedIdsCacheKey = profile.GetSelectedEntityIdsCacheKey(); - var selectedEntityIds = HttpRuntime.Cache[selectedIdsCacheKey] as string; - HttpRuntime.Cache.Remove(selectedIdsCacheKey); - // load provider var provider = _exportProfileService.LoadProvider(profile.ProviderSystemName); if (provider == null) @@ -50,10 +45,10 @@ public void Execute(TaskExecutionContext ctx) ctx.SetProgress(null, msg, true); }; - if (selectedEntityIds.HasValue()) + if (ctx.Parameters.ContainsKey("SelectedIds")) { - request.EntitiesToExport = selectedEntityIds.ToIntArray(); - } + request.EntitiesToExport = ctx.Parameters["SelectedIds"].ToIntArray(); + } // process! _exporter.Export(request, ctx.CancellationToken); diff --git a/src/Libraries/SmartStore.Services/DataExchange/Internal/DataExporter.cs b/src/Libraries/SmartStore.Services/DataExchange/Internal/DataExporter.cs index faccb9748f..cc263c1b5b 100644 --- a/src/Libraries/SmartStore.Services/DataExchange/Internal/DataExporter.cs +++ b/src/Libraries/SmartStore.Services/DataExchange/Internal/DataExporter.cs @@ -1061,6 +1061,11 @@ public DataExportResult Export(DataExportRequest request, CancellationToken canc { var ctx = new DataExporterContext(request, cancellationToken); + if (request.EntitiesToExport != null) + { + ctx.EntityIdsSelected.AddRange(request.EntitiesToExport); + } + ExportCoreOuter(ctx); if (ctx.Result != null && ctx.Result.Succeeded && ctx.Result.Files.Count > 0) @@ -1068,7 +1073,6 @@ public DataExportResult Export(DataExportRequest request, CancellationToken canc string prefix = null; string suffix = null; var extension = Path.GetExtension(ctx.Result.Files.First().FileName); - var selectedEntityCount = (request.EntitiesToExport == null ? 0 : request.EntitiesToExport.Count()); if (request.Provider.Value.EntityType == ExportEntityType.Product) prefix = T("Admin.Catalog.Products"); @@ -1085,6 +1089,8 @@ public DataExportResult Export(DataExportRequest request, CancellationToken canc else prefix = request.Provider.Value.EntityType.ToString(); + var selectedEntityCount = (request.EntitiesToExport == null ? 0 : request.EntitiesToExport.Count()); + if (selectedEntityCount == 0) suffix = T("Common.All"); else @@ -1104,7 +1110,7 @@ public IList Preview(DataExportRequest request) var resultData = new List(); var cancellation = new CancellationTokenSource(TimeSpan.FromMinutes(5.0)); - var ctx = new DataExporterContext(request, cancellation.Token, null, true); + var ctx = new DataExporterContext(request, cancellation.Token, true); var unused = Init(ctx, totalRecords); @@ -1138,7 +1144,7 @@ public int GetDataCount(DataExportRequest request) { var cancellation = new CancellationTokenSource(TimeSpan.FromMinutes(5.0)); - var ctx = new DataExporterContext(request, cancellation.Token, null, true); + var ctx = new DataExporterContext(request, cancellation.Token, true); var unused = Init(ctx); diff --git a/src/Libraries/SmartStore.Services/DataExchange/Internal/DataExporterContext.cs b/src/Libraries/SmartStore.Services/DataExchange/Internal/DataExporterContext.cs index 2ae610ca6d..b12b3a1bdb 100644 --- a/src/Libraries/SmartStore.Services/DataExchange/Internal/DataExporterContext.cs +++ b/src/Libraries/SmartStore.Services/DataExchange/Internal/DataExporterContext.cs @@ -26,19 +26,18 @@ internal class DataExporterContext public DataExporterContext( DataExportRequest request, CancellationToken cancellationToken, - string selectedIds = null, bool isPreview = false) { Request = request; CancellationToken = cancellationToken; Filter = XmlHelper.Deserialize(request.Profile.Filtering); Projection = XmlHelper.Deserialize(request.Profile.Projection); - EntityIdsSelected = selectedIds.SplitSafe(",").Select(x => x.ToInt()).ToList(); IsPreview = isPreview; FolderContent = FileSystemHelper.TempDir(@"Profile\Export\{0}\Content".FormatInvariant(request.Profile.FolderName)); FolderRoot = System.IO.Directory.GetParent(FolderContent).FullName; + EntityIdsSelected = new List(); Categories = new Dictionary(); CategoryPathes = new Dictionary(); Countries = new Dictionary(); diff --git a/src/Libraries/SmartStore.Services/Tasks/TaskScheduler.cs b/src/Libraries/SmartStore.Services/Tasks/TaskScheduler.cs index 3ff2e5e04f..22cecb7046 100644 --- a/src/Libraries/SmartStore.Services/Tasks/TaskScheduler.cs +++ b/src/Libraries/SmartStore.Services/Tasks/TaskScheduler.cs @@ -113,7 +113,7 @@ public void RunSingleTask(int scheduleTaskId, IDictionary taskPa query = qs.ToString(); } - CallEndpoint(_baseUrl + "/Execute/{0}{1}".FormatInvariant(scheduleTaskId, query)); + CallEndpoint("{0}/Execute/{1}{2}".FormatInvariant(_baseUrl, scheduleTaskId, query)); } private void Elapsed(object sender, System.Timers.ElapsedEventArgs e) diff --git a/src/Presentation/SmartStore.Web/Administration/Controllers/ExportController.cs b/src/Presentation/SmartStore.Web/Administration/Controllers/ExportController.cs index 55ac7330ac..518e66169c 100644 --- a/src/Presentation/SmartStore.Web/Administration/Controllers/ExportController.cs +++ b/src/Presentation/SmartStore.Web/Administration/Controllers/ExportController.cs @@ -826,7 +826,7 @@ public ActionResult PreviewList(GridCommand command, int id, int totalRecords) } [HttpPost] - public ActionResult Execute(int id, string selectedIds, bool exportAll) + public ActionResult Execute(int id, string selectedIds) { if (!_services.Permissions.Authorize(StandardPermissionProvider.ManageExports)) return AccessDeniedView(); @@ -835,10 +835,15 @@ public ActionResult Execute(int id, string selectedIds, bool exportAll) if (profile == null) return RedirectToAction("List"); - // TODO: - profile.CacheSelectedEntityIds(selectedIds); + Dictionary taskParams = null; - _taskScheduler.RunSingleTask(profile.SchedulingTaskId); + if (selectedIds.HasValue()) + { + taskParams = new Dictionary(); + taskParams.Add("SelectedIds", selectedIds); + } + + _taskScheduler.RunSingleTask(profile.SchedulingTaskId, taskParams); NotifyInfo(T("Admin.System.ScheduleTasks.RunNow.Progress")); diff --git a/src/Presentation/SmartStore.Web/Administration/Views/Export/List.cshtml b/src/Presentation/SmartStore.Web/Administration/Views/Export/List.cshtml index 689da7f9a4..740e0447ce 100644 --- a/src/Presentation/SmartStore.Web/Administration/Views/Export/List.cshtml +++ b/src/Presentation/SmartStore.Web/Administration/Views/Export/List.cshtml @@ -18,7 +18,6 @@
-
@if(Model.Count > 0) diff --git a/src/Presentation/SmartStore.Web/Administration/Views/Export/Preview.cshtml b/src/Presentation/SmartStore.Web/Administration/Views/Export/Preview.cshtml index b5e527976d..2bca030bc9 100644 --- a/src/Presentation/SmartStore.Web/Administration/Views/Export/Preview.cshtml +++ b/src/Presentation/SmartStore.Web/Administration/Views/Export/Preview.cshtml @@ -16,7 +16,6 @@
- @if (Model.LogFileExists) { @@ -42,8 +41,13 @@ e.preventDefault(); var form = $('#ProfileExportForm'), exportAll = $(this).attr('name') === 'ExportAll'; + + if (!exportAll && selectedIds.length === 0) { + EventBroker.publish("message", { title: '@T("Admin.Common.NoEntriesSelected")', type: 'warning' }); + return false; + } + form.find('[name=SelectedIds]').val(exportAll ? '' : selectedIds.join(',')); - form.find('[name=ExportAll]').val(exportAll.toString()); form.submit(); return false; }); From bde240e9c660249616febc6d46fd603dd8caea62 Mon Sep 17 00:00:00 2001 From: Murat Cakir Date: Wed, 11 Nov 2015 23:12:06 +0100 Subject: [PATCH 043/707] (Perf) more refactoring --- .../Extensions/MiscExtensions.cs | 6 +- .../Infrastructure/ComparableObject.cs | 118 ++++----- .../DependencyManagement/ContainerManager.cs | 2 +- .../SmartStore.Core/SmartStore.Core.csproj | 1 + .../Utilities/HashCodeCombiner.cs | 90 +++++++ .../Utilities/Reflection/FastActivator.cs | 12 +- .../Extensions/DataReaderExtensions.cs | 223 ++++++++++-------- .../Extensions/SqlDataReaderExtensions.cs | 30 --- .../SmartStore.Data/SmartStore.Data.csproj | 1 - .../SmartStore.Core.Tests/PerformanceTests.cs | 31 ++- 10 files changed, 296 insertions(+), 218 deletions(-) create mode 100644 src/Libraries/SmartStore.Core/Utilities/HashCodeCombiner.cs delete mode 100644 src/Libraries/SmartStore.Data/Extensions/SqlDataReaderExtensions.cs diff --git a/src/Libraries/SmartStore.Core/Extensions/MiscExtensions.cs b/src/Libraries/SmartStore.Core/Extensions/MiscExtensions.cs index 865d5f8ed4..c59cb07b21 100644 --- a/src/Libraries/SmartStore.Core/Extensions/MiscExtensions.cs +++ b/src/Libraries/SmartStore.Core/Extensions/MiscExtensions.cs @@ -11,12 +11,12 @@ namespace SmartStore { public static class MiscExtensions { - public static void Dump(this Exception exc) + public static void Dump(this Exception exception) { try { - exc.StackTrace.Dump(); - exc.Message.Dump(); + exception.StackTrace.Dump(); + exception.Message.Dump(); } catch { } } diff --git a/src/Libraries/SmartStore.Core/Infrastructure/ComparableObject.cs b/src/Libraries/SmartStore.Core/Infrastructure/ComparableObject.cs index ed24bd71f4..7291139dd8 100644 --- a/src/Libraries/SmartStore.Core/Infrastructure/ComparableObject.cs +++ b/src/Libraries/SmartStore.Core/Infrastructure/ComparableObject.cs @@ -4,6 +4,9 @@ using System.Linq.Expressions; using System.Reflection; using System.ComponentModel; +using SmartStore.Utilities.Reflection; +using SmartStore.Utilities; +using System.Collections.Concurrent; namespace SmartStore { @@ -13,26 +16,9 @@ namespace SmartStore [Serializable] public abstract class ComparableObject { - /// - /// To help ensure hashcode uniqueness, a carefully selected random number multiplier - /// is used within the calculation. Goodrich and Tamassia's Data Structures and - /// Algorithms in Java asserts that 31, 33, 37, 39 and 41 will produce the fewest number - /// of collissions. See http://computinglife.wordpress.com/2008/11/20/why-do-hash-functions-use-prime-numbers/ - /// for more information. - /// - protected const int HashMultiplier = 31; - - private readonly List _extraSignatureProperties = new List(); + private readonly HashSet _extraSignatureProperties = new HashSet(StringComparer.OrdinalIgnoreCase); - /// - /// This static member caches the domain signature properties to avoid looking them up for - /// each instance of the same type. - /// - /// A description of the ThreadStatic attribute may be found at - /// http://www.dotnetjunkies.com/WebLog/chris.taylor/archive/2005/08/18/132026.aspx - /// - [ThreadStatic] - private static IDictionary> s_signatureProperties; + private static readonly ConcurrentDictionary _signaturePropertyNames = new ConcurrentDictionary(); public override bool Equals(object obj) { @@ -58,21 +44,23 @@ public override int GetHashCode() var signatureProperties = GetSignatureProperties(); Type t = this.GetType(); - // It's possible for two objects to return the same hash code based on - // identically valued properties, even if they're of two different types, - // so we include the object's type in the hash calculation - int hashCode = t.GetHashCode(); + var combiner = HashCodeCombiner.Start(); - foreach (var pi in signatureProperties) + // It's possible for two objects to return the same hash code based on + // identically valued properties, even if they're of two different types, + // so we include the object's type in the hash calculation + combiner.Add(t.GetHashCode()); + + foreach (var prop in signatureProperties) { - object value = pi.GetValue(this); + object value = prop.GetValue(this); if (value != null) - hashCode = (hashCode * HashMultiplier) ^ value.GetHashCode(); + combiner.Add(value.GetHashCode()); } if (signatureProperties.Any()) - return hashCode; + return combiner.CombinedHash; // If no properties were flagged as being part of the signature of the object, // then simply return the hashcode of the base object as the hashcode. @@ -121,56 +109,46 @@ protected virtual bool HasSameSignatureAs(ComparableObject compareTo) /// /// - public IEnumerable GetSignatureProperties() + public IEnumerable GetSignatureProperties() { - IEnumerable properties; - - // Init the signaturePropertiesDictionary here due to reasons described at - // http://blogs.msdn.com/jfoscoding/archive/2006/07/18/670497.aspx - if (s_signatureProperties == null) - s_signatureProperties = new Dictionary>(); - - var t = GetType(); - - if (s_signatureProperties.TryGetValue(t, out properties)) - return properties; - - return (s_signatureProperties[t] = GetSignaturePropertiesCore()); + var type = GetType(); + var propertyNames = GetSignaturePropertyNamesCore(); + + foreach (var name in propertyNames) + { + var fastProperty = FastProperty.GetProperty(type, name); + if (fastProperty != null) + { + yield return fastProperty; + } + } } /// /// Enforces the template method pattern to have child objects determine which specific /// properties should and should not be included in the object signature comparison. /// - protected virtual IEnumerable GetSignaturePropertiesCore() + protected virtual string[] GetSignaturePropertyNamesCore() { - Type t = this.GetType(); - //var properties = TypeDescriptor.GetProvider(t).GetTypeDescriptor(t) - // .GetPropertiesWith(); + Type type = this.GetType(); + string[] names; - //if (_extraSignatureProperties.Count > 0) - //{ - // properties = properties.Union(_extraSignatureProperties); - //} + if (!_signaturePropertyNames.TryGetValue(type, out names)) + { + names = type.GetProperties(BindingFlags.Public | BindingFlags.Instance) + .Where(p => Attribute.IsDefined(p, typeof(ObjectSignatureAttribute), true)) + .Select(p => p.Name) + .ToArray(); - //return new PropertyDescriptorCollection(properties.ToArray(), true); + _signaturePropertyNames.TryAdd(type, names); + } - var properties = t.GetProperties() - .Where(p => Attribute.IsDefined(p, typeof(ObjectSignatureAttribute), true)); + if (_extraSignatureProperties.Count == 0) + { + return names; + } - return properties.Union(_extraSignatureProperties).ToList(); - } - - /// - /// Adds an extra property to the type specific signature properties list. - /// - /// The property to add. - /// Both lists are unioned, so - /// that no duplicates can occur within the global descriptor collection. - protected void RegisterSignatureProperty(PropertyInfo propertyInfo) - { - Guard.ArgumentNotNull(() => propertyInfo); - _extraSignatureProperties.Add(propertyInfo); + return names.Union(_extraSignatureProperties).ToArray(); } /// @@ -183,13 +161,7 @@ protected void RegisterSignatureProperty(string propertyName) { Guard.ArgumentNotEmpty(() => propertyName); - Type t = GetType(); - - var pi = t.GetProperty(propertyName, BindingFlags.Public | BindingFlags.Instance); - if (pi == null) - throw Error.Argument("propertyName", "Could not find property '{0}' on type '{1}'.", propertyName, t); - - RegisterSignatureProperty(pi); + _extraSignatureProperties.Add(propertyName); } } @@ -212,7 +184,7 @@ protected void RegisterSignatureProperty(Expression> expression) { Guard.ArgumentNotNull(() => expression); - base.RegisterSignatureProperty(expression.ExtractPropertyInfo()); + base.RegisterSignatureProperty(expression.ExtractPropertyInfo().Name); } public virtual bool Equals(T other) diff --git a/src/Libraries/SmartStore.Core/Infrastructure/DependencyManagement/ContainerManager.cs b/src/Libraries/SmartStore.Core/Infrastructure/DependencyManagement/ContainerManager.cs index d0effe4bee..6e314c8f0c 100644 --- a/src/Libraries/SmartStore.Core/Infrastructure/DependencyManagement/ContainerManager.cs +++ b/src/Libraries/SmartStore.Core/Infrastructure/DependencyManagement/ContainerManager.cs @@ -70,7 +70,7 @@ public object ResolveUnregistered(Type type, ILifetimeScope scope = null) if (!_cachedActivators.TryGetValue(type, out activator)) { - var constructors = type.GetConstructors(BindingFlags.Public | BindingFlags.CreateInstance | BindingFlags.Instance); + var constructors = type.GetConstructors(BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly); foreach (var constructor in constructors) { var parameterTypes = constructor.GetParameters().Select(p => p.ParameterType).ToArray(); diff --git a/src/Libraries/SmartStore.Core/SmartStore.Core.csproj b/src/Libraries/SmartStore.Core/SmartStore.Core.csproj index e4bb819bdb..8019c3d8d6 100644 --- a/src/Libraries/SmartStore.Core/SmartStore.Core.csproj +++ b/src/Libraries/SmartStore.Core/SmartStore.Core.csproj @@ -558,6 +558,7 @@ + diff --git a/src/Libraries/SmartStore.Core/Utilities/HashCodeCombiner.cs b/src/Libraries/SmartStore.Core/Utilities/HashCodeCombiner.cs new file mode 100644 index 0000000000..b69d640a05 --- /dev/null +++ b/src/Libraries/SmartStore.Core/Utilities/HashCodeCombiner.cs @@ -0,0 +1,90 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.CompilerServices; +using System.Threading.Tasks; + +/* + Copied over from Microsoft.Framework.Internal +*/ + +namespace SmartStore.Utilities +{ + internal struct HashCodeCombiner + { + private long _combinedHash64; + + public int CombinedHash + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get { return _combinedHash64.GetHashCode(); } + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private HashCodeCombiner(long seed) + { + _combinedHash64 = seed; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public HashCodeCombiner Add(IEnumerable e) + { + if (e == null) + { + Add(0); + } + else + { + var count = 0; + foreach (object o in e) + { + Add(o); + count++; + } + Add(count); + } + return this; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static implicit operator int (HashCodeCombiner self) + { + return self.CombinedHash; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public HashCodeCombiner Add(int i) + { + _combinedHash64 = ((_combinedHash64 << 5) + _combinedHash64) ^ i; + return this; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public HashCodeCombiner Add(string s) + { + var hashCode = (s != null) ? s.GetHashCode() : 0; + return Add(hashCode); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public HashCodeCombiner Add(object o) + { + var hashCode = (o != null) ? o.GetHashCode() : 0; + return Add(hashCode); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public HashCodeCombiner Add(TValue value, IEqualityComparer comparer) + { + var hashCode = value != null ? comparer.GetHashCode(value) : 0; + return Add(hashCode); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static HashCodeCombiner Start() + { + return new HashCodeCombiner(0x1505L); + } + } +} diff --git a/src/Libraries/SmartStore.Core/Utilities/Reflection/FastActivator.cs b/src/Libraries/SmartStore.Core/Utilities/Reflection/FastActivator.cs index 3f95ddeee4..ce0ea4b9a2 100644 --- a/src/Libraries/SmartStore.Core/Utilities/Reflection/FastActivator.cs +++ b/src/Libraries/SmartStore.Core/Utilities/Reflection/FastActivator.cs @@ -131,7 +131,7 @@ public static T CreateInstance(params object[] args) /// A reference to the newly created object. public static object CreateInstance(Type type, params object[] args) { - Guard.ArgumentNotNull(() => type); + Guard.ArgumentNotNull(type, "type"); if (args == null || args.Length == 0) { @@ -164,8 +164,8 @@ private static FastActivator FindMatchingActivatorCore(FastActivator[] activator { return null; } - - if (activators.Length == 1) + + if (activators.Length == 1) { // this seems to be bad design, but it's on purpose for performance reasons. // In nearly ALL cases there is only one constructor. @@ -173,7 +173,11 @@ private static FastActivator FindMatchingActivatorCore(FastActivator[] activator } var argTypes = args.Select(x => x.GetType()).ToArray(); - var constructor = type.GetConstructor(BindingFlags.Instance | BindingFlags.CreateInstance | BindingFlags.Public, null, argTypes, null); + var constructor = type.GetConstructor( + BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly, + null, + argTypes, + null); if (constructor != null) { diff --git a/src/Libraries/SmartStore.Data/Extensions/DataReaderExtensions.cs b/src/Libraries/SmartStore.Data/Extensions/DataReaderExtensions.cs index 9581cf4ce4..edd6e3dba4 100644 --- a/src/Libraries/SmartStore.Data/Extensions/DataReaderExtensions.cs +++ b/src/Libraries/SmartStore.Data/Extensions/DataReaderExtensions.cs @@ -4,112 +4,141 @@ using System.Collections.Generic; using System.Data; using System.Reflection; +using System.Linq; +using SmartStore.Utilities.Reflection; +using System.Dynamic; namespace SmartStore.Data { public static class DataReaderExtensions { - /// - /// Creates a list of a given type from all the rows in a DataReader. - /// - /// Note this method uses Reflection so this isn't a high performance - /// operation, but it can be useful for generic data reader to entity - /// conversions on the fly and with anonymous types. - /// - /// - /// An open DataReader that's in position to read - /// Optional - comma delimited list of fields that you don't want to update - /// - /// Optional - Cached PropertyInfo dictionary that holds property info data for this object. - /// Can be used for caching hte PropertyInfo structure for multiple operations to speed up - /// translation. If not passed automatically created. - /// - /// - public static List DataReaderToObjectList(this IDataReader reader, string fieldsToSkip = null, Dictionary piList = null) - where TType : new() - { - if (reader == null) - return null; - - var items = new List(); - - // Create lookup list of property info objects - if (piList == null) - { - piList = new Dictionary(); - var props = typeof(TType).GetProperties(BindingFlags.Instance | BindingFlags.Public); - foreach (var prop in props) - piList.Add(prop.Name.ToLower(), prop); - } + public static object GetValue(this IDataReader reader, string columnName) + { + try + { + if (reader != null && !reader.IsClosed && columnName.HasValue()) + { + int ordinal = reader.GetOrdinal(columnName); + return reader.GetValue(ordinal); + } + } + catch (Exception ex) + { + ex.Dump(); + } + + return null; + } + + public static IEnumerable MapSequence(this IDataReader reader, params string[] fieldsToSkip) + where T : new() + { + Guard.ArgumentNotNull(() => reader); + while (reader.Read()) + { + yield return reader.Map(fieldsToSkip); + } + } + + public static IEnumerable MapSequence(this IDataReader reader, params string[] fieldsToSkip) + { + Guard.ArgumentNotNull(() => reader); + while (reader.Read()) - { - var inst = new TType(); - DataReaderToObject(reader, inst, fieldsToSkip, piList); - items.Add(inst); - } + { + yield return reader.Map(fieldsToSkip); + } + } - return items; - } - - /// - /// Populates the properties of an object from a single DataReader row using - /// Reflection by matching the DataReader fields to a public property on - /// the object passed in. Unmatched properties are left unchanged. - /// - /// You need to pass in a data reader located on the active row you want - /// to serialize. - /// - /// This routine works best for matching pure data entities and should - /// be used only in low volume environments where retrieval speed is not - /// critical due to its use of Reflection. - /// - /// Instance of the DataReader to read data from. Should be located on the correct record (Read() should have been called on it before calling this method) - /// Instance of the object to populate properties on - /// Optional - A comma delimited list of object properties that should not be updated - /// Optional - Cached PropertyInfo dictionary that holds property info data for this object - public static void DataReaderToObject(this IDataReader reader, object instance, string fieldsToSkip = null, Dictionary piList = null) - { - if (reader.IsClosed) - throw new InvalidOperationException("Data reader cannot be used because it's already closed"); - - if (string.IsNullOrEmpty(fieldsToSkip)) - fieldsToSkip = string.Empty; - else - fieldsToSkip = "," + fieldsToSkip + ","; - - fieldsToSkip = fieldsToSkip.ToLower(); - - // create a dictionary of properties to look up - // we can pass this in so we can cache the list once - // for a list operation - if (piList == null) - { - piList = new Dictionary(); - var props = instance.GetType().GetProperties(BindingFlags.Instance | BindingFlags.Public); - foreach (var prop in props) - piList.Add(prop.Name.ToLower(), prop); - } + /// + /// Populates an object from a single DataReader row using + /// fast reflection routines by matching the DataReader fields to a public property on + /// the object passed in. Unmatched properties are left unchanged. + /// + /// You need to pass in a data reader located on the active row you want + /// to serialize. + /// + /// Instance of the DataReader to read data from. Should be located on the correct record (Read() should have been called on it before calling this method) + /// An array of reader field names to ignore + public static T Map(this IDataReader reader, params string[] fieldsToSkip) + where T : new() + { + if (reader.IsClosed) + throw new InvalidOperationException("Data reader cannot be used because it's already closed"); + + var instance = new T(); + MapObject(reader, instance, fieldsToSkip); + return instance; + } + + public static dynamic Map(this IDataReader reader, params string[] fieldsToSkip) + { + if (reader.IsClosed) + throw new InvalidOperationException("Data reader cannot be used because it's already closed"); + + dynamic instance = new ExpandoObject(); + MapDictionary(reader, instance, fieldsToSkip); + return instance; + } + + public static void Map(this IDataReader reader, object instance, params string[] fieldsToSkip) + { + Guard.ArgumentNotNull(instance, "instance"); - for (int index = 0; index < reader.FieldCount; index++) - { - string name = reader.GetName(index).ToLower(); - if (piList.ContainsKey(name)) - { - var prop = piList[name]; - - if (fieldsToSkip.Contains("," + name + ",")) - continue; - - if ((prop != null) && prop.CanWrite) - { - var val = reader.GetValue(index); - prop.SetValue(instance, (val == DBNull.Value) ? null : val, null); - } - } + if (reader.IsClosed) + throw new InvalidOperationException("Data reader cannot be used because it's already closed"); + + var dict = instance as IDictionary; + + if (dict != null) + { + MapDictionary(reader, dict, fieldsToSkip); } + else + { + MapObject(reader, instance, fieldsToSkip); + } + } + + private static void MapObject(IDataReader reader, object instance, params string[] fieldsToSkip) + { + var fastProperties = FastProperty.GetProperties(instance); + + if (fastProperties.Count == 0) + return; + + for (int i = 0; i < reader.FieldCount; i++) + { + string name = reader.GetName(i); + if (fastProperties.ContainsKey(name)) + { + var fastProp = fastProperties[name]; - return; - } - } + if (fieldsToSkip.Contains(name)) + continue; + + if ((fastProp != null) && fastProp.Property.CanWrite) + { + var dbValue = reader.GetValue(i); + fastProp.SetValue(instance, (dbValue == DBNull.Value) ? null : dbValue); + } + } + } + } + + private static void MapDictionary(IDataReader reader, IDictionary instance, params string[] fieldsToSkip) + { + for (int i = 0; i < reader.FieldCount; i++) + { + string name = reader.GetName(i); + + if (fieldsToSkip.Contains(name)) + continue; + + var dbValue = reader.GetValue(i); + instance[name] = (dbValue == DBNull.Value) ? null : dbValue; + } + } + } } diff --git a/src/Libraries/SmartStore.Data/Extensions/SqlDataReaderExtensions.cs b/src/Libraries/SmartStore.Data/Extensions/SqlDataReaderExtensions.cs deleted file mode 100644 index becda17803..0000000000 --- a/src/Libraries/SmartStore.Data/Extensions/SqlDataReaderExtensions.cs +++ /dev/null @@ -1,30 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Data.SqlClient; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace SmartStore -{ - - public static class SqlDataReaderExtensions - { - public static object GetValue(this SqlDataReader reader, string columnName) - { - try - { - if (reader != null && columnName.HasValue()) - { - int ordinal = reader.GetOrdinal(columnName); - return reader.GetValue(ordinal); - } - } - catch (Exception exc) - { - exc.Dump(); - } - return null; - } - } -} diff --git a/src/Libraries/SmartStore.Data/SmartStore.Data.csproj b/src/Libraries/SmartStore.Data/SmartStore.Data.csproj index 8764a6a9ed..5c46f0934d 100644 --- a/src/Libraries/SmartStore.Data/SmartStore.Data.csproj +++ b/src/Libraries/SmartStore.Data/SmartStore.Data.csproj @@ -375,7 +375,6 @@ - diff --git a/src/Tests/SmartStore.Core.Tests/PerformanceTests.cs b/src/Tests/SmartStore.Core.Tests/PerformanceTests.cs index 1f1330805e..36e99e743f 100644 --- a/src/Tests/SmartStore.Core.Tests/PerformanceTests.cs +++ b/src/Tests/SmartStore.Core.Tests/PerformanceTests.cs @@ -19,6 +19,7 @@ public void InstantiatePerfTest() Chronometer.Measure(cycles, "Create Product NATIVE", i => new Product()); Chronometer.Measure(cycles, "Create Product Reflection", i => Activator.CreateInstance(typeof(Product))); + Chronometer.Measure(cycles, "Create Product FASTACTIVATOR", i => FastActivator.CreateInstance(typeof(Product))); var list = new List(); @@ -43,15 +44,27 @@ public TestClass() public TestClass(IEnumerable param1) { } - public TestClass(int param1) - { - } - public TestClass(IEnumerable param1, int param2) - { - } - public TestClass(IEnumerable param1, int param2, string param3) - { - } + //public TestClass(int param1) + //{ + //} + //public TestClass(IEnumerable param1, int param2) + //{ + //} + //public TestClass(IEnumerable param1, int param2, string param3) + //{ + //} + //public TestClass(DateTime param1) + //{ + //} + //public TestClass(double param1) + //{ + //} + //public TestClass(decimal param1) + //{ + //} + //public TestClass(long param1) + //{ + //} } } From 14b775db26a66e9c292a5a3d93bb6aa1cd528c26 Mon Sep 17 00:00:00 2001 From: Murat Cakir Date: Wed, 11 Nov 2015 23:20:01 +0100 Subject: [PATCH 044/707] Updated AutoMapper to version 4.1.1 --- .../SmartStore.WebApi/SmartStore.WebApi.csproj | 9 +++------ src/Plugins/SmartStore.WebApi/packages.config | 2 +- .../SmartStore.Web.Framework.csproj | 11 +++-------- .../SmartStore.Web.Framework/packages.config | 2 +- .../Administration/SmartStore.Admin.csproj | 11 +++-------- .../SmartStore.Web/Administration/Web.config | 4 ++++ .../SmartStore.Web/Administration/packages.config | 2 +- .../SmartStore.Web.MVC.Tests.csproj | 11 +++-------- src/Tests/SmartStore.Web.MVC.Tests/packages.config | 2 +- 9 files changed, 20 insertions(+), 34 deletions(-) diff --git a/src/Plugins/SmartStore.WebApi/SmartStore.WebApi.csproj b/src/Plugins/SmartStore.WebApi/SmartStore.WebApi.csproj index 20e3fc318c..f5e2443c24 100644 --- a/src/Plugins/SmartStore.WebApi/SmartStore.WebApi.csproj +++ b/src/Plugins/SmartStore.WebApi/SmartStore.WebApi.csproj @@ -87,11 +87,9 @@ ..\..\packages\Autofac.WebApi.3.1.0\lib\net40\Autofac.Integration.WebApi.dll - - ..\..\packages\AutoMapper.3.2.1\lib\net40\AutoMapper.dll - - - ..\..\packages\AutoMapper.3.2.1\lib\net40\AutoMapper.Net4.dll + + ..\..\packages\AutoMapper.4.1.1\lib\net45\AutoMapper.dll + True ..\..\packages\EntityFramework.6.1.3\lib\net45\EntityFramework.dll @@ -324,7 +322,6 @@ - - - + + - - - - - + + + + + - - - - - - - - - - + + + + + + + + + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - \ No newline at end of file + diff --git a/src/Plugins/SmartStore.DevTools/Web.config b/src/Plugins/SmartStore.DevTools/Web.config index b3e042e7ec..e4010c8209 100644 --- a/src/Plugins/SmartStore.DevTools/Web.config +++ b/src/Plugins/SmartStore.DevTools/Web.config @@ -1,135 +1,135 @@ - + -
+
- - + + - - - - - + + + + + - - - - - - - - - - + + + + + + + + + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - + - + - \ No newline at end of file + diff --git a/src/Plugins/SmartStore.DiscountRules/web.config b/src/Plugins/SmartStore.DiscountRules/web.config index 3766af5f74..c6048447e5 100644 --- a/src/Plugins/SmartStore.DiscountRules/web.config +++ b/src/Plugins/SmartStore.DiscountRules/web.config @@ -1,117 +1,117 @@ - + - - + + - - - - - + + + + + - - - - - - - - - - + + + + + + + + + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - \ No newline at end of file + diff --git a/src/Plugins/SmartStore.FacebookAuth/web.config b/src/Plugins/SmartStore.FacebookAuth/web.config index e0c21864c3..3a843a4ce5 100644 --- a/src/Plugins/SmartStore.FacebookAuth/web.config +++ b/src/Plugins/SmartStore.FacebookAuth/web.config @@ -1,121 +1,121 @@ - + - - + + - - - - - + + + + + - - - - - - - - - - + + + + + + + + + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - \ No newline at end of file + diff --git a/src/Plugins/SmartStore.GoogleAnalytics/web.config b/src/Plugins/SmartStore.GoogleAnalytics/web.config index 8e255a8d61..06e0d9a92a 100644 --- a/src/Plugins/SmartStore.GoogleAnalytics/web.config +++ b/src/Plugins/SmartStore.GoogleAnalytics/web.config @@ -1,116 +1,116 @@ - + - - + + - - - - - + + + + + - - - - - - - - - - + + + + + + + + + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - \ No newline at end of file + diff --git a/src/Plugins/SmartStore.GoogleMerchantCenter/web.config b/src/Plugins/SmartStore.GoogleMerchantCenter/web.config index 3766af5f74..c6048447e5 100644 --- a/src/Plugins/SmartStore.GoogleMerchantCenter/web.config +++ b/src/Plugins/SmartStore.GoogleMerchantCenter/web.config @@ -1,117 +1,117 @@ - + - - + + - - - - - + + + + + - - - - - - - - - - + + + + + + + + + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - \ No newline at end of file + diff --git a/src/Plugins/SmartStore.OfflinePayment/web.config b/src/Plugins/SmartStore.OfflinePayment/web.config index 3766af5f74..c6048447e5 100644 --- a/src/Plugins/SmartStore.OfflinePayment/web.config +++ b/src/Plugins/SmartStore.OfflinePayment/web.config @@ -1,117 +1,117 @@ - + - - + + - - - - - + + + + + - - - - - - - - - - + + + + + + + + + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - \ No newline at end of file + diff --git a/src/Plugins/SmartStore.PayPal/web.config b/src/Plugins/SmartStore.PayPal/web.config index 76f7e23429..92a2529d51 100644 --- a/src/Plugins/SmartStore.PayPal/web.config +++ b/src/Plugins/SmartStore.PayPal/web.config @@ -1,11 +1,11 @@ - + -
+
- + @@ -14,128 +14,128 @@ - - + + - - - - - + + + + + - - - - - - - - - - + + + + + + + + + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - \ No newline at end of file + diff --git a/src/Plugins/SmartStore.Shipping/web.config b/src/Plugins/SmartStore.Shipping/web.config index 8e255a8d61..06e0d9a92a 100644 --- a/src/Plugins/SmartStore.Shipping/web.config +++ b/src/Plugins/SmartStore.Shipping/web.config @@ -1,116 +1,116 @@ - + - - + + - - - - - + + + + + - - - - - - - - - - + + + + + + + + + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - \ No newline at end of file + diff --git a/src/Plugins/SmartStore.ShippingByWeight/web.config b/src/Plugins/SmartStore.ShippingByWeight/web.config index 8e255a8d61..06e0d9a92a 100644 --- a/src/Plugins/SmartStore.ShippingByWeight/web.config +++ b/src/Plugins/SmartStore.ShippingByWeight/web.config @@ -1,116 +1,116 @@ - + - - + + - - - - - + + + + + - - - - - - - - - - + + + + + + + + + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - \ No newline at end of file + diff --git a/src/Plugins/SmartStore.Tax/web.config b/src/Plugins/SmartStore.Tax/web.config index 3766af5f74..c6048447e5 100644 --- a/src/Plugins/SmartStore.Tax/web.config +++ b/src/Plugins/SmartStore.Tax/web.config @@ -1,117 +1,117 @@ - + - - + + - - - - - + + + + + - - - - - - - - - - + + + + + + + + + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - \ No newline at end of file + diff --git a/src/Presentation/SmartStore.Web/Administration/Controllers/CommonController.cs b/src/Presentation/SmartStore.Web/Administration/Controllers/CommonController.cs index 3a44246262..8d6e7b5986 100644 --- a/src/Presentation/SmartStore.Web/Administration/Controllers/CommonController.cs +++ b/src/Presentation/SmartStore.Web/Administration/Controllers/CommonController.cs @@ -828,6 +828,9 @@ public ActionResult MaintenanceDeleteImageCache() _imageCache.Value.DeleteCachedImages(); + // get rid of cached image metadata + _cache("static").Clear(); + return RedirectToAction("Maintenance"); } From 6a008e6474066afd56c291119db2b9d8fa097785 Mon Sep 17 00:00:00 2001 From: Murat Cakir Date: Thu, 12 Nov 2015 00:15:14 +0100 Subject: [PATCH 049/707] Updated MsieJavaScriptEngine to latest version --- src/Plugins/SmartStore.AmazonPay/web.config | 132 ++++++++--------- src/Plugins/SmartStore.Clickatell/web.config | 116 +++++++-------- src/Plugins/SmartStore.DevTools/Web.config | 130 ++++++++--------- .../SmartStore.DiscountRules/web.config | 116 +++++++-------- .../SmartStore.FacebookAuth/web.config | 120 ++++++++-------- .../SmartStore.GoogleAnalytics/web.config | 116 +++++++-------- .../web.config | 116 +++++++-------- .../SmartStore.OfflinePayment/web.config | 116 +++++++-------- src/Plugins/SmartStore.PayPal/web.config | 136 +++++++++--------- src/Plugins/SmartStore.Shipping/web.config | 116 +++++++-------- .../SmartStore.ShippingByWeight/web.config | 116 +++++++-------- src/Plugins/SmartStore.Tax/web.config | 116 +++++++-------- src/Plugins/SmartStore.WebApi/web.config | 2 +- .../SmartStore.Web.Framework.csproj | 6 +- .../SmartStore.Web.Framework/app.config | 4 +- .../SmartStore.Web.Framework/packages.config | 2 +- .../SmartStore.Web/Administration/Web.config | 2 +- .../SmartStore.Web/SmartStore.Web.csproj | 16 ++- src/Presentation/SmartStore.Web/Web.config | 6 +- .../SmartStore.Web/packages.config | 6 +- src/Tests/SmartStore.Web.MVC.Tests/App.config | 6 +- 21 files changed, 757 insertions(+), 739 deletions(-) diff --git a/src/Plugins/SmartStore.AmazonPay/web.config b/src/Plugins/SmartStore.AmazonPay/web.config index 56c636965f..0e57dde0c1 100644 --- a/src/Plugins/SmartStore.AmazonPay/web.config +++ b/src/Plugins/SmartStore.AmazonPay/web.config @@ -1,127 +1,131 @@ - + - - + + - - - - - + + + + + - - - - - - - - - - + + + + + + + + + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + + + + + diff --git a/src/Plugins/SmartStore.Clickatell/web.config b/src/Plugins/SmartStore.Clickatell/web.config index c6048447e5..3e1b370f5d 100644 --- a/src/Plugins/SmartStore.Clickatell/web.config +++ b/src/Plugins/SmartStore.Clickatell/web.config @@ -1,116 +1,116 @@ - + - - + + - - - - - + + + + + - - - - - - - - - - + + + + + + + + + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + diff --git a/src/Plugins/SmartStore.DevTools/Web.config b/src/Plugins/SmartStore.DevTools/Web.config index e4010c8209..e1ac213bd8 100644 --- a/src/Plugins/SmartStore.DevTools/Web.config +++ b/src/Plugins/SmartStore.DevTools/Web.config @@ -1,135 +1,135 @@ - + -
+
- - + + - - - - - + + + + + - - - - - - - - - - + + + + + + + + + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - + - + diff --git a/src/Plugins/SmartStore.DiscountRules/web.config b/src/Plugins/SmartStore.DiscountRules/web.config index c6048447e5..3e1b370f5d 100644 --- a/src/Plugins/SmartStore.DiscountRules/web.config +++ b/src/Plugins/SmartStore.DiscountRules/web.config @@ -1,116 +1,116 @@ - + - - + + - - - - - + + + + + - - - - - - - - - - + + + + + + + + + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + diff --git a/src/Plugins/SmartStore.FacebookAuth/web.config b/src/Plugins/SmartStore.FacebookAuth/web.config index 3a843a4ce5..6b304e839a 100644 --- a/src/Plugins/SmartStore.FacebookAuth/web.config +++ b/src/Plugins/SmartStore.FacebookAuth/web.config @@ -1,120 +1,120 @@ - + - - + + - - - - - + + + + + - - - - - - - - - - + + + + + + + + + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + diff --git a/src/Plugins/SmartStore.GoogleAnalytics/web.config b/src/Plugins/SmartStore.GoogleAnalytics/web.config index 06e0d9a92a..32347fc005 100644 --- a/src/Plugins/SmartStore.GoogleAnalytics/web.config +++ b/src/Plugins/SmartStore.GoogleAnalytics/web.config @@ -1,115 +1,115 @@ - + - - + + - - - - - + + + + + - - - - - - - - - - + + + + + + + + + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + diff --git a/src/Plugins/SmartStore.GoogleMerchantCenter/web.config b/src/Plugins/SmartStore.GoogleMerchantCenter/web.config index c6048447e5..3e1b370f5d 100644 --- a/src/Plugins/SmartStore.GoogleMerchantCenter/web.config +++ b/src/Plugins/SmartStore.GoogleMerchantCenter/web.config @@ -1,116 +1,116 @@ - + - - + + - - - - - + + + + + - - - - - - - - - - + + + + + + + + + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + diff --git a/src/Plugins/SmartStore.OfflinePayment/web.config b/src/Plugins/SmartStore.OfflinePayment/web.config index c6048447e5..3e1b370f5d 100644 --- a/src/Plugins/SmartStore.OfflinePayment/web.config +++ b/src/Plugins/SmartStore.OfflinePayment/web.config @@ -1,116 +1,116 @@ - + - - + + - - - - - + + + + + - - - - - - - - - - + + + + + + + + + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + diff --git a/src/Plugins/SmartStore.PayPal/web.config b/src/Plugins/SmartStore.PayPal/web.config index 92a2529d51..d9badc0f86 100644 --- a/src/Plugins/SmartStore.PayPal/web.config +++ b/src/Plugins/SmartStore.PayPal/web.config @@ -1,11 +1,11 @@ - + -
+
- + @@ -14,127 +14,131 @@ - - + + - - - - - + + + + + - - - - - - - - - - + + + + + + + + + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + + + + + diff --git a/src/Plugins/SmartStore.Shipping/web.config b/src/Plugins/SmartStore.Shipping/web.config index 06e0d9a92a..32347fc005 100644 --- a/src/Plugins/SmartStore.Shipping/web.config +++ b/src/Plugins/SmartStore.Shipping/web.config @@ -1,115 +1,115 @@ - + - - + + - - - - - + + + + + - - - - - - - - - - + + + + + + + + + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + diff --git a/src/Plugins/SmartStore.ShippingByWeight/web.config b/src/Plugins/SmartStore.ShippingByWeight/web.config index 06e0d9a92a..32347fc005 100644 --- a/src/Plugins/SmartStore.ShippingByWeight/web.config +++ b/src/Plugins/SmartStore.ShippingByWeight/web.config @@ -1,115 +1,115 @@ - + - - + + - - - - - + + + + + - - - - - - - - - - + + + + + + + + + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + diff --git a/src/Plugins/SmartStore.Tax/web.config b/src/Plugins/SmartStore.Tax/web.config index c6048447e5..3e1b370f5d 100644 --- a/src/Plugins/SmartStore.Tax/web.config +++ b/src/Plugins/SmartStore.Tax/web.config @@ -1,116 +1,116 @@ - + - - + + - - - - - + + + + + - - - - - - - - - - + + + + + + + + + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + diff --git a/src/Plugins/SmartStore.WebApi/web.config b/src/Plugins/SmartStore.WebApi/web.config index b6bf71d919..71013386a2 100644 --- a/src/Plugins/SmartStore.WebApi/web.config +++ b/src/Plugins/SmartStore.WebApi/web.config @@ -46,7 +46,7 @@ - + diff --git a/src/Presentation/SmartStore.Web.Framework/SmartStore.Web.Framework.csproj b/src/Presentation/SmartStore.Web.Framework/SmartStore.Web.Framework.csproj index e4907bffb2..1c59563458 100644 --- a/src/Presentation/SmartStore.Web.Framework/SmartStore.Web.Framework.csproj +++ b/src/Presentation/SmartStore.Web.Framework/SmartStore.Web.Framework.csproj @@ -102,9 +102,9 @@ ..\..\packages\FluentValidation.5.6.2.0\lib\Net45\FluentValidation.dll True - - False - ..\..\packages\JavaScriptEngineSwitcher.Core.1.1.3\lib\net40\JavaScriptEngineSwitcher.Core.dll + + ..\..\packages\JavaScriptEngineSwitcher.Core.1.2.4\lib\net40\JavaScriptEngineSwitcher.Core.dll + True False diff --git a/src/Presentation/SmartStore.Web.Framework/app.config b/src/Presentation/SmartStore.Web.Framework/app.config index f31d89f1ed..5d4773d412 100644 --- a/src/Presentation/SmartStore.Web.Framework/app.config +++ b/src/Presentation/SmartStore.Web.Framework/app.config @@ -16,7 +16,7 @@ - + @@ -52,4 +52,4 @@ - + diff --git a/src/Presentation/SmartStore.Web.Framework/packages.config b/src/Presentation/SmartStore.Web.Framework/packages.config index 64af87c9ed..d105ec9f25 100644 --- a/src/Presentation/SmartStore.Web.Framework/packages.config +++ b/src/Presentation/SmartStore.Web.Framework/packages.config @@ -10,7 +10,7 @@ - + diff --git a/src/Presentation/SmartStore.Web/Administration/Web.config b/src/Presentation/SmartStore.Web/Administration/Web.config index 7f2608b189..82720de3ee 100644 --- a/src/Presentation/SmartStore.Web/Administration/Web.config +++ b/src/Presentation/SmartStore.Web/Administration/Web.config @@ -92,7 +92,7 @@ - + diff --git a/src/Presentation/SmartStore.Web/SmartStore.Web.csproj b/src/Presentation/SmartStore.Web/SmartStore.Web.csproj index aea5811809..2d2216c935 100644 --- a/src/Presentation/SmartStore.Web/SmartStore.Web.csproj +++ b/src/Presentation/SmartStore.Web/SmartStore.Web.csproj @@ -114,12 +114,13 @@ ..\..\packages\FluentValidation.MVC5.5.6.2.0\lib\Net45\FluentValidation.Mvc.dll True - - False - ..\..\packages\JavaScriptEngineSwitcher.Core.1.1.3\lib\net40\JavaScriptEngineSwitcher.Core.dll + + ..\..\packages\JavaScriptEngineSwitcher.Core.1.2.4\lib\net40\JavaScriptEngineSwitcher.Core.dll + True - - ..\..\packages\JavaScriptEngineSwitcher.Msie.1.1.4\lib\net40\JavaScriptEngineSwitcher.Msie.dll + + ..\..\packages\JavaScriptEngineSwitcher.Msie.1.2.11\lib\net40\JavaScriptEngineSwitcher.Msie.dll + True False @@ -129,8 +130,9 @@ True ..\..\packages\Microsoft.Web.Infrastructure.1.0.0.0\lib\net40\Microsoft.Web.Infrastructure.dll - - ..\..\packages\MsieJavaScriptEngine.1.4.2\lib\net40\MsieJavaScriptEngine.dll + + ..\..\packages\MsieJavaScriptEngine.1.5.6\lib\net40\MsieJavaScriptEngine.dll + True False diff --git a/src/Presentation/SmartStore.Web/Web.config b/src/Presentation/SmartStore.Web/Web.config index 61b4ad427c..72900c3413 100644 --- a/src/Presentation/SmartStore.Web/Web.config +++ b/src/Presentation/SmartStore.Web/Web.config @@ -256,7 +256,7 @@ - + @@ -306,6 +306,10 @@ + + + + diff --git a/src/Presentation/SmartStore.Web/packages.config b/src/Presentation/SmartStore.Web/packages.config index 555ecc8763..46414d814b 100644 --- a/src/Presentation/SmartStore.Web/packages.config +++ b/src/Presentation/SmartStore.Web/packages.config @@ -11,8 +11,8 @@ - - + + @@ -26,7 +26,7 @@ - + diff --git a/src/Tests/SmartStore.Web.MVC.Tests/App.config b/src/Tests/SmartStore.Web.MVC.Tests/App.config index 0d3c92bfdd..47411d9ac8 100644 --- a/src/Tests/SmartStore.Web.MVC.Tests/App.config +++ b/src/Tests/SmartStore.Web.MVC.Tests/App.config @@ -43,7 +43,7 @@ - + @@ -73,6 +73,10 @@ + + + + From 48cc39feaea772e6a39f689540a4148af9f39389 Mon Sep 17 00:00:00 2001 From: Marcus Gesing Date: Thu, 12 Nov 2015 12:05:37 +0100 Subject: [PATCH 050/707] Further IDataExporter implementation --- .../DataExchange/IDataExporter.cs | 9 ++++- .../DataExchange/Internal/DataExportTask.cs | 7 +++- .../DataExchange/Internal/DataExporter.cs | 37 +++++++++---------- .../Internal/DataExporterContext.cs | 4 -- .../Controllers/ExportController.cs | 4 +- 5 files changed, 30 insertions(+), 31 deletions(-) diff --git a/src/Libraries/SmartStore.Services/DataExchange/IDataExporter.cs b/src/Libraries/SmartStore.Services/DataExchange/IDataExporter.cs index 843a15351e..b39c61fcf5 100644 --- a/src/Libraries/SmartStore.Services/DataExchange/IDataExporter.cs +++ b/src/Libraries/SmartStore.Services/DataExchange/IDataExporter.cs @@ -1,7 +1,9 @@ using System; using System.Collections.Generic; +using System.Linq; using System.Threading; using SmartStore.Core.Domain; +using SmartStore.Core.Domain.Catalog; using SmartStore.Core.Plugins; namespace SmartStore.Services.DataExchange @@ -13,7 +15,7 @@ public interface IDataExporter { DataExportResult Export(DataExportRequest request, CancellationToken cancellationToken); - IList Preview(DataExportRequest request); + IList Preview(DataExportRequest request, int pageIndex, int? totalRecords = null); int GetDataCount(DataExportRequest request); } @@ -35,6 +37,7 @@ public DataExportRequest(ExportProfile profile, Provider provid ProgressValueSetter = _voidProgressValueSetter; ProgressMessageSetter = _voidProgressMessageSetter; + EntitiesToExport = new List(); CustomData = new Dictionary(StringComparer.OrdinalIgnoreCase); } @@ -42,13 +45,15 @@ public DataExportRequest(ExportProfile profile, Provider provid public Provider Provider { get; private set; } - public IEnumerable EntitiesToExport { get; set; } + public IList EntitiesToExport { get; set; } public ProgressValueSetter ProgressValueSetter { get; set; } public ProgressMessageSetter ProgressMessageSetter { get; set; } public IDictionary CustomData { get; private set; } + public IQueryable ProductQuery { get; set; } + private static void SetProgress(int val, int max, string msg) { diff --git a/src/Libraries/SmartStore.Services/DataExchange/Internal/DataExportTask.cs b/src/Libraries/SmartStore.Services/DataExchange/Internal/DataExportTask.cs index ab5d8e40c5..54ed0768e6 100644 --- a/src/Libraries/SmartStore.Services/DataExchange/Internal/DataExportTask.cs +++ b/src/Libraries/SmartStore.Services/DataExchange/Internal/DataExportTask.cs @@ -1,4 +1,4 @@ -using System.Web; +using System.Linq; using SmartStore.Core.Localization; using SmartStore.Services.Tasks; @@ -47,7 +47,10 @@ public void Execute(TaskExecutionContext ctx) if (ctx.Parameters.ContainsKey("SelectedIds")) { - request.EntitiesToExport = ctx.Parameters["SelectedIds"].ToIntArray(); + request.EntitiesToExport = ctx.Parameters["SelectedIds"] + .SplitSafe(",") + .Select(x => x.ToInt()) + .ToList(); } // process! diff --git a/src/Libraries/SmartStore.Services/DataExchange/Internal/DataExporter.cs b/src/Libraries/SmartStore.Services/DataExchange/Internal/DataExporter.cs index cc263c1b5b..43cf433f7a 100644 --- a/src/Libraries/SmartStore.Services/DataExchange/Internal/DataExporter.cs +++ b/src/Libraries/SmartStore.Services/DataExchange/Internal/DataExporter.cs @@ -380,12 +380,12 @@ private IQueryable GetProductQuery(DataExporterContext ctx, int skip, i { IQueryable query = null; - if (ctx.QueryProducts == null) + if (ctx.Request.ProductQuery == null) { var searchContext = new ProductSearchContext { OrderBy = ProductSortingEnum.CreatedOn, - ProductIds = ctx.EntityIdsSelected, + ProductIds = ctx.Request.EntitiesToExport, StoreId = (ctx.Request.Profile.PerStore ? ctx.Store.Id : ctx.Filter.StoreId), VisibleIndividuallyOnly = true, PriceMin = ctx.Filter.PriceMinimum, @@ -421,7 +421,7 @@ private IQueryable GetProductQuery(DataExporterContext ctx, int skip, i } else { - query = ctx.QueryProducts; + query = ctx.Request.ProductQuery; } if (skip > 0) @@ -495,8 +495,8 @@ private IQueryable GetOrderQuery(DataExporterContext ctx, int skip, int t null, null); - if (ctx.EntityIdsSelected.Count > 0) - query = query.Where(x => ctx.EntityIdsSelected.Contains(x.Id)); + if (ctx.Request.EntitiesToExport.Count > 0) + query = query.Where(x => ctx.Request.EntitiesToExport.Contains(x.Id)); query = query.OrderByDescending(x => x.CreatedOnUtc); @@ -610,10 +610,8 @@ private IQueryable GetCustomerQuery(DataExporterContext ctx, int skip, .Expand(x => x.CustomerRoles) .Where(x => !x.Deleted); - if (ctx.EntityIdsSelected.Count > 0) - { - query = query.Where(x => ctx.EntityIdsSelected.Contains(x.Id)); - } + if (ctx.Request.EntitiesToExport.Count > 0) + query = query.Where(x => ctx.Request.EntitiesToExport.Contains(x.Id)); query = query.OrderByDescending(x => x.CreatedOnUtc); @@ -890,6 +888,11 @@ private void ExportCoreOuter(DataExporterContext ctx) throw new SmartException("Export aborted because the export provider is not valid"); } + foreach (var item in ctx.Request.CustomData) + { + ctx.ExecuteContext.CustomProperties.Add(item.Key, item.Value); + } + ctx.Log = logger; ctx.ExecuteContext.Log = logger; ctx.ProgressInfo = T("Admin.DataExchange.Export.ProgressInfo"); @@ -1025,13 +1028,15 @@ private void ExportCoreOuter(DataExporterContext ctx) ctx.DeliveryTimes.Clear(); ctx.CategoryPathes.Clear(); ctx.Categories.Clear(); - ctx.EntityIdsSelected.Clear(); ctx.ProductExportContext = null; ctx.OrderExportContext = null; ctx.ManufacturerExportContext = null; ctx.CategoryExportContext = null; ctx.CustomerExportContext = null; + ctx.Request.EntitiesToExport.Clear(); + ctx.Request.CustomData.Clear(); + ctx.ExecuteContext.CustomProperties.Clear(); ctx.ExecuteContext.Log = null; ctx.Log = null; @@ -1061,11 +1066,6 @@ public DataExportResult Export(DataExportRequest request, CancellationToken canc { var ctx = new DataExporterContext(request, cancellationToken); - if (request.EntitiesToExport != null) - { - ctx.EntityIdsSelected.AddRange(request.EntitiesToExport); - } - ExportCoreOuter(ctx); if (ctx.Result != null && ctx.Result.Succeeded && ctx.Result.Files.Count > 0) @@ -1089,7 +1089,7 @@ public DataExportResult Export(DataExportRequest request, CancellationToken canc else prefix = request.Provider.Value.EntityType.ToString(); - var selectedEntityCount = (request.EntitiesToExport == null ? 0 : request.EntitiesToExport.Count()); + var selectedEntityCount = (request.EntitiesToExport == null ? 0 : request.EntitiesToExport.Count); if (selectedEntityCount == 0) suffix = T("Common.All"); @@ -1102,11 +1102,8 @@ public DataExportResult Export(DataExportRequest request, CancellationToken canc return ctx.Result; } - public IList Preview(DataExportRequest request) + public IList Preview(DataExportRequest request, int pageIndex, int? totalRecords = null) { - var pageIndex = (request.CustomData.ContainsKey("PageIndex") ? (int)request.CustomData["PageIndex"] : 0); - var totalRecords = (request.CustomData.ContainsKey("TotalRecords") ? (int)request.CustomData["TotalRecords"] : 0); - var resultData = new List(); var cancellation = new CancellationTokenSource(TimeSpan.FromMinutes(5.0)); diff --git a/src/Libraries/SmartStore.Services/DataExchange/Internal/DataExporterContext.cs b/src/Libraries/SmartStore.Services/DataExchange/Internal/DataExporterContext.cs index b12b3a1bdb..23da17e069 100644 --- a/src/Libraries/SmartStore.Services/DataExchange/Internal/DataExporterContext.cs +++ b/src/Libraries/SmartStore.Services/DataExchange/Internal/DataExporterContext.cs @@ -1,6 +1,5 @@ using System.Collections.Generic; using System.IO; -using System.Linq; using System.Threading; using SmartStore.Core; using SmartStore.Core.Domain; @@ -37,7 +36,6 @@ public DataExporterContext( FolderContent = FileSystemHelper.TempDir(@"Profile\Export\{0}\Content".FormatInvariant(request.Profile.FolderName)); FolderRoot = System.IO.Directory.GetParent(FolderContent).FullName; - EntityIdsSelected = new List(); Categories = new Dictionary(); CategoryPathes = new Dictionary(); Countries = new Dictionary(); @@ -56,13 +54,11 @@ public DataExporterContext( ExecuteContext.Projection = XmlHelper.Deserialize(request.Profile.Projection); } - public List EntityIdsSelected { get; private set; } public List EntityIdsLoaded { get; set; } public int RecordCount { get; set; } public Dictionary RecordsPerStore { get; set; } public string ProgressInfo { get; set; } - public IQueryable QueryProducts { get; set; } public DataExportRequest Request { get; private set; } public CancellationToken CancellationToken { get; private set; } diff --git a/src/Presentation/SmartStore.Web/Administration/Controllers/ExportController.cs b/src/Presentation/SmartStore.Web/Administration/Controllers/ExportController.cs index 518e66169c..354da99fe9 100644 --- a/src/Presentation/SmartStore.Web/Administration/Controllers/ExportController.cs +++ b/src/Presentation/SmartStore.Web/Administration/Controllers/ExportController.cs @@ -754,10 +754,8 @@ public ActionResult PreviewList(GridCommand command, int id, int totalRecords) var orderModel = new List(); var request = new DataExportRequest(profile, provider); - request.CustomData.Add("PageIndex", command.Page - 1); - request.CustomData.Add("TotalRecords", totalRecords); - var data = _dataExporter.Preview(request); + var data = _dataExporter.Preview(request, command.Page - 1, totalRecords); foreach (dynamic item in data) { From f685b80399f4584fccecd17c19af37756278ebe5 Mon Sep 17 00:00:00 2001 From: Marcus Gesing Date: Thu, 12 Nov 2015 17:16:49 +0100 Subject: [PATCH 051/707] Creating system export profiles --- .../Domain/DataExchange/ExportProfile.cs | 10 + .../Mapping/DataExchange/ExportProfileMap.cs | 1 + ...1511121139009_ExportFramework3.Designer.cs | 29 +++ .../201511121139009_ExportFramework3.cs | 193 ++++++++++++++++++ .../201511121139009_ExportFramework3.resx | 126 ++++++++++++ .../SmartStore.Data/SmartStore.Data.csproj | 7 + .../{Internal => }/DataExportTask.cs | 2 +- .../{Internal => }/DataExporter.cs | 3 +- .../{Internal => }/DynamicEntityHelper.cs | 3 +- .../DataExchange/ExportProfileService.cs | 8 +- .../Providers/CategoryXmlExportProvider.cs | 3 +- .../Providers/CustomerXlsxExportProvider.cs | 3 +- .../Providers/CustomerXmlExportProvider.cs | 3 +- .../ManufacturerXmlExportProvider.cs | 3 +- .../Providers/OrderXlsxExportProvider.cs | 3 +- .../Providers/OrderXmlExportProvider.cs | 3 +- .../Providers/ProductXlsxExportProvider.cs | 3 +- .../Providers/ProductXmlExportProvider.cs | 3 +- .../Providers/SubscriberCsvExportProvider.cs | 3 +- .../SmartStore.Services.csproj | 6 +- .../Localization/resources.en-us.xml | 2 +- .../Controllers/ExportController.cs | 2 + .../Models/DataExchange/ExportProfileModel.cs | 6 + .../Administration/Views/Export/Edit.cshtml | 25 ++- .../Administration/Views/Export/List.cshtml | 12 ++ 25 files changed, 432 insertions(+), 30 deletions(-) create mode 100644 src/Libraries/SmartStore.Data/Migrations/201511121139009_ExportFramework3.Designer.cs create mode 100644 src/Libraries/SmartStore.Data/Migrations/201511121139009_ExportFramework3.cs create mode 100644 src/Libraries/SmartStore.Data/Migrations/201511121139009_ExportFramework3.resx rename src/Libraries/SmartStore.Services/DataExchange/{Internal => }/DataExportTask.cs (96%) rename src/Libraries/SmartStore.Services/DataExchange/{Internal => }/DataExporter.cs (99%) rename src/Libraries/SmartStore.Services/DataExchange/{Internal => }/DynamicEntityHelper.cs (99%) diff --git a/src/Libraries/SmartStore.Core/Domain/DataExchange/ExportProfile.cs b/src/Libraries/SmartStore.Core/Domain/DataExchange/ExportProfile.cs index ea98e0838b..b49d8d76d1 100644 --- a/src/Libraries/SmartStore.Core/Domain/DataExchange/ExportProfile.cs +++ b/src/Libraries/SmartStore.Core/Domain/DataExchange/ExportProfile.cs @@ -32,11 +32,21 @@ public ExportProfile() ///
public string FileNamePattern { get; set; } + /// + /// The system name of the profile + /// + public string SystemName { get; set; } + /// /// The system name of the export provider /// public string ProviderSystemName { get; set; } + /// + /// Whether the profile is an unremovable system profile + /// + public bool IsSystemProfile { get; set; } + /// /// Whether the export profile is enabled /// diff --git a/src/Libraries/SmartStore.Data/Mapping/DataExchange/ExportProfileMap.cs b/src/Libraries/SmartStore.Data/Mapping/DataExchange/ExportProfileMap.cs index d54bf034e3..6e5e6758fe 100644 --- a/src/Libraries/SmartStore.Data/Mapping/DataExchange/ExportProfileMap.cs +++ b/src/Libraries/SmartStore.Data/Mapping/DataExchange/ExportProfileMap.cs @@ -12,6 +12,7 @@ public ExportProfileMap() this.Property(x => x.Name).IsRequired().HasMaxLength(100); this.Property(x => x.FolderName).IsRequired().HasMaxLength(100); + this.Property(x => x.SystemName).HasMaxLength(400); this.Property(x => x.ProviderSystemName).IsRequired().HasMaxLength(4000); this.Property(x => x.Filtering).IsMaxLength(); this.Property(x => x.Projection).IsMaxLength(); diff --git a/src/Libraries/SmartStore.Data/Migrations/201511121139009_ExportFramework3.Designer.cs b/src/Libraries/SmartStore.Data/Migrations/201511121139009_ExportFramework3.Designer.cs new file mode 100644 index 0000000000..634dd864d5 --- /dev/null +++ b/src/Libraries/SmartStore.Data/Migrations/201511121139009_ExportFramework3.Designer.cs @@ -0,0 +1,29 @@ +// +namespace SmartStore.Data.Migrations +{ + using System.CodeDom.Compiler; + using System.Data.Entity.Migrations; + using System.Data.Entity.Migrations.Infrastructure; + using System.Resources; + + [GeneratedCode("EntityFramework.Migrations", "6.1.3-40302")] + public sealed partial class ExportFramework3 : IMigrationMetadata + { + private readonly ResourceManager Resources = new ResourceManager(typeof(ExportFramework3)); + + string IMigrationMetadata.Id + { + get { return "201511121139009_ExportFramework3"; } + } + + string IMigrationMetadata.Source + { + get { return null; } + } + + string IMigrationMetadata.Target + { + get { return Resources.GetString("Target"); } + } + } +} diff --git a/src/Libraries/SmartStore.Data/Migrations/201511121139009_ExportFramework3.cs b/src/Libraries/SmartStore.Data/Migrations/201511121139009_ExportFramework3.cs new file mode 100644 index 0000000000..34a97d19bc --- /dev/null +++ b/src/Libraries/SmartStore.Data/Migrations/201511121139009_ExportFramework3.cs @@ -0,0 +1,193 @@ +namespace SmartStore.Data.Migrations +{ + using System.Data.Entity.Migrations; + using Setup; + using Core.Domain.Tasks; + using System.Collections.Generic; + using Core.Domain; + using System.Linq; + using Utilities; + + public partial class ExportFramework3 : DbMigration, ILocaleResourcesProvider, IDataSeeder + { + public override void Up() + { + AddColumn("dbo.ExportProfile", "SystemName", c => c.String(maxLength: 400)); + AddColumn("dbo.ExportProfile", "IsSystemProfile", c => c.Boolean(nullable: false)); + } + + public override void Down() + { + DropColumn("dbo.ExportProfile", "IsSystemProfile"); + DropColumn("dbo.ExportProfile", "SystemName"); + } + + public bool RollbackOnFailure + { + get { return false; } + } + + public void Seed(SmartObjectContext context) + { + context.MigrateLocaleResources(MigrateLocaleResources); + + var systemProfilesInfos = new List + { + new SystemProfileInfo { SystemName = "SmartStoreCategoryXml", ProviderSystemName = "Exports.SmartStoreCategoryXml", Name = "Category XML Export" }, + new SystemProfileInfo { SystemName = "SmartStoreCustomerXlsx", ProviderSystemName = "Exports.SmartStoreCustomerXlsx", Name = "Customer Excel Export" }, + new SystemProfileInfo { SystemName = "SmartStoreCustomerXml", ProviderSystemName = "Exports.SmartStoreCustomerXml", Name = "Customer XML Export" }, + new SystemProfileInfo { SystemName = "SmartStoreManufacturerXml", ProviderSystemName = "Exports.SmartStoreManufacturerXml", Name = "Manufacturer XML Export" }, + new SystemProfileInfo { SystemName = "SmartStoreOrderXlsx", ProviderSystemName = "Exports.SmartStoreOrderXlsx", Name = "Order Excel Export" }, + new SystemProfileInfo { SystemName = "SmartStoreOrderXml", ProviderSystemName = "Exports.SmartStoreOrderXml", Name = "Order XML Export" }, + new SystemProfileInfo { SystemName = "SmartStoreProductXlsx", ProviderSystemName = "Exports.SmartStoreProductXlsx", Name = "Product Excel Export" }, + new SystemProfileInfo { SystemName = "SmartStoreProductXml", ProviderSystemName = "Exports.SmartStoreProductXml", Name = "Product XML Export" }, + new SystemProfileInfo { SystemName = "SmartStoreNewsSubscriptionCsv", ProviderSystemName = "Exports.SmartStoreNewsSubscriptionCsv", Name = "Newsletter Subscribers CSV Export" } + }; + + var tasks = context.Set(); + var profiles = context.Set(); + + foreach (var profileInfo in systemProfilesInfos) + { + var profile = profiles.FirstOrDefault(x => x.IsSystemProfile && x.SystemName == profileInfo.SystemName && x.ProviderSystemName == profileInfo.ProviderSystemName); + + if (profile != null) + continue; + + var task = new ScheduleTask + { + CronExpression = "0 */6 * * *", // every six hours + Type = "SmartStore.Services.DataExchange.DataExportTask, SmartStore.Services", + Enabled = false, + StopOnError = false, + IsHidden = true + }; + + task.Name = string.Concat(profileInfo.Name, " task"); + + task = tasks.Add(task); + context.SaveChanges(); + + var seoName = SeoHelper.GetSeName(profileInfo.Name, true, false).Replace("/", "").Replace("-", ""); + + profile = new ExportProfile + { + IsSystemProfile = true, + Name = profileInfo.Name, + SystemName = profileInfo.SystemName, + ProviderSystemName = profileInfo.ProviderSystemName, + FolderName = string.Concat("sm-", seoName.Replace("export", "").ToValidPath().Truncate(50)), + FileNamePattern = "%Store.Id%-%Profile.Id%-%File.Index%-%Profile.SeoName%", + Enabled = true, + PerStore = false, + CreateZipArchive = false, + Cleanup = false, + SchedulingTaskId = task.Id + }; + + profile = profiles.Add(profile); + + task.Alias = profile.Id.ToString(); + + tasks.AddOrUpdate(task); + context.SaveChanges(); + } + } + + public void MigrateLocaleResources(LocaleResourcesBuilder builder) + { + builder.AddOrUpdate("Enums.SmartStore.Core.Domain.DataExchange.ExportEntityType.NewsLetterSubscription", + "Newsletter Subscribers", + "Newsletter Abonnenten"); + + + builder.AddOrUpdate("Providers.FriendlyName.Exports.SmartStoreCategoryXml", + "Category XML Export", + "Warengruppen XML Export"); + builder.AddOrUpdate("Providers.Description.Exports.SmartStoreCategoryXml", + "Allows to export category data in XML format.", + "Ermglicht den Export von Warengruppendaten im XML Format."); + + builder.AddOrUpdate("Providers.FriendlyName.Exports.SmartStoreCustomerXlsx", + "Customer Excel Export", + "Kunden Excel Export"); + builder.AddOrUpdate("Providers.Description.Exports.SmartStoreCustomerXlsx", + "Allows to export customer data in Excel format.", + "Ermglicht den Export von Kundendaten im Excel Format."); + + builder.AddOrUpdate("Providers.FriendlyName.Exports.SmartStoreCustomerXml", + "Customer XML Export", + "Kunden XML Export"); + builder.AddOrUpdate("Providers.Description.Exports.SmartStoreCustomerXml", + "Allows to export customer data in XML format.", + "Ermglicht den Export von Kundendaten im XML Format."); + + builder.AddOrUpdate("Providers.FriendlyName.Exports.SmartStoreManufacturerXml", + "Manufacturer XML Export", + "Hersteller XML Export"); + builder.AddOrUpdate("Providers.Description.Exports.SmartStoreManufacturerXml", + "Allows to export manufacturer data in XML format.", + "Ermglicht den Export von Herstellerdaten im XML Format."); + + builder.AddOrUpdate("Providers.FriendlyName.Exports.SmartStoreOrderXlsx", + "Order Excel Export", + "Auftrags Excel Export"); + builder.AddOrUpdate("Providers.Description.Exports.SmartStoreOrderXlsx", + "Allows to export order data in Excel format.", + "Ermglicht den Export von Auftragsdaten im Excel Format."); + + builder.AddOrUpdate("Providers.FriendlyName.Exports.SmartStoreOrderXml", + "Order XML Export", + "Auftrags XML Export"); + builder.AddOrUpdate("Providers.Description.Exports.SmartStoreOrderXml", + "Allows to export order data in XML format.", + "Ermglicht den Export von Auftragsdaten im XML Format."); + + builder.AddOrUpdate("Providers.FriendlyName.Exports.SmartStoreProductXlsx", + "Product Excel Export", + "Produkt Excel Export"); + builder.AddOrUpdate("Providers.Description.Exports.SmartStoreProductXlsx", + "Allows to export product data in Excel format.", + "Ermglicht den Export von Produktdaten im Excel Format."); + + builder.AddOrUpdate("Providers.FriendlyName.Exports.SmartStoreProductXml", + "Product XML Export", + "Produkt XML Export"); + builder.AddOrUpdate("Providers.Description.Exports.SmartStoreProductXml", + "Allows to export product data in XML format.", + "Ermglicht den Export von Produktdaten im XML Format."); + + builder.AddOrUpdate("Providers.FriendlyName.Exports.SmartStoreNewsSubscriptionCsv", + "Newsletter Subscribers CSV Export", + "Newsletter Abonnenten CSV Export"); + builder.AddOrUpdate("Providers.Description.Exports.SmartStoreNewsSubscriptionCsv", + "Allows to export newsletter subscriber data in CSV format.", + "Ermglicht den Export von Newsletter Abonnentendaten im CSV Format."); + + + builder.AddOrUpdate("Admin.DataExchange.Export.SystemName", + "System name of profile", + "Systemname des Profils", + "The system name of the export profile.", + "Der Systemname des Exportprofils."); + + builder.AddOrUpdate("Admin.DataExchange.Export.IsSystemProfile", + "System profile", + "Systemprofil", + "Indicates whether the export profile is a system profile. System profiles cannot be removed.", + "Gibt an, ob es sich bei dem Exportprofil um eine Systemprofil handelt. Systemprofile knnen nicht entfernt werden."); + + builder.AddOrUpdate("Admin.DataExchange.Export.CannotDeleteSystemProfile", + "Cannot delete a system export profile.", + "Ein System-Exportprofil kann nicht gelscht werden."); + } + } + + + internal class SystemProfileInfo + { + public string SystemName { get; set; } + public string ProviderSystemName { get; set; } + public string Name { get; set; } + } +} \ No newline at end of file diff --git a/src/Libraries/SmartStore.Data/Migrations/201511121139009_ExportFramework3.resx b/src/Libraries/SmartStore.Data/Migrations/201511121139009_ExportFramework3.resx new file mode 100644 index 0000000000..1ed5a1d758 --- /dev/null +++ b/src/Libraries/SmartStore.Data/Migrations/201511121139009_ExportFramework3.resx @@ -0,0 +1,126 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 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 + + + dbo + + \ No newline at end of file diff --git a/src/Libraries/SmartStore.Data/SmartStore.Data.csproj b/src/Libraries/SmartStore.Data/SmartStore.Data.csproj index 8764a6a9ed..b328653e66 100644 --- a/src/Libraries/SmartStore.Data/SmartStore.Data.csproj +++ b/src/Libraries/SmartStore.Data/SmartStore.Data.csproj @@ -366,6 +366,10 @@ 201509150931528_ExportFramework2.cs + + + 201511121139009_ExportFramework3.cs + @@ -687,6 +691,9 @@ 201509150931528_ExportFramework2.cs + + 201511121139009_ExportFramework3.cs + diff --git a/src/Libraries/SmartStore.Services/DataExchange/Internal/DataExportTask.cs b/src/Libraries/SmartStore.Services/DataExchange/DataExportTask.cs similarity index 96% rename from src/Libraries/SmartStore.Services/DataExchange/Internal/DataExportTask.cs rename to src/Libraries/SmartStore.Services/DataExchange/DataExportTask.cs index 54ed0768e6..0622be6566 100644 --- a/src/Libraries/SmartStore.Services/DataExchange/Internal/DataExportTask.cs +++ b/src/Libraries/SmartStore.Services/DataExchange/DataExportTask.cs @@ -2,7 +2,7 @@ using SmartStore.Core.Localization; using SmartStore.Services.Tasks; -namespace SmartStore.Services.DataExchange.Internal +namespace SmartStore.Services.DataExchange { // note: namespace persisted in ScheduleTask.Type public partial class DataExportTask : ITask diff --git a/src/Libraries/SmartStore.Services/DataExchange/Internal/DataExporter.cs b/src/Libraries/SmartStore.Services/DataExchange/DataExporter.cs similarity index 99% rename from src/Libraries/SmartStore.Services/DataExchange/Internal/DataExporter.cs rename to src/Libraries/SmartStore.Services/DataExchange/DataExporter.cs index 43cf433f7a..b409401da6 100644 --- a/src/Libraries/SmartStore.Services/DataExchange/Internal/DataExporter.cs +++ b/src/Libraries/SmartStore.Services/DataExchange/DataExporter.cs @@ -21,6 +21,7 @@ using SmartStore.Services.Catalog; using SmartStore.Services.Common; using SmartStore.Services.Customers; +using SmartStore.Services.DataExchange.Internal; using SmartStore.Services.Directory; using SmartStore.Services.Helpers; using SmartStore.Services.Localization; @@ -33,7 +34,7 @@ using SmartStore.Utilities; using SmartStore.Utilities.Threading; -namespace SmartStore.Services.DataExchange.Internal +namespace SmartStore.Services.DataExchange { public partial class DataExporter : IDataExporter { diff --git a/src/Libraries/SmartStore.Services/DataExchange/Internal/DynamicEntityHelper.cs b/src/Libraries/SmartStore.Services/DataExchange/DynamicEntityHelper.cs similarity index 99% rename from src/Libraries/SmartStore.Services/DataExchange/Internal/DynamicEntityHelper.cs rename to src/Libraries/SmartStore.Services/DataExchange/DynamicEntityHelper.cs index e3de6b5e56..73cb0ae431 100644 --- a/src/Libraries/SmartStore.Services/DataExchange/Internal/DynamicEntityHelper.cs +++ b/src/Libraries/SmartStore.Services/DataExchange/DynamicEntityHelper.cs @@ -21,10 +21,11 @@ using SmartStore.Core.Domain.Stores; using SmartStore.Core.Html; using SmartStore.Services.Catalog; +using SmartStore.Services.DataExchange.Internal; using SmartStore.Services.Localization; using SmartStore.Services.Seo; -namespace SmartStore.Services.DataExchange.Internal +namespace SmartStore.Services.DataExchange { public partial class DataExporter { diff --git a/src/Libraries/SmartStore.Services/DataExchange/ExportProfileService.cs b/src/Libraries/SmartStore.Services/DataExchange/ExportProfileService.cs index 414e5c073a..f2860ed481 100644 --- a/src/Libraries/SmartStore.Services/DataExchange/ExportProfileService.cs +++ b/src/Libraries/SmartStore.Services/DataExchange/ExportProfileService.cs @@ -104,7 +104,7 @@ public virtual ExportProfile InsertExportProfile(Provider provi task.LastEndUtc = task.LastStartUtc = task.LastSuccessUtc = null; } - task.Name = string.Concat(name, " export task"); + task.Name = string.Concat(name, " task"); _scheduleTaskService.InsertTask(task); @@ -196,6 +196,9 @@ public virtual void DeleteExportProfile(ExportProfile profile) if (profile == null) throw new ArgumentNullException("profile"); + if (profile.IsSystemProfile) + throw new SmartException(_localizationService.GetResource("Admin.DataExchange.Export.CannotDeleteSystemProfile")); + int scheduleTaskId = profile.SchedulingTaskId; var folder = profile.GetExportFolder(); @@ -224,7 +227,8 @@ from x in _exportProfileRepository.Table.Expand(x => x.ScheduleTask) } query = query - .OrderBy(x => x.ProviderSystemName) + .OrderBy(x => x.IsSystemProfile) + .ThenBy(x => x.ProviderSystemName) .ThenBy(x => x.Name); return query; diff --git a/src/Libraries/SmartStore.Services/DataExchange/Providers/CategoryXmlExportProvider.cs b/src/Libraries/SmartStore.Services/DataExchange/Providers/CategoryXmlExportProvider.cs index 401b9a165c..8733ac6a1e 100644 --- a/src/Libraries/SmartStore.Services/DataExchange/Providers/CategoryXmlExportProvider.cs +++ b/src/Libraries/SmartStore.Services/DataExchange/Providers/CategoryXmlExportProvider.cs @@ -10,8 +10,7 @@ namespace SmartStore.Services.DataExchange.Providers /// Exports XML formatted category data to a file /// [SystemName("Exports.SmartStoreCategoryXml")] - [FriendlyName("SmartStore XML category export")] - [IsHidden(true)] + [FriendlyName("Category XML Export")] public class CategoryXmlExportProvider : ExportProviderBase { public static string SystemName diff --git a/src/Libraries/SmartStore.Services/DataExchange/Providers/CustomerXlsxExportProvider.cs b/src/Libraries/SmartStore.Services/DataExchange/Providers/CustomerXlsxExportProvider.cs index 133ea6e3a7..75437762ee 100644 --- a/src/Libraries/SmartStore.Services/DataExchange/Providers/CustomerXlsxExportProvider.cs +++ b/src/Libraries/SmartStore.Services/DataExchange/Providers/CustomerXlsxExportProvider.cs @@ -14,8 +14,7 @@ namespace SmartStore.Services.DataExchange.Providers /// Exports Excel formatted customer data to a file /// [SystemName("Exports.SmartStoreCustomerXlsx")] - [FriendlyName("SmartStore Excel customer export")] - [IsHidden(true)] + [FriendlyName("Customer Excel Export")] public class CustomerXlsxExportProvider : ExportProviderBase { private string[] Properties diff --git a/src/Libraries/SmartStore.Services/DataExchange/Providers/CustomerXmlExportProvider.cs b/src/Libraries/SmartStore.Services/DataExchange/Providers/CustomerXmlExportProvider.cs index 7b7611fb2a..a5f7a56048 100644 --- a/src/Libraries/SmartStore.Services/DataExchange/Providers/CustomerXmlExportProvider.cs +++ b/src/Libraries/SmartStore.Services/DataExchange/Providers/CustomerXmlExportProvider.cs @@ -9,8 +9,7 @@ namespace SmartStore.Services.DataExchange.Providers /// Exports XML formatted customer data to a file /// [SystemName("Exports.SmartStoreCustomerXml")] - [FriendlyName("SmartStore XML customer export")] - [IsHidden(true)] + [FriendlyName("Customer XML Export")] public class CustomerXmlExportProvider : ExportProviderBase { public static string SystemName diff --git a/src/Libraries/SmartStore.Services/DataExchange/Providers/ManufacturerXmlExportProvider.cs b/src/Libraries/SmartStore.Services/DataExchange/Providers/ManufacturerXmlExportProvider.cs index 74eb5551a7..e4bb40c427 100644 --- a/src/Libraries/SmartStore.Services/DataExchange/Providers/ManufacturerXmlExportProvider.cs +++ b/src/Libraries/SmartStore.Services/DataExchange/Providers/ManufacturerXmlExportProvider.cs @@ -10,8 +10,7 @@ namespace SmartStore.Services.DataExchange.Providers /// Exports XML formatted manufacturer data to a file /// [SystemName("Exports.SmartStoreManufacturerXml")] - [FriendlyName("SmartStore XML manufacturer export")] - [IsHidden(true)] + [FriendlyName("Manufacturer XML Export")] public class ManufacturerXmlExportProvider : ExportProviderBase { public static string SystemName diff --git a/src/Libraries/SmartStore.Services/DataExchange/Providers/OrderXlsxExportProvider.cs b/src/Libraries/SmartStore.Services/DataExchange/Providers/OrderXlsxExportProvider.cs index b36b4286d9..f6b34744d0 100644 --- a/src/Libraries/SmartStore.Services/DataExchange/Providers/OrderXlsxExportProvider.cs +++ b/src/Libraries/SmartStore.Services/DataExchange/Providers/OrderXlsxExportProvider.cs @@ -12,8 +12,7 @@ namespace SmartStore.Services.DataExchange.Providers /// Exports Excel formatted order data to a file /// [SystemName("Exports.SmartStoreOrderXlsx")] - [FriendlyName("SmartStore Excel order export")] - [IsHidden(true)] + [FriendlyName("Order Excel Export")] public class OrderXlsxExportProvider : ExportProviderBase { private string[] Properties diff --git a/src/Libraries/SmartStore.Services/DataExchange/Providers/OrderXmlExportProvider.cs b/src/Libraries/SmartStore.Services/DataExchange/Providers/OrderXmlExportProvider.cs index 6a878ddb84..85069df675 100644 --- a/src/Libraries/SmartStore.Services/DataExchange/Providers/OrderXmlExportProvider.cs +++ b/src/Libraries/SmartStore.Services/DataExchange/Providers/OrderXmlExportProvider.cs @@ -13,8 +13,7 @@ namespace SmartStore.Services.DataExchange.Providers /// Exports XML formatted order data to a file /// [SystemName("Exports.SmartStoreOrderXml")] - [FriendlyName("SmartStore XML order export")] - [IsHidden(true)] + [FriendlyName("Order XML Export")] public class OrderXmlExportProvider : ExportProviderBase { public static string SystemName diff --git a/src/Libraries/SmartStore.Services/DataExchange/Providers/ProductXlsxExportProvider.cs b/src/Libraries/SmartStore.Services/DataExchange/Providers/ProductXlsxExportProvider.cs index e908fa8001..284388bbb0 100644 --- a/src/Libraries/SmartStore.Services/DataExchange/Providers/ProductXlsxExportProvider.cs +++ b/src/Libraries/SmartStore.Services/DataExchange/Providers/ProductXlsxExportProvider.cs @@ -18,8 +18,7 @@ namespace SmartStore.Services.DataExchange.Providers /// Exports Excel formatted product data to a file /// [SystemName("Exports.SmartStoreProductXlsx")] - [FriendlyName("SmartStore Excel product export")] - [IsHidden(true)] + [FriendlyName("Product Excel Export")] public class ProductXlsxExportProvider : ExportProviderBase { private readonly ILanguageService _languageService; diff --git a/src/Libraries/SmartStore.Services/DataExchange/Providers/ProductXmlExportProvider.cs b/src/Libraries/SmartStore.Services/DataExchange/Providers/ProductXmlExportProvider.cs index 4c2f86ccfd..a5f88db4b4 100644 --- a/src/Libraries/SmartStore.Services/DataExchange/Providers/ProductXmlExportProvider.cs +++ b/src/Libraries/SmartStore.Services/DataExchange/Providers/ProductXmlExportProvider.cs @@ -9,8 +9,7 @@ namespace SmartStore.Services.DataExchange.Providers /// Exports XML formatted product data to a file /// [SystemName("Exports.SmartStoreProductXml")] - [FriendlyName("SmartStore XML product export")] - [IsHidden(true)] + [FriendlyName("Product XML Export")] public class ProductXmlExportProvider : ExportProviderBase { public static string SystemName diff --git a/src/Libraries/SmartStore.Services/DataExchange/Providers/SubscriberCsvExportProvider.cs b/src/Libraries/SmartStore.Services/DataExchange/Providers/SubscriberCsvExportProvider.cs index bf8b192421..ff2873ee92 100644 --- a/src/Libraries/SmartStore.Services/DataExchange/Providers/SubscriberCsvExportProvider.cs +++ b/src/Libraries/SmartStore.Services/DataExchange/Providers/SubscriberCsvExportProvider.cs @@ -11,8 +11,7 @@ namespace SmartStore.Services.DataExchange.Providers /// Exports CSV formatted newsletter subscription data to a file /// [SystemName("Exports.SmartStoreNewsSubscriptionCsv")] - [FriendlyName("SmartStore CSV newsletter subscription export")] - [IsHidden(true)] + [FriendlyName("Newsletter Subscribers CSV Export")] public class SubscriberCsvExportProvider : ExportProviderBase { public static string SystemName diff --git a/src/Libraries/SmartStore.Services/SmartStore.Services.csproj b/src/Libraries/SmartStore.Services/SmartStore.Services.csproj index 83fe5c10e4..ec4af99cbd 100644 --- a/src/Libraries/SmartStore.Services/SmartStore.Services.csproj +++ b/src/Libraries/SmartStore.Services/SmartStore.Services.csproj @@ -168,9 +168,9 @@ - + - + @@ -198,7 +198,7 @@ - + diff --git a/src/Plugins/SmartStore.GoogleMerchantCenter/Localization/resources.en-us.xml b/src/Plugins/SmartStore.GoogleMerchantCenter/Localization/resources.en-us.xml index 8e7528f68e..a80721be22 100644 --- a/src/Plugins/SmartStore.GoogleMerchantCenter/Localization/resources.en-us.xml +++ b/src/Plugins/SmartStore.GoogleMerchantCenter/Localization/resources.en-us.xml @@ -9,7 +9,7 @@ Google Merchant Center XML feed - Allows you to export product data in the XML feed format of Google Merchant Center (GMC). + Allows to export product data in XML feed format of Google Merchant Center (GMC). diff --git a/src/Presentation/SmartStore.Web/Administration/Controllers/ExportController.cs b/src/Presentation/SmartStore.Web/Administration/Controllers/ExportController.cs index 354da99fe9..f15c4fe3a0 100644 --- a/src/Presentation/SmartStore.Web/Administration/Controllers/ExportController.cs +++ b/src/Presentation/SmartStore.Web/Administration/Controllers/ExportController.cs @@ -104,6 +104,8 @@ private void PrepareProfileModel(ExportProfileModel model, ExportProfile profile { model.Id = profile.Id; model.Name = profile.Name; + model.SystemName = profile.SystemName; + model.IsSystemProfile = profile.IsSystemProfile; model.ProviderSystemName = profile.ProviderSystemName; model.FolderName = profile.FolderName; model.FileNamePattern = profile.FileNamePattern; diff --git a/src/Presentation/SmartStore.Web/Administration/Models/DataExchange/ExportProfileModel.cs b/src/Presentation/SmartStore.Web/Administration/Models/DataExchange/ExportProfileModel.cs index 493636f238..7ea59f0921 100644 --- a/src/Presentation/SmartStore.Web/Administration/Models/DataExchange/ExportProfileModel.cs +++ b/src/Presentation/SmartStore.Web/Administration/Models/DataExchange/ExportProfileModel.cs @@ -24,6 +24,12 @@ public partial class ExportProfileModel : EntityModelBase [SmartResourceDisplayName("Admin.DataExchange.Export.Name")] public string Name { get; set; } + [SmartResourceDisplayName("Admin.DataExchange.Export.SystemName")] + public string SystemName { get; set; } + + [SmartResourceDisplayName("Admin.DataExchange.Export.IsSystemProfile")] + public bool IsSystemProfile { get; set; } + [SmartResourceDisplayName("Admin.DataExchange.Export.ProviderSystemName")] public string ProviderSystemName { get; set; } public List AvailableProviders { get; set; } diff --git a/src/Presentation/SmartStore.Web/Administration/Views/Export/Edit.cshtml b/src/Presentation/SmartStore.Web/Administration/Views/Export/Edit.cshtml index 55bac26fec..ecf22fd744 100644 --- a/src/Presentation/SmartStore.Web/Administration/Views/Export/Edit.cshtml +++ b/src/Presentation/SmartStore.Web/Administration/Views/Export/Edit.cshtml @@ -35,9 +35,12 @@ - + @if (!Model.IsSystemProfile) + { + + } @@ -73,6 +76,22 @@ @Html.ValidationMessageFor(x => x.Name)
+ @Html.SmartLabelFor(x => x.SystemName) + +
@(Model.SystemName.NaIfEmpty())
+
+ @Html.SmartLabelFor(x => x.IsSystemProfile) + + @T(Model.IsSystemProfile ? "Admin.Common.Yes" : "Admin.Common.No") +
@Html.SmartLabelFor(x => x.Enabled) diff --git a/src/Presentation/SmartStore.Web/Administration/Views/Export/List.cshtml b/src/Presentation/SmartStore.Web/Administration/Views/Export/List.cshtml index 740e0447ce..6448df05a3 100644 --- a/src/Presentation/SmartStore.Web/Administration/Views/Export/List.cshtml +++ b/src/Presentation/SmartStore.Web/Administration/Views/Export/List.cshtml @@ -31,6 +31,7 @@ @T("Common.Enabled") @T("Admin.DataExchange.Export.EntityType") @T("Admin.DataExchange.Export.FileExtension")@T("Admin.DataExchange.Export.IsSystemProfile") @T("Admin.System.ScheduleTasks.LastStart") @T("Admin.System.ScheduleTasks.NextRun") @T("Admin.Common.Actions") @profile.Name + @if (profile.SystemName.HasValue()) + { +
@profile.SystemName
+ }
@if (profile.Provider.ConfigurationUrl.HasValue()) { @profile.Provider.FriendlyName.NaIfEmpty() } + else + { + @profile.Provider.FriendlyName.NaIfEmpty() + }
@profile.ProviderSystemName
@@ -62,6 +71,9 @@ @Html.IconForFileExtension(profile.Provider.FileExtension, true) + @Html.SymbolForBool(profile.IsSystemProfile) +
@Html.Partial("~/Administration/Views/ScheduleTask/_LastRun.cshtml", profile.TaskModel) From dda09131ef478a0a10b7e4d7381438723df69204 Mon Sep 17 00:00:00 2001 From: Murat Cakir Date: Thu, 12 Nov 2015 20:20:53 +0100 Subject: [PATCH 052/707] Cleaned, renamed and (re)moved a bunch of extension methods --- .../Extensions/CollectionExtensions.cs | 4 - .../Extensions/DateTimeExtensions.cs | 1 - .../Extensions/EnumerableExtensions.cs | 2 +- .../Extensions/HtmlTextWriterExtensions.cs | 7 +- .../Extensions/HttpExtensions.cs | 3 +- .../Extensions/MiscExtensions.cs | 29 +- .../Extensions/StringExtensions.cs | 1 - .../Utilities/Reflection/FastProperty.cs | 10 +- .../Extensions/MiscExtensions.cs | 43 +- .../Extensions/DateTimeExtensions.cs | 154 ++++++ .../Extensions/Extensions.cs | 455 ------------------ .../Extensions/HtmlSelectListExtensions.cs | 66 +++ .../Extensions/RouteExtensions.cs | 9 +- .../Extensions/TelerikExtensions.cs | 233 +++++++++ .../Plugins/PluginExtensions.cs | 32 ++ .../SmartStore.Web.Framework.csproj | 5 +- 16 files changed, 509 insertions(+), 545 deletions(-) create mode 100644 src/Presentation/SmartStore.Web.Framework/Extensions/DateTimeExtensions.cs delete mode 100644 src/Presentation/SmartStore.Web.Framework/Extensions/Extensions.cs create mode 100644 src/Presentation/SmartStore.Web.Framework/Extensions/HtmlSelectListExtensions.cs create mode 100644 src/Presentation/SmartStore.Web.Framework/Extensions/TelerikExtensions.cs create mode 100644 src/Presentation/SmartStore.Web.Framework/Plugins/PluginExtensions.cs diff --git a/src/Libraries/SmartStore.Core/Extensions/CollectionExtensions.cs b/src/Libraries/SmartStore.Core/Extensions/CollectionExtensions.cs index e5ab2c829a..b6fec3780a 100644 --- a/src/Libraries/SmartStore.Core/Extensions/CollectionExtensions.cs +++ b/src/Libraries/SmartStore.Core/Extensions/CollectionExtensions.cs @@ -7,10 +7,8 @@ namespace SmartStore { - public static class CollectionExtensions { - public static void AddRange(this ICollection initial, IEnumerable other) { if (other == null) @@ -31,7 +29,5 @@ public static bool IsNullOrEmpty(this ICollection source) { return (source == null || source.Count == 0); } - } - } diff --git a/src/Libraries/SmartStore.Core/Extensions/DateTimeExtensions.cs b/src/Libraries/SmartStore.Core/Extensions/DateTimeExtensions.cs index fc0cf3eacb..6ec7fc1cf9 100644 --- a/src/Libraries/SmartStore.Core/Extensions/DateTimeExtensions.cs +++ b/src/Libraries/SmartStore.Core/Extensions/DateTimeExtensions.cs @@ -5,7 +5,6 @@ namespace SmartStore { - public static class DateTimeExtensions { private static readonly DateTime MinDate = new DateTime(1900, 1, 1); diff --git a/src/Libraries/SmartStore.Core/Extensions/EnumerableExtensions.cs b/src/Libraries/SmartStore.Core/Extensions/EnumerableExtensions.cs index 34b4babed5..bae0a18392 100644 --- a/src/Libraries/SmartStore.Core/Extensions/EnumerableExtensions.cs +++ b/src/Libraries/SmartStore.Core/Extensions/EnumerableExtensions.cs @@ -170,7 +170,7 @@ public static void AddRange(this NameValueCollection initial, NameValueCollectio /// /// Builds an URL query string /// - /// Namer value collection + /// Name value collection /// Encoding type. Can be null. /// Whether to encode keys and values /// The query string without leading a question mark diff --git a/src/Libraries/SmartStore.Core/Extensions/HtmlTextWriterExtensions.cs b/src/Libraries/SmartStore.Core/Extensions/HtmlTextWriterExtensions.cs index 26edc0d0e3..27b16ca907 100644 --- a/src/Libraries/SmartStore.Core/Extensions/HtmlTextWriterExtensions.cs +++ b/src/Libraries/SmartStore.Core/Extensions/HtmlTextWriterExtensions.cs @@ -4,11 +4,9 @@ using System.Web.UI; namespace SmartStore -{ - +{ public static class HtmlTextWriterExtensions { - public static void AddAttributes(this HtmlTextWriter writer, IDictionary attributes) { if (attributes.Any>()) @@ -20,8 +18,5 @@ public static void AddAttributes(this HtmlTextWriter writer, IDictionary 0; - } - - public static string GetDataType(this DataTable dt, string columnName) - { - dt.DefaultView.RowFilter = "ColumnName='" + columnName + "'"; - return dt.Rows[0]["DataType"].ToString(); - } - - public static int CountExecute(this OleDbConnection conn, string sqlCount) - { - using (OleDbCommand cmd = new OleDbCommand(sqlCount, conn)) - { - return (int)cmd.ExecuteScalar(); - } - } - public static object SafeConvert(this TypeConverter converter, string value) { try @@ -79,6 +59,7 @@ public static object SafeConvert(this TypeConverter converter, string value) { exc.Dump(); } + return null; } @@ -128,14 +109,6 @@ public static T GetMergedDataValue(this IMergedData mergedData, string key, T return defaultValue; } - public static bool IsRouteEqual(this RouteData routeData, string controller, string action) - { - if (routeData == null) - return false; - - return routeData.GetRequiredString("controller").IsCaseInsensitiveEqual(controller) && routeData.GetRequiredString("action").IsCaseInsensitiveEqual(action); - } - /// /// Append grow if string builder is empty. Append delimiter and grow otherwise. /// diff --git a/src/Libraries/SmartStore.Core/Extensions/StringExtensions.cs b/src/Libraries/SmartStore.Core/Extensions/StringExtensions.cs index 4a7f28e209..10a5fcc557 100644 --- a/src/Libraries/SmartStore.Core/Extensions/StringExtensions.cs +++ b/src/Libraries/SmartStore.Core/Extensions/StringExtensions.cs @@ -11,7 +11,6 @@ namespace SmartStore { - public static class StringExtensions { public const string CarriageReturnLineFeed = "\r\n"; diff --git a/src/Libraries/SmartStore.Core/Utilities/Reflection/FastProperty.cs b/src/Libraries/SmartStore.Core/Utilities/Reflection/FastProperty.cs index 65a726248f..ada0e55b7a 100644 --- a/src/Libraries/SmartStore.Core/Utilities/Reflection/FastProperty.cs +++ b/src/Libraries/SmartStore.Core/Utilities/Reflection/FastProperty.cs @@ -31,7 +31,7 @@ public class FastProperty private Action _valueSetter; /// - /// Initializes a fast . + /// Initializes a . /// This constructor does not cache the helper. For caching, use . /// public FastProperty(PropertyInfo property) @@ -100,7 +100,7 @@ public void SetValue(object instance, object value) /// underlying type. /// /// the instance to extract property accessors for. - /// a cached array of all public property getters from the underlying type of target instance. + /// A cached array of all public property getters from the underlying type of target instance. /// public static IReadOnlyDictionary GetProperties(object instance) { @@ -111,8 +111,8 @@ public static IReadOnlyDictionary GetProperties(object ins /// Creates and caches fast property helpers that expose getters for every public get property on the /// specified type. /// - /// the type to extract property accessors for. - /// a cached array of all public property getters from the type of target instance. + /// The type to extract property accessors for. + /// A cached array of all public property getters from the type of target instance. /// public static IReadOnlyDictionary GetProperties(Type type) { @@ -337,7 +337,7 @@ public static Action MakeFastPropertySetter(PropertyInfo propert /// is returned. /// /// - /// The implementation of PropertyHelper will cache the property accessors per-type. This is + /// The implementation of FastProperty will cache the property accessors per-type. This is /// faster when the the same type is used multiple times with ObjectToDictionary. /// public static IDictionary ObjectToDictionary(object value, Func keySelector = null) diff --git a/src/Libraries/SmartStore.Data/Extensions/MiscExtensions.cs b/src/Libraries/SmartStore.Data/Extensions/MiscExtensions.cs index ba396e84fe..70efa11f18 100644 --- a/src/Libraries/SmartStore.Data/Extensions/MiscExtensions.cs +++ b/src/Libraries/SmartStore.Data/Extensions/MiscExtensions.cs @@ -1,49 +1,12 @@ -using System; -using System.Collections.Generic; -using System.Data.OleDb; -using System.Data.SqlClient; -using System.Linq; -using System.Text; -using System.Threading.Tasks; +using System.Linq; namespace SmartStore { - public static class MiscExtensions { - public static bool IsDatabaseAvailable(this SqlConnectionStringBuilder sb) - { - bool res = false; - try - { - using (SqlConnection conn = new SqlConnection(sb.ToString())) - { - conn.Open(); - res = (conn.State == System.Data.ConnectionState.Open); - conn.Close(); - } - } - catch (Exception) - { - } - return res; - } - - public static T GetValue(this OleDbDataReader reader, string name, T defaultValue = default(T)) + public static bool IsEntityFrameworkProvider(this IQueryProvider provider) { - try - { - object value; - if (reader != null && name.HasValue() && (value = reader[name]) != null && value != DBNull.Value) - { - return (T)Convert.ChangeType(value, typeof(T)); - } - } - catch (Exception exc) - { - exc.Dump(); - } - return defaultValue; + return provider.GetType().FullName == "System.Data.Objects.ELinq.ObjectQueryProvider"; } } diff --git a/src/Presentation/SmartStore.Web.Framework/Extensions/DateTimeExtensions.cs b/src/Presentation/SmartStore.Web.Framework/Extensions/DateTimeExtensions.cs new file mode 100644 index 0000000000..3277e60cb6 --- /dev/null +++ b/src/Presentation/SmartStore.Web.Framework/Extensions/DateTimeExtensions.cs @@ -0,0 +1,154 @@ +using System; +using SmartStore.Core.Infrastructure; +using SmartStore.Core.Localization; +using SmartStore.Services.Helpers; +using SmartStore.Web.Framework.Localization; + +namespace SmartStore.Web.Framework +{ + public static class DateTimeExtensions + { + /// + /// Relative formatting of DateTime (e.g. 2 hours ago, a month ago) + /// + /// Source (UTC format) + /// Formatted date and time string + public static string RelativeFormat(this DateTime source) + { + return RelativeFormat(source, string.Empty); + } + + /// + /// Relative formatting of DateTime (e.g. 2 hours ago, a month ago) + /// + /// Source (UTC format) + /// Default format string (in case relative formatting is not applied) + /// Formatted date and time string + public static string RelativeFormat(this DateTime source, string defaultFormat) + { + return RelativeFormat(source, false, defaultFormat); + } + + /// + /// Relative formatting of DateTime (e.g. 2 hours ago, a month ago) + /// + /// Source (UTC format) + /// A value indicating whether we should convet DateTime instance to user local time (in case relative formatting is not applied) + /// Default format string (in case relative formatting is not applied) + /// Formatted date and time string + public static string RelativeFormat(this DateTime source, bool convertToUserTime, string defaultFormat) + { + string result = ""; + Localizer T = EngineContext.Current.Resolve().Get; + + var ts = new TimeSpan(DateTime.UtcNow.Ticks - source.Ticks); + double delta = ts.TotalSeconds; + + if (delta > 0) + { + if (delta < 60) // 60 (seconds) + { + result = ts.Seconds == 1 ? T("Time.OneSecondAgo") : T("Time.SecondsAgo", ts.Seconds); + } + else if (delta < 120) //2 (minutes) * 60 (seconds) + { + result = T("Time.OneMinuteAgo"); + } + else if (delta < 2700) // 45 (minutes) * 60 (seconds) + { + result = String.Format(T("Time.MinutesAgo"), ts.Minutes); + } + else if (delta < 5400) // 90 (minutes) * 60 (seconds) + { + result = T("Time.OneHourAgo"); + } + else if (delta < 86400) // 24 (hours) * 60 (minutes) * 60 (seconds) + { + int hours = ts.Hours; + if (hours == 1) + hours = 2; + result = T("Time.HoursAgo", hours); + } + else if (delta < 172800) // 48 (hours) * 60 (minutes) * 60 (seconds) + { + result = T("Time.Yesterday"); + } + else if (delta < 2592000) // 30 (days) * 24 (hours) * 60 (minutes) * 60 (seconds) + { + result = String.Format(T("Time.DaysAgo"), ts.Days); + } + else if (delta < 31104000) // 12 (months) * 30 (days) * 24 (hours) * 60 (minutes) * 60 (seconds) + { + int months = Convert.ToInt32(Math.Floor((double)ts.Days / 30)); + result = months <= 1 ? T("Time.OneMonthAgo") : T("Time.MonthsAgo", months); + } + else + { + int years = Convert.ToInt32(Math.Floor((double)ts.Days / 365)); + result = years <= 1 ? T("Time.OneYearAgo") : T("Time.YearsAgo", years); + } + } + else + { + DateTime tmp1 = source; + if (convertToUserTime) + { + tmp1 = EngineContext.Current.Resolve().ConvertToUserTime(tmp1, DateTimeKind.Utc); + } + //default formatting + if (!String.IsNullOrEmpty(defaultFormat)) + { + result = tmp1.ToString(defaultFormat); + } + else + { + result = tmp1.ToString(); + } + } + return result; + } + + public static string Prettify(this TimeSpan ts) + { + Localizer T = EngineContext.Current.Resolve().Get; + double seconds = ts.TotalSeconds; + + try + { + int secsTemp = Convert.ToInt32(seconds); + string label = T("Time.SecondsAbbr"); + int remainder = 0; + string remainderLabel = ""; + + if (secsTemp > 59) + { + remainder = secsTemp % 60; + secsTemp /= 60; + label = T("Time.MinutesAbbr"); + remainderLabel = T("Time.SecondsAbbr"); + } + + if (secsTemp > 59) + { + remainder = secsTemp % 60; + secsTemp /= 60; + label = (secsTemp == 1) ? T("Time.HourAbbr") : T("Time.HoursAbbr"); + remainderLabel = T("Time.MinutesAbbr"); + } + + if (remainder == 0) + { + return string.Format("{0:#,##0.#} {1}", secsTemp, label); + } + else + { + return string.Format("{0:#,##0} {1} {2} {3}", secsTemp, label, remainder, remainderLabel); + } + } + catch + { + return "(-)"; + } + } + } +} diff --git a/src/Presentation/SmartStore.Web.Framework/Extensions/Extensions.cs b/src/Presentation/SmartStore.Web.Framework/Extensions/Extensions.cs deleted file mode 100644 index 504cc92ab6..0000000000 --- a/src/Presentation/SmartStore.Web.Framework/Extensions/Extensions.cs +++ /dev/null @@ -1,455 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Reflection; -using System.Web.Mvc; -using SmartStore.Core; -using SmartStore.Core.Domain.Stores; -using SmartStore.Core.Infrastructure; -using SmartStore.Core.Localization; -using SmartStore.Core.Plugins; -using SmartStore.Services.Configuration; -using SmartStore.Services.Helpers; -using SmartStore.Services.Localization; -using SmartStore.Web.Framework.Localization; -using Telerik.Web.Mvc; -using Telerik.Web.Mvc.Extensions; -using Telerik.Web.Mvc.UI.Fluent; - -namespace SmartStore.Web.Framework -{ - - [Serializable] - public class GridStateInfo - { - public GridState State { get; set; } - public string Path { get; set; } - } - - - public static class Extensions - { - - public static GridBuilder PreserveGridState(this GridBuilder builder) where T : class - { - var grid = builder.ToComponent(); - - if (!grid.DataBinding.Ajax.Enabled) - return builder; - - if (grid.Id.IsEmpty()) - throw new SmartException("A grid with preservable state must have a valid Id or Name"); - - var urlHelper = new UrlHelper(grid.ViewContext.RequestContext); - - var gridId = "GridState." + grid.Id + "__" + grid.ViewContext.RouteData.GenerateRouteIdentifier(); - - grid.AppendCssClass("grid-preservestate"); - grid.HtmlAttributes.Add("data-statepreserver-href", urlHelper.Action("SetGridState", "Common", new { area = "admin" })); - grid.HtmlAttributes.Add("data-statepreserver-key", gridId); - - // Try restore state from a previous request - var info = (GridStateInfo)grid.ViewContext.TempData[gridId]; - - if (info == null) - return builder; - - var state = info.State; - var command = GridCommand.Parse(state.Page, state.Size, state.OrderBy, state.GroupBy, state.Filter); - - if (grid.Paging.Enabled) - { - var pathChanged = !info.Path.Equals(grid.ViewContext.HttpContext.Request.RawUrl, StringComparison.OrdinalIgnoreCase); - if (!pathChanged) - { - if (command.PageSize > 0) - grid.Paging.PageSize = command.PageSize; - if (command.Page > 0) - grid.Paging.CurrentPage = command.Page; - } - } - - if (grid.Sorting.Enabled) - { - foreach (var sort in command.SortDescriptors) - { - var existingSort = grid.Sorting.OrderBy.FirstOrDefault(x => x.Member.IsCaseInsensitiveEqual(sort.Member)); - if (existingSort != null) - { - grid.Sorting.OrderBy.Remove(existingSort); - } - grid.Sorting.OrderBy.Add(sort); - } - } - - if (grid.Grouping.Enabled) - { - foreach (var group in command.GroupDescriptors) - { - var existingGroup = grid.Grouping.Groups.FirstOrDefault(x => x.Member.IsCaseInsensitiveEqual(group.Member)); - if (existingGroup != null) - { - grid.Grouping.Groups.Remove(existingGroup); - } - grid.Grouping.Groups.Add(group); - } - } - - if (grid.Filtering.Enabled) - { - foreach (var filter in command.FilterDescriptors) - { - var compositeFilter = filter as CompositeFilterDescriptor; - if (compositeFilter == null) - { - compositeFilter = new CompositeFilterDescriptor { LogicalOperator = FilterCompositionLogicalOperator.And }; - compositeFilter.FilterDescriptors.Add(filter); - } - grid.Filtering.Filters.Add(compositeFilter); - } - } - - // persist again for the next request - grid.ViewContext.TempData[gridId] = info; - - return builder; - } - - public static IEnumerable ForCommand(this IEnumerable current, GridCommand command) - { - var queryable = current.AsQueryable() as IQueryable; - if (command.FilterDescriptors.Any()) - { - queryable = queryable.Where(command.FilterDescriptors.AsEnumerable()).AsQueryable() as IQueryable; - } - - IList temporarySortDescriptors = new List(); - - if (!command.SortDescriptors.Any() && queryable.Provider.IsEntityFrameworkProvider()) - { - // The Entity Framework provider demands OrderBy before calling Skip. - SortDescriptor sortDescriptor = new SortDescriptor - { - Member = GetFirstSortableProperty(queryable.ElementType) - }; - command.SortDescriptors.Add(sortDescriptor); - temporarySortDescriptors.Add(sortDescriptor); - } - - if (command.GroupDescriptors.Any()) - { - command.GroupDescriptors.Reverse().Each(groupDescriptor => - { - SortDescriptor sortDescriptor = new SortDescriptor - { - Member = groupDescriptor.Member, - SortDirection = groupDescriptor.SortDirection - }; - - command.SortDescriptors.Insert(0, sortDescriptor); - temporarySortDescriptors.Add(sortDescriptor); - }); - } - - if (command.SortDescriptors.Any()) - { - queryable = queryable.Sort(command.SortDescriptors); - } - - return queryable as IQueryable; - } - - public static IEnumerable PagedForCommand(this IEnumerable current, GridCommand command) - { - return current.Skip((command.Page - 1) * command.PageSize).Take(command.PageSize); - } - - public static bool IsEntityFrameworkProvider(this IQueryProvider provider) - { - return provider.GetType().FullName == "System.Data.Objects.ELinq.ObjectQueryProvider"; - } - - private static string GetFirstSortableProperty(Type type) - { - PropertyInfo firstSortableProperty = type.GetProperties().Where(property => property.PropertyType.IsPredefinedSimpleType()).FirstOrDefault(); - - if (firstSortableProperty == null) - { - throw new NotSupportedException("Cannot find property to sort by."); - } - - return firstSortableProperty.Name; - } - - public static GridBoundColumnBuilder Centered(this GridBoundColumnBuilder columnBuilder) where T:class - { - return columnBuilder.HtmlAttributes(new { align = "center" }).HeaderHtmlAttributes(new { style = "text-align:center;" }); - } - - public static GridTemplateColumnBuilder Centered(this GridTemplateColumnBuilder columnBuilder) where T : class - { - return columnBuilder.HtmlAttributes(new { align = "center" }).HeaderHtmlAttributes(new { style = "text-align:center;" }); - } - - public static GridBoundColumnBuilder RightAlign(this GridBoundColumnBuilder columnBuilder) where T : class - { - return columnBuilder.HtmlAttributes(new { style = "text-align:right;" }).HeaderHtmlAttributes(new { style = "text-align:right;" }); - } - - public static GridTemplateColumnBuilder RightAlign(this GridTemplateColumnBuilder columnBuilder) where T : class - { - return columnBuilder.HtmlAttributes(new { style = "text-align:right;" }).HeaderHtmlAttributes(new { style = "text-align:right;" }); - } - - public static SelectList ToSelectList(this TEnum enumObj, bool markCurrentAsSelected = true) where TEnum : struct - { - if (!typeof(TEnum).IsEnum) - throw new ArgumentException("An Enumeration type is required.", "enumObj"); - - var localizationService = EngineContext.Current.Resolve(); - var workContext = EngineContext.Current.Resolve(); - - var values = from TEnum enumValue in Enum.GetValues(typeof(TEnum)) - select new { ID = Convert.ToInt32(enumValue), Name = enumValue.GetLocalizedEnum(localizationService, workContext) }; - object selectedValue = null; - if (markCurrentAsSelected) - selectedValue = Convert.ToInt32(enumObj); - return new SelectList(values, "ID", "Name", selectedValue); - } - - - public static string GetValueFromAppliedFilter(this IFilterDescriptor filter, string valueName, FilterOperator? filterOperator = null) - { - if (filter is CompositeFilterDescriptor) - { - foreach (IFilterDescriptor childFilter in ((CompositeFilterDescriptor)filter).FilterDescriptors) - { - var val1 = GetValueFromAppliedFilter(childFilter, valueName, filterOperator); - if (!String.IsNullOrEmpty(val1)) - return val1; - } - } - else - { - var filterDescriptor = (FilterDescriptor)filter; - if (filterDescriptor != null && - filterDescriptor.Member.Equals(valueName, StringComparison.InvariantCultureIgnoreCase)) - { - if (!filterOperator.HasValue || filterDescriptor.Operator == filterOperator.Value) - return Convert.ToString(filterDescriptor.Value); - } - } - - return ""; - } - - public static string GetValueFromAppliedFilters(this IList filters, string valueName, FilterOperator? filterOperator = null) - { - foreach (var filter in filters) - { - var val1 = GetValueFromAppliedFilter(filter, valueName, filterOperator); - if (!String.IsNullOrEmpty(val1)) - return val1; - } - return ""; - } - - /// - /// Relative formatting of DateTime (e.g. 2 hours ago, a month ago) - /// - /// Source (UTC format) - /// Formatted date and time string - public static string RelativeFormat(this DateTime source) - { - return RelativeFormat(source, string.Empty); - } - - /// - /// Relative formatting of DateTime (e.g. 2 hours ago, a month ago) - /// - /// Source (UTC format) - /// Default format string (in case relative formatting is not applied) - /// Formatted date and time string - public static string RelativeFormat(this DateTime source, string defaultFormat) - { - return RelativeFormat(source, false, defaultFormat); - } - - /// - /// Relative formatting of DateTime (e.g. 2 hours ago, a month ago) - /// - /// Source (UTC format) - /// A value indicating whether we should convet DateTime instance to user local time (in case relative formatting is not applied) - /// Default format string (in case relative formatting is not applied) - /// Formatted date and time string - public static string RelativeFormat(this DateTime source, bool convertToUserTime, string defaultFormat) - { - string result = ""; - Localizer T = EngineContext.Current.Resolve().Get; - - var ts = new TimeSpan(DateTime.UtcNow.Ticks - source.Ticks); - double delta = ts.TotalSeconds; - - if (delta > 0) - { - if (delta < 60) // 60 (seconds) - { - result = ts.Seconds == 1 ? T("Time.OneSecondAgo") : T("Time.SecondsAgo", ts.Seconds); - } - else if (delta < 120) //2 (minutes) * 60 (seconds) - { - result = T("Time.OneMinuteAgo"); - } - else if (delta < 2700) // 45 (minutes) * 60 (seconds) - { - result = String.Format(T("Time.MinutesAgo"), ts.Minutes); - } - else if (delta < 5400) // 90 (minutes) * 60 (seconds) - { - result = T("Time.OneHourAgo"); - } - else if (delta < 86400) // 24 (hours) * 60 (minutes) * 60 (seconds) - { - int hours = ts.Hours; - if (hours == 1) - hours = 2; - result = T("Time.HoursAgo", hours); - } - else if (delta < 172800) // 48 (hours) * 60 (minutes) * 60 (seconds) - { - result = T("Time.Yesterday"); - } - else if (delta < 2592000) // 30 (days) * 24 (hours) * 60 (minutes) * 60 (seconds) - { - result = String.Format(T("Time.DaysAgo"), ts.Days); - } - else if (delta < 31104000) // 12 (months) * 30 (days) * 24 (hours) * 60 (minutes) * 60 (seconds) - { - int months = Convert.ToInt32(Math.Floor((double)ts.Days / 30)); - result = months <= 1 ? T("Time.OneMonthAgo") : T("Time.MonthsAgo", months); - } - else - { - int years = Convert.ToInt32(Math.Floor((double)ts.Days / 365)); - result = years <= 1 ? T("Time.OneYearAgo") : T("Time.YearsAgo", years); - } - } - else - { - DateTime tmp1 = source; - if (convertToUserTime) - { - tmp1 = EngineContext.Current.Resolve().ConvertToUserTime(tmp1, DateTimeKind.Utc); - } - //default formatting - if (!String.IsNullOrEmpty(defaultFormat)) - { - result = tmp1.ToString(defaultFormat); - } - else - { - result = tmp1.ToString(); - } - } - return result; - } - - public static string Prettify(this TimeSpan ts) - { - Localizer T = EngineContext.Current.Resolve().Get; - double seconds = ts.TotalSeconds; - - try - { - int secsTemp = Convert.ToInt32(seconds); - string label = T("Time.SecondsAbbr"); - int remainder = 0; - string remainderLabel = ""; - - if (secsTemp > 59) - { - remainder = secsTemp % 60; - secsTemp /= 60; - label = T("Time.MinutesAbbr"); - remainderLabel = T("Time.SecondsAbbr"); - } - - if (secsTemp > 59) - { - remainder = secsTemp % 60; - secsTemp /= 60; - label = (secsTemp == 1) ? T("Time.HourAbbr") : T("Time.HoursAbbr"); - remainderLabel = T("Time.MinutesAbbr"); - } - - if (remainder == 0) - { - return string.Format("{0:#,##0.#} {1}", secsTemp, label); - } - else - { - return string.Format("{0:#,##0} {1} {2} {3}", secsTemp, label, remainder, remainderLabel); - } - } - catch - { - return "(-)"; - } - } - - /// - /// Get a list of all stores - /// - /// codehint: sm-add - public static IList ToSelectListItems(this IEnumerable stores) - { - var lst = new List(); - - foreach (var store in stores) - { - lst.Add(new SelectListItem - { - Text = store.Name, - Value = store.Id.ToString() - }); - } - return lst; - } - - public static void SelectValue(this List lst, string value, string defaultValue = null) - { - if (lst != null) - { - var itm = lst.FirstOrDefault(i => i.Value.IsCaseInsensitiveEqual(value)); - - if (itm == null && defaultValue != null) - itm = lst.FirstOrDefault(i => i.Value.IsCaseInsensitiveEqual(defaultValue)); - - if (itm != null) - itm.Selected = true; - } - } - - /// - /// Determines whether a plugin is installed and activated for a particular store. - /// - public static bool IsPluginReady(this IPluginFinder pluginFinder, ISettingService settingService, string systemName, int storeId) - { - try - { - var pluginDescriptor = pluginFinder.GetPluginDescriptorBySystemName(systemName); - - if (pluginDescriptor != null && pluginDescriptor.Installed) - { - if (storeId == 0 || settingService.GetSettingByKey(pluginDescriptor.GetSettingKey("LimitedToStores")).ToIntArrayContains(storeId, true)) - return true; - } - } - catch (Exception exc) - { - exc.Dump(); - } - return false; - } - } -} diff --git a/src/Presentation/SmartStore.Web.Framework/Extensions/HtmlSelectListExtensions.cs b/src/Presentation/SmartStore.Web.Framework/Extensions/HtmlSelectListExtensions.cs new file mode 100644 index 0000000000..33455155a2 --- /dev/null +++ b/src/Presentation/SmartStore.Web.Framework/Extensions/HtmlSelectListExtensions.cs @@ -0,0 +1,66 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Web.Mvc; +using SmartStore.Core; +using SmartStore.Core.Domain.Stores; +using SmartStore.Core.Infrastructure; +using SmartStore.Services.Localization; + +namespace SmartStore.Web.Framework +{ + public static class HtmlSelectListExtensions + { + public static SelectList ToSelectList(this TEnum enumObj, bool markCurrentAsSelected = true) where TEnum : struct + { + if (!typeof(TEnum).IsEnum) + throw new ArgumentException("An Enumeration type is required.", "enumObj"); + + var localizationService = EngineContext.Current.Resolve(); + var workContext = EngineContext.Current.Resolve(); + + var values = from TEnum enumValue in Enum.GetValues(typeof(TEnum)) + select new { ID = Convert.ToInt32(enumValue), Name = enumValue.GetLocalizedEnum(localizationService, workContext) }; + + object selectedValue = null; + if (markCurrentAsSelected) + selectedValue = Convert.ToInt32(enumObj); + + return new SelectList(values, "ID", "Name", selectedValue); + } + + /// + /// Get a list of all stores + /// + public static IList ToSelectListItems(this IEnumerable stores) + { + var lst = new List(); + + foreach (var store in stores) + { + lst.Add(new SelectListItem + { + Text = store.Name, + Value = store.Id.ToString() + }); + } + return lst; + } + + public static void SelectValue(this List lst, string value, string defaultValue = null) + { + if (lst != null) + { + var itm = lst.FirstOrDefault(i => i.Value.IsCaseInsensitiveEqual(value)); + + if (itm == null && defaultValue != null) + itm = lst.FirstOrDefault(i => i.Value.IsCaseInsensitiveEqual(defaultValue)); + + if (itm != null) + itm.Selected = true; + } + } + } +} diff --git a/src/Presentation/SmartStore.Web.Framework/Extensions/RouteExtensions.cs b/src/Presentation/SmartStore.Web.Framework/Extensions/RouteExtensions.cs index bfbffe4c03..f6cfa11a01 100644 --- a/src/Presentation/SmartStore.Web.Framework/Extensions/RouteExtensions.cs +++ b/src/Presentation/SmartStore.Web.Framework/Extensions/RouteExtensions.cs @@ -11,7 +11,6 @@ namespace SmartStore { public static class RouteExtensions { - public static string GetAreaName(this RouteData routeData) { object obj2; @@ -49,5 +48,13 @@ public static string GenerateRouteIdentifier(this RouteData routeData) return "{0}{1}.{2}".FormatInvariant(area.HasValue() ? area + "." : "", controller, action); } + public static bool IsRouteEqual(this RouteData routeData, string controller, string action) + { + if (routeData == null) + return false; + + return routeData.GetRequiredString("controller").IsCaseInsensitiveEqual(controller) && routeData.GetRequiredString("action").IsCaseInsensitiveEqual(action); + } + } } diff --git a/src/Presentation/SmartStore.Web.Framework/Extensions/TelerikExtensions.cs b/src/Presentation/SmartStore.Web.Framework/Extensions/TelerikExtensions.cs new file mode 100644 index 0000000000..08cd2d8951 --- /dev/null +++ b/src/Presentation/SmartStore.Web.Framework/Extensions/TelerikExtensions.cs @@ -0,0 +1,233 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Web.Mvc; +using SmartStore.Core; +using SmartStore.Core.Domain.Stores; +using SmartStore.Core.Infrastructure; +using SmartStore.Core.Localization; +using SmartStore.Core.Plugins; +using SmartStore.Services.Configuration; +using SmartStore.Services.Helpers; +using SmartStore.Services.Localization; +using SmartStore.Web.Framework.Localization; +using Telerik.Web.Mvc; +using Telerik.Web.Mvc.Extensions; +using Telerik.Web.Mvc.UI.Fluent; + +namespace SmartStore.Web.Framework +{ + [Serializable] + public class GridStateInfo + { + public GridState State { get; set; } + public string Path { get; set; } + } + + public static class TelerikExtensions + { + public static GridBuilder PreserveGridState(this GridBuilder builder) where T : class + { + var grid = builder.ToComponent(); + + if (!grid.DataBinding.Ajax.Enabled) + return builder; + + if (grid.Id.IsEmpty()) + throw new SmartException("A grid with preservable state must have a valid Id or Name"); + + var urlHelper = new UrlHelper(grid.ViewContext.RequestContext); + + var gridId = "GridState." + grid.Id + "__" + grid.ViewContext.RouteData.GenerateRouteIdentifier(); + + grid.AppendCssClass("grid-preservestate"); + grid.HtmlAttributes.Add("data-statepreserver-href", urlHelper.Action("SetGridState", "Common", new { area = "admin" })); + grid.HtmlAttributes.Add("data-statepreserver-key", gridId); + + // Try restore state from a previous request + var info = (GridStateInfo)grid.ViewContext.TempData[gridId]; + + if (info == null) + return builder; + + var state = info.State; + var command = GridCommand.Parse(state.Page, state.Size, state.OrderBy, state.GroupBy, state.Filter); + + if (grid.Paging.Enabled) + { + var pathChanged = !info.Path.Equals(grid.ViewContext.HttpContext.Request.RawUrl, StringComparison.OrdinalIgnoreCase); + if (!pathChanged) + { + if (command.PageSize > 0) + grid.Paging.PageSize = command.PageSize; + if (command.Page > 0) + grid.Paging.CurrentPage = command.Page; + } + } + + if (grid.Sorting.Enabled) + { + foreach (var sort in command.SortDescriptors) + { + var existingSort = grid.Sorting.OrderBy.FirstOrDefault(x => x.Member.IsCaseInsensitiveEqual(sort.Member)); + if (existingSort != null) + { + grid.Sorting.OrderBy.Remove(existingSort); + } + grid.Sorting.OrderBy.Add(sort); + } + } + + if (grid.Grouping.Enabled) + { + foreach (var group in command.GroupDescriptors) + { + var existingGroup = grid.Grouping.Groups.FirstOrDefault(x => x.Member.IsCaseInsensitiveEqual(group.Member)); + if (existingGroup != null) + { + grid.Grouping.Groups.Remove(existingGroup); + } + grid.Grouping.Groups.Add(group); + } + } + + if (grid.Filtering.Enabled) + { + foreach (var filter in command.FilterDescriptors) + { + var compositeFilter = filter as CompositeFilterDescriptor; + if (compositeFilter == null) + { + compositeFilter = new CompositeFilterDescriptor { LogicalOperator = FilterCompositionLogicalOperator.And }; + compositeFilter.FilterDescriptors.Add(filter); + } + grid.Filtering.Filters.Add(compositeFilter); + } + } + + // persist again for the next request + grid.ViewContext.TempData[gridId] = info; + + return builder; + } + + public static IEnumerable ForCommand(this IEnumerable current, GridCommand command) + { + var queryable = current.AsQueryable() as IQueryable; + if (command.FilterDescriptors.Any()) + { + queryable = queryable.Where(command.FilterDescriptors.AsEnumerable()).AsQueryable() as IQueryable; + } + + IList temporarySortDescriptors = new List(); + + if (!command.SortDescriptors.Any() && queryable.Provider.IsEntityFrameworkProvider()) + { + // The Entity Framework provider demands OrderBy before calling Skip. + SortDescriptor sortDescriptor = new SortDescriptor + { + Member = GetFirstSortableProperty(queryable.ElementType) + }; + command.SortDescriptors.Add(sortDescriptor); + temporarySortDescriptors.Add(sortDescriptor); + } + + if (command.GroupDescriptors.Any()) + { + command.GroupDescriptors.Reverse().Each(groupDescriptor => + { + SortDescriptor sortDescriptor = new SortDescriptor + { + Member = groupDescriptor.Member, + SortDirection = groupDescriptor.SortDirection + }; + + command.SortDescriptors.Insert(0, sortDescriptor); + temporarySortDescriptors.Add(sortDescriptor); + }); + } + + if (command.SortDescriptors.Any()) + { + queryable = queryable.Sort(command.SortDescriptors); + } + + return queryable as IQueryable; + } + + public static IEnumerable PagedForCommand(this IEnumerable current, GridCommand command) + { + return current.Skip((command.Page - 1) * command.PageSize).Take(command.PageSize); + } + + + public static GridBoundColumnBuilder Centered(this GridBoundColumnBuilder columnBuilder) where T : class + { + return columnBuilder.HtmlAttributes(new { align = "center" }).HeaderHtmlAttributes(new { style = "text-align:center;" }); + } + + public static GridTemplateColumnBuilder Centered(this GridTemplateColumnBuilder columnBuilder) where T : class + { + return columnBuilder.HtmlAttributes(new { align = "center" }).HeaderHtmlAttributes(new { style = "text-align:center;" }); + } + + public static GridBoundColumnBuilder RightAlign(this GridBoundColumnBuilder columnBuilder) where T : class + { + return columnBuilder.HtmlAttributes(new { style = "text-align:right;" }).HeaderHtmlAttributes(new { style = "text-align:right;" }); + } + + public static GridTemplateColumnBuilder RightAlign(this GridTemplateColumnBuilder columnBuilder) where T : class + { + return columnBuilder.HtmlAttributes(new { style = "text-align:right;" }).HeaderHtmlAttributes(new { style = "text-align:right;" }); + } + + public static string GetValueFromAppliedFilter(this IFilterDescriptor filter, string valueName, FilterOperator? filterOperator = null) + { + if (filter is CompositeFilterDescriptor) + { + foreach (IFilterDescriptor childFilter in ((CompositeFilterDescriptor)filter).FilterDescriptors) + { + var val1 = GetValueFromAppliedFilter(childFilter, valueName, filterOperator); + if (!String.IsNullOrEmpty(val1)) + return val1; + } + } + else + { + var filterDescriptor = (FilterDescriptor)filter; + if (filterDescriptor != null && + filterDescriptor.Member.Equals(valueName, StringComparison.InvariantCultureIgnoreCase)) + { + if (!filterOperator.HasValue || filterDescriptor.Operator == filterOperator.Value) + return Convert.ToString(filterDescriptor.Value); + } + } + + return ""; + } + + public static string GetValueFromAppliedFilters(this IList filters, string valueName, FilterOperator? filterOperator = null) + { + foreach (var filter in filters) + { + var val1 = GetValueFromAppliedFilter(filter, valueName, filterOperator); + if (!String.IsNullOrEmpty(val1)) + return val1; + } + return ""; + } + + private static string GetFirstSortableProperty(Type type) + { + PropertyInfo firstSortableProperty = type.GetProperties().Where(property => property.PropertyType.IsPredefinedSimpleType()).FirstOrDefault(); + + if (firstSortableProperty == null) + { + throw new NotSupportedException("Cannot find property to sort by."); + } + + return firstSortableProperty.Name; + } + } +} diff --git a/src/Presentation/SmartStore.Web.Framework/Plugins/PluginExtensions.cs b/src/Presentation/SmartStore.Web.Framework/Plugins/PluginExtensions.cs new file mode 100644 index 0000000000..0925a59f65 --- /dev/null +++ b/src/Presentation/SmartStore.Web.Framework/Plugins/PluginExtensions.cs @@ -0,0 +1,32 @@ +using System; +using SmartStore.Core.Plugins; +using SmartStore.Services.Configuration; + +namespace SmartStore.Web.Framework +{ + public static class PluginExtensions + { + /// + /// Determines whether a plugin is installed and activated for a particular store. + /// + public static bool IsPluginReady(this IPluginFinder pluginFinder, ISettingService settingService, string systemName, int storeId) + { + try + { + var pluginDescriptor = pluginFinder.GetPluginDescriptorBySystemName(systemName); + + if (pluginDescriptor != null && pluginDescriptor.Installed) + { + if (storeId == 0 || settingService.GetSettingByKey(pluginDescriptor.GetSettingKey("LimitedToStores")).ToIntArrayContains(storeId, true)) + return true; + } + } + catch (Exception exc) + { + exc.Dump(); + } + + return false; + } + } +} diff --git a/src/Presentation/SmartStore.Web.Framework/SmartStore.Web.Framework.csproj b/src/Presentation/SmartStore.Web.Framework/SmartStore.Web.Framework.csproj index 1c59563458..2ae06313d2 100644 --- a/src/Presentation/SmartStore.Web.Framework/SmartStore.Web.Framework.csproj +++ b/src/Presentation/SmartStore.Web.Framework/SmartStore.Web.Framework.csproj @@ -232,12 +232,14 @@ + + @@ -248,6 +250,7 @@ + @@ -308,7 +311,7 @@ - + From ef722954594c39f1f9aa7c99ea8515ca7607ee4c Mon Sep 17 00:00:00 2001 From: Murat Cakir Date: Thu, 12 Nov 2015 20:52:29 +0100 Subject: [PATCH 053/707] Export: Added RowExportingEvent --- .../DataExchange/DataExporter.cs | 15 +++--- .../DataExchange/DynamicEntityHelper.cs | 54 +++++++++++++++++-- .../DataExchange/Events/RowExportingEvent.cs | 17 ++++++ .../SmartStore.Services.csproj | 1 + 4 files changed, 77 insertions(+), 10 deletions(-) create mode 100644 src/Libraries/SmartStore.Services/DataExchange/Events/RowExportingEvent.cs diff --git a/src/Libraries/SmartStore.Services/DataExchange/DataExporter.cs b/src/Libraries/SmartStore.Services/DataExchange/DataExporter.cs index b409401da6..b09801ff15 100644 --- a/src/Libraries/SmartStore.Services/DataExchange/DataExporter.cs +++ b/src/Libraries/SmartStore.Services/DataExchange/DataExporter.cs @@ -1074,21 +1074,22 @@ public DataExportResult Export(DataExportRequest request, CancellationToken canc string prefix = null; string suffix = null; var extension = Path.GetExtension(ctx.Result.Files.First().FileName); + var provider = request.Provider.Value; - if (request.Provider.Value.EntityType == ExportEntityType.Product) + if (provider.EntityType == ExportEntityType.Product) prefix = T("Admin.Catalog.Products"); - else if (request.Provider.Value.EntityType == ExportEntityType.Order) + else if (provider.EntityType == ExportEntityType.Order) prefix = T("Admin.Orders"); - else if (request.Provider.Value.EntityType == ExportEntityType.Category) + else if (provider.EntityType == ExportEntityType.Category) prefix = T("Admin.Catalog.Categories"); - else if (request.Provider.Value.EntityType == ExportEntityType.Manufacturer) + else if (provider.EntityType == ExportEntityType.Manufacturer) prefix = T("Admin.Catalog.Manufacturers"); - else if (request.Provider.Value.EntityType == ExportEntityType.Customer) + else if (provider.EntityType == ExportEntityType.Customer) prefix = T("Admin.Customers"); - else if (request.Provider.Value.EntityType == ExportEntityType.NewsLetterSubscription) + else if (provider.EntityType == ExportEntityType.NewsLetterSubscription) prefix = T("Admin.Promotions.NewsLetterSubscriptions"); else - prefix = request.Provider.Value.EntityType.ToString(); + prefix = provider.EntityType.ToString(); var selectedEntityCount = (request.EntitiesToExport == null ? 0 : request.EntitiesToExport.Count); diff --git a/src/Libraries/SmartStore.Services/DataExchange/DynamicEntityHelper.cs b/src/Libraries/SmartStore.Services/DataExchange/DynamicEntityHelper.cs index 73cb0ae431..7faca463f9 100644 --- a/src/Libraries/SmartStore.Services/DataExchange/DynamicEntityHelper.cs +++ b/src/Libraries/SmartStore.Services/DataExchange/DynamicEntityHelper.cs @@ -21,6 +21,7 @@ using SmartStore.Core.Domain.Stores; using SmartStore.Core.Html; using SmartStore.Services.Catalog; +using SmartStore.Services.DataExchange.Events; using SmartStore.Services.DataExchange.Internal; using SmartStore.Services.Localization; using SmartStore.Services.Seo; @@ -973,6 +974,14 @@ private List Convert(DataExporterContext ctx, Product product) result.Add(dynObject); } + _services.EventPublisher.Publish(new RowExportingEvent + { + Row = dynObject, + EntityType = ExportEntityType.Product, + ExportRequest = ctx.Request, + ExecuteContext = ctx.ExecuteContext + }); + return result; } @@ -1042,6 +1051,14 @@ private List Convert(DataExporterContext ctx, Order order) result.Add(dynObject); + _services.EventPublisher.Publish(new RowExportingEvent + { + Row = dynObject, + EntityType = ExportEntityType.Order, + ExportRequest = ctx.Request, + ExecuteContext = ctx.ExecuteContext + }); + return result; } @@ -1073,13 +1090,21 @@ private List Convert(DataExporterContext ctx, Manufacturer manufacturer result.Add(dynObject); + _services.EventPublisher.Publish(new RowExportingEvent + { + Row = dynObject, + EntityType = ExportEntityType.Manufacturer, + ExportRequest = ctx.Request, + ExecuteContext = ctx.ExecuteContext + }); + return result; } private List Convert(DataExporterContext ctx, Category category) { var result = new List(); - + var productCategories = ctx.CategoryExportContext.ProductCategories.Load(category.Id); dynamic dynObject = ToDynamic(ctx, category); @@ -1104,6 +1129,14 @@ private List Convert(DataExporterContext ctx, Category category) result.Add(dynObject); + _services.EventPublisher.Publish(new RowExportingEvent + { + Row = dynObject, + EntityType = ExportEntityType.Category, + ExportRequest = ctx.Request, + ExecuteContext = ctx.ExecuteContext + }); + return result; } @@ -1140,16 +1173,31 @@ private List Convert(DataExporterContext ctx, Customer customer) result.Add(dynObject); + _services.EventPublisher.Publish(new RowExportingEvent + { + Row = dynObject, + EntityType = ExportEntityType.Customer, + ExportRequest = ctx.Request, + ExecuteContext = ctx.ExecuteContext + }); + return result; } private List Convert(DataExporterContext ctx, NewsLetterSubscription subscription) { var result = new List(); - dynamic dynObject = ToDynamic(ctx, subscription); - result.Add(dynObject); + + _services.EventPublisher.Publish(new RowExportingEvent + { + Row = dynObject, + EntityType = ExportEntityType.NewsLetterSubscription, + ExportRequest = ctx.Request, + ExecuteContext = ctx.ExecuteContext + }); + return result; } } diff --git a/src/Libraries/SmartStore.Services/DataExchange/Events/RowExportingEvent.cs b/src/Libraries/SmartStore.Services/DataExchange/Events/RowExportingEvent.cs new file mode 100644 index 0000000000..31922ae3b9 --- /dev/null +++ b/src/Libraries/SmartStore.Services/DataExchange/Events/RowExportingEvent.cs @@ -0,0 +1,17 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using SmartStore.Core.Domain.DataExchange; + +namespace SmartStore.Services.DataExchange.Events +{ + public class RowExportingEvent + { + public dynamic Row { get; internal set; } + public ExportEntityType EntityType { get; internal set; } + public DataExportRequest ExportRequest { get; internal set; } + public IExportExecuteContext ExecuteContext { get; internal set; } + } +} diff --git a/src/Libraries/SmartStore.Services/SmartStore.Services.csproj b/src/Libraries/SmartStore.Services/SmartStore.Services.csproj index ec4af99cbd..0c121d3896 100644 --- a/src/Libraries/SmartStore.Services/SmartStore.Services.csproj +++ b/src/Libraries/SmartStore.Services/SmartStore.Services.csproj @@ -166,6 +166,7 @@ + From c468baf706b86c3965f424f16c140f3b97ddb438 Mon Sep 17 00:00:00 2001 From: Murat Cakir Date: Thu, 12 Nov 2015 21:06:22 +0100 Subject: [PATCH 054/707] Export: some experimenting with RowExportingEvent --- .../DataExchange/Events/RowExportingEvent.cs | 4 +++ .../SmartStore.GoogleMerchantCenter/Events.cs | 32 +++++++++++++++++-- 2 files changed, 34 insertions(+), 2 deletions(-) diff --git a/src/Libraries/SmartStore.Services/DataExchange/Events/RowExportingEvent.cs b/src/Libraries/SmartStore.Services/DataExchange/Events/RowExportingEvent.cs index 31922ae3b9..0b1dbcc017 100644 --- a/src/Libraries/SmartStore.Services/DataExchange/Events/RowExportingEvent.cs +++ b/src/Libraries/SmartStore.Services/DataExchange/Events/RowExportingEvent.cs @@ -7,6 +7,10 @@ namespace SmartStore.Services.DataExchange.Events { + // TODO: Another event message must be implemented, say 'ColumnsBuildingEvent' + // The consumer of this event (most likely a plugin) could push a list of specific column headers + // into global the export definition. + public class RowExportingEvent { public dynamic Row { get; internal set; } diff --git a/src/Plugins/SmartStore.GoogleMerchantCenter/Events.cs b/src/Plugins/SmartStore.GoogleMerchantCenter/Events.cs index 5ca8aeb5dc..4d0019134f 100644 --- a/src/Plugins/SmartStore.GoogleMerchantCenter/Events.cs +++ b/src/Plugins/SmartStore.GoogleMerchantCenter/Events.cs @@ -5,12 +5,16 @@ using SmartStore.GoogleMerchantCenter.Services; using SmartStore.Web.Framework.Events; using SmartStore.Web.Framework.Mvc; +using SmartStore.Services.DataExchange.Events; +using SmartStore.Core.Domain.DataExchange; +using SmartStore.Core.Domain.Catalog; namespace SmartStore.GoogleMerchantCenter { public class Events : IConsumer, - IConsumer + IConsumer/*, + IConsumer*/ { private readonly IGoogleFeedService _googleService; @@ -18,7 +22,7 @@ public Events(IGoogleFeedService googleService) { this._googleService = googleService; } - + public void HandleEvent(TabStripCreated eventMessage) { if (eventMessage.TabStripName == "product-edit") @@ -33,6 +37,30 @@ public void HandleEvent(TabStripCreated eventMessage) } } + //public void HandleEvent(RowExportingEvent eventMessage) + //{ + // if (eventMessage.EntityType != ExportEntityType.Product) + // return; + + // var row = eventMessage.Row; + // var product = eventMessage.Row.Entity as Product; + + // if (product == null) + // return; + + // var gmc = _googleService.GetGoogleProductRecord(product.Id); + // if (gmc == null) + // return; + + // row["_GMC_AgeGroup"] = gmc.AgeGroup; + // row["_GMC_Color"] = gmc.Color; + // row["_GMC_Gender"] = gmc.Gender; + // row["_GMC_Size"] = gmc.Size; + // row["_GMC_Taxonomy"] = gmc.Taxonomy; + // row["_GMC_Material"] = gmc.Material; + // row["_GMC_Pattern"] = gmc.Pattern; + //} + public void HandleEvent(ModelBoundEvent eventMessage) { if (!eventMessage.BoundModel.CustomProperties.ContainsKey("GMC")) From 5f74aecb89db44a7eee2d3884b1838d35d691c2c Mon Sep 17 00:00:00 2001 From: Marcus Gesing Date: Fri, 13 Nov 2015 12:46:05 +0100 Subject: [PATCH 055/707] Export preview for all supported entity types --- .../201511121139009_ExportFramework3.cs | 1 + .../DataExchange/DataExporter.cs | 11 +- .../DataExchange/DynamicEntityHelper.cs | 21 ++ .../Controllers/ExportController.cs | 138 +++++++-- .../Models/DataExchange/ExportPreviewModel.cs | 78 +++++ .../Administration/Views/Category/List.cshtml | 9 +- .../Views/Export/Preview.cshtml | 286 +++++++++++++----- .../Views/Manufacturer/List.cshtml | 58 ++-- 8 files changed, 468 insertions(+), 134 deletions(-) diff --git a/src/Libraries/SmartStore.Data/Migrations/201511121139009_ExportFramework3.cs b/src/Libraries/SmartStore.Data/Migrations/201511121139009_ExportFramework3.cs index 34a97d19bc..132d36fee6 100644 --- a/src/Libraries/SmartStore.Data/Migrations/201511121139009_ExportFramework3.cs +++ b/src/Libraries/SmartStore.Data/Migrations/201511121139009_ExportFramework3.cs @@ -86,6 +86,7 @@ public void Seed(SmartObjectContext context) }; profile = profiles.Add(profile); + context.SaveChanges(); task.Alias = profile.Id.ToString(); diff --git a/src/Libraries/SmartStore.Services/DataExchange/DataExporter.cs b/src/Libraries/SmartStore.Services/DataExchange/DataExporter.cs index b09801ff15..d839d3d839 100644 --- a/src/Libraries/SmartStore.Services/DataExchange/DataExporter.cs +++ b/src/Libraries/SmartStore.Services/DataExchange/DataExporter.cs @@ -540,6 +540,9 @@ private IQueryable GetManufacturerQuery(DataExporterContext ctx, i var query = _manufacturerService.Value.GetManufacturers(showHidden, storeId); + if (ctx.Request.EntitiesToExport.Count > 0) + query = query.Where(x => ctx.Request.EntitiesToExport.Contains(x.Id)); + query = query.OrderBy(x => x.DisplayOrder); if (skip > 0) @@ -573,6 +576,9 @@ private IQueryable GetCategoryQuery(DataExporterContext ctx, int skip, var query = _categoryService.Value.GetCategories(null, showHidden, null, true, storeId); + if (ctx.Request.EntitiesToExport.Count > 0) + query = query.Where(x => ctx.Request.EntitiesToExport.Contains(x.Id)); + query = query .OrderBy(x => x.ParentCategoryId) .ThenBy(x => x.DisplayOrder); @@ -647,9 +653,10 @@ private IQueryable GetNewsLetterSubscriptionQuery(DataEx var query = _subscriptionRepository.Value.TableUntracked; if (storeId > 0) - { query = query.Where(x => x.StoreId == storeId); - } + + if (ctx.Request.EntitiesToExport.Count > 0) + query = query.Where(x => ctx.Request.EntitiesToExport.Contains(x.Id)); query = query .OrderBy(x => x.StoreId) diff --git a/src/Libraries/SmartStore.Services/DataExchange/DynamicEntityHelper.cs b/src/Libraries/SmartStore.Services/DataExchange/DynamicEntityHelper.cs index 7faca463f9..cb964a59f8 100644 --- a/src/Libraries/SmartStore.Services/DataExchange/DynamicEntityHelper.cs +++ b/src/Libraries/SmartStore.Services/DataExchange/DynamicEntityHelper.cs @@ -392,6 +392,8 @@ private dynamic ToDynamic(DataExporterContext ctx, Customer customer) result._GenericAttributes = null; result._HasNewsletterSubscription = false; + result._FullName = null; + return result; } @@ -1171,6 +1173,24 @@ private List Convert(DataExporterContext ctx, Customer customer) dynObject._HasNewsletterSubscription = ctx.NewsletterSubscriptions.Contains(customer.Email, StringComparer.CurrentCultureIgnoreCase); + var attrFirstName = genericAttributes.FirstOrDefault(x => x.Key == SystemCustomerAttributeNames.FirstName); + var attrLastName = genericAttributes.FirstOrDefault(x => x.Key == SystemCustomerAttributeNames.LastName); + + string firstName = (attrFirstName == null ? "" : attrFirstName.Value); + string lastName = (attrLastName == null ? "" : attrLastName.Value); + + if (firstName.IsEmpty() && lastName.IsEmpty()) + { + var address = customer.Addresses.FirstOrDefault(); + if (address != null) + { + firstName = address.FirstName; + lastName = address.LastName; + } + } + + dynObject._FullName = firstName.Grow(lastName, " "); + result.Add(dynObject); _services.EventPublisher.Publish(new RowExportingEvent @@ -1198,6 +1218,7 @@ private List Convert(DataExporterContext ctx, NewsLetterSubscription su ExecuteContext = ctx.ExecuteContext }); + return result; } } diff --git a/src/Presentation/SmartStore.Web/Administration/Controllers/ExportController.cs b/src/Presentation/SmartStore.Web/Administration/Controllers/ExportController.cs index f15c4fe3a0..c0e200ccc8 100644 --- a/src/Presentation/SmartStore.Web/Administration/Controllers/ExportController.cs +++ b/src/Presentation/SmartStore.Web/Administration/Controllers/ExportController.cs @@ -9,10 +9,13 @@ using SmartStore.Core; using SmartStore.Core.Domain; using SmartStore.Core.Domain.Catalog; +using SmartStore.Core.Domain.Customers; using SmartStore.Core.Domain.DataExchange; +using SmartStore.Core.Domain.Messages; using SmartStore.Core.Domain.Orders; using SmartStore.Core.Domain.Payments; using SmartStore.Core.Domain.Shipping; +using SmartStore.Core.Domain.Stores; using SmartStore.Core.Plugins; using SmartStore.Services; using SmartStore.Services.Catalog; @@ -50,6 +53,7 @@ public class ExportController : AdminControllerBase private readonly DataExchangeSettings _dataExchangeSettings; private readonly ITaskScheduler _taskScheduler; private readonly IDataExporter _dataExporter; + private readonly Lazy _customerSettings; public ExportController( ICommonServices services, @@ -65,7 +69,8 @@ public ExportController( IDateTimeHelper dateTimeHelper, DataExchangeSettings dataExchangeSettings, ITaskScheduler taskScheduler, - IDataExporter dataExporter) + IDataExporter dataExporter, + Lazy customerSettings) { _services = services; _exportService = exportService; @@ -81,6 +86,7 @@ public ExportController( _dataExchangeSettings = dataExchangeSettings; _taskScheduler = taskScheduler; _dataExporter = dataExporter; + _customerSettings = customerSettings; } #region Utilities @@ -736,7 +742,8 @@ public ActionResult Preview(int id) GridPageSize = DataExporter.PageSize, EntityType = provider.Value.EntityType, TotalRecords = totalRecords, - LogFileExists = System.IO.File.Exists(profile.GetExportLogFilePath()) + LogFileExists = System.IO.File.Exists(profile.GetExportLogFilePath()), + UsernamesEnabled = _customerSettings.Value.UsernamesEnabled }; return View(model); @@ -754,8 +761,20 @@ public ActionResult PreviewList(GridCommand command, int id, int totalRecords) { var productModel = new List(); var orderModel = new List(); + var categoryModel = new List(); + var manuModel = new List(); + var customerModel = new List(); + var subscriberModel = new List(); + + object gridData = null; + Dictionary allCategories = null; + IList allStores = null; var request = new DataExportRequest(profile, provider); + var normalizedTotal = totalRecords; + + if (profile.Limit > 0 && normalizedTotal > profile.Limit) + normalizedTotal = profile.Limit; var data = _dataExporter.Preview(request, command.Page - 1, totalRecords); @@ -764,7 +783,8 @@ public ActionResult PreviewList(GridCommand command, int id, int totalRecords) if (provider.Value.EntityType == ExportEntityType.Product) { var product = item.Entity as Product; - var pm = new ExportPreviewProductModel + + productModel.Add(new ExportPreviewProductModel { Id = product.Id, ProductTypeId = product.ProductTypeId, @@ -776,13 +796,11 @@ public ActionResult PreviewList(GridCommand command, int id, int totalRecords) Published = product.Published, StockQuantity = product.StockQuantity, AdminComment = item.AdminComment - }; - - productModel.Add(pm); + }); } else if (provider.Value.EntityType == ExportEntityType.Order) { - var om = new ExportPreviewOrderModel + orderModel.Add(new ExportPreviewOrderModel { Id = item.Id, HasNewPaymentNotification = item.HasNewPaymentNotification, @@ -794,33 +812,105 @@ public ActionResult PreviewList(GridCommand command, int id, int totalRecords) StoreName = (item.Store == null ? "".NaIfEmpty() : item.Store.Name), CreatedOn = _dateTimeHelper.ConvertToUserTime(item.CreatedOnUtc, DateTimeKind.Utc), OrderTotal = item.OrderTotal - }; + }); + } + else if (provider.Value.EntityType == ExportEntityType.Category) + { + var category = item.Entity as Category; + + if (allCategories == null) + { + allCategories = _categoryService.GetAllCategories(showHidden: true, applyNavigationFilters: false) + .ToDictionary(x => x.Id); + } - orderModel.Add(om); + categoryModel.Add(new ExportPreviewCategoryModel + { + Id = category.Id, + Breadcrumb = category.GetCategoryBreadCrumb(_categoryService, allCategories), + FullName = item.FullName, + Alias = item.Alias, + Published = category.Published, + DisplayOrder = category.DisplayOrder, + LimitedToStores = category.LimitedToStores + }); + } + else if (provider.Value.EntityType == ExportEntityType.Manufacturer) + { + manuModel.Add(new ExportPreviewManufacturerModel + { + Id = item.Id, + Name = item.Name, + Published = item.Published, + DisplayOrder = item.DisplayOrder, + LimitedToStores = item.LimitedToStores + }); } - } + else if (provider.Value.EntityType == ExportEntityType.Customer) + { + var customer = item.Entity as Customer; + var customerRoles = item.CustomerRoles as List; + var customerRolesString = string.Join(", ", customerRoles.Select(x => x.Name)); - var normalizedTotal = totalRecords; + customerModel.Add(new ExportPreviewCustomerModel + { + Id = customer.Id, + Active = customer.Active, + CreatedOn = _dateTimeHelper.ConvertToUserTime(customer.CreatedOnUtc, DateTimeKind.Utc), + CustomerRoleNames = customerRolesString, + Email = customer.Email, + FullName = item._FullName, + LastActivityDate = _dateTimeHelper.ConvertToUserTime(customer.LastActivityDateUtc, DateTimeKind.Utc), + Username = customer.Username + }); + } + else if (provider.Value.EntityType == ExportEntityType.NewsLetterSubscription) + { + var subscription = item.Entity as NewsLetterSubscription; - if (profile.Limit > 0 && normalizedTotal > profile.Limit) - normalizedTotal = profile.Limit; + if (allStores == null) + allStores = _services.StoreService.GetAllStores(); + + var store = allStores.FirstOrDefault(x => x.Id == subscription.StoreId); + + subscriberModel.Add(new ExportPreviewNewsLetterSubscriptionModel + { + Id = subscription.Id, + Active = subscription.Active, + CreatedOn = _dateTimeHelper.ConvertToUserTime(subscription.CreatedOnUtc, DateTimeKind.Utc), + Email = subscription.Email, + StoreName = (store == null ? "".NaIfEmpty() : store.Name) + }); + } + } if (provider.Value.EntityType == ExportEntityType.Product) { - return new JsonResult - { - Data = new GridModel { Data = productModel, Total = normalizedTotal } - }; + gridData = new GridModel { Data = productModel, Total = normalizedTotal }; } - - if (provider.Value.EntityType == ExportEntityType.Order) + else if (provider.Value.EntityType == ExportEntityType.Order) { - return new JsonResult - { - Data = new GridModel { Data = orderModel, Total = normalizedTotal } - }; + gridData = new GridModel { Data = orderModel, Total = normalizedTotal }; } - } + else if (provider.Value.EntityType == ExportEntityType.Category) + { + gridData = new GridModel { Data = categoryModel, Total = normalizedTotal }; + } + else if (provider.Value.EntityType == ExportEntityType.Manufacturer) + { + gridData = new GridModel { Data = manuModel, Total = normalizedTotal }; + } + else if (provider.Value.EntityType == ExportEntityType.Customer) + { + gridData = new GridModel { Data = customerModel, Total = normalizedTotal }; + } + else if (provider.Value.EntityType == ExportEntityType.NewsLetterSubscription) + { + gridData = new GridModel { Data = subscriberModel, Total = normalizedTotal }; + } + + return new JsonResult { Data = gridData }; + } return new EmptyResult(); } diff --git a/src/Presentation/SmartStore.Web/Administration/Models/DataExchange/ExportPreviewModel.cs b/src/Presentation/SmartStore.Web/Administration/Models/DataExchange/ExportPreviewModel.cs index 4dbcde6c6a..eff05703f6 100644 --- a/src/Presentation/SmartStore.Web/Administration/Models/DataExchange/ExportPreviewModel.cs +++ b/src/Presentation/SmartStore.Web/Administration/Models/DataExchange/ExportPreviewModel.cs @@ -14,6 +14,7 @@ public class ExportPreviewModel : EntityModelBase public int TotalRecords { get; set; } public ExportEntityType EntityType { get; set; } public bool LogFileExists { get; set; } + public bool UsernamesEnabled { get; set; } } public class ExportPreviewProductModel : EntityModelBase @@ -71,4 +72,81 @@ public class ExportPreviewOrderModel : EntityModelBase [SmartResourceDisplayName("Admin.Orders.Fields.OrderTotal")] public decimal OrderTotal { get; set; } } + + public class ExportPreviewCategoryModel : EntityModelBase + { + [SmartResourceDisplayName("Admin.Catalog.Products.Categories.Fields.Category")] + public string Breadcrumb { get; set; } + + [SmartResourceDisplayName("Admin.Catalog.Categories.Fields.FullName")] + public string FullName { get; set; } + + [SmartResourceDisplayName("Admin.Catalog.Categories.Fields.Alias")] + public string Alias { get; set; } + + [SmartResourceDisplayName("Admin.Catalog.Categories.Fields.Published")] + public bool Published { get; set; } + + [SmartResourceDisplayName("Admin.Catalog.Categories.Fields.DisplayOrder")] + public int DisplayOrder { get; set; } + + [SmartResourceDisplayName("Admin.Common.Store.LimitedTo")] + public bool LimitedToStores { get; set; } + } + + public class ExportPreviewManufacturerModel : EntityModelBase + { + [SmartResourceDisplayName("Admin.Catalog.Manufacturers.Fields.Name")] + public string Name { get; set; } + + [SmartResourceDisplayName("Admin.Catalog.Manufacturers.Fields.Published")] + public bool Published { get; set; } + + [SmartResourceDisplayName("Admin.Catalog.Manufacturers.Fields.DisplayOrder")] + public int DisplayOrder { get; set; } + + [SmartResourceDisplayName("Admin.Common.Store.LimitedTo")] + public bool LimitedToStores { get; set; } + } + + public class ExportPreviewCustomerModel : EntityModelBase + { + public bool UsernamesEnabled { get; set; } + + [SmartResourceDisplayName("Admin.Customers.Customers.Fields.Username")] + public string Username { get; set; } + + [SmartResourceDisplayName("Admin.Customers.Customers.Fields.FullName")] + public string FullName { get; set; } + + [SmartResourceDisplayName("Admin.Customers.Customers.Fields.Email")] + public string Email { get; set; } + + [SmartResourceDisplayName("Admin.Customers.Customers.Fields.CustomerRoles")] + public string CustomerRoleNames { get; set; } + + [SmartResourceDisplayName("Admin.Customers.Customers.Fields.Active")] + public bool Active { get; set; } + + [SmartResourceDisplayName("Admin.Customers.Customers.Fields.CreatedOn")] + public DateTime CreatedOn { get; set; } + + [SmartResourceDisplayName("Admin.Customers.Customers.Fields.LastActivityDate")] + public DateTime LastActivityDate { get; set; } + } + + public class ExportPreviewNewsLetterSubscriptionModel : EntityModelBase + { + [SmartResourceDisplayName("Admin.Promotions.NewsLetterSubscriptions.Fields.Email")] + public string Email { get; set; } + + [SmartResourceDisplayName("Admin.Promotions.NewsLetterSubscriptions.Fields.Active")] + public bool Active { get; set; } + + [SmartResourceDisplayName("Admin.Promotions.NewsLetterSubscriptions.Fields.CreatedOn")] + public DateTime CreatedOn { get; set; } + + [SmartResourceDisplayName("Admin.Common.Store")] + public string StoreName { get; set; } + } } \ No newline at end of file diff --git a/src/Presentation/SmartStore.Web/Administration/Views/Category/List.cshtml b/src/Presentation/SmartStore.Web/Administration/Views/Category/List.cshtml index 9a3b2abd9f..08d7f81a83 100644 --- a/src/Presentation/SmartStore.Web/Administration/Views/Category/List.cshtml +++ b/src/Presentation/SmartStore.Web/Administration/Views/Category/List.cshtml @@ -65,13 +65,18 @@ columns.Bound(x => x.FullName); columns.Bound(x => x.Alias); columns.Bound(x => x.Published) - .Width(100) + .Width(160) .Template(item => @Html.SymbolForBool(item.Published)) .ClientTemplate(@Html.SymbolForBool("Published")) .Centered(); columns.Bound(x => x.DisplayOrder) - .Width(100) + .Width(160) .Centered(); + columns.Bound(x => x.LimitedToStores) + .Width(160) + .Template(item => @Html.SymbolForBool(item.LimitedToStores)) + .ClientTemplate(@Html.SymbolForBool("LimitedToStores")) + .Centered(); }) .Pageable(settings => settings.PageSize(Model.GridPageSize).Position(GridPagerPosition.Both)) .DataBinding(dataBinding => dataBinding.Ajax().Select("List", "Category")) diff --git a/src/Presentation/SmartStore.Web/Administration/Views/Export/Preview.cshtml b/src/Presentation/SmartStore.Web/Administration/Views/Export/Preview.cshtml index 2bca030bc9..9cd9abb59e 100644 --- a/src/Presentation/SmartStore.Web/Administration/Views/Export/Preview.cshtml +++ b/src/Presentation/SmartStore.Web/Administration/Views/Export/Preview.cshtml @@ -100,81 +100,215 @@ } -@if (Model.EntityType == ExportEntityType.Product) -{ -
+
+ @if (Model.EntityType == ExportEntityType.Product) + { @(Html.Telerik().Grid() - .Name("export-grid-product") - .DataKeys(keys => keys.Add(x => x.Id) - .RouteKey("Id")) - .Columns(columns => - { - columns.Bound(x => x.Id) - .ClientTemplate("") - .Title("") - .Width(50) - .HtmlAttributes(new { style = "text-align:center" }) - .HeaderHtmlAttributes(new { style = "text-align:center" }); - columns.Bound(x => x.Id) - .Width(80) - .Centered(); - columns.Bound(x => x.Name) - .ClientTemplate(@Html.LabeledProductName("Id", "Name")); - columns.Bound(x => x.Sku); - columns.Bound(x => x.Price) - .Format("{0:0.00}") - .RightAlign(); - columns.Bound(x => x.StockQuantity) - .Centered(); - columns.Bound(x => x.Published) - .Width(100) - .ClientTemplate(@Html.SymbolForBool("Published")) - .Centered(); - columns.Bound(x => x.AdminComment); - }) - .Pageable(settings => settings.PageSize(Model.GridPageSize).Position(GridPagerPosition.Both)) - .DataBinding(dataBinding => dataBinding.Ajax().Select("PreviewList", "Export", new { id = Model.Id, totalRecords = Model.TotalRecords })) - .ClientEvents(events => events.OnDataBound("OnDataBound")) - .EnableCustomBinding(true)) -
-} -else if (Model.EntityType == ExportEntityType.Order) -{ -
+ .Name("export-grid-product") + .DataKeys(keys => keys.Add(x => x.Id) + .RouteKey("Id")) + .Columns(columns => + { + columns.Bound(x => x.Id) + .ClientTemplate("") + .Title("") + .Width(50) + .HtmlAttributes(new { style = "text-align:center" }) + .HeaderHtmlAttributes(new { style = "text-align:center" }); + columns.Bound(x => x.Id) + .Width(80) + .Centered(); + columns.Bound(x => x.Name) + .ClientTemplate(@Html.LabeledProductName("Id", "Name")); + columns.Bound(x => x.Sku); + columns.Bound(x => x.Price) + .Format("{0:0.00}") + .RightAlign(); + columns.Bound(x => x.StockQuantity) + .Centered(); + columns.Bound(x => x.Published) + .Width(160) + .ClientTemplate(@Html.SymbolForBool("Published")) + .Centered(); + columns.Bound(x => x.AdminComment); + }) + .Pageable(settings => settings.PageSize(Model.GridPageSize).Position(GridPagerPosition.Both)) + .DataBinding(dataBinding => dataBinding.Ajax().Select("PreviewList", "Export", new { id = Model.Id, totalRecords = Model.TotalRecords })) + .ClientEvents(events => events.OnDataBound("OnDataBound")) + .EnableCustomBinding(true)) + } + else if (Model.EntityType == ExportEntityType.Order) + { @(Html.Telerik().Grid() - .Name("export-grid-order") - .DataKeys(keys => keys.Add(x => x.Id) - .RouteKey("Id")) - .Columns(columns => - { - columns.Bound(x => x.Id) - .ClientTemplate("") - .Title("") - .Width(50) - .HtmlAttributes(new { style = "text-align:center" }) - .HeaderHtmlAttributes(new { style = "text-align:center" }); - columns.Bound(x => x.Id) - .Width(80) - .Centered(); - columns.Bound(x => x.OrderNumber) - .ClientTemplate(@Html.LabeledOrderNumber()); - columns.Bound(x => x.OrderStatus); - columns.Bound(x => x.PaymentStatus); - columns.Bound(x => x.ShippingStatus); - columns.Bound(x => x.CustomerEmail); - columns.Bound(x => x.StoreName); - columns.Bound(x => x.CreatedOn); - columns.Bound(x => x.OrderTotal) - .Format("{0:0.00}") - .RightAlign(); - }) - .Pageable(settings => settings.PageSize(Model.GridPageSize).Position(GridPagerPosition.Both)) - .DataBinding(dataBinding => dataBinding.Ajax().Select("PreviewList", "Export", new { id = Model.Id, totalRecords = Model.TotalRecords })) - .ClientEvents(events => events.OnDataBound("OnDataBound")) - .EnableCustomBinding(true)) -
-} -else -{ -
@T("Admin.DataExchange.Export.NoPreview")
-} \ No newline at end of file + .Name("export-grid-order") + .DataKeys(keys => keys.Add(x => x.Id) + .RouteKey("Id")) + .Columns(columns => + { + columns.Bound(x => x.Id) + .ClientTemplate("") + .Title("") + .Width(50) + .HtmlAttributes(new { style = "text-align:center" }) + .HeaderHtmlAttributes(new { style = "text-align:center" }); + columns.Bound(x => x.Id) + .Width(80) + .Centered(); + columns.Bound(x => x.OrderNumber) + .ClientTemplate(@Html.LabeledOrderNumber()); + columns.Bound(x => x.OrderStatus); + columns.Bound(x => x.PaymentStatus); + columns.Bound(x => x.ShippingStatus); + columns.Bound(x => x.CustomerEmail); + columns.Bound(x => x.StoreName); + columns.Bound(x => x.CreatedOn); + columns.Bound(x => x.OrderTotal) + .Format("{0:0.00}") + .RightAlign(); + }) + .Pageable(settings => settings.PageSize(Model.GridPageSize).Position(GridPagerPosition.Both)) + .DataBinding(dataBinding => dataBinding.Ajax().Select("PreviewList", "Export", new { id = Model.Id, totalRecords = Model.TotalRecords })) + .ClientEvents(events => events.OnDataBound("OnDataBound")) + .EnableCustomBinding(true)) + } + else if (Model.EntityType == ExportEntityType.Category) + { + @(Html.Telerik().Grid() + .Name("export-grid-order") + .DataKeys(keys => keys.Add(x => x.Id) + .RouteKey("Id")) + .Columns(columns => + { + columns.Bound(x => x.Id) + .ClientTemplate("") + .Title("") + .Width(50) + .HtmlAttributes(new { style = "text-align:center" }) + .HeaderHtmlAttributes(new { style = "text-align:center" }); + columns.Bound(x => x.Id) + .Width(80) + .Centered(); + columns.Bound(x => x.Breadcrumb); + columns.Bound(x => x.FullName); + columns.Bound(x => x.Alias); + columns.Bound(x => x.Published) + .Width(160) + .ClientTemplate(@Html.SymbolForBool("Published")) + .Centered(); + columns.Bound(x => x.DisplayOrder) + .Width(160) + .Centered(); + columns.Bound(x => x.LimitedToStores) + .Width(160) + .ClientTemplate(@Html.SymbolForBool("LimitedToStores")) + .Centered(); + }) + .Pageable(settings => settings.PageSize(Model.GridPageSize).Position(GridPagerPosition.Both)) + .DataBinding(dataBinding => dataBinding.Ajax().Select("PreviewList", "Export", new { id = Model.Id, totalRecords = Model.TotalRecords })) + .ClientEvents(events => events.OnDataBound("OnDataBound")) + .EnableCustomBinding(true)) + } + else if (Model.EntityType == ExportEntityType.Manufacturer) + { + @(Html.Telerik().Grid() + .Name("export-grid-order") + .DataKeys(keys => keys.Add(x => x.Id) + .RouteKey("Id")) + .Columns(columns => + { + columns.Bound(x => x.Id) + .ClientTemplate("") + .Title("") + .Width(50) + .HtmlAttributes(new { style = "text-align:center" }) + .HeaderHtmlAttributes(new { style = "text-align:center" }); + columns.Bound(x => x.Id) + .Width(80) + .Centered(); + columns.Bound(x => x.Name); + columns.Bound(x => x.Published) + .Width(160) + .ClientTemplate(@Html.SymbolForBool("Published")) + .Centered(); + columns.Bound(x => x.DisplayOrder) + .Width(160) + .Centered(); + columns.Bound(x => x.LimitedToStores) + .Width(160) + .ClientTemplate(@Html.SymbolForBool("LimitedToStores")) + .Centered(); + }) + .Pageable(settings => settings.PageSize(Model.GridPageSize).Position(GridPagerPosition.Both)) + .DataBinding(dataBinding => dataBinding.Ajax().Select("PreviewList", "Export", new { id = Model.Id, totalRecords = Model.TotalRecords })) + .ClientEvents(events => events.OnDataBound("OnDataBound")) + .EnableCustomBinding(true)) + } + else if (Model.EntityType == ExportEntityType.Customer) + { + @(Html.Telerik().Grid() + .Name("export-grid-order") + .DataKeys(keys => keys.Add(x => x.Id) + .RouteKey("Id")) + .Columns(columns => + { + columns.Bound(x => x.Id) + .ClientTemplate("") + .Title("") + .Width(50) + .HtmlAttributes(new { style = "text-align:center" }) + .HeaderHtmlAttributes(new { style = "text-align:center" }); + columns.Bound(x => x.Id) + .Width(80) + .Centered(); + columns.Bound(x => x.Email); + columns.Bound(x => x.Username) + .Visible(Model.UsernamesEnabled); + columns.Bound(x => x.FullName); + columns.Bound(x => x.CustomerRoleNames); + columns.Bound(x => x.Active) + .ClientTemplate(@Html.SymbolForBool("Active")) + .Width(160) + .Centered(); + columns.Bound(x => x.CreatedOn); + columns.Bound(x => x.LastActivityDate); + }) + .Pageable(settings => settings.PageSize(Model.GridPageSize).Position(GridPagerPosition.Both)) + .DataBinding(dataBinding => dataBinding.Ajax().Select("PreviewList", "Export", new { id = Model.Id, totalRecords = Model.TotalRecords })) + .ClientEvents(events => events.OnDataBound("OnDataBound")) + .EnableCustomBinding(true)) + } + else if (Model.EntityType == ExportEntityType.NewsLetterSubscription) + { + @(Html.Telerik().Grid() + .Name("export-grid-order") + .DataKeys(keys => keys.Add(x => x.Id) + .RouteKey("Id")) + .Columns(columns => + { + columns.Bound(x => x.Id) + .ClientTemplate("") + .Title("") + .Width(50) + .HtmlAttributes(new { style = "text-align:center" }) + .HeaderHtmlAttributes(new { style = "text-align:center" }); + columns.Bound(x => x.Id) + .Width(80) + .Centered(); + columns.Bound(x => x.Email); + columns.Bound(x => x.Active) + .ClientTemplate(@Html.SymbolForBool("Active")) + .Centered() + .Width(160); + columns.Bound(x => x.StoreName); + columns.Bound(x => x.CreatedOn); + }) + .Pageable(settings => settings.PageSize(Model.GridPageSize).Position(GridPagerPosition.Both)) + .DataBinding(dataBinding => dataBinding.Ajax().Select("PreviewList", "Export", new { id = Model.Id, totalRecords = Model.TotalRecords })) + .ClientEvents(events => events.OnDataBound("OnDataBound")) + .EnableCustomBinding(true)) + } + else + { +
@T("Admin.DataExchange.Export.NoPreview")
+ } +
\ No newline at end of file diff --git a/src/Presentation/SmartStore.Web/Administration/Views/Manufacturer/List.cshtml b/src/Presentation/SmartStore.Web/Administration/Views/Manufacturer/List.cshtml index 87310a67ee..be3c64facb 100644 --- a/src/Presentation/SmartStore.Web/Administration/Views/Manufacturer/List.cshtml +++ b/src/Presentation/SmartStore.Web/Administration/Views/Manufacturer/List.cshtml @@ -40,45 +40,43 @@
+

+
@(Html.Telerik().Grid(Model.Manufacturers.Data) - .Name("manufacturers-grid") - .ClientEvents(events => events - .OnDataBinding("onDataBinding")) - .Columns(columns => - { - columns.Bound(x => x.Name).Width(300) - .Template(x => Html.ActionLink(x.Name, "Edit", new { id = x.Id })) - .ClientTemplate("\"><#= Name #>"); - - // .Template(x => Html.ActionLink(x.Name, "Edit", new { id = x.Id })) - //.ClientTemplate("'><#= Name #>"); - - columns.Bound(x => x.Published) - .Width(100) - .Template(item => @Html.SymbolForBool(item.Published)) - .ClientTemplate(@Html.SymbolForBool("Published")) - .Centered(); - columns.Bound(x => x.DisplayOrder) - .Width(100) - .Centered(); - columns.Bound(x => x.Id) - .Width(50) - .Centered() - .Template(x => Html.ActionLink(T("Admin.Common.Edit").Text, "Edit", new { id = x.Id })) - .ClientTemplate("\">" + T("Admin.Common.Edit").Text + "") - .Title(T("Admin.Common.Edit").Text); - }) - .Pageable(settings => settings.Total(Model.Manufacturers.Total).PageSize(gridPageSize).Position(GridPagerPosition.Both)) - .DataBinding(dataBinding => dataBinding.Ajax().Select("List", "Manufacturer")) + .Name("manufacturers-grid") + .ClientEvents(events => events + .OnDataBinding("onDataBinding")) + .Columns(columns => + { + columns.Bound(x => x.Name) + .Template(x => Html.ActionLink(x.Name, "Edit", new { id = x.Id })) + .ClientTemplate("\"><#= Name #>"); + columns.Bound(x => x.Published) + .Width(160) + .Template(item => @Html.SymbolForBool(item.Published)) + .ClientTemplate(@Html.SymbolForBool("Published")) + .Centered(); + columns.Bound(x => x.DisplayOrder) + .Width(160) + .Centered(); + columns.Bound(x => x.LimitedToStores) + .Width(160) + .Template(item => @Html.SymbolForBool(item.LimitedToStores)) + .ClientTemplate(@Html.SymbolForBool("LimitedToStores")) + .Centered(); + }) + .Pageable(settings => settings.Total(Model.Manufacturers.Total).PageSize(gridPageSize).Position(GridPagerPosition.Both)) + .DataBinding(dataBinding => dataBinding.Ajax().Select("List", "Manufacturer")) .PreserveGridState() - .EnableCustomBinding(true)) + .EnableCustomBinding(true))
+ From afce7e6f3eac3cf6ae6b47a0cb774333be42f0be Mon Sep 17 00:00:00 2001 From: Marcus Gesing Date: Tue, 17 Nov 2015 10:42:22 +0100 Subject: [PATCH 065/707] Minor changes --- .../Data/IDbContextExtensions.cs | 28 --------- .../SmartStore.Data/ObjectContextBase.cs | 60 +++++++++++-------- .../DataExchange/DataExporter.cs | 45 +++++++++----- .../Deployment/EmailFilePublisher.cs | 14 +++-- .../Deployment/FileSystemFilePublisher.cs | 9 --- .../Deployment/FtpFilePublisher.cs | 9 --- .../Deployment/HttpFilePublisher.cs | 8 --- .../DataExchange/Deployment/IFilePublisher.cs | 3 - .../DataExchange/DynamicEntityHelper.cs | 25 +++----- .../Internal/DataExporterContext.cs | 10 +--- 10 files changed, 79 insertions(+), 132 deletions(-) diff --git a/src/Libraries/SmartStore.Core/Data/IDbContextExtensions.cs b/src/Libraries/SmartStore.Core/Data/IDbContextExtensions.cs index 0bc3d4dc7f..0889cd6684 100644 --- a/src/Libraries/SmartStore.Core/Data/IDbContextExtensions.cs +++ b/src/Libraries/SmartStore.Core/Data/IDbContextExtensions.cs @@ -28,34 +28,6 @@ public static void DetachEntities(this IDbContext ctx, IEnumerable ctx.DetachEntity(x)); } - public static void Attach(this IDbContext ctx, TEntity entity) where TEntity : BaseEntity - { - var dbSet = ctx.Set(); - var alreadyAttached = dbSet.Local.FirstOrDefault(x => x.Id == entity.Id); - - if (alreadyAttached == null) - { - dbSet.Attach(entity); - } - } - - public static void Attach(this IDbContext ctx, IEnumerable entities) where TEntity : BaseEntity - { - Guard.ArgumentNotNull(() => ctx); - - var dbSet = ctx.Set(); - - entities.Each(entity => - { - var alreadyAttached = dbSet.Local.FirstOrDefault(x => x.Id == entity.Id); - - if (alreadyAttached == null) - { - dbSet.Attach(entity); - } - }); - } - /// /// Changes the object state to unchanged /// diff --git a/src/Libraries/SmartStore.Data/ObjectContextBase.cs b/src/Libraries/SmartStore.Data/ObjectContextBase.cs index 5f722e155f..278d88d984 100644 --- a/src/Libraries/SmartStore.Data/ObjectContextBase.cs +++ b/src/Libraries/SmartStore.Data/ObjectContextBase.cs @@ -2,27 +2,26 @@ using System.Collections.Generic; using System.Data; using System.Data.Common; -using System.Data.SqlClient; using System.Data.Entity; using System.Data.Entity.Infrastructure; using System.Data.Entity.Validation; +using System.Data.SqlClient; using System.Linq; -using System.Linq.Expressions; using System.Text; using System.Text.RegularExpressions; using System.Threading.Tasks; +using Microsoft.SqlServer.Management.Common; +using Microsoft.SqlServer.Management.Smo; using SmartStore.Core; using SmartStore.Core.Data; using SmartStore.Core.Data.Hooks; -using Microsoft.SqlServer.Management.Common; -using Microsoft.SqlServer.Management.Smo; using SmartStore.Core.Events; namespace SmartStore.Data { - /// - /// Object context - /// + /// + /// Object context + /// [DbConfigurationType(typeof(SmartDbConfiguration))] public abstract class ObjectContextBase : DbContext, IDbContext { @@ -496,32 +495,41 @@ protected internal bool IsSqlServer2012OrHigher() return s_isSqlServer2012OrHigher.Value; } - /// - /// Attach an entity to the context or return an already attached entity (if it was already attached) - /// - /// TEntity - /// Entity - /// Attached entity - protected virtual TEntity AttachEntity(TEntity entity) where TEntity : BaseEntity, new() - { - // little hack here until Entity Framework really supports stored procedures - // otherwise, navigation properties of loaded entities are not loaded until an entity is attached to the context - var dbSet = Set(); - var alreadyAttached = dbSet.Local.Where(x => x.Id == entity.Id).FirstOrDefault(); + private TEntity Attach(DbSet dbSet, TEntity entity) where TEntity : BaseEntity + { + var alreadyAttached = dbSet.Local.FirstOrDefault(x => x.Id == entity.Id); + if (alreadyAttached == null) { - // attach new entity dbSet.Attach(entity); return entity; } - else - { - // entity is already loaded. - return alreadyAttached; - } + + return alreadyAttached; + } + + /// + /// Attach an entity to the context or return an already attached entity (if it was already attached) + /// + /// TEntity + /// Entity + /// Attached entity + public TEntity AttachEntity(TEntity entity) where TEntity : BaseEntity + { + // little hack here until Entity Framework really supports stored procedures + // otherwise, navigation properties of loaded entities are not loaded until an entity is attached to the context + + return Attach(Set(), entity); } - public bool IsAttached(TEntity entity) where TEntity : BaseEntity + public void AttachEntities(IEnumerable entities) where TEntity : BaseEntity + { + var dbSet = Set(); + + entities.Each(entity => Attach(dbSet, entity)); + } + + public bool IsAttached(TEntity entity) where TEntity : BaseEntity { if (entity != null) { diff --git a/src/Libraries/SmartStore.Services/DataExchange/DataExporter.cs b/src/Libraries/SmartStore.Services/DataExchange/DataExporter.cs index 3ccd178409..1fb126c0de 100644 --- a/src/Libraries/SmartStore.Services/DataExchange/DataExporter.cs +++ b/src/Libraries/SmartStore.Services/DataExchange/DataExporter.cs @@ -19,6 +19,7 @@ using SmartStore.Core.Infrastructure; using SmartStore.Core.Localization; using SmartStore.Core.Logging; +using SmartStore.Data; using SmartStore.Services.Catalog; using SmartStore.Services.Common; using SmartStore.Services.Customers; @@ -69,10 +70,10 @@ public partial class DataExporter : IDataExporter private readonly Lazy _shipmentService; private readonly Lazy _genericAttributeService; private readonly Lazy _emailAccountService; + private readonly Lazy _queuedEmailService; private readonly Lazy _emailSender; private readonly Lazy _deliveryTimeService; private readonly Lazy _quantityUnitService; - private readonly Lazy _typeFinder; private readonly Lazy>_customerRepository; private readonly Lazy> _subscriptionRepository; @@ -107,10 +108,10 @@ public DataExporter( Lazy shipmentService, Lazy genericAttributeService, Lazy emailAccountService, - Lazy emailSender, + Lazy queuedEmailService, + Lazy emailSender, Lazy deliveryTimeService, Lazy quantityUnitService, - Lazy typeFinder, Lazy> customerRepository, Lazy> subscriptionRepository, Lazy> orderRepository, @@ -142,10 +143,10 @@ public DataExporter( _shipmentService = shipmentService; _genericAttributeService = genericAttributeService; _emailAccountService = emailAccountService; + _queuedEmailService = queuedEmailService; _emailSender = emailSender; _deliveryTimeService = deliveryTimeService; _quantityUnitService = quantityUnitService; - _typeFinder = typeFinder; _customerRepository = customerRepository; _subscriptionRepository = subscriptionRepository; @@ -210,10 +211,11 @@ private void DetachAllEntitiesAndClear(DataExporterContext ctx) try { // now again attach what is globally required + var dataContextBase = _dbContext as ObjectContextBase; - _dbContext.Attach(ctx.Request.Profile); + dataContextBase.AttachEntity(ctx.Request.Profile); - _dbContext.Attach(ctx.Stores.Values); + dataContextBase.AttachEntities(ctx.Stores.Values); } catch (Exception exception) { @@ -421,10 +423,6 @@ private void Deploy(DataExporterContext ctx) var containerManager = EngineContext.Current.ContainerManager; var allFiles = System.IO.Directory.GetFiles(ctx.FolderContent, "*.*", SearchOption.AllDirectories); - var publishers = _typeFinder.Value.FindClassesOfType(ignoreInactivePlugins: true) - .Select(x => containerManager.ResolveUnregistered(x) as IFilePublisher) - .ToList(); - var context = new ExportDeploymentContext { Log = ctx.Log, @@ -439,17 +437,33 @@ private void Deploy(DataExporterContext ctx) else context.DeploymentFiles = allFiles; - foreach (var publisher in publishers.Where(x => x.DeploymentType == deployment.DeploymentType)) + try { - try + if (deployment.DeploymentType == ExportDeploymentType.Email) { + var publisher = new EmailFilePublisher(_emailAccountService.Value, _queuedEmailService.Value); publisher.Publish(context, deployment); } - catch (Exception exception) + else if (deployment.DeploymentType == ExportDeploymentType.FileSystem) { - ctx.Log.Error("Deployment \"{0}\" of type {1} failed: {2}".FormatInvariant( - deployment.Name, deployment.DeploymentType.ToString(), exception.Message), exception); + var publisher = new FileSystemFilePublisher(); + publisher.Publish(context, deployment); + } + else if (deployment.DeploymentType == ExportDeploymentType.Ftp) + { + var publisher = new FtpFilePublisher(); + publisher.Publish(context, deployment); } + else if (deployment.DeploymentType == ExportDeploymentType.Http) + { + var publisher = new HttpFilePublisher(); + publisher.Publish(context, deployment); + } + } + catch (Exception exception) + { + ctx.Log.Error("Deployment \"{0}\" of type {1} failed: {2}".FormatInvariant( + deployment.Name, deployment.DeploymentType.ToString(), exception.Message), exception); } } } @@ -1096,7 +1110,6 @@ private void ExportCoreOuter(DataExporterContext ctx) ctx.DeliveryTimes.Clear(); ctx.CategoryPathes.Clear(); ctx.Categories.Clear(); - ctx.PropertiesCache.Clear(); ctx.Request.CustomData.Clear(); diff --git a/src/Libraries/SmartStore.Services/DataExchange/Deployment/EmailFilePublisher.cs b/src/Libraries/SmartStore.Services/DataExchange/Deployment/EmailFilePublisher.cs index bc9903e734..d6ee4b4f2c 100644 --- a/src/Libraries/SmartStore.Services/DataExchange/Deployment/EmailFilePublisher.cs +++ b/src/Libraries/SmartStore.Services/DataExchange/Deployment/EmailFilePublisher.cs @@ -2,7 +2,6 @@ using System.IO; using System.Linq; using SmartStore.Core.Domain; -using SmartStore.Core.Domain.DataExchange; using SmartStore.Core.Domain.Messages; using SmartStore.Core.Email; using SmartStore.Core.Infrastructure; @@ -14,12 +13,15 @@ namespace SmartStore.Services.DataExchange.Deployment { public class EmailFilePublisher : IFilePublisher { - public ExportDeploymentType DeploymentType + private IEmailAccountService _emailAccountService; + private IQueuedEmailService _queuedEmailService; + + public EmailFilePublisher( + IEmailAccountService emailAccountService, + IQueuedEmailService queuedEmailService) { - get - { - return ExportDeploymentType.Email; - } + _emailAccountService = emailAccountService; + _queuedEmailService = queuedEmailService; } public virtual void Publish(ExportDeploymentContext context, ExportDeployment deployment) diff --git a/src/Libraries/SmartStore.Services/DataExchange/Deployment/FileSystemFilePublisher.cs b/src/Libraries/SmartStore.Services/DataExchange/Deployment/FileSystemFilePublisher.cs index 392ab82680..2fba5924a0 100644 --- a/src/Libraries/SmartStore.Services/DataExchange/Deployment/FileSystemFilePublisher.cs +++ b/src/Libraries/SmartStore.Services/DataExchange/Deployment/FileSystemFilePublisher.cs @@ -1,7 +1,6 @@ using System.IO; using System.Web; using SmartStore.Core.Domain; -using SmartStore.Core.Domain.DataExchange; using SmartStore.Core.Logging; using SmartStore.Utilities; @@ -9,14 +8,6 @@ namespace SmartStore.Services.DataExchange.Deployment { public class FileSystemFilePublisher : IFilePublisher { - public ExportDeploymentType DeploymentType - { - get - { - return ExportDeploymentType.FileSystem; - } - } - public virtual void Publish(ExportDeploymentContext context, ExportDeployment deployment) { string folderDestination = null; diff --git a/src/Libraries/SmartStore.Services/DataExchange/Deployment/FtpFilePublisher.cs b/src/Libraries/SmartStore.Services/DataExchange/Deployment/FtpFilePublisher.cs index 4fad3cc146..bba604f38a 100644 --- a/src/Libraries/SmartStore.Services/DataExchange/Deployment/FtpFilePublisher.cs +++ b/src/Libraries/SmartStore.Services/DataExchange/Deployment/FtpFilePublisher.cs @@ -3,21 +3,12 @@ using System.Linq; using System.Net; using SmartStore.Core.Domain; -using SmartStore.Core.Domain.DataExchange; using SmartStore.Core.Logging; namespace SmartStore.Services.DataExchange.Deployment { public class FtpFilePublisher : IFilePublisher { - public ExportDeploymentType DeploymentType - { - get - { - return ExportDeploymentType.Ftp; - } - } - public virtual void Publish(ExportDeploymentContext context, ExportDeployment deployment) { var bytesRead = 0; diff --git a/src/Libraries/SmartStore.Services/DataExchange/Deployment/HttpFilePublisher.cs b/src/Libraries/SmartStore.Services/DataExchange/Deployment/HttpFilePublisher.cs index fadcf8a8d3..b2ab9001cb 100644 --- a/src/Libraries/SmartStore.Services/DataExchange/Deployment/HttpFilePublisher.cs +++ b/src/Libraries/SmartStore.Services/DataExchange/Deployment/HttpFilePublisher.cs @@ -10,14 +10,6 @@ namespace SmartStore.Services.DataExchange.Deployment { public class HttpFilePublisher : IFilePublisher { - public ExportDeploymentType DeploymentType - { - get - { - return ExportDeploymentType.Http; - } - } - public virtual void Publish(ExportDeploymentContext context, ExportDeployment deployment) { var succeeded = 0; diff --git a/src/Libraries/SmartStore.Services/DataExchange/Deployment/IFilePublisher.cs b/src/Libraries/SmartStore.Services/DataExchange/Deployment/IFilePublisher.cs index 9f13724efb..36b9d7eb6a 100644 --- a/src/Libraries/SmartStore.Services/DataExchange/Deployment/IFilePublisher.cs +++ b/src/Libraries/SmartStore.Services/DataExchange/Deployment/IFilePublisher.cs @@ -1,13 +1,10 @@ using SmartStore.Core.Domain; -using SmartStore.Core.Domain.DataExchange; using SmartStore.Core.Logging; namespace SmartStore.Services.DataExchange.Deployment { public interface IFilePublisher { - ExportDeploymentType DeploymentType { get; } - void Publish(ExportDeploymentContext context, ExportDeployment deployment); } diff --git a/src/Libraries/SmartStore.Services/DataExchange/DynamicEntityHelper.cs b/src/Libraries/SmartStore.Services/DataExchange/DynamicEntityHelper.cs index a007c8763e..f88aa7cda1 100644 --- a/src/Libraries/SmartStore.Services/DataExchange/DynamicEntityHelper.cs +++ b/src/Libraries/SmartStore.Services/DataExchange/DynamicEntityHelper.cs @@ -1,6 +1,5 @@ using System; using System.Collections.Generic; -using System.ComponentModel.DataAnnotations.Schema; using System.Linq; using System.Linq.Expressions; using System.Reflection; @@ -26,6 +25,7 @@ using SmartStore.Services.DataExchange.Internal; using SmartStore.Services.Localization; using SmartStore.Services.Seo; +using SmartStore.Utilities.Reflection; namespace SmartStore.Services.DataExchange { @@ -953,28 +953,17 @@ private List Convert(DataExporterContext ctx, Product product) if (!ctx.IsPreview && ctx.Projection.AttributeCombinationAsProduct && combinations.Where(x => x.IsActive).Count() > 0) { var productType = typeof(Product); - IEnumerable properties = null; var productValues = new Dictionary(); - // fetch all cloneable product properties once per export - if (ctx.PropertiesCache.ContainsKey(productType)) - { - properties = ctx.PropertiesCache[productType]; - } - else - { - properties = productType - .GetProperties() - .Where(x => x.CanRead && x.CanWrite && 0 == x.GetCustomAttributes(typeof(NotMappedAttribute), true).Length); - - ctx.PropertiesCache.Add(productType, properties); - } + var properties = FastProperty.GetProperties(product.GetUnproxiedType()) + .Values + .Where(x => x.Property.CanRead && x.Property.CanWrite); // fetch all property values once per product foreach (var property in properties) { - productValues.Add(property.Name, property.GetValue(product, null)); - } + productValues.Add(property.Name, property.GetValue(product)); + } foreach (var combination in combinations.Where(x => x.IsActive)) { @@ -982,7 +971,7 @@ private List Convert(DataExporterContext ctx, Product product) foreach (var property in properties) { - property.SetValue(productClone, productValues[property.Name], null); + property.SetValue(productClone, productValues[property.Name]); } var dynObject = ToDynamic(ctx, productClone, combinations, combination); diff --git a/src/Libraries/SmartStore.Services/DataExchange/Internal/DataExporterContext.cs b/src/Libraries/SmartStore.Services/DataExchange/Internal/DataExporterContext.cs index 6dbaf059d4..0d44c9843e 100644 --- a/src/Libraries/SmartStore.Services/DataExchange/Internal/DataExporterContext.cs +++ b/src/Libraries/SmartStore.Services/DataExchange/Internal/DataExporterContext.cs @@ -1,8 +1,6 @@ -using System; -using System.Collections.Generic; +using System.Collections.Generic; using System.IO; using System.Linq; -using System.Reflection; using System.Threading; using SmartStore.Core; using SmartStore.Core.Domain.Catalog; @@ -41,7 +39,6 @@ public DataExporterContext( RecordsPerStore = new Dictionary(); EntityIdsLoaded = new List(); EntityIdsPerSegment = new List(); - PropertiesCache = new Dictionary>(); Result = new DataExportResult { @@ -69,11 +66,6 @@ public void SetLoadedEntityIds(IEnumerable ids) /// public List EntityIdsPerSegment { get; set; } - /// - /// For faster reflection - /// - public Dictionary> PropertiesCache { get; set; } - public int RecordCount { get; set; } public Dictionary RecordsPerStore { get; set; } public string ProgressInfo { get; set; } From 7883c7c7f607a37f164281ebeeeff2c258fa5384 Mon Sep 17 00:00:00 2001 From: Marcus Gesing Date: Tue, 17 Nov 2015 11:43:36 +0100 Subject: [PATCH 066/707] Removed necessity of handling with volatile export profiles --- .../DataExchange/ExportProfileService.cs | 38 +++++-------------- .../DataExchange/IExportProfileService.cs | 7 ---- .../Controllers/ExportController.cs | 2 +- 3 files changed, 11 insertions(+), 36 deletions(-) diff --git a/src/Libraries/SmartStore.Services/DataExchange/ExportProfileService.cs b/src/Libraries/SmartStore.Services/DataExchange/ExportProfileService.cs index faa5dcefb5..df8f6b6832 100644 --- a/src/Libraries/SmartStore.Services/DataExchange/ExportProfileService.cs +++ b/src/Libraries/SmartStore.Services/DataExchange/ExportProfileService.cs @@ -47,32 +47,6 @@ public ExportProfileService( #region Export profiles - public virtual ExportProfile CreateVolatileProfile(Provider provider) - { - var name = provider.GetName(_localizationService); - var seoName = SeoHelper.GetSeName(name, true, false).Replace("/", "").Replace("-", ""); - - var profile = new ExportProfile - { - Id = 0, - Name = name, - FolderName = seoName.ToValidPath().Truncate(_dataExchangeSettings.MaxFileNameLength), - FileNamePattern = _defaultFileNamePattern, - ProviderSystemName = provider.Metadata.SystemName, - Enabled = true, - SchedulingTaskId = 0, - PerStore = false, - CreateZipArchive = false, - Cleanup = false, - ScheduleTask = null, // volatile schedule task impossible cause of database accesses by core - Deployments = new List() - }; - - // profile.Projection and profile.Filtering should be null here - - return profile; - } - public virtual ExportProfile InsertExportProfile( string providerSystemName, string name, @@ -90,7 +64,6 @@ public virtual ExportProfile InsertExportProfile( ScheduleTask task = null; ExportProfile profile = null; - var seoName = SeoHelper.GetSeName(name, true, false).Replace("/", "").Replace("-", ""); if (cloneProfile == null) { @@ -155,10 +128,19 @@ public virtual ExportProfile InsertExportProfile( profile.IsSystemProfile = isSystemProfile; profile.Name = name; - profile.FolderName = seoName.ToValidPath().Truncate(_dataExchangeSettings.MaxFileNameLength); profile.ProviderSystemName = providerSystemName; profile.SchedulingTaskId = task.Id; + var folderName = providerSystemName + .Replace("Exports.", "") + .Replace("Feeds.", "") + .Replace("/", "") + .Replace("-", ""); + + profile.FolderName = SeoHelper.GetSeName(folderName, true, false) + .ToValidPath() + .Truncate(_dataExchangeSettings.MaxFileNameLength); + _exportProfileRepository.Insert(profile); task.Alias = profile.Id.ToString(); diff --git a/src/Libraries/SmartStore.Services/DataExchange/IExportProfileService.cs b/src/Libraries/SmartStore.Services/DataExchange/IExportProfileService.cs index 4e583b38f2..27b353d532 100644 --- a/src/Libraries/SmartStore.Services/DataExchange/IExportProfileService.cs +++ b/src/Libraries/SmartStore.Services/DataExchange/IExportProfileService.cs @@ -8,13 +8,6 @@ namespace SmartStore.Services.DataExchange { public interface IExportProfileService { - /// - /// Creates a volatile export profile - /// - /// Export provider - /// New export profile - ExportProfile CreateVolatileProfile(Provider provider); - /// /// Inserts an export profile /// diff --git a/src/Presentation/SmartStore.Web/Administration/Controllers/ExportController.cs b/src/Presentation/SmartStore.Web/Administration/Controllers/ExportController.cs index ce5494ab60..5fafb8d0df 100644 --- a/src/Presentation/SmartStore.Web/Administration/Controllers/ExportController.cs +++ b/src/Presentation/SmartStore.Web/Administration/Controllers/ExportController.cs @@ -460,7 +460,7 @@ public ActionResult List() if (!_services.Permissions.Authorize(StandardPermissionProvider.ManageExports)) return AccessDeniedView(); - var providers = _exportService.LoadAllExportProviders().ToList(); + var providers = _exportService.LoadAllExportProviders(0, false).ToList(); var profiles = _exportService.GetExportProfiles().ToList(); var model = new List(); From a1428df101e727e4865e29680e1798c4aed5e682 Mon Sep 17 00:00:00 2001 From: Marcus Gesing Date: Tue, 17 Nov 2015 12:06:42 +0100 Subject: [PATCH 067/707] Added new permission record "ManageUrlRecords" --- .../Migrations/201511121139009_ExportFramework3.cs | 12 ++++++++++++ .../Security/StandardPermissionProvider.cs | 10 ++++++---- .../Controllers/UrlRecordController.cs | 13 ++++++------- 3 files changed, 24 insertions(+), 11 deletions(-) diff --git a/src/Libraries/SmartStore.Data/Migrations/201511121139009_ExportFramework3.cs b/src/Libraries/SmartStore.Data/Migrations/201511121139009_ExportFramework3.cs index b35af29179..093398f968 100644 --- a/src/Libraries/SmartStore.Data/Migrations/201511121139009_ExportFramework3.cs +++ b/src/Libraries/SmartStore.Data/Migrations/201511121139009_ExportFramework3.cs @@ -7,6 +7,8 @@ namespace SmartStore.Data.Migrations using Core.Domain; using System.Linq; using Utilities; + using Core.Domain.Security; + using Core.Domain.Customers; public partial class ExportFramework3 : DbMigration, ILocaleResourcesProvider, IDataSeeder { @@ -31,6 +33,16 @@ public void Seed(SmartObjectContext context) { context.MigrateLocaleResources(MigrateLocaleResources); + var permissionMigrator = new PermissionMigrator(context); + + permissionMigrator.AddPermission(new PermissionRecord + { + Name = "Admin area. Manage Url Records", + SystemName = "ManageUrlRecords", + Category = "Standard" + }, new string[] { SystemCustomerRoleNames.Administrators }); + + var systemProfilesInfos = new List { new SystemProfileInfo { SystemName = "SmartStoreCategoryXml", ProviderSystemName = "Exports.SmartStoreCategoryXml", Name = "Category XML Export" }, diff --git a/src/Libraries/SmartStore.Services/Security/StandardPermissionProvider.cs b/src/Libraries/SmartStore.Services/Security/StandardPermissionProvider.cs index 7018c51146..4f37e81bb0 100644 --- a/src/Libraries/SmartStore.Services/Security/StandardPermissionProvider.cs +++ b/src/Libraries/SmartStore.Services/Security/StandardPermissionProvider.cs @@ -50,10 +50,10 @@ public partial class StandardPermissionProvider : IPermissionProvider public static readonly PermissionRecord UploadPictures = new PermissionRecord { Name = "Admin area. Upload Pictures", SystemName = "UploadPictures", Category = "Configuration" }; public static readonly PermissionRecord ManageScheduleTasks = new PermissionRecord { Name = "Admin area. Manage Schedule Tasks", SystemName = "ManageScheduleTasks", Category = "Configuration" }; public static readonly PermissionRecord ManageExports = new PermissionRecord { Name = "Admin area. Manage Exports", SystemName = "ManageExports", Category = "Configuration" }; + public static readonly PermissionRecord ManageUrlRecords = new PermissionRecord { Name = "Admin area. Manage Url Records", SystemName = "ManageUrlRecords", Category = "Standard" }; - - //public store permissions - public static readonly PermissionRecord DisplayPrices = new PermissionRecord { Name = "Public store. Display Prices", SystemName = "DisplayPrices", Category = "PublicStore" }; + //public store permissions + public static readonly PermissionRecord DisplayPrices = new PermissionRecord { Name = "Public store. Display Prices", SystemName = "DisplayPrices", Category = "PublicStore" }; public static readonly PermissionRecord EnableShoppingCart = new PermissionRecord { Name = "Public store. Enable shopping cart", SystemName = "EnableShoppingCart", Category = "PublicStore" }; public static readonly PermissionRecord EnableWishlist = new PermissionRecord { Name = "Public store. Enable wishlist", SystemName = "EnableWishlist", Category = "PublicStore" }; public static readonly PermissionRecord PublicStoreAllowNavigation = new PermissionRecord { Name = "Public store. Allow navigation", SystemName = "PublicStoreAllowNavigation", Category = "PublicStore" }; @@ -105,7 +105,8 @@ public virtual IEnumerable GetPermissions() UploadPictures, ManageScheduleTasks, ManageExports, - DisplayPrices, + ManageUrlRecords, + DisplayPrices, EnableShoppingCart, EnableWishlist, PublicStoreAllowNavigation, @@ -163,6 +164,7 @@ public virtual IEnumerable GetDefaultPermissions() UploadPictures, ManageScheduleTasks, ManageExports, + ManageUrlRecords, DisplayPrices, EnableShoppingCart, EnableWishlist, diff --git a/src/Presentation/SmartStore.Web/Administration/Controllers/UrlRecordController.cs b/src/Presentation/SmartStore.Web/Administration/Controllers/UrlRecordController.cs index 1eb07d10a5..358b174f27 100644 --- a/src/Presentation/SmartStore.Web/Administration/Controllers/UrlRecordController.cs +++ b/src/Presentation/SmartStore.Web/Administration/Controllers/UrlRecordController.cs @@ -14,7 +14,6 @@ namespace SmartStore.Admin.Controllers { - // TODO: add new permisssion record "ManageUrlRecords" [AdminAuthorize] public class UrlRecordController : AdminControllerBase { @@ -82,7 +81,7 @@ private void PrepareUrlRecordModel(UrlRecordModel model, UrlRecord urlRecord, bo public ActionResult List(string entityName, int? entityId) { - if (!_services.Permissions.Authorize(StandardPermissionProvider.ManageMaintenance)) + if (!_services.Permissions.Authorize(StandardPermissionProvider.ManageUrlRecords)) return AccessDeniedView(); var model = new UrlRecordListModel @@ -106,7 +105,7 @@ public ActionResult List(string entityName, int? entityId) [HttpPost, GridAction(EnableCustomBinding = true)] public ActionResult List(GridCommand command, UrlRecordListModel model) { - if (!_services.Permissions.Authorize(StandardPermissionProvider.ManageMaintenance)) + if (!_services.Permissions.Authorize(StandardPermissionProvider.ManageUrlRecords)) return AccessDeniedView(); var allLanguages = _languageService.GetAllLanguages(true); @@ -152,7 +151,7 @@ public ActionResult List(GridCommand command, UrlRecordListModel model) public ActionResult Edit(int id) { - if (!_services.Permissions.Authorize(StandardPermissionProvider.ManageMaintenance)) + if (!_services.Permissions.Authorize(StandardPermissionProvider.ManageUrlRecords)) return AccessDeniedView(); var urlRecord = _urlRecordService.GetUrlRecordById(id); @@ -168,7 +167,7 @@ public ActionResult Edit(int id) [HttpPost, ParameterBasedOnFormNameAttribute("save-continue", "continueEditing")] public ActionResult Edit(UrlRecordModel model, bool continueEditing) { - if (!_services.Permissions.Authorize(StandardPermissionProvider.ManageMaintenance)) + if (!_services.Permissions.Authorize(StandardPermissionProvider.ManageUrlRecords)) return AccessDeniedView(); var urlRecord = _urlRecordService.GetUrlRecordById(model.Id); @@ -206,7 +205,7 @@ public ActionResult Edit(UrlRecordModel model, bool continueEditing) [HttpPost, ActionName("Delete")] public ActionResult DeleteConfirmed(int id) { - if (!_services.Permissions.Authorize(StandardPermissionProvider.ManageMaintenance)) + if (!_services.Permissions.Authorize(StandardPermissionProvider.ManageUrlRecords)) return AccessDeniedView(); var urlRecord = _urlRecordService.GetUrlRecordById(id); @@ -231,7 +230,7 @@ public ActionResult DeleteConfirmed(int id) [HttpPost] public ActionResult DeleteSelected(ICollection selectedIds) { - if (!_services.Permissions.Authorize(StandardPermissionProvider.ManageMaintenance)) + if (!_services.Permissions.Authorize(StandardPermissionProvider.ManageUrlRecords)) return AccessDeniedView(); if (selectedIds != null) From 2d81510e80dff032894a7eaefd4dd1e5ad94f38f Mon Sep 17 00:00:00 2001 From: Marcus Gesing Date: Tue, 17 Nov 2015 12:09:19 +0100 Subject: [PATCH 068/707] Minor change --- .../Migrations/201511121139009_ExportFramework3.cs | 2 +- .../SmartStore.Services/Security/StandardPermissionProvider.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Libraries/SmartStore.Data/Migrations/201511121139009_ExportFramework3.cs b/src/Libraries/SmartStore.Data/Migrations/201511121139009_ExportFramework3.cs index 093398f968..b3b39a74de 100644 --- a/src/Libraries/SmartStore.Data/Migrations/201511121139009_ExportFramework3.cs +++ b/src/Libraries/SmartStore.Data/Migrations/201511121139009_ExportFramework3.cs @@ -39,7 +39,7 @@ public void Seed(SmartObjectContext context) { Name = "Admin area. Manage Url Records", SystemName = "ManageUrlRecords", - Category = "Standard" + Category = "Configuration" }, new string[] { SystemCustomerRoleNames.Administrators }); diff --git a/src/Libraries/SmartStore.Services/Security/StandardPermissionProvider.cs b/src/Libraries/SmartStore.Services/Security/StandardPermissionProvider.cs index 4f37e81bb0..886196b240 100644 --- a/src/Libraries/SmartStore.Services/Security/StandardPermissionProvider.cs +++ b/src/Libraries/SmartStore.Services/Security/StandardPermissionProvider.cs @@ -50,7 +50,7 @@ public partial class StandardPermissionProvider : IPermissionProvider public static readonly PermissionRecord UploadPictures = new PermissionRecord { Name = "Admin area. Upload Pictures", SystemName = "UploadPictures", Category = "Configuration" }; public static readonly PermissionRecord ManageScheduleTasks = new PermissionRecord { Name = "Admin area. Manage Schedule Tasks", SystemName = "ManageScheduleTasks", Category = "Configuration" }; public static readonly PermissionRecord ManageExports = new PermissionRecord { Name = "Admin area. Manage Exports", SystemName = "ManageExports", Category = "Configuration" }; - public static readonly PermissionRecord ManageUrlRecords = new PermissionRecord { Name = "Admin area. Manage Url Records", SystemName = "ManageUrlRecords", Category = "Standard" }; + public static readonly PermissionRecord ManageUrlRecords = new PermissionRecord { Name = "Admin area. Manage Url Records", SystemName = "ManageUrlRecords", Category = "Configuration" }; //public store permissions public static readonly PermissionRecord DisplayPrices = new PermissionRecord { Name = "Public store. Display Prices", SystemName = "DisplayPrices", Category = "PublicStore" }; From 97eecfbaf4d9b15f15ae217600da356168e20163 Mon Sep 17 00:00:00 2001 From: Marcus Gesing Date: Tue, 17 Nov 2015 14:21:28 +0100 Subject: [PATCH 069/707] Export framework should not create empty files --- src/Libraries/SmartStore.Services/DataExchange/DataExporter.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Libraries/SmartStore.Services/DataExchange/DataExporter.cs b/src/Libraries/SmartStore.Services/DataExchange/DataExporter.cs index 1fb126c0de..eb1a0d2306 100644 --- a/src/Libraries/SmartStore.Services/DataExchange/DataExporter.cs +++ b/src/Libraries/SmartStore.Services/DataExchange/DataExporter.cs @@ -383,7 +383,7 @@ private bool CallProvider(DataExporterContext ctx, string streamId, string metho ctx.Request.Provider.Value.OnExecuted(ctx.ExecuteContext); } - if (ctx.IsFileBasedExport && path.HasValue()) + if (ctx.IsFileBasedExport && path.HasValue() && ctx.ExecuteContext.DataStream.Length > 0) { if (!ctx.ExecuteContext.DataStream.CanSeek) ctx.Log.Warning("Data stream seems to be closed!"); From 96156cf5001dc4cfb19df3fd7b1fc0fdb2a1d088 Mon Sep 17 00:00:00 2001 From: Marcus Gesing Date: Tue, 17 Nov 2015 15:31:50 +0100 Subject: [PATCH 070/707] Perf: Statically cache types of payment method filters and shipping method filters --- .../Payments/PaymentService.cs | 27 +++++++++++++++---- .../Shipping/ShippingService.cs | 25 ++++++++++++++--- 2 files changed, 43 insertions(+), 9 deletions(-) diff --git a/src/Libraries/SmartStore.Services/Payments/PaymentService.cs b/src/Libraries/SmartStore.Services/Payments/PaymentService.cs index 6a5587bc72..9280f99bb0 100644 --- a/src/Libraries/SmartStore.Services/Payments/PaymentService.cs +++ b/src/Libraries/SmartStore.Services/Payments/PaymentService.cs @@ -25,10 +25,13 @@ public partial class PaymentService : IPaymentService #region Constants private const string PAYMENTMETHOD_ALL_KEY = "SmartStore.paymentmethod.all"; - + #endregion - #region Fields + #region Fields + + private readonly static object _lock = new object(); + private static IList _paymentMethodFilterTypes = null; private readonly IRepository _paymentMethodRepository; private readonly PaymentSettings _paymentSettings; @@ -722,11 +725,25 @@ public virtual string GetMaskedCreditCardNumber(string creditCardNumber) public virtual IList GetAllPaymentMethodFilters() { - return _typeFinder.FindClassesOfType(ignoreInactivePlugins: true) + if (_paymentMethodFilterTypes == null) + { + lock (_lock) + { + if (_paymentMethodFilterTypes == null) + { + _paymentMethodFilterTypes = _typeFinder.FindClassesOfType(ignoreInactivePlugins: true) + .ToList(); + } + } + } + + var paymentMethodFilters = _paymentMethodFilterTypes .Select(x => EngineContext.Current.ContainerManager.ResolveUnregistered(x) as IPaymentMethodFilter) .ToList(); + + return paymentMethodFilters; } - #endregion - } + #endregion + } } diff --git a/src/Libraries/SmartStore.Services/Shipping/ShippingService.cs b/src/Libraries/SmartStore.Services/Shipping/ShippingService.cs index 78d21c628b..6b35961b79 100644 --- a/src/Libraries/SmartStore.Services/Shipping/ShippingService.cs +++ b/src/Libraries/SmartStore.Services/Shipping/ShippingService.cs @@ -22,9 +22,12 @@ namespace SmartStore.Services.Shipping { public partial class ShippingService : IShippingService { - #region Fields + #region Fields - private readonly IRepository _shippingMethodRepository; + private readonly static object _lock = new object(); + private static IList _shippingMethodFilterTypes = null; + + private readonly IRepository _shippingMethodRepository; private readonly ICacheManager _cacheManager; private readonly ILogger _logger; private readonly IProductAttributeParser _productAttributeParser; @@ -461,10 +464,24 @@ public virtual GetShippingOptionResponse GetShippingOptions(IList GetAllShippingMethodFilters() { - return _typeFinder.FindClassesOfType(ignoreInactivePlugins: true) + if (_shippingMethodFilterTypes == null) + { + lock (_lock) + { + if (_shippingMethodFilterTypes == null) + { + _shippingMethodFilterTypes = _typeFinder.FindClassesOfType(ignoreInactivePlugins: true) + .ToList(); + } + } + } + + var shippingMethodFilters = _shippingMethodFilterTypes .Select(x => EngineContext.Current.ContainerManager.ResolveUnregistered(x) as IShippingMethodFilter) .ToList(); - } + + return shippingMethodFilters; + } #endregion From 96a50f743bea96947c3970300284e03fba81c862 Mon Sep 17 00:00:00 2001 From: Murat Cakir Date: Tue, 17 Nov 2015 18:40:38 +0100 Subject: [PATCH 071/707] Export framework: minor refactoring --- .../SmartStore.Core/Data/IDbContext.cs | 20 ++++++--- .../Data/IDbContextExtensions.cs | 5 +++ .../SmartStore.Data/ObjectContextBase.cs | 41 +++++-------------- .../DataExchange/DataExporter.cs | 24 +++++------ .../DataExchange/DynamicEntityHelper.cs | 23 ++++++++--- 5 files changed, 59 insertions(+), 54 deletions(-) diff --git a/src/Libraries/SmartStore.Core/Data/IDbContext.cs b/src/Libraries/SmartStore.Core/Data/IDbContext.cs index cec8a1a2ce..cb276a03ac 100644 --- a/src/Libraries/SmartStore.Core/Data/IDbContext.cs +++ b/src/Libraries/SmartStore.Core/Data/IDbContext.cs @@ -87,12 +87,20 @@ IList ExecuteStoredProcedureList(string commandText, params ob /// true when the entity is attched already, false otherwise bool IsAttached(TEntity entity) where TEntity : BaseEntity; - /// - /// Detaches an entity from the current object context if it's attached - /// - /// Type of entity - /// The entity instance to detach - void DetachEntity(TEntity entity) where TEntity : BaseEntity; + /// + /// Attaches an entity to the context or returns an already attached entity (if it was already attached) + /// + /// Type of entity + /// Entity + /// Attached entity + TEntity Attach(TEntity entity) where TEntity : BaseEntity; + + /// + /// Detaches an entity from the current object context if it's attached + /// + /// Type of entity + /// The entity instance to detach + void DetachEntity(TEntity entity) where TEntity : BaseEntity; /// /// Detaches all entities of type TEntity from the current object context diff --git a/src/Libraries/SmartStore.Core/Data/IDbContextExtensions.cs b/src/Libraries/SmartStore.Core/Data/IDbContextExtensions.cs index 0889cd6684..c4c1c82196 100644 --- a/src/Libraries/SmartStore.Core/Data/IDbContextExtensions.cs +++ b/src/Libraries/SmartStore.Core/Data/IDbContextExtensions.cs @@ -167,5 +167,10 @@ public static void LoadReference( } } + public static void AttachRange(this IDbContext ctx, IEnumerable entities) where TEntity : BaseEntity + { + entities.Each(x => ctx.Attach(x)); + } + } } diff --git a/src/Libraries/SmartStore.Data/ObjectContextBase.cs b/src/Libraries/SmartStore.Data/ObjectContextBase.cs index 278d88d984..5db3d6b0ef 100644 --- a/src/Libraries/SmartStore.Data/ObjectContextBase.cs +++ b/src/Libraries/SmartStore.Data/ObjectContextBase.cs @@ -191,7 +191,7 @@ private IEnumerable ToParameters(params object[] parameters) { for (int i = 0; i < result.Count; i++) { - result[i] = AttachEntity(result[i]); + result[i] = Attach(result[i]); } } } @@ -224,7 +224,7 @@ private IEnumerable ToParameters(params object[] parameters) { for (int i = 0; i < result.Count; i++) { - result[i] = AttachEntity(result[i]); + result[i] = Attach(result[i]); } } // close up the reader, we're done saving results @@ -336,13 +336,14 @@ public IDictionary GetModifiedProperties(BaseEntity entity) // be aware of the entity state. you cannot get modified properties for detached entities. if (entry.State != System.Data.Entity.EntityState.Detached) { - var modifiedPropertyNames = from p in entry.CurrentValues.PropertyNames - where entry.Property(p).IsModified - select p; + var modifiedProperties = from p in entry.CurrentValues.PropertyNames + let prop = entry.Property(p) + where prop.IsModified + select prop; - foreach (var name in modifiedPropertyNames) + foreach (var prop in modifiedProperties) { - props.Add(name, entry.Property(name).OriginalValue); + props.Add(prop.Name, prop.OriginalValue); } } @@ -495,8 +496,9 @@ protected internal bool IsSqlServer2012OrHigher() return s_isSqlServer2012OrHigher.Value; } - private TEntity Attach(DbSet dbSet, TEntity entity) where TEntity : BaseEntity - { + public TEntity Attach(TEntity entity) where TEntity : BaseEntity + { + var dbSet = Set(); var alreadyAttached = dbSet.Local.FirstOrDefault(x => x.Id == entity.Id); if (alreadyAttached == null) @@ -508,27 +510,6 @@ private TEntity Attach(DbSet dbSet, TEntity entity) where TEnt return alreadyAttached; } - /// - /// Attach an entity to the context or return an already attached entity (if it was already attached) - /// - /// TEntity - /// Entity - /// Attached entity - public TEntity AttachEntity(TEntity entity) where TEntity : BaseEntity - { - // little hack here until Entity Framework really supports stored procedures - // otherwise, navigation properties of loaded entities are not loaded until an entity is attached to the context - - return Attach(Set(), entity); - } - - public void AttachEntities(IEnumerable entities) where TEntity : BaseEntity - { - var dbSet = Set(); - - entities.Each(entity => Attach(dbSet, entity)); - } - public bool IsAttached(TEntity entity) where TEntity : BaseEntity { if (entity != null) diff --git a/src/Libraries/SmartStore.Services/DataExchange/DataExporter.cs b/src/Libraries/SmartStore.Services/DataExchange/DataExporter.cs index eb1a0d2306..5f7650cf10 100644 --- a/src/Libraries/SmartStore.Services/DataExchange/DataExporter.cs +++ b/src/Libraries/SmartStore.Services/DataExchange/DataExporter.cs @@ -211,11 +211,8 @@ private void DetachAllEntitiesAndClear(DataExporterContext ctx) try { // now again attach what is globally required - var dataContextBase = _dbContext as ObjectContextBase; - - dataContextBase.AttachEntity(ctx.Request.Profile); - - dataContextBase.AttachEntities(ctx.Stores.Values); + _dbContext.Attach(ctx.Request.Profile); + _dbContext.AttachRange(ctx.Stores.Values); } catch (Exception exception) { @@ -439,24 +436,27 @@ private void Deploy(DataExporterContext ctx) try { + IFilePublisher publisher = null; + if (deployment.DeploymentType == ExportDeploymentType.Email) { - var publisher = new EmailFilePublisher(_emailAccountService.Value, _queuedEmailService.Value); - publisher.Publish(context, deployment); + publisher = new EmailFilePublisher(_emailAccountService.Value, _queuedEmailService.Value); } else if (deployment.DeploymentType == ExportDeploymentType.FileSystem) { - var publisher = new FileSystemFilePublisher(); - publisher.Publish(context, deployment); + publisher = new FileSystemFilePublisher(); } else if (deployment.DeploymentType == ExportDeploymentType.Ftp) { - var publisher = new FtpFilePublisher(); - publisher.Publish(context, deployment); + publisher = new FtpFilePublisher(); } else if (deployment.DeploymentType == ExportDeploymentType.Http) { - var publisher = new HttpFilePublisher(); + publisher = new HttpFilePublisher(); + } + + if (publisher != null) + { publisher.Publish(context, deployment); } } diff --git a/src/Libraries/SmartStore.Services/DataExchange/DynamicEntityHelper.cs b/src/Libraries/SmartStore.Services/DataExchange/DynamicEntityHelper.cs index f88aa7cda1..9e4940d4e7 100644 --- a/src/Libraries/SmartStore.Services/DataExchange/DynamicEntityHelper.cs +++ b/src/Libraries/SmartStore.Services/DataExchange/DynamicEntityHelper.cs @@ -540,7 +540,9 @@ private dynamic ToDynamic(DataExporterContext ctx, Product product) return result; } - private dynamic ToDynamic(DataExporterContext ctx, Product product, + private dynamic ToDynamic( + DataExporterContext ctx, + Product product, ICollection combinations, ProductVariantAttributeCombination combination) { @@ -655,7 +657,7 @@ private dynamic ToDynamic(DataExporterContext ctx, Product product, .Select(x => ToDynamic(ctx, x)) .ToList(); - dynObject.ProductAttributeCombinations = combinations + dynObject.ProductAttributeCombinations = (combinations ?? Enumerable.Empty()) .Select(x => { dynamic dyn = ToDynamic(ctx, x); @@ -948,13 +950,20 @@ private List Convert(DataExporterContext ctx, Product product) { var result = new List(); - var combinations = ctx.ProductExportContext.AttributeCombinations.Load(product.Id); + var hasAttributeCombinations = false; - if (!ctx.IsPreview && ctx.Projection.AttributeCombinationAsProduct && combinations.Where(x => x.IsActive).Count() > 0) + if (!ctx.IsPreview && ctx.Projection.AttributeCombinationAsProduct) + { + hasAttributeCombinations = _dbContext.QueryForCollection(product, (Product p) => p.ProductVariantAttributeCombinations).Where(c => c.IsActive).Any(); + } + + if (hasAttributeCombinations) { var productType = typeof(Product); var productValues = new Dictionary(); + // TODO: work with Entry().CurrentValues instead of Reflection. + // First attach the object, determine all values and detach again. var properties = FastProperty.GetProperties(product.GetUnproxiedType()) .Values .Where(x => x.Property.CanRead && x.Property.CanWrite); @@ -965,7 +974,9 @@ private List Convert(DataExporterContext ctx, Product product) productValues.Add(property.Name, property.GetValue(product)); } - foreach (var combination in combinations.Where(x => x.IsActive)) + var combinations = ctx.ProductExportContext.AttributeCombinations.Load(product.Id); + + foreach (var combination in combinations) { var productClone = new Product(); @@ -980,7 +991,7 @@ private List Convert(DataExporterContext ctx, Product product) } else { - var dynObject = ToDynamic(ctx, product, combinations, null); + var dynObject = ToDynamic(ctx, product, null, null); result.Add(dynObject); } From fd08f0367ae431ed67e4776ec930a341450275a0 Mon Sep 17 00:00:00 2001 From: Marcus Gesing Date: Wed, 18 Nov 2015 11:25:41 +0100 Subject: [PATCH 072/707] Changed folder for export profiles --- .gitignore | 1 + .../SmartStore.Services/DataExchange/ExportExtensions.cs | 8 ++++++-- .../DataExchange/Internal/DataExporterContext.cs | 3 +-- 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/.gitignore b/.gitignore index 3b997b1c64..460b0b95df 100644 --- a/.gitignore +++ b/.gitignore @@ -200,6 +200,7 @@ Kopie von* /build /src/Presentation/SmartStore.Web/Plugins /src/Presentation/SmartStore.Web/App_Data/_temp/ +/src/Presentation/SmartStore.Web/App_Data/ExportProfiles/ /src/Presentation/SmartStore.Web/App_Data/Settings.txt /src/Presentation/SmartStore.Web/App_Data/InstalledPlugins.txt /src/Presentation/SmartStore.Web/App_Data/Licenses.lic diff --git a/src/Libraries/SmartStore.Services/DataExchange/ExportExtensions.cs b/src/Libraries/SmartStore.Services/DataExchange/ExportExtensions.cs index cf86f0d411..f46fb9094a 100644 --- a/src/Libraries/SmartStore.Services/DataExchange/ExportExtensions.cs +++ b/src/Libraries/SmartStore.Services/DataExchange/ExportExtensions.cs @@ -42,9 +42,13 @@ public static string GetName(this Provider provider, ILocalizat /// /// Export profile /// Folder path - public static string GetExportFolder(this ExportProfile profile, bool content = false) + public static string GetExportFolder(this ExportProfile profile, bool content = false, bool create = false) { - var path = Path.Combine(FileSystemHelper.TempDir(), @"Profile\Export\{0}{1}".FormatInvariant(profile.FolderName, content ? @"\Content" : "")); + var path = CommonHelper.MapPath(string.Concat("~/App_Data/ExportProfiles/", profile.FolderName, content ? "/Content" : "")); + + if (create && !System.IO.Directory.Exists(path)) + System.IO.Directory.CreateDirectory(path); + return path; } diff --git a/src/Libraries/SmartStore.Services/DataExchange/Internal/DataExporterContext.cs b/src/Libraries/SmartStore.Services/DataExchange/Internal/DataExporterContext.cs index 0d44c9843e..031406df3a 100644 --- a/src/Libraries/SmartStore.Services/DataExchange/Internal/DataExporterContext.cs +++ b/src/Libraries/SmartStore.Services/DataExchange/Internal/DataExporterContext.cs @@ -10,7 +10,6 @@ using SmartStore.Core.Domain.Localization; using SmartStore.Core.Domain.Stores; using SmartStore.Core.Logging; -using SmartStore.Utilities; namespace SmartStore.Services.DataExchange.Internal { @@ -27,7 +26,7 @@ public DataExporterContext( Projection = XmlHelper.Deserialize(request.Profile.Projection); IsPreview = isPreview; - FolderContent = FileSystemHelper.TempDir(@"Profile\Export\{0}\Content".FormatInvariant(request.Profile.FolderName)); + FolderContent = request.Profile.GetExportFolder(true, true); FolderRoot = System.IO.Directory.GetParent(FolderContent).FullName; Categories = new Dictionary(); From 86b8d4485487debfd34c088fb581a6afbec9da3c Mon Sep 17 00:00:00 2001 From: Marcus Gesing Date: Wed, 18 Nov 2015 18:04:25 +0100 Subject: [PATCH 073/707] Added column with export file number in export profile list --- .../201511121139009_ExportFramework3.cs | 6 +- .../DataExchange/DataExporter.cs | 22 ++--- .../DataExchange/ExportExtensions.cs | 36 +++++++- .../Internal/DataExporterContext.cs | 15 ---- .../Controllers/ExportController.cs | 83 +++++++++++++++++-- .../Models/DataExchange/ExportProfileModel.cs | 20 +++++ .../Administration/SmartStore.Admin.csproj | 2 + .../Administration/Views/Export/Edit.cshtml | 2 +- .../Administration/Views/Export/List.cshtml | 53 ++++++++++-- .../Views/Export/ProfileFileCount.cshtml | 13 +++ .../Views/Export/ProfileFileDetails.cshtml | 23 +++++ .../Views/Export/_Tab.Deployment.cshtml | 1 - 12 files changed, 235 insertions(+), 41 deletions(-) create mode 100644 src/Presentation/SmartStore.Web/Administration/Views/Export/ProfileFileCount.cshtml create mode 100644 src/Presentation/SmartStore.Web/Administration/Views/Export/ProfileFileDetails.cshtml diff --git a/src/Libraries/SmartStore.Data/Migrations/201511121139009_ExportFramework3.cs b/src/Libraries/SmartStore.Data/Migrations/201511121139009_ExportFramework3.cs index b3b39a74de..acf47b44eb 100644 --- a/src/Libraries/SmartStore.Data/Migrations/201511121139009_ExportFramework3.cs +++ b/src/Libraries/SmartStore.Data/Migrations/201511121139009_ExportFramework3.cs @@ -197,7 +197,11 @@ public void MigrateLocaleResources(LocaleResourcesBuilder builder) builder.AddOrUpdate("Admin.DataExchange.Export.MissingSystemProfile", "The system export profile {0} was not found.", "Das System-Exportprofil {0} wurde nicht gefunden."); - } + + builder.AddOrUpdate("Admin.DataExchange.Export.ExportFiles", + "Export files", + "Exportdateien"); + } } diff --git a/src/Libraries/SmartStore.Services/DataExchange/DataExporter.cs b/src/Libraries/SmartStore.Services/DataExchange/DataExporter.cs index 5f7650cf10..25a0651cbd 100644 --- a/src/Libraries/SmartStore.Services/DataExchange/DataExporter.cs +++ b/src/Libraries/SmartStore.Services/DataExchange/DataExporter.cs @@ -415,22 +415,21 @@ private bool CallProvider(DataExporterContext ctx, string streamId, string metho return (ctx.ExecuteContext.Abort != ExportAbortion.Hard); } - private void Deploy(DataExporterContext ctx) + private void Deploy(DataExporterContext ctx, string zipPath) { - var containerManager = EngineContext.Current.ContainerManager; var allFiles = System.IO.Directory.GetFiles(ctx.FolderContent, "*.*", SearchOption.AllDirectories); var context = new ExportDeploymentContext { Log = ctx.Log, FolderContent = ctx.FolderContent, - ZipPath = ctx.ZipPath + ZipPath = zipPath }; foreach (var deployment in ctx.Request.Profile.Deployments.OrderBy(x => x.DeploymentTypeId).Where(x => x.Enabled)) { if (deployment.CreateZip) - context.DeploymentFiles = new string[] { ctx.ZipPath }; + context.DeploymentFiles = new string[] { zipPath }; else context.DeploymentFiles = allFiles; @@ -977,11 +976,14 @@ private void ExportCoreOuter(DataExporterContext ctx) if (ctx.Request.Profile == null || !ctx.Request.Profile.Enabled) return; - FileSystemHelper.Delete(ctx.LogPath); + var logPath = ctx.Request.Profile.GetExportLogPath(); + var zipPath = ctx.Request.Profile.GetExportZipPath(); + + FileSystemHelper.Delete(logPath); + FileSystemHelper.Delete(zipPath); FileSystemHelper.ClearDirectory(ctx.FolderContent, false); - FileSystemHelper.Delete(ctx.ZipPath); - using (var logger = new TraceLogger(ctx.LogPath)) + using (var logger = new TraceLogger(logPath)) { try { @@ -1053,14 +1055,14 @@ private void ExportCoreOuter(DataExporterContext ctx) { if (ctx.Request.Profile.CreateZipArchive || ctx.Request.Profile.Deployments.Any(x => x.Enabled && x.CreateZip)) { - ZipFile.CreateFromDirectory(ctx.FolderContent, ctx.ZipPath, CompressionLevel.Fastest, true); + ZipFile.CreateFromDirectory(ctx.FolderContent, zipPath, CompressionLevel.Fastest, true); } if (ctx.Request.Profile.Deployments.Any(x => x.Enabled)) { SetProgress(ctx, T("Common.Deployment")); - Deploy(ctx); + Deploy(ctx, zipPath); } } @@ -1127,7 +1129,7 @@ private void ExportCoreOuter(DataExporterContext ctx) // post process order entities if (ctx.EntityIdsLoaded.Count > 0 && ctx.Request.Provider.Value.EntityType == ExportEntityType.Order && ctx.Projection.OrderStatusChange != ExportOrderStatusChange.None) { - using (var logger = new TraceLogger(ctx.LogPath)) + using (var logger = new TraceLogger(logPath)) { try { diff --git a/src/Libraries/SmartStore.Services/DataExchange/ExportExtensions.cs b/src/Libraries/SmartStore.Services/DataExchange/ExportExtensions.cs index f46fb9094a..4de3aadd7c 100644 --- a/src/Libraries/SmartStore.Services/DataExchange/ExportExtensions.cs +++ b/src/Libraries/SmartStore.Services/DataExchange/ExportExtensions.cs @@ -1,6 +1,8 @@ using System; +using System.Collections.Generic; using System.Globalization; using System.IO; +using System.Linq; using System.Text; using SmartStore.Core.Domain; using SmartStore.Core.Domain.Stores; @@ -57,12 +59,40 @@ public static string GetExportFolder(this ExportProfile profile, bool content = /// /// Export profile /// Log file path - public static string GetExportLogFilePath(this ExportProfile profile) + public static string GetExportLogPath(this ExportProfile profile) { - var path = Path.Combine(profile.GetExportFolder(), "log.txt"); - return path; + return Path.Combine(profile.GetExportFolder(), "log.txt"); + } + + /// + /// Gets the ZIP path for a profile + /// + /// Export profile + /// ZIP file path + public static string GetExportZipPath(this ExportProfile profile) + { + return Path.Combine(profile.GetExportFolder(), profile.FolderName + ".zip"); } + /// + /// Gets existing export files for an export profile + /// + /// Export profile + /// List of file names + public static List GetExportFiles(this ExportProfile profile) + { + var exportFolder = profile.GetExportFolder(true); + + if (System.IO.Directory.Exists(exportFolder)) + { + return System.IO.Directory.EnumerateFiles(exportFolder, "*", SearchOption.TopDirectoryOnly) + .OrderBy(x => x) + .ToList(); + } + + return new List(); + } + /// /// Resolves the file name pattern for an export profile /// diff --git a/src/Libraries/SmartStore.Services/DataExchange/Internal/DataExporterContext.cs b/src/Libraries/SmartStore.Services/DataExchange/Internal/DataExporterContext.cs index 031406df3a..0b09514a17 100644 --- a/src/Libraries/SmartStore.Services/DataExchange/Internal/DataExporterContext.cs +++ b/src/Libraries/SmartStore.Services/DataExchange/Internal/DataExporterContext.cs @@ -1,5 +1,4 @@ using System.Collections.Generic; -using System.IO; using System.Linq; using System.Threading; using SmartStore.Core; @@ -27,7 +26,6 @@ public DataExporterContext( IsPreview = isPreview; FolderContent = request.Profile.GetExportFolder(true, true); - FolderRoot = System.IO.Directory.GetParent(FolderContent).FullName; Categories = new Dictionary(); CategoryPathes = new Dictionary(); @@ -87,20 +85,7 @@ public bool Supports(ExportFeatures feature) public TraceLogger Log { get; set; } public Store Store { get; set; } - public string FolderRoot { get; private set; } public string FolderContent { get; private set; } - public string ZipName - { - get { return Request.Profile.FolderName + ".zip"; } - } - public string ZipPath - { - get { return Path.Combine(FolderRoot, ZipName); } - } - public string LogPath - { - get { return Path.Combine(FolderRoot, "log.txt"); } - } public bool IsFileBasedExport { diff --git a/src/Presentation/SmartStore.Web/Administration/Controllers/ExportController.cs b/src/Presentation/SmartStore.Web/Administration/Controllers/ExportController.cs index 5fafb8d0df..aba647e6cf 100644 --- a/src/Presentation/SmartStore.Web/Administration/Controllers/ExportController.cs +++ b/src/Presentation/SmartStore.Web/Administration/Controllers/ExportController.cs @@ -16,12 +16,12 @@ using SmartStore.Core.Domain.Payments; using SmartStore.Core.Domain.Shipping; using SmartStore.Core.Domain.Stores; +using SmartStore.Core.IO; using SmartStore.Core.Plugins; using SmartStore.Services; using SmartStore.Services.Catalog; using SmartStore.Services.Customers; using SmartStore.Services.DataExchange; -using SmartStore.Services.DataExchange.Internal; using SmartStore.Services.Directory; using SmartStore.Services.Helpers; using SmartStore.Services.Localization; @@ -106,6 +106,20 @@ private string GetThumbnailUrl(Provider provider) return url; } + private ExportProfileDetailsModel PrepareProfileDetailsModel(ExportProfile profile) + { + var zipPath = profile.GetExportZipPath(); + + var model = new ExportProfileDetailsModel + { + Id = profile.Id, + ZipPath = (System.IO.File.Exists(zipPath) ? zipPath : null), + ExportFiles = profile.GetExportFiles() + }; + + return model; + } + private void PrepareProfileModel(ExportProfileModel model, ExportProfile profile, Provider provider) { model.Id = profile.Id; @@ -120,13 +134,15 @@ private void PrepareProfileModel(ExportProfileModel model, ExportProfile profile model.ScheduleTaskName = profile.ScheduleTask.Name.NaIfEmpty(); model.IsTaskRunning = profile.ScheduleTask.IsRunning; model.IsTaskEnabled = profile.ScheduleTask.Enabled; - model.LogFileExists = System.IO.File.Exists(profile.GetExportLogFilePath()); + model.LogFileExists = System.IO.File.Exists(profile.GetExportLogPath()); model.HasActiveProvider = (provider != null); model.FileNamePatternDescriptions = T("Admin.DataExchange.Export.FileNamePatternDescriptions").Text.SplitSafe(";"); model.Provider = new ExportProfileModel.ProviderModel(); model.Provider.ThumbnailUrl = GetThumbnailUrl(provider); + model.Details = PrepareProfileDetailsModel(profile); + if (provider != null) { var descriptor = provider.Metadata.PluginDescriptor; @@ -145,7 +161,7 @@ private void PrepareProfileModel(ExportProfileModel model, ExportProfile profile model.Provider.EntityTypeName = provider.Value.EntityType.GetLocalizedEnum(_services.Localization, _services.WorkContext); model.Provider.FileExtension = provider.Value.FileExtension; } - } + } private void PrepareProfileModelForEdit(ExportProfileModel model, ExportProfile profile, Provider provider) { @@ -478,6 +494,41 @@ public ActionResult List() return View(model); } + public ActionResult ProfileListDetails(int profileId) + { + if (_services.Permissions.Authorize(StandardPermissionProvider.ManageExports)) + { + var profile = _exportService.GetExportProfileById(profileId); + if (profile != null) + { + var model = PrepareProfileDetailsModel(profile); + + return Json(new + { + exportFileCount = this.RenderPartialViewToString("ProfileFileCount", model) + }, JsonRequestBehavior.AllowGet); + } + } + + return new EmptyResult(); + } + + public ActionResult ProfileFileDetails(int profileId) + { + if (_services.Permissions.Authorize(StandardPermissionProvider.ManageExports)) + { + var profile = _exportService.GetExportProfileById(profileId); + if (profile != null) + { + var model = PrepareProfileDetailsModel(profile); + + return PartialView(model); + } + } + + return new EmptyResult(); + } + public ActionResult Create() { if (!_services.Permissions.Authorize(StandardPermissionProvider.ManageExports)) @@ -742,7 +793,7 @@ public ActionResult Preview(int id) GridPageSize = DataExporter.PageSize, EntityType = provider.Value.EntityType, TotalRecords = totalRecords, - LogFileExists = System.IO.File.Exists(profile.GetExportLogFilePath()), + LogFileExists = System.IO.File.Exists(profile.GetExportLogPath()), UsernamesEnabled = _customerSettings.Value.UsernamesEnabled }; @@ -979,7 +1030,7 @@ public ActionResult DownloadLogFile(int id) if (profile == null) return RedirectToAction("List"); - var path = profile.GetExportLogFilePath(); + var path = profile.GetExportLogPath(); var stream = new FileStream(path, FileMode.Open); var result = new FileStreamResult(stream, "text/plain; charset=utf-8"); @@ -988,6 +1039,28 @@ public ActionResult DownloadLogFile(int id) return result; } + public ActionResult DownloadExportFile(int id, string name) + { + if (!_services.Permissions.Authorize(StandardPermissionProvider.ManageExports)) + return AccessDeniedView(); + + var profile = _exportService.GetExportProfileById(id); + if (profile == null) + return RedirectToAction("List"); + + var path = Path.Combine(profile.GetExportFolder(true), name); + + if (!System.IO.File.Exists(path)) + path = Path.Combine(profile.GetExportFolder(false), name); + + var stream = new FileStream(path, FileMode.Open); + + var result = new FileStreamResult(stream, MimeTypes.MapNameToMimeType(path)); + result.FileDownloadName = Path.GetFileName(path); + + return result; + } + public ActionResult ResolveFileNamePatternExample(int id, string pattern) { var profile = _exportService.GetExportProfileById(id); diff --git a/src/Presentation/SmartStore.Web/Administration/Models/DataExchange/ExportProfileModel.cs b/src/Presentation/SmartStore.Web/Administration/Models/DataExchange/ExportProfileModel.cs index 7ea59f0921..b41f8fc1f5 100644 --- a/src/Presentation/SmartStore.Web/Administration/Models/DataExchange/ExportProfileModel.cs +++ b/src/Presentation/SmartStore.Web/Administration/Models/DataExchange/ExportProfileModel.cs @@ -95,6 +95,8 @@ public partial class ExportProfileModel : EntityModelBase public ScheduleTaskModel TaskModel { get; set; } + public ExportProfileDetailsModel Details { get; set; } + public class ProviderModel { public string ConfigPartialViewName { get; set; } @@ -152,4 +154,22 @@ public class ProviderSelectItem public string Description { get; set; } } } + + + public partial class ExportProfileDetailsModel : EntityModelBase + { + [SmartResourceDisplayName("Admin.DataExchange.Export.ExportFiles")] + public List ExportFiles { get; set; } + + public string ZipPath { get; set; } + + [SmartResourceDisplayName("Admin.DataExchange.Export.ExportFiles")] + public int ExportFileCount + { + get + { + return (ExportFiles.Count + (ZipPath.HasValue() ? 1 : 0)); + } + } + } } \ No newline at end of file diff --git a/src/Presentation/SmartStore.Web/Administration/SmartStore.Admin.csproj b/src/Presentation/SmartStore.Web/Administration/SmartStore.Admin.csproj index 5bc8e616ad..189b2f717d 100644 --- a/src/Presentation/SmartStore.Web/Administration/SmartStore.Admin.csproj +++ b/src/Presentation/SmartStore.Web/Administration/SmartStore.Admin.csproj @@ -535,6 +535,8 @@ + + diff --git a/src/Presentation/SmartStore.Web/Administration/Views/Export/Edit.cshtml b/src/Presentation/SmartStore.Web/Administration/Views/Export/Edit.cshtml index ecf22fd744..17a71d5ebc 100644 --- a/src/Presentation/SmartStore.Web/Administration/Views/Export/Edit.cshtml +++ b/src/Presentation/SmartStore.Web/Administration/Views/Export/Edit.cshtml @@ -25,7 +25,7 @@ } @if (Model.LogFileExists) { - +  @T("Admin.Configuration.ActivityLog") } diff --git a/src/Presentation/SmartStore.Web/Administration/Views/Export/List.cshtml b/src/Presentation/SmartStore.Web/Administration/Views/Export/List.cshtml index 6448df05a3..c1e1a0beb3 100644 --- a/src/Presentation/SmartStore.Web/Administration/Views/Export/List.cshtml +++ b/src/Presentation/SmartStore.Web/Administration/Views/Export/List.cshtml @@ -27,11 +27,12 @@ @T("Common.Image") @T("Admin.DataExchange.Export.Name") + @T("Admin.DataExchange.Export.IsSystemProfile") @T("Common.Provider") @T("Common.Enabled") @T("Admin.DataExchange.Export.EntityType") @T("Admin.DataExchange.Export.FileExtension") - @T("Admin.DataExchange.Export.IsSystemProfile") + @T("Admin.DataExchange.Export.ExportFiles") @T("Admin.System.ScheduleTasks.LastStart") @T("Admin.System.ScheduleTasks.NextRun") @T("Admin.Common.Actions") @@ -40,7 +41,7 @@ @foreach (var profile in Model) { - + @profile.Provider.FriendlyName @@ -51,6 +52,9 @@
@profile.SystemName
} + + @Html.SymbolForBool(profile.IsSystemProfile) + @if (profile.Provider.ConfigurationUrl.HasValue()) { @@ -71,8 +75,8 @@ @Html.IconForFileExtension(profile.Provider.FileExtension, true) - - @Html.SymbolForBool(profile.IsSystemProfile) + + @Html.Partial("ProfileFileCount", profile.Details)
@@ -127,6 +131,17 @@ else
+ + -} - - - - +} \ No newline at end of file diff --git a/src/Presentation/SmartStore.Web/Administration/Views/Product/List.cshtml b/src/Presentation/SmartStore.Web/Administration/Views/Product/List.cshtml index 129406b9a5..9d9bacaa8a 100644 --- a/src/Presentation/SmartStore.Web/Administration/Views/Product/List.cshtml +++ b/src/Presentation/SmartStore.Web/Administration/Views/Product/List.cshtml @@ -37,13 +37,13 @@ @@ -217,7 +217,7 @@ \ No newline at end of file From 5a05d01dea5c2e8cc779617a573874168825b41d Mon Sep 17 00:00:00 2001 From: Marcus Gesing Date: Fri, 27 Nov 2015 14:17:19 +0100 Subject: [PATCH 102/707] Added manufacturer CSV export --- .../Controllers/ManufacturerController.cs | 19 +++--- .../Models/Catalog/ManufacturerListModel.cs | 5 +- .../Views/Manufacturer/List.cshtml | 61 +++++++++++++++++-- 3 files changed, 66 insertions(+), 19 deletions(-) diff --git a/src/Presentation/SmartStore.Web/Administration/Controllers/ManufacturerController.cs b/src/Presentation/SmartStore.Web/Administration/Controllers/ManufacturerController.cs index 6d40857243..1382fe86c0 100644 --- a/src/Presentation/SmartStore.Web/Administration/Controllers/ManufacturerController.cs +++ b/src/Presentation/SmartStore.Web/Administration/Controllers/ManufacturerController.cs @@ -241,14 +241,12 @@ public ActionResult List() if (!_permissionService.Authorize(StandardPermissionProvider.ManageCatalog)) return AccessDeniedView(); - var model = new ManufacturerListModel(); - var manufacturers = _manufacturerService.GetAllManufacturers(null, 0, _adminAreaSettings.GridPageSize, true); - model.Manufacturers = new GridModel - { - Data = manufacturers.Select(x => x.ToModel()), - Total = manufacturers.TotalCount - }; - return View(model); + var model = new ManufacturerListModel + { + GridPageSize = _adminAreaSettings.GridPageSize + }; + + return View(model); } [HttpPost, GridAction(EnableCustomBinding = true)] @@ -257,13 +255,14 @@ public ActionResult List(GridCommand command, ManufacturerListModel model) if (!_permissionService.Authorize(StandardPermissionProvider.ManageCatalog)) return AccessDeniedView(); - var manufacturers = _manufacturerService.GetAllManufacturers(model.SearchManufacturerName, - command.Page - 1, command.PageSize, true); + var manufacturers = _manufacturerService.GetAllManufacturers(model.SearchManufacturerName, command.Page - 1, command.PageSize, true); + var gridModel = new GridModel { Data = manufacturers.Select(x => x.ToModel()), Total = manufacturers.TotalCount }; + return new JsonResult { Data = gridModel diff --git a/src/Presentation/SmartStore.Web/Administration/Models/Catalog/ManufacturerListModel.cs b/src/Presentation/SmartStore.Web/Administration/Models/Catalog/ManufacturerListModel.cs index 9fedd4f0bd..f683ac54c0 100644 --- a/src/Presentation/SmartStore.Web/Administration/Models/Catalog/ManufacturerListModel.cs +++ b/src/Presentation/SmartStore.Web/Administration/Models/Catalog/ManufacturerListModel.cs @@ -1,16 +1,15 @@ using System.Web.Mvc; using SmartStore.Web.Framework; using SmartStore.Web.Framework.Mvc; -using Telerik.Web.Mvc; namespace SmartStore.Admin.Models.Catalog { - public class ManufacturerListModel : ModelBase + public class ManufacturerListModel : ModelBase { [SmartResourceDisplayName("Admin.Catalog.Manufacturers.List.SearchManufacturerName")] [AllowHtml] public string SearchManufacturerName { get; set; } - public GridModel Manufacturers { get; set; } + public int GridPageSize { get; set; } } } \ No newline at end of file diff --git a/src/Presentation/SmartStore.Web/Administration/Views/Manufacturer/List.cshtml b/src/Presentation/SmartStore.Web/Administration/Views/Manufacturer/List.cshtml index 4d867bfcad..c5f8fccc99 100644 --- a/src/Presentation/SmartStore.Web/Administration/Views/Manufacturer/List.cshtml +++ b/src/Presentation/SmartStore.Web/Administration/Views/Manufacturer/List.cshtml @@ -1,8 +1,6 @@ @model ManufacturerListModel @using Telerik.Web.Mvc.UI -@{ - var gridPageSize = EngineContext.Current.Resolve().GridPageSize; - +@{ ViewBag.Title = T("Admin.Catalog.Manufacturers").Text; }
@@ -45,12 +43,19 @@
- @(Html.Telerik().Grid(Model.Manufacturers.Data) + @(Html.Telerik().Grid() .Name("manufacturers-grid") .ClientEvents(events => events - .OnDataBinding("onDataBinding")) + .OnDataBinding("onDataBinding") + .OnDataBound("onDataBound")) .Columns(columns => { + columns.Bound(x => x.Id) + .ClientTemplate("") + .Title("") + .Width(50) + .HtmlAttributes(new { style = "text-align:center" }) + .HeaderHtmlAttributes(new { style = "text-align:center" }); columns.Bound(x => x.Name) .Template(x => Html.ActionLink(x.Name, "Edit", new { id = x.Id })) .ClientTemplate("\"><#= Name #>"); @@ -68,7 +73,7 @@ .ClientTemplate(@Html.SymbolForBool("LimitedToStores")) .Centered(); }) - .Pageable(settings => settings.Total(Model.Manufacturers.Total).PageSize(gridPageSize).Position(GridPagerPosition.Both)) + .Pageable(settings => settings.PageSize(Model.GridPageSize).Position(GridPagerPosition.Both)) .DataBinding(dataBinding => dataBinding.Ajax().Select("List", "Manufacturer")) .PreserveGridState() .EnableCustomBinding(true)) @@ -77,6 +82,9 @@
\ No newline at end of file From 7233247becc5ecd01ea68fa7b64054832aa6af8d Mon Sep 17 00:00:00 2001 From: Marcus Gesing Date: Sat, 28 Nov 2015 11:12:22 +0100 Subject: [PATCH 103/707] Resolves #820 ConfigureTheme page contains German --- .../Migrations/201509150931528_ExportFramework2.cs | 4 ++++ .../SmartStore.Web/Views/Shared/ConfigureTheme.cshtml | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/Libraries/SmartStore.Data/Migrations/201509150931528_ExportFramework2.cs b/src/Libraries/SmartStore.Data/Migrations/201509150931528_ExportFramework2.cs index c73e7769f1..d3fe755327 100644 --- a/src/Libraries/SmartStore.Data/Migrations/201509150931528_ExportFramework2.cs +++ b/src/Libraries/SmartStore.Data/Migrations/201509150931528_ExportFramework2.cs @@ -249,6 +249,10 @@ public void MigrateLocaleResources(LocaleResourcesBuilder builder) builder.AddOrUpdate("Admin.System.SystemInfo.GarbageCollectSuccessful", "The memory has been successfully cleaned up.", "Der Arbeitsspeicher wurde erfolgreich aufgerumt."); + + builder.AddOrUpdate("Admin.Configuration.Themes.NoConfigurationRequired", + "Theme requires no configuration", + "Theme bentigt keine Konfiguration"); } } } diff --git a/src/Presentation/SmartStore.Web/Views/Shared/ConfigureTheme.cshtml b/src/Presentation/SmartStore.Web/Views/Shared/ConfigureTheme.cshtml index ca0152ce09..a6e34081b9 100644 --- a/src/Presentation/SmartStore.Web/Views/Shared/ConfigureTheme.cshtml +++ b/src/Presentation/SmartStore.Web/Views/Shared/ConfigureTheme.cshtml @@ -2,4 +2,4 @@ Layout = null; } -
Theme benötigt keine Konfiguration
+
@T("Admin.Configuration.Themes.NoConfigurationRequired")
From fcc2608a7f946272da638d8c2331eb114d2f63e0 Mon Sep 17 00:00:00 2001 From: Marcus Gesing Date: Mon, 30 Nov 2015 10:57:39 +0100 Subject: [PATCH 104/707] Further improvements in presenting download links of export files --- .../Logging/LoggingExtensions.cs | 12 ++- .../201511271019577_ExportFramework3.cs | 6 ++ .../DataExchange/DataExportResult.cs | 2 +- .../DataExchange/DataExporter.cs | 23 +++-- .../Controllers/ExportController.cs | 94 ++++++++++--------- .../DataExchange/ExportDeploymentModel.cs | 9 +- .../Models/DataExchange/ExportProfileModel.cs | 12 ++- .../Views/Export/InfoDeployment.cshtml | 59 +++++++----- .../Administration/Views/Export/List.cshtml | 2 +- .../Views/Export/ProfileFileCount.cshtml | 9 +- .../Views/Export/ProfileFileDetails.cshtml | 34 +++++-- .../Views/Export/_Tab.Deployment.cshtml | 7 ++ 12 files changed, 165 insertions(+), 104 deletions(-) diff --git a/src/Libraries/SmartStore.Core/Logging/LoggingExtensions.cs b/src/Libraries/SmartStore.Core/Logging/LoggingExtensions.cs index de1266efd4..f7c2633e40 100644 --- a/src/Libraries/SmartStore.Core/Logging/LoggingExtensions.cs +++ b/src/Libraries/SmartStore.Core/Logging/LoggingExtensions.cs @@ -37,7 +37,17 @@ public static void Error(this ILogger logger, Exception exception, Customer cust FilteredLog(logger, LogLevel.Error, exception.ToAllMessages(), exception, customer); } - private static void FilteredLog(ILogger logger, LogLevel level, string message, Exception exception = null, Customer customer = null) + public static void ErrorsAll(this ILogger logger, Exception exception, Customer customer = null) + { + while (exception != null) + { + FilteredLog(logger, LogLevel.Error, exception.Message, exception, customer); + + exception = exception.InnerException; + } + } + + private static void FilteredLog(ILogger logger, LogLevel level, string message, Exception exception = null, Customer customer = null) { // don't log thread abort exception if ((exception != null) && (exception is System.Threading.ThreadAbortException)) diff --git a/src/Libraries/SmartStore.Data/Migrations/201511271019577_ExportFramework3.cs b/src/Libraries/SmartStore.Data/Migrations/201511271019577_ExportFramework3.cs index 42fe9dd04d..00ea19fba6 100644 --- a/src/Libraries/SmartStore.Data/Migrations/201511271019577_ExportFramework3.cs +++ b/src/Libraries/SmartStore.Data/Migrations/201511271019577_ExportFramework3.cs @@ -59,6 +59,12 @@ public void Seed(SmartObjectContext context) public void MigrateLocaleResources(LocaleResourcesBuilder builder) { builder.AddOrUpdate("Admin.Common.Export.PDF", "PDF Export", "PDF Export"); + builder.AddOrUpdate("Admin.Common.TemporaryFiles", "Temporary files", "Temporre Dateien"); + builder.AddOrUpdate("Admin.Common.PublicFiles", "Public files", "ffentliche Dateien"); + + builder.AddOrUpdate("Admin.Common.NoTempFilesFound", + "No temporary files were found.", + "Es wurden keine temporren Dateien gefunden."); builder.AddOrUpdate("Enums.SmartStore.Core.Domain.DataExchange.ExportEntityType.NewsLetterSubscription", "Newsletter Subscribers", diff --git a/src/Libraries/SmartStore.Services/DataExchange/DataExportResult.cs b/src/Libraries/SmartStore.Services/DataExchange/DataExportResult.cs index cfbe0db7bf..d7e0d9fa6a 100644 --- a/src/Libraries/SmartStore.Services/DataExchange/DataExportResult.cs +++ b/src/Libraries/SmartStore.Services/DataExchange/DataExportResult.cs @@ -29,7 +29,7 @@ public bool Succeeded /// /// Files created by last export /// - public IList Files { get; set; } + public List Files { get; set; } /// /// The path of the folder with the export files diff --git a/src/Libraries/SmartStore.Services/DataExchange/DataExporter.cs b/src/Libraries/SmartStore.Services/DataExchange/DataExporter.cs index 528bc1f1b4..9193f38739 100644 --- a/src/Libraries/SmartStore.Services/DataExchange/DataExporter.cs +++ b/src/Libraries/SmartStore.Services/DataExchange/DataExporter.cs @@ -1135,7 +1135,7 @@ private void ExportCoreOuter(DataExporterContext ctx) } catch (Exception exception) { - logger.Error(exception); + logger.ErrorsAll(exception); ctx.Result.LastError = exception.ToString(); } finally @@ -1149,7 +1149,10 @@ private void ExportCoreOuter(DataExporterContext ctx) _exportProfileService.Value.UpdateExportProfile(ctx.Request.Profile); } } - catch { } + catch (Exception exception) + { + logger.ErrorsAll(exception); + } try { @@ -1158,7 +1161,10 @@ private void ExportCoreOuter(DataExporterContext ctx) FileSystemHelper.ClearDirectory(ctx.FolderContent, false); } } - catch { } + catch (Exception exception) + { + logger.ErrorsAll(exception); + } DetachAllEntitiesAndClear(ctx); @@ -1180,7 +1186,10 @@ private void ExportCoreOuter(DataExporterContext ctx) ctx.ExecuteContext.Log = null; ctx.Log = null; } - catch { } + catch (Exception exception) + { + logger.ErrorsAll(exception); + } } } @@ -1215,10 +1224,10 @@ private void ExportCoreOuter(DataExporterContext ctx) logger.Information("Updated order status for {0} order(s).".FormatInvariant(ctx.EntityIdsLoaded.Count())); } - catch (Exception exc) + catch (Exception exception) { - logger.Error(exc); - ctx.Result.LastError = exc.ToString(); + logger.ErrorsAll(exception); + ctx.Result.LastError = exception.ToString(); } } } diff --git a/src/Presentation/SmartStore.Web/Administration/Controllers/ExportController.cs b/src/Presentation/SmartStore.Web/Administration/Controllers/ExportController.cs index 11d5681e86..b54951bcc0 100644 --- a/src/Presentation/SmartStore.Web/Administration/Controllers/ExportController.cs +++ b/src/Presentation/SmartStore.Web/Administration/Controllers/ExportController.cs @@ -106,21 +106,56 @@ private string GetThumbnailUrl(Provider provider) return url; } - private ExportProfileDetailsModel PrepareProfileDetailsModel(ExportProfile profile) + private ExportProfileDetailsModel PrepareProfileDetailsModel(ExportProfile profile, bool forEdit) { - var zipPath = profile.GetExportZipPath(); - var model = new ExportProfileDetailsModel { Id = profile.Id, - ZipPath = (System.IO.File.Exists(zipPath) ? zipPath : null), - ExportFiles = profile.GetExportFiles() + PublicFiles = new List() }; + try + { + var zipPath = profile.GetExportZipPath(); + + model.ZipPath = (System.IO.File.Exists(zipPath) ? zipPath : null); + model.ExportFiles = profile.GetExportFiles(); + + if (forEdit && profile.Deployments.Any(x => x.IsPublic && x.DeploymentType == ExportDeploymentType.FileSystem)) + { + var allStores = _services.StoreService.GetAllStores(); + var publicFolder = Path.Combine(HttpRuntime.AppDomainAppPath, DataExporter.PublicFolder); + var resultInfo = XmlHelper.Deserialize(profile.ResultInfo); + + if (resultInfo != null && resultInfo.Files != null) + { + foreach (var fileInfo in resultInfo.Files) + { + if (System.IO.File.Exists(Path.Combine(publicFolder, fileInfo.FileName)) && !model.PublicFiles.Any(x => x.FileName == fileInfo.FileName)) + { + var store = allStores.FirstOrDefault(y => y.Id == fileInfo.StoreId) ?? _services.StoreContext.CurrentStore; + + model.PublicFiles.Add(new ExportProfileDetailsModel.PublicFile + { + StoreId = store.Id, + StoreName = store.Name, + FileName = fileInfo.FileName, + FileUrl = string.Concat(store.Url.EnsureEndsWith("/"), DataExporter.PublicFolder.EnsureEndsWith("/"), fileInfo.FileName) + }); + } + } + } + } + } + catch (Exception exception) + { + NotifyError(exception); + } + return model; } - private void PrepareProfileModel(ExportProfileModel model, ExportProfile profile, Provider provider) + private void PrepareProfileModel(ExportProfileModel model, ExportProfile profile, Provider provider, bool forEdit) { model.Id = profile.Id; model.Name = profile.Name; @@ -141,7 +176,7 @@ private void PrepareProfileModel(ExportProfileModel model, ExportProfile profile model.Provider = new ExportProfileModel.ProviderModel(); model.Provider.ThumbnailUrl = GetThumbnailUrl(provider); - model.Details = PrepareProfileDetailsModel(profile); + model.Details = PrepareProfileDetailsModel(profile, forEdit); if (provider != null) { @@ -266,37 +301,7 @@ private void PrepareProfileModelForEdit(ExportProfileModel model, ExportProfile { var deploymentModel = PrepareDeploymentModel(x, null, false); - if (x.IsPublic) - { - try - { - var publicFolder = Path.Combine(HttpRuntime.AppDomainAppPath, DataExporter.PublicFolder); - var resultInfo = XmlHelper.Deserialize(profile.ResultInfo); - - if (resultInfo != null && resultInfo.Files != null) - { - foreach (var fileInfo in resultInfo.Files) - { - if (System.IO.File.Exists(Path.Combine(publicFolder, fileInfo.FileName)) && !deploymentModel.PublicFiles.Any(y => y.FileName == fileInfo.FileName)) - { - var store = allStores.FirstOrDefault(y => y.Id == fileInfo.StoreId) ?? _services.StoreContext.CurrentStore; - - deploymentModel.PublicFiles.Add(new ExportDeploymentModel.PublicFile - { - StoreId = store.Id, - StoreName = store.Name, - FileName = fileInfo.FileName, - FileUrl = string.Concat(store.Url.EnsureEndsWith("/"), DataExporter.PublicFolder.EnsureEndsWith("/"), fileInfo.FileName) - }); - } - } - } - } - catch (Exception exc) - { - exc.Dump(); - } - } + deploymentModel.ProfileDetails = PrepareProfileDetailsModel(profile, true); return deploymentModel; }) @@ -402,8 +407,7 @@ private ExportDeploymentModel PrepareDeploymentModel(ExportDeployment deployment EmailSubject = deployment.EmailSubject, EmailAccountId = deployment.EmailAccountId, PassiveMode = deployment.PassiveMode, - UseSsl = deployment.UseSsl, - PublicFiles = new List() + UseSsl = deployment.UseSsl }; if (forEdit) @@ -484,7 +488,7 @@ public ActionResult List() { var profileModel = new ExportProfileModel(); - PrepareProfileModel(profileModel, profile, providers.FirstOrDefault(x => x.Metadata.SystemName == profile.ProviderSystemName)); + PrepareProfileModel(profileModel, profile, providers.FirstOrDefault(x => x.Metadata.SystemName == profile.ProviderSystemName), false); profileModel.TaskModel = profile.ScheduleTask.ToScheduleTaskModel(_services.Localization, _dateTimeHelper, Url); @@ -501,7 +505,7 @@ public ActionResult ProfileListDetails(int profileId) var profile = _exportService.GetExportProfileById(profileId); if (profile != null) { - var model = PrepareProfileDetailsModel(profile); + var model = PrepareProfileDetailsModel(profile, false); return Json(new { @@ -520,7 +524,7 @@ public ActionResult ProfileFileDetails(int profileId) var profile = _exportService.GetExportProfileById(profileId); if (profile != null) { - var model = PrepareProfileDetailsModel(profile); + var model = PrepareProfileDetailsModel(profile, true); return PartialView(model); } @@ -610,7 +614,7 @@ public ActionResult Edit(int id) var model = new ExportProfileModel(); - PrepareProfileModel(model, profile, provider); + PrepareProfileModel(model, profile, provider, true); PrepareProfileModelForEdit(model, profile, provider); return View(model); @@ -631,7 +635,7 @@ public ActionResult Edit(ExportProfileModel model, bool continueEditing) if (!ModelState.IsValid) { - PrepareProfileModel(model, profile, provider); + PrepareProfileModel(model, profile, provider, true); PrepareProfileModelForEdit(model, profile, provider); return View(model); } diff --git a/src/Presentation/SmartStore.Web/Administration/Models/DataExchange/ExportDeploymentModel.cs b/src/Presentation/SmartStore.Web/Administration/Models/DataExchange/ExportDeploymentModel.cs index ffecae4f0a..6a0c317ab1 100644 --- a/src/Presentation/SmartStore.Web/Administration/Models/DataExchange/ExportDeploymentModel.cs +++ b/src/Presentation/SmartStore.Web/Administration/Models/DataExchange/ExportDeploymentModel.cs @@ -55,7 +55,6 @@ public string DeploymentTypeIconClass [SmartResourceDisplayName("Admin.DataExchange.Export.Deployment.IsPublic")] public bool IsPublic { get; set; } - public List PublicFiles { get; set; } [SmartResourceDisplayName("Admin.DataExchange.Export.Deployment.Username")] public string Username { get; set; } @@ -91,12 +90,6 @@ public string DeploymentTypeIconClass [SmartResourceDisplayName("Admin.DataExchange.Export.Deployment.UseSsl")] public bool UseSsl { get; set; } - public class PublicFile - { - public int StoreId { get; set; } - public string StoreName { get; set; } - public string FileName { get; set; } - public string FileUrl { get; set; } - } + public ExportProfileDetailsModel ProfileDetails { get; set; } } } \ No newline at end of file diff --git a/src/Presentation/SmartStore.Web/Administration/Models/DataExchange/ExportProfileModel.cs b/src/Presentation/SmartStore.Web/Administration/Models/DataExchange/ExportProfileModel.cs index b41f8fc1f5..a1a535a5f6 100644 --- a/src/Presentation/SmartStore.Web/Administration/Models/DataExchange/ExportProfileModel.cs +++ b/src/Presentation/SmartStore.Web/Administration/Models/DataExchange/ExportProfileModel.cs @@ -1,6 +1,5 @@ using System; using System.Collections.Generic; -using System.IO; using System.Web.Mvc; using FluentValidation.Attributes; using SmartStore.Admin.Models.Tasks; @@ -82,7 +81,6 @@ public partial class ExportProfileModel : EntityModelBase [SmartResourceDisplayName("Admin.DataExchange.Export.CloneProfile")] public int? CloneProfileId { get; set; } - //public List AvailableProfiles { get; set; } public List AvailableProfiles { get; set; } public ProviderModel Provider { get; set; } @@ -171,5 +169,15 @@ public int ExportFileCount return (ExportFiles.Count + (ZipPath.HasValue() ? 1 : 0)); } } + + public List PublicFiles { get; set; } + + public class PublicFile + { + public int StoreId { get; set; } + public string StoreName { get; set; } + public string FileName { get; set; } + public string FileUrl { get; set; } + } } } \ No newline at end of file diff --git a/src/Presentation/SmartStore.Web/Administration/Views/Export/InfoDeployment.cshtml b/src/Presentation/SmartStore.Web/Administration/Views/Export/InfoDeployment.cshtml index 67ce817d18..fce2ac18c7 100644 --- a/src/Presentation/SmartStore.Web/Administration/Views/Export/InfoDeployment.cshtml +++ b/src/Presentation/SmartStore.Web/Administration/Views/Export/InfoDeployment.cshtml @@ -4,42 +4,51 @@ @{ Layout = null; } -

+@helper FileDownloadLink(string path, string fileName) +{ +

+ @Html.IconForFileExtension(Path.GetExtension(fileName), false) + @fileName +
+} +
 @Model.DeploymentTypeName @if (Model.DeploymentType == ExportDeploymentType.FileSystem && Model.IsPublic) { (@T("Common.Public")) } -

-@if (Model.DeploymentType == ExportDeploymentType.FileSystem) -{ - if (Model.IsPublic) +
+
+ @if (Model.DeploymentType == ExportDeploymentType.FileSystem) { - foreach (var grp in Model.PublicFiles.OrderBy(x => x.StoreId).GroupBy(x => x.StoreId)) + foreach (var path in Model.ProfileDetails.ExportFiles) + { + @FileDownloadLink(path, Path.GetFileName(path)) + } + + if (Model.ProfileDetails.PublicFiles.Count > 0) { -

+ foreach (var grp in Model.ProfileDetails.PublicFiles.OrderBy(x => x.StoreId).GroupBy(x => x.StoreId)) + { +

@(grp.First().StoreName):
- @foreach (var file in grp) + foreach (var file in grp) { - + } -

+ } } } - else + else if (Model.DeploymentType == ExportDeploymentType.Email) { -
@Model.FileSystemPath
+
@Model.EmailAddresses
} -} -else if (Model.DeploymentType == ExportDeploymentType.Email) -{ -
@Model.EmailAddresses
-} -else if (Model.DeploymentType == ExportDeploymentType.Http) -{ -
@Model.Url
-} -else if (Model.DeploymentType == ExportDeploymentType.Ftp) -{ -
@Model.Url
-} + else if (Model.DeploymentType == ExportDeploymentType.Http) + { +
@Model.Url
+ } + else if (Model.DeploymentType == ExportDeploymentType.Ftp) + { +
@Model.Url
+ } +
\ No newline at end of file diff --git a/src/Presentation/SmartStore.Web/Administration/Views/Export/List.cshtml b/src/Presentation/SmartStore.Web/Administration/Views/Export/List.cshtml index c1e1a0beb3..9ddcf27347 100644 --- a/src/Presentation/SmartStore.Web/Administration/Views/Export/List.cshtml +++ b/src/Presentation/SmartStore.Web/Administration/Views/Export/List.cshtml @@ -131,7 +131,7 @@ else
- -
+
@if (Model.ShippingOptions.Any()) {
@@ -107,10 +107,13 @@
}
-
-
- @Html.Raw(String.Format(T("ShoppingCart.ShippingInfoLink"), Url.RouteUrl("Topic", new { SystemName = "shippinginfo" }))) + @if (Model.ShippingInfoUrl.HasValue()) + { +
+ @Html.Raw(T("ShoppingCart.ShippingInfoLink", Model.ShippingInfoUrl)) +
+ }
} \ No newline at end of file From 9fd8247a3e5e5799e54efe79385d37d337c4b597 Mon Sep 17 00:00:00 2001 From: Murat Cakir Date: Mon, 30 Nov 2015 23:21:34 +0100 Subject: [PATCH 110/707] Minor comment fix --- src/Presentation/SmartStore.Web/Global.asax.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Presentation/SmartStore.Web/Global.asax.cs b/src/Presentation/SmartStore.Web/Global.asax.cs index 1ab1679bc0..ed07214c7e 100644 --- a/src/Presentation/SmartStore.Web/Global.asax.cs +++ b/src/Presentation/SmartStore.Web/Global.asax.cs @@ -115,7 +115,7 @@ protected void Application_Start() HostingEnvironment.RegisterVirtualPathProvider(new PluginDebugViewVirtualPathProvider()); } - // Install filter + // "throw-away" filter for task scheduler initialization (the filter removes itself when processed) GlobalFilters.Filters.Add(new InitializeSchedulerFilter()); } else From 0a67d0e374feb96138393722c524919b0ee080a6 Mon Sep 17 00:00:00 2001 From: Murat Cakir Date: Tue, 1 Dec 2015 01:29:30 +0100 Subject: [PATCH 111/707] FastProperty did not handle caching strategy as expected --- .../Utilities/Reflection/FastProperty.cs | 33 +++---- .../Configuration/SettingService.cs | 2 +- .../Localization/LocalizationExtentions.cs | 2 +- .../WebApi/WebApiEntityController.cs | 4 +- .../FastPropertyTests.cs | 95 +++++++++++++++++++ .../SmartStore.Core.Tests.csproj | 1 + 6 files changed, 115 insertions(+), 22 deletions(-) create mode 100644 src/Tests/SmartStore.Core.Tests/FastPropertyTests.cs diff --git a/src/Libraries/SmartStore.Core/Utilities/Reflection/FastProperty.cs b/src/Libraries/SmartStore.Core/Utilities/Reflection/FastProperty.cs index 3d1c61590c..09775e9545 100644 --- a/src/Libraries/SmartStore.Core/Utilities/Reflection/FastProperty.cs +++ b/src/Libraries/SmartStore.Core/Utilities/Reflection/FastProperty.cs @@ -16,15 +16,15 @@ public enum PropertyCachingStrategy /// /// Don't cache FastProperty instances /// - Uncached, + Uncached = 0, /// /// Always cache FastProperty instances /// - Cached, + Cached = 1, /// /// Always cache FastProperty instances. PLUS cache all other properties of the declaring type. /// - EagerCached + EagerCached = 2 } public class FastProperty @@ -85,7 +85,7 @@ public bool IsPublicSettable _isPublicSettable = Property.CanWrite && Property.GetSetMethod(false) != null; } return _isPublicSettable.Value; - } + } } public bool IsSequenceType @@ -125,7 +125,7 @@ public Action ValueSetter public object GetValue(object instance) { return ValueGetter(instance); - } + } /// /// Sets the property value for the specified . @@ -208,16 +208,15 @@ public static IReadOnlyDictionary GetVisibleProperties(Typ } public static FastProperty GetProperty( - T type, - Expression> property, + Expression> property, PropertyCachingStrategy cachingStrategy = PropertyCachingStrategy.Cached) { - return GetProperty(typeof(T), property.ExtractPropertyInfo(), cachingStrategy); + return GetProperty(property.ExtractPropertyInfo(), cachingStrategy); } public static FastProperty GetProperty( - Type type, - string propertyName, + Type type, + string propertyName, PropertyCachingStrategy cachingStrategy = PropertyCachingStrategy.Cached) { Guard.ArgumentNotNull(() => type); @@ -233,7 +232,7 @@ public static FastProperty GetProperty( var key = new PropertyKey(type, propertyName); if (!_singlePropertiesCache.TryGetValue(key, out fastProperty)) { - var pi = type.GetProperty(propertyName, BindingFlags.GetProperty | BindingFlags.IgnoreCase); + var pi = type.GetProperty(propertyName, BindingFlags.Public | BindingFlags.Static | BindingFlags.Instance | BindingFlags.IgnoreCase); if (pi != null) { fastProperty = CreateInstance(pi); @@ -248,21 +247,19 @@ public static FastProperty GetProperty( } public static FastProperty GetProperty( - Type type, PropertyInfo propertyInfo, PropertyCachingStrategy cachingStrategy = PropertyCachingStrategy.Cached) { - Guard.ArgumentNotNull(() => type); Guard.ArgumentNotNull(() => propertyInfo); FastProperty fastProperty = null; - if (TryGetCachedProperty(type, propertyInfo.Name, cachingStrategy == PropertyCachingStrategy.EagerCached, out fastProperty)) + if (TryGetCachedProperty(propertyInfo.ReflectedType, propertyInfo.Name, cachingStrategy == PropertyCachingStrategy.EagerCached, out fastProperty)) { return fastProperty; } - var key = new PropertyKey(type, propertyInfo.Name); + var key = new PropertyKey(propertyInfo.ReflectedType, propertyInfo.Name); if (!_singlePropertiesCache.TryGetValue(key, out fastProperty)) { fastProperty = CreateInstance(propertyInfo); @@ -588,11 +585,11 @@ protected static IDictionary GetVisibleProperties( break; } - if (currentTypeInfo.BaseType != null) + if (currentTypeInfo.BaseType != null) { currentTypeInfo = currentTypeInfo.BaseType.GetTypeInfo(); } - + } if (!ignoreProperty) @@ -619,7 +616,7 @@ protected static IDictionary GetProperties( if (!cache.TryGetValue(type, out fastProperties)) { var candidates = GetCandidateProperties(type); - fastProperties = candidates.Select(p => createPropertyHelper(p)).ToDictionary(x => x.Name, StringComparer.OrdinalIgnoreCase); + fastProperties = candidates.Select(p => createPropertyHelper(p)).ToDictionary(x => x.Name, StringComparer.OrdinalIgnoreCase); cache.TryAdd(type, fastProperties); } diff --git a/src/Libraries/SmartStore.Services/Configuration/SettingService.cs b/src/Libraries/SmartStore.Services/Configuration/SettingService.cs index cddc88a5e1..58659b3386 100644 --- a/src/Libraries/SmartStore.Services/Configuration/SettingService.cs +++ b/src/Libraries/SmartStore.Services/Configuration/SettingService.cs @@ -466,7 +466,7 @@ public virtual void SaveSetting(T settings, string key = typeof(T).Name + "." + propInfo.Name; // Duck typing is not supported in C#. That's why we're using dynamic type - var fastProp = FastProperty.GetProperty(settings.GetType(), propInfo, PropertyCachingStrategy.EagerCached); + var fastProp = FastProperty.GetProperty(propInfo, PropertyCachingStrategy.EagerCached); dynamic value = fastProp.GetValue(settings); SetSetting(key, value ?? "", storeId, false); diff --git a/src/Libraries/SmartStore.Services/Localization/LocalizationExtentions.cs b/src/Libraries/SmartStore.Services/Localization/LocalizationExtentions.cs index 72f1524895..3fb8b75d82 100644 --- a/src/Libraries/SmartStore.Services/Localization/LocalizationExtentions.cs +++ b/src/Libraries/SmartStore.Services/Localization/LocalizationExtentions.cs @@ -321,7 +321,7 @@ public static string GetLocalizedValue(this PluginDescriptor descriptor, ILocali if (String.IsNullOrEmpty(result) && returnDefaultValue) { - var fastProp = FastProperty.GetProperty(descriptor.GetType(), propertyName, PropertyCachingStrategy.EagerCached); + var fastProp = FastProperty.GetProperty(descriptor.GetType(), propertyName); if (fastProp != null) { result = fastProp.GetValue(descriptor) as string; diff --git a/src/Presentation/SmartStore.Web.Framework/WebApi/WebApiEntityController.cs b/src/Presentation/SmartStore.Web.Framework/WebApi/WebApiEntityController.cs index b789c1785c..beea7244e8 100644 --- a/src/Presentation/SmartStore.Web.Framework/WebApi/WebApiEntityController.cs +++ b/src/Presentation/SmartStore.Web.Framework/WebApi/WebApiEntityController.cs @@ -89,7 +89,7 @@ protected virtual internal HttpResponseMessage UnmappedGetProperty(ODataPath oda propertyName = propertySegment.PropertyName; if (propertyName.HasValue()) - prop = FastProperty.GetProperty(entity.GetType(), propertyName, PropertyCachingStrategy.EagerCached); + prop = FastProperty.GetProperty(entity.GetType(), propertyName); if (prop == null) return UnmappedGetProperty(entity, propertyName ?? ""); @@ -471,7 +471,7 @@ protected internal virtual TEntity FulfillPropertiesOn(TEntity entity) if (propertyName.HasValue() && queryValue.HasValue()) { - var prop = FastProperty.GetProperty(entity.GetType(), propertyName, PropertyCachingStrategy.EagerCached); + var prop = FastProperty.GetProperty(entity.GetType(), propertyName); if (prop != null) { var propertyValue = prop.GetValue(entity); diff --git a/src/Tests/SmartStore.Core.Tests/FastPropertyTests.cs b/src/Tests/SmartStore.Core.Tests/FastPropertyTests.cs new file mode 100644 index 0000000000..4cba9dc3f3 --- /dev/null +++ b/src/Tests/SmartStore.Core.Tests/FastPropertyTests.cs @@ -0,0 +1,95 @@ +using System; +using System.Collections.Generic; +using NUnit.Framework; +using SmartStore.Core.Domain.Catalog; +using SmartStore.Tests; +using SmartStore.Utilities.Reflection; + +namespace SmartStore.Core.Tests +{ + [TestFixture] + public class FastPropertyTests + { + [Test] + public void CanCreateFastPropertyByLambda() + { + var fastProp = FastProperty.GetProperty(x => x.Name, PropertyCachingStrategy.Cached); + fastProp.ShouldNotBeNull(); + + Assert.AreEqual(fastProp.Property.Name, "Name"); + + // from cache + var fastProp2 = FastProperty.GetProperty(x => x.Name); + Assert.AreSame(fastProp, fastProp2); + } + + [Test] + public void CanCreateFastPropertyByPropInfo() + { + var pi = typeof(Product).GetProperty("Name"); + + var fastProp = FastProperty.GetProperty(pi, PropertyCachingStrategy.Cached); + fastProp.ShouldNotBeNull(); + + Assert.AreEqual(fastProp.Property.Name, "Name"); + + // from cache + var fastProp2 = FastProperty.GetProperty(x => x.Name); + Assert.AreSame(fastProp, fastProp2); + Assert.AreSame(fastProp.Property, pi); + } + + [Test] + public void CanCreateFastPropertyByName() + { + var fastProp = FastProperty.GetProperty(typeof(Product), "Name", PropertyCachingStrategy.Cached); + fastProp.ShouldNotBeNull(); + + Assert.AreEqual(fastProp.Property.Name, "Name"); + + // from cache + var fastProp2 = FastProperty.GetProperty(x => x.Name); + Assert.AreSame(fastProp, fastProp2); + + var product = new Product { Name = "MyName" }; + var name = fastProp.GetValue(product); + + Assert.AreEqual("MyName", name); + } + } + + public class TestClass + { + public TestClass() + { + } + public TestClass(IEnumerable param1) + { + } + public TestClass(int param1) + { + } + public TestClass(IEnumerable param1, int param2) + { + } + public TestClass(IEnumerable param1, int param2, string param3) + { + } + public TestClass(DateTime param1) + { + } + public TestClass(double param1) + { + } + public TestClass(decimal param1) + { + } + public TestClass(long param1) + { + } + } + +} + + + diff --git a/src/Tests/SmartStore.Core.Tests/SmartStore.Core.Tests.csproj b/src/Tests/SmartStore.Core.Tests/SmartStore.Core.Tests.csproj index 7563fbc2f2..398459e843 100644 --- a/src/Tests/SmartStore.Core.Tests/SmartStore.Core.Tests.csproj +++ b/src/Tests/SmartStore.Core.Tests/SmartStore.Core.Tests.csproj @@ -84,6 +84,7 @@ + From f21474c7c12bbd41da6f58f24c1c0c2452da5f73 Mon Sep 17 00:00:00 2001 From: Marcus Gesing Date: Tue, 1 Dec 2015 12:47:26 +0100 Subject: [PATCH 112/707] Moved some string resources into plugin --- .../201511271019577_ExportFramework3.cs | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/src/Libraries/SmartStore.Data/Migrations/201511271019577_ExportFramework3.cs b/src/Libraries/SmartStore.Data/Migrations/201511271019577_ExportFramework3.cs index 00ea19fba6..848f18de7a 100644 --- a/src/Libraries/SmartStore.Data/Migrations/201511271019577_ExportFramework3.cs +++ b/src/Libraries/SmartStore.Data/Migrations/201511271019577_ExportFramework3.cs @@ -94,14 +94,6 @@ public void MigrateLocaleResources(LocaleResourcesBuilder builder) "Export files", "Exportdateien"); - builder.AddOrUpdate("Admin.Common.ExportToCsv.All", - "Export to CSV (all)", - "Alles als CSV exportieren"); - - builder.AddOrUpdate("Admin.Common.ExportToCsv.Selected", - "Export to CSV (selected)", - "Nur Ausgewhlte nach CSV exportieren"); - builder.AddOrUpdate("Admin.Configuration.Payment.Methods.RestrictionNote", "There were no possibilities found to restrict payment methods.", @@ -126,7 +118,12 @@ public void MigrateLocaleResources(LocaleResourcesBuilder builder) "Enums.SmartStore.Core.Domain.Common.CountryRestrictionContextType.ShippingAddress", "Admin.Configuration.Shipping.Methods.ExcludedCustomerRole", "Admin.Configuration.Shipping.Methods.ExcludedCountry", - "Admin.Configuration.Restrictions.CountryExclusionContext" + "Admin.Configuration.Restrictions.CountryExclusionContext", + "Admin.Common.ExportToXml.All", + "Admin.Common.ExportToXml.Selected", + "Admin.Common.ExportToCsv.All", + "Admin.Common.ExportToCsv.Selected", + "Admin.Common.ExportToCsv" ); } } From 5ffbbd0ec74ec11f3758c782d655f363ce338388 Mon Sep 17 00:00:00 2001 From: Murat Cakir Date: Tue, 1 Dec 2015 18:29:23 +0100 Subject: [PATCH 113/707] * Added "Services" property to ICommonServices (useful to resolve other services from current Autofac lifetime scope) * Any property with type ICommonServices gets auto-injected by Autofac * Minor refactoring in WebApiEntityController --- .../DefaultLifetimeScopeAccessor.cs | 20 +- .../SmartStore.Services/CommonServices.cs | 16 +- .../SmartStore.Services/ICommonServices.cs | 10 +- .../DependencyRegistrar.cs | 296 ++++++++++-------- .../WebApi/AutofacWebApiDependencyResolver.cs | 11 +- .../WebApi/WebApiEntityController.cs | 47 ++- 6 files changed, 230 insertions(+), 170 deletions(-) diff --git a/src/Libraries/SmartStore.Core/Infrastructure/DependencyManagement/DefaultLifetimeScopeAccessor.cs b/src/Libraries/SmartStore.Core/Infrastructure/DependencyManagement/DefaultLifetimeScopeAccessor.cs index 79626e5775..03e0fbbba7 100644 --- a/src/Libraries/SmartStore.Core/Infrastructure/DependencyManagement/DefaultLifetimeScopeAccessor.cs +++ b/src/Libraries/SmartStore.Core/Infrastructure/DependencyManagement/DefaultLifetimeScopeAccessor.cs @@ -71,17 +71,17 @@ public ILifetimeScope GetLifetimeScope(Action configurationAct return scope; } - private void OnScopeBeginning(object sender, LifetimeScopeBeginningEventArgs args) - { - bool isWeb = System.Web.HttpContext.Current != null; - Debug.WriteLine("Scope Begin, Web: " + isWeb); - } + //private void OnScopeBeginning(object sender, LifetimeScopeBeginningEventArgs args) + //{ + // bool isWeb = System.Web.HttpContext.Current != null; + // Debug.WriteLine("Scope Begin, Web: " + isWeb); + //} - private void OnScopeEnding(object sender, LifetimeScopeEndingEventArgs args) - { - bool isWeb = System.Web.HttpContext.Current != null; - Debug.WriteLine("Scope END, Web: " + isWeb); - } + //private void OnScopeEnding(object sender, LifetimeScopeEndingEventArgs args) + //{ + // bool isWeb = System.Web.HttpContext.Current != null; + // Debug.WriteLine("Scope END, Web: " + isWeb); + //} private ILifetimeScope BeginLifetimeScope(Action configurationAction) { diff --git a/src/Libraries/SmartStore.Services/CommonServices.cs b/src/Libraries/SmartStore.Services/CommonServices.cs index 86742ade49..df20bfdadb 100644 --- a/src/Libraries/SmartStore.Services/CommonServices.cs +++ b/src/Libraries/SmartStore.Services/CommonServices.cs @@ -10,11 +10,13 @@ using SmartStore.Services.Security; using SmartStore.Services.Configuration; using SmartStore.Services.Stores; +using Autofac; namespace SmartStore.Services { public class CommonServices : ICommonServices { + private readonly IComponentContext _container; private readonly Lazy _cache; private readonly Lazy _dbContext; private readonly Lazy _storeContext; @@ -29,7 +31,8 @@ public class CommonServices : ICommonServices private readonly Lazy _storeService; public CommonServices( - Func> cache, + IComponentContext container, + Func> cache, Lazy dbContext, Lazy storeContext, Lazy webHelper, @@ -42,6 +45,7 @@ public CommonServices( Lazy settings, Lazy storeService) { + this._container = container; this._cache = cache("static"); this._dbContext = dbContext; this._storeContext = storeContext; @@ -55,7 +59,15 @@ public CommonServices( this._settings = settings; this._storeService = storeService; } - + + public IComponentContext Container + { + get + { + return _container; + } + } + public ICacheManager Cache { get diff --git a/src/Libraries/SmartStore.Services/ICommonServices.cs b/src/Libraries/SmartStore.Services/ICommonServices.cs index cc9a048b54..37b0fc1838 100644 --- a/src/Libraries/SmartStore.Services/ICommonServices.cs +++ b/src/Libraries/SmartStore.Services/ICommonServices.cs @@ -10,12 +10,17 @@ using SmartStore.Services.Security; using SmartStore.Services.Configuration; using SmartStore.Services.Stores; +using Autofac; namespace SmartStore.Services -{ - +{ public interface ICommonServices { + IComponentContext Container + { + get; + } + ICacheManager Cache { get; @@ -76,5 +81,4 @@ IStoreService StoreService get; } } - } diff --git a/src/Presentation/SmartStore.Web.Framework/DependencyRegistrar.cs b/src/Presentation/SmartStore.Web.Framework/DependencyRegistrar.cs index e8cd2fdfc7..28d0b9e187 100644 --- a/src/Presentation/SmartStore.Web.Framework/DependencyRegistrar.cs +++ b/src/Presentation/SmartStore.Web.Framework/DependencyRegistrar.cs @@ -87,8 +87,9 @@ public virtual void Register(ContainerBuilder builder, ITypeFinder typeFinder, b var pluginFinder = new PluginFinder(); builder.RegisterInstance(pluginFinder).As().SingleInstance(); builder.RegisterType(); - + // modules + builder.RegisterModule(new CoreModule(typeFinder)); builder.RegisterModule(new DbModule(typeFinder)); builder.RegisterModule(new CachingModule()); builder.RegisterModule(new LocalizationModule()); @@ -102,20 +103,40 @@ public virtual void Register(ContainerBuilder builder, ITypeFinder typeFinder, b builder.RegisterModule(new PackagingModule()); builder.RegisterModule(new ProvidersModule(typeFinder, pluginFinder)); builder.RegisterModule(new TasksModule(typeFinder)); + } + + public int Order + { + get { return -100; } + } + } + + #region Modules + public class CoreModule : Module + { + private readonly ITypeFinder _typeFinder; + + public CoreModule(ITypeFinder typeFinder) + { + _typeFinder = typeFinder; + } + + protected override void Load(ContainerBuilder builder) + { // sources builder.RegisterSource(new SettingsSource()); - // web helper - builder.RegisterType().As().InstancePerRequest(); + // web helper + builder.RegisterType().As().InstancePerRequest(); + + // work context + builder.RegisterType().As().WithStaticCache().InstancePerRequest(); - // work context - builder.RegisterType().As().WithStaticCache().InstancePerRequest(); - // store context builder.RegisterType().As().InstancePerRequest(); - // services + // services builder.RegisterType().As().InstancePerRequest(); builder.RegisterType().Named("nocache") .WithNullCache() @@ -131,42 +152,42 @@ public virtual void Register(ContainerBuilder builder, ITypeFinder typeFinder, b builder.RegisterType().As().InstancePerRequest(); builder.RegisterType().Named("nocache").InstancePerRequest(); - builder.RegisterType().As().InstancePerRequest(); - builder.RegisterType().As().InstancePerRequest(); - builder.RegisterType().As().InstancePerRequest(); - builder.RegisterType().As().InstancePerRequest(); - builder.RegisterType().As().InstancePerRequest(); - builder.RegisterType().As().InstancePerLifetimeScope(); - builder.RegisterType().As().InstancePerRequest(); + builder.RegisterType().As().InstancePerRequest(); + builder.RegisterType().As().InstancePerRequest(); + builder.RegisterType().As().InstancePerRequest(); + builder.RegisterType().As().InstancePerRequest(); + builder.RegisterType().As().InstancePerRequest(); + builder.RegisterType().As().InstancePerLifetimeScope(); + builder.RegisterType().As().InstancePerRequest(); builder.RegisterType().As().InstancePerRequest(); - builder.RegisterType().As().InstancePerRequest(); + builder.RegisterType().As().InstancePerRequest(); builder.RegisterType().As().InstancePerRequest(); - builder.RegisterType().As().InstancePerRequest(); + builder.RegisterType().As().InstancePerRequest(); builder.RegisterType().As().InstancePerRequest(); builder.RegisterType().As().InstancePerRequest(); builder.RegisterType().As().WithStaticCache().InstancePerRequest(); - builder.RegisterType().As().InstancePerRequest(); - builder.RegisterType().As().InstancePerRequest(); + builder.RegisterType().As().InstancePerRequest(); + builder.RegisterType().As().InstancePerRequest(); builder.RegisterType().As().InstancePerRequest(); - builder.RegisterType().As().InstancePerRequest(); - builder.RegisterType().As().InstancePerRequest(); + builder.RegisterType().As().InstancePerRequest(); + builder.RegisterType().As().InstancePerRequest(); builder.RegisterType().As().InstancePerRequest(); builder.RegisterType().As().InstancePerRequest(); - builder.RegisterType().As().InstancePerRequest(); - builder.RegisterType().As().InstancePerRequest(); + builder.RegisterType().As().InstancePerRequest(); + builder.RegisterType().As().InstancePerRequest(); - builder.RegisterType().As().WithStaticCache() .InstancePerRequest(); + builder.RegisterType().As().WithStaticCache().InstancePerRequest(); - builder.RegisterType().As().WithStaticCache().InstancePerRequest(); + builder.RegisterType().As().WithStaticCache().InstancePerRequest(); - builder.RegisterType().As().InstancePerRequest(); + builder.RegisterType().As().InstancePerRequest(); builder.RegisterType().As().InstancePerRequest(); builder.RegisterType().As().InstancePerRequest(); builder.RegisterType().As().InstancePerRequest(); - builder.RegisterType().As().InstancePerRequest(); + builder.RegisterType().As().InstancePerRequest(); builder.RegisterType().As().InstancePerRequest(); builder.RegisterType().As().InstancePerRequest(); @@ -175,73 +196,135 @@ public virtual void Register(ContainerBuilder builder, ITypeFinder typeFinder, b builder.RegisterType().As().InstancePerRequest(); - builder.RegisterType().As().WithStaticCache().InstancePerRequest(); + builder.RegisterType().As().WithStaticCache().InstancePerRequest(); - builder.RegisterType().As().InstancePerRequest(); - builder.RegisterType().As().InstancePerRequest(); - builder.RegisterType().As().SingleInstance(); - builder.RegisterType().As().InstancePerRequest(); + builder.RegisterType().As().InstancePerRequest(); + builder.RegisterType().As().InstancePerRequest(); + builder.RegisterType().As().SingleInstance(); + builder.RegisterType().As().InstancePerRequest(); - builder.RegisterType().As().InstancePerRequest(); - builder.RegisterType().As().InstancePerRequest(); + builder.RegisterType().As().InstancePerRequest(); + builder.RegisterType().As().InstancePerRequest(); builder.RegisterType().As().InstancePerRequest(); - builder.RegisterType().As().InstancePerRequest(); - builder.RegisterType().As().InstancePerRequest(); - builder.RegisterType().As().InstancePerRequest(); - builder.RegisterType().As().InstancePerRequest(); - builder.RegisterType().As().InstancePerRequest(); - builder.RegisterType().As().InstancePerRequest(); + builder.RegisterType().As().InstancePerRequest(); + builder.RegisterType().As().InstancePerRequest(); + builder.RegisterType().As().InstancePerRequest(); + builder.RegisterType().As().InstancePerRequest(); + builder.RegisterType().As().InstancePerRequest(); + builder.RegisterType().As().InstancePerRequest(); - builder.RegisterType().As().InstancePerRequest(); + builder.RegisterType().As().InstancePerRequest(); - builder.RegisterType().As().InstancePerRequest(); - builder.RegisterType().As().InstancePerRequest(); + builder.RegisterType().As().InstancePerRequest(); + builder.RegisterType().As().InstancePerRequest(); builder.RegisterType().As().WithStaticCache().InstancePerRequest(); - builder.RegisterType().As().InstancePerRequest(); + builder.RegisterType().As().InstancePerRequest(); builder.RegisterType().As().InstancePerRequest(); builder.RegisterType().As().InstancePerRequest(); - builder.RegisterType().As().InstancePerRequest(); + builder.RegisterType().As().InstancePerRequest(); builder.RegisterType().As().InstancePerRequest(); builder.RegisterType().As().InstancePerRequest(); - builder.RegisterType().As().InstancePerRequest(); - builder.RegisterType().As().InstancePerRequest(); - builder.RegisterType().As().InstancePerRequest(); + builder.RegisterType().As().InstancePerRequest(); + builder.RegisterType().As().InstancePerRequest(); + builder.RegisterType().As().InstancePerRequest(); builder.RegisterType().As().InstancePerRequest(); - builder.RegisterType().As().InstancePerRequest(); - builder.RegisterType().As().InstancePerRequest(); - builder.RegisterType().As().InstancePerRequest(); + builder.RegisterType().As().InstancePerRequest(); + builder.RegisterType().As().InstancePerRequest(); + builder.RegisterType().As().InstancePerRequest(); - builder.RegisterType().As().InstancePerRequest(); + builder.RegisterType().As().InstancePerRequest(); - builder.RegisterType().As().InstancePerRequest(); + builder.RegisterType().As().InstancePerRequest(); builder.RegisterType().As().InstancePerRequest(); builder.RegisterType().As().InstancePerRequest(); - builder.RegisterType().As().InstancePerRequest(); + builder.RegisterType().As().InstancePerRequest(); builder.RegisterType().As().InstancePerRequest(); builder.RegisterType().As().InstancePerRequest(); - builder.RegisterType().As().InstancePerRequest(); - builder.RegisterType().As().InstancePerRequest(); + builder.RegisterType().As().InstancePerRequest(); + builder.RegisterType().As().InstancePerRequest(); - builder.RegisterType().As().InstancePerRequest(); + builder.RegisterType().As().InstancePerRequest(); builder.RegisterType().As().WithStaticCache().InstancePerRequest(); - } + } - public int Order - { - get { return -100; } - } - } + protected override void AttachToComponentRegistration(IComponentRegistry componentRegistry, IComponentRegistration registration) + { + // Look for first settable property of type "ICommonServices" and inject + var servicesProperty = FindCommonServicesProperty(registration.Activator.LimitType); - #region Modules + if (servicesProperty == null) + return; + + var fastProperty = new FastProperty(servicesProperty); + + registration.Activated += (sender, e) => + { + if (DataSettings.DatabaseIsInstalled()) + { + var services = e.Context.Resolve(); + fastProperty.SetValue(e.Instance, services); + } + }; + } + + private static PropertyInfo FindCommonServicesProperty(Type type) + { + var prop = type + .GetProperties(BindingFlags.SetProperty | BindingFlags.Public | BindingFlags.Instance) + .Select(p => new + { + PropertyInfo = p, + p.PropertyType, + IndexParameters = p.GetIndexParameters(), + Accessors = p.GetAccessors(false) + }) + .Where(x => x.PropertyType == typeof(ICommonServices)) // must be ICommonServices + .Where(x => x.IndexParameters.Count() == 0) // must not be an indexer + .Where(x => x.Accessors.Length != 1 || x.Accessors[0].ReturnType == typeof(void)) //must have get/set, or only set + .Select(x => x.PropertyInfo) + .FirstOrDefault(); + + return prop; + } + + private IEnumerable> BuildLoggerInjectors(Type componentType) + { + // Look for first settable property of type "ICommonServices" + var loggerProperties = componentType + .GetProperties(BindingFlags.SetProperty | BindingFlags.Public | BindingFlags.Instance) + .Select(p => new + { + PropertyInfo = p, + p.PropertyType, + IndexParameters = p.GetIndexParameters(), + Accessors = p.GetAccessors(false) + }) + .Where(x => x.PropertyType == typeof(ILogger)) // must be a logger + .Where(x => x.IndexParameters.Count() == 0) // must not be an indexer + .Where(x => x.Accessors.Length != 1 || x.Accessors[0].ReturnType == typeof(void)) //must have get/set, or only set + .Select(x => new FastProperty(x.PropertyInfo)); + + // Return an array of actions that resolve a logger and assign the property + foreach (var prop in loggerProperties) + { + yield return (ctx, instance) => + { + string component = componentType.ToString(); + var logger = ctx.Resolve(); + prop.SetValue(instance, logger); + }; + } + } + } public class DbModule : Module { @@ -379,33 +462,30 @@ protected override void AttachToComponentRegistration(IComponentRegistry compone private IEnumerable> BuildLoggerInjectors(Type componentType) { - if (DataSettings.DatabaseIsInstalled()) + // Look for settable properties of type "ILogger" + var loggerProperties = componentType + .GetProperties(BindingFlags.SetProperty | BindingFlags.Public | BindingFlags.Instance) + .Select(p => new + { + PropertyInfo = p, + p.PropertyType, + IndexParameters = p.GetIndexParameters(), + Accessors = p.GetAccessors(false) + }) + .Where(x => x.PropertyType == typeof(ILogger)) // must be a logger + .Where(x => x.IndexParameters.Count() == 0) // must not be an indexer + .Where(x => x.Accessors.Length != 1 || x.Accessors[0].ReturnType == typeof(void)) //must have get/set, or only set + .Select(x => new FastProperty(x.PropertyInfo)); + + // Return an array of actions that resolve a logger and assign the property + foreach (var prop in loggerProperties) { - // Look for settable properties of type "ILogger" - var loggerProperties = componentType - .GetProperties(BindingFlags.SetProperty | BindingFlags.Public | BindingFlags.Instance) - .Select(p => new - { - PropertyInfo = p, - p.PropertyType, - IndexParameters = p.GetIndexParameters(), - Accessors = p.GetAccessors(false) - }) - .Where(x => x.PropertyType == typeof(ILogger)) // must be a logger - .Where(x => x.IndexParameters.Count() == 0) // must not be an indexer - .Where(x => x.Accessors.Length != 1 || x.Accessors[0].ReturnType == typeof(void)) //must have get/set, or only set - .Select(x => new FastProperty(x.PropertyInfo)); - - // Return an array of actions that resolve a logger and assign the property - foreach (var prop in loggerProperties) + yield return (ctx, instance) => { - yield return (ctx, instance) => - { - string component = componentType.ToString(); - var logger = ctx.Resolve(); - prop.SetValue(instance, logger); - }; - } + string component = componentType.ToString(); + var logger = ctx.Resolve(); + prop.SetValue(instance, logger); + }; } } } @@ -657,13 +737,7 @@ protected override void AttachToComponentRegistration(IComponentRegistry compone var repoProperty = FindRepositoryProperty(type, implementingType.GetGenericArguments()[0]); var serviceProperty = FindServiceProperty(type, implementingType.GetGenericArguments()[1]); - var countryServiceProperty = type.GetProperty("CountryService", typeof(ICountryService)); - var stateProvinceServiceProperty = type.GetProperty("StateProvinceService", typeof(IStateProvinceService)); - var languageServiceProperty = type.GetProperty("LanguageService", typeof(ILanguageService)); - var currencyServiceProperty = type.GetProperty("CurrencyService", typeof(ICurrencyService)); - - if (repoProperty != null || serviceProperty != null || - countryServiceProperty != null || stateProvinceServiceProperty != null || languageServiceProperty != null || currencyServiceProperty != null) + if (repoProperty != null || serviceProperty != null) { registration.Activated += (sender, e) => { @@ -678,30 +752,6 @@ protected override void AttachToComponentRegistration(IComponentRegistry compone var service = e.Context.Resolve(serviceProperty.PropertyType); serviceProperty.SetValue(e.Instance, service, null); } - - if (countryServiceProperty != null) - { - var service = e.Context.Resolve(typeof(ICountryService)); - countryServiceProperty.SetValue(e.Instance, service, null); - } - - if (stateProvinceServiceProperty != null) - { - var service = e.Context.Resolve(typeof(IStateProvinceService)); - stateProvinceServiceProperty.SetValue(e.Instance, service, null); - } - - if (languageServiceProperty != null) - { - var service = e.Context.Resolve(typeof(ILanguageService)); - languageServiceProperty.SetValue(e.Instance, service, null); - } - - if (currencyServiceProperty != null) - { - var service = e.Context.Resolve(typeof(ICurrencyService)); - currencyServiceProperty.SetValue(e.Instance, service, null); - } }; } } @@ -1052,14 +1102,6 @@ public IEnumerable RegistrationsFor( { var buildMethod = BuildMethod.MakeGenericMethod(ts.ServiceType); yield return (IComponentRegistration)buildMethod.Invoke(null, null); - - //// Perf with Fasterflect - //yield return (IComponentRegistration)Fasterflect.TryInvokeWithValuesExtensions.TryCallMethodWithValues( - // typeof(SettingsSource), - // null, - // "BuildRegistration", - // new Type[] { ts.ServiceType }, - // BindingFlags.Static | BindingFlags.NonPublic); } } diff --git a/src/Presentation/SmartStore.Web.Framework/WebApi/AutofacWebApiDependencyResolver.cs b/src/Presentation/SmartStore.Web.Framework/WebApi/AutofacWebApiDependencyResolver.cs index 10cb3ceb7c..74ed3154ae 100644 --- a/src/Presentation/SmartStore.Web.Framework/WebApi/AutofacWebApiDependencyResolver.cs +++ b/src/Presentation/SmartStore.Web.Framework/WebApi/AutofacWebApiDependencyResolver.cs @@ -4,6 +4,7 @@ using System.Web.Http.Dependencies; using Autofac; using SmartStore.Core.Infrastructure; +using SmartStore.Core.Infrastructure.DependencyManagement; namespace SmartStore.Web.Framework.WebApi { @@ -14,14 +15,15 @@ public class AutofacWebApiDependencyResolver : IDependencyResolver private bool _disposed; readonly ILifetimeScope _container; readonly IDependencyScope _rootDependencyScope; + readonly ILifetimeScopeAccessor _accessor; internal static readonly string ApiRequestTag = "AutofacWebRequest"; public AutofacWebApiDependencyResolver() { - var container = EngineContext.Current.ContainerManager.Container; - _container = container; - _rootDependencyScope = new AutofacWebApiDependencyScope(container); + _container = EngineContext.Current.ContainerManager.Container; + _accessor = _container.Resolve(); + _rootDependencyScope = new AutofacWebApiDependencyScope(_container); } public ILifetimeScope Container @@ -41,7 +43,8 @@ public IEnumerable GetServices(Type serviceType) public IDependencyScope BeginScope() { - ILifetimeScope lifetimeScope = _container.BeginLifetimeScope(ApiRequestTag); + //ILifetimeScope lifetimeScope = _container.BeginLifetimeScope(ApiRequestTag); + ILifetimeScope lifetimeScope = _accessor.GetLifetimeScope(null); return new AutofacWebApiDependencyScope(lifetimeScope); } diff --git a/src/Presentation/SmartStore.Web.Framework/WebApi/WebApiEntityController.cs b/src/Presentation/SmartStore.Web.Framework/WebApi/WebApiEntityController.cs index beea7244e8..c8889391d0 100644 --- a/src/Presentation/SmartStore.Web.Framework/WebApi/WebApiEntityController.cs +++ b/src/Presentation/SmartStore.Web.Framework/WebApi/WebApiEntityController.cs @@ -5,18 +5,18 @@ using System.Linq.Expressions; using System.Net; using System.Net.Http; -using System.Reflection; using System.Web.Http; using System.Web.Http.OData; using System.Web.Http.OData.Routing; using System.Data.Entity; using SmartStore.Core; using SmartStore.Core.Data; -using SmartStore.Core.Infrastructure; using SmartStore.Services.Directory; using SmartStore.Services.Localization; using System.Collections.Generic; using SmartStore.Utilities.Reflection; +using SmartStore.Services; +using Autofac; namespace SmartStore.Web.Framework.WebApi { @@ -137,16 +137,6 @@ protected virtual internal HttpResponseMessage UnmappedGetNavigation(ODataPath o return base.HandleUnmappedRequest(odataPath); } - //protected virtual IRepository CreateRepository() - //{ - // var repository = EngineContext.Current.Resolve>(); - - // // false means not resolving navigation properties (related entities) - // repository.Context.ProxyCreationEnabled = false; - - // return repository; - //} - /// /// Auto injected by Autofac /// @@ -165,16 +155,20 @@ public virtual TService Service set; } - public virtual ICountryService CountryService { get; set; } - public virtual IStateProvinceService StateProvinceService { get; set; } - public virtual ILanguageService LanguageService { get; set; } - public virtual ICurrencyService CurrencyService { get; set; } + /// + /// Auto injected by Autofac + /// + public virtual ICommonServices Services + { + get; + set; + } public override IQueryable Get() { if (!ModelState.IsValid) throw this.ExceptionInvalidModelState(); - + return this.GetEntitySet(); } @@ -433,22 +427,25 @@ protected internal virtual void Delete(TEntity entity) protected internal virtual object FulfillPropertyOn(TEntity entity, string propertyName, string queryValue) { + var container = Services.Container; + if (propertyName.IsCaseInsensitiveEqual("Country")) { - return CountryService.GetCountryByTwoOrThreeLetterIsoCode(queryValue); + return container.Resolve().GetCountryByTwoOrThreeLetterIsoCode(queryValue); } else if (propertyName.IsCaseInsensitiveEqual("StateProvince")) { - return StateProvinceService.GetStateProvinceByAbbreviation(queryValue); + return container.Resolve().GetStateProvinceByAbbreviation(queryValue); } else if (propertyName.IsCaseInsensitiveEqual("Language")) { - return LanguageService.GetLanguageByCulture(queryValue); + return container.Resolve().GetLanguageByCulture(queryValue); } else if (propertyName.IsCaseInsensitiveEqual("Currency")) { - return CurrencyService.GetCurrencyByCode(queryValue); + return container.Resolve().GetCurrencyByCode(queryValue); } + return null; } @@ -479,7 +476,8 @@ protected internal virtual TEntity FulfillPropertiesOn(TEntity entity) { object value = FulfillPropertyOn(entity, propertyName, queryValue); - if (value != null) // there's no requirement to set a property value of null + // there's no requirement to set a property value of null + if (value != null) { prop.SetValue(entity, value); } @@ -488,10 +486,11 @@ protected internal virtual TEntity FulfillPropertiesOn(TEntity entity) } } } - catch (Exception exc) + catch (Exception ex) { - throw this.ExceptionUnprocessableEntity(exc.Message); + throw this.ExceptionUnprocessableEntity(ex.Message); } + return entity; } } From 503bbb2a48e071651250415bd7b2dedb42fbd3cf Mon Sep 17 00:00:00 2001 From: Murat Cakir Date: Tue, 1 Dec 2015 18:53:56 +0100 Subject: [PATCH 114/707] WebApi test client did not save and load user settings correctly --- .../SmartStore.WebApi.Client/MainForm.cs | 75 +++++++++++-------- 1 file changed, 43 insertions(+), 32 deletions(-) diff --git a/src/Tools/SmartStore.WebApi.Client/MainForm.cs b/src/Tools/SmartStore.WebApi.Client/MainForm.cs index be4c903df9..7c282f6265 100644 --- a/src/Tools/SmartStore.WebApi.Client/MainForm.cs +++ b/src/Tools/SmartStore.WebApi.Client/MainForm.cs @@ -14,30 +14,51 @@ public MainForm() { InitializeComponent(); - this.FormClosing += MainForm_Closing; - this.Text = Program.AppName; - cboMethod.SelectedIndex = 0; - radioJson.Checked = true; - radioOdata.Checked = true; - txtPublicKey.Text = Settings.Default.ApiPublicKey; - txtSecretKey.Text = Settings.Default.ApiSecretKey; - cboPath.Items.FromString(Settings.Default.ApiPaths); - cboQuery.Items.FromString(Settings.Default.ApiQuery); - cboContent.Items.FromString(Settings.Default.ApiContent); - - if (cboPath.Items.Count <= 0) - cboPath.Items.Add("/Customers"); - - cboMethod_changeCommitted(null, null); - radioApi_CheckedChanged(null, null); - - openFileDialog1.Filter = "Image files (*.jpg, *.jpeg, *.jpe, *.jfif, *.png) | *.jpg; *.jpeg; *.jpe; *.jfif; *.png"; - openFileDialog1.DefaultExt = ".jpg"; - openFileDialog1.FileName = ""; - openFileDialog1.Title = "Please select an image file to upload"; - openFileDialog1.Multiselect = true; + this.Load += (object sender, EventArgs e) => + { + var s = Settings.Default; + s.Reload(); + + cboMethod.SelectedIndex = 0; + radioJson.Checked = true; + radioOdata.Checked = true; + txtPublicKey.Text = s.ApiPublicKey; + txtSecretKey.Text = s.ApiSecretKey; + txtUrl.Text = s.ApiUrl; + txtVersion.Text = s.ApiVersion; + cboPath.Items.FromString(s.ApiPaths); + cboQuery.Items.FromString(s.ApiQuery); + cboContent.Items.FromString(s.ApiContent); + + if (cboPath.Items.Count <= 0) + cboPath.Items.Add("/Customers"); + + cboMethod_changeCommitted(null, null); + radioApi_CheckedChanged(null, null); + + openFileDialog1.Filter = "Image files (*.jpg, *.jpeg, *.jpe, *.jfif, *.png) | *.jpg; *.jpeg; *.jpe; *.jfif; *.png"; + openFileDialog1.DefaultExt = ".jpg"; + openFileDialog1.FileName = ""; + openFileDialog1.Title = "Please select an image file to upload"; + openFileDialog1.Multiselect = true; + }; + + this.FormClosing += (object sender, FormClosingEventArgs e) => + { + var s = Settings.Default; + + s.ApiPublicKey = txtPublicKey.Text; + s.ApiSecretKey = txtSecretKey.Text; + s.ApiUrl = txtUrl.Text; + s.ApiVersion = txtVersion.Text; + Settings.Default[radioOdata.Checked ? "ApiPaths" : "ApiPaths2"] = cboPath.Items.IntoString(); + s.ApiQuery = cboQuery.Items.IntoString(); + s.ApiContent = cboContent.Items.IntoString(); + + s.Save(); + }; } private void CallTheApi() @@ -120,16 +141,6 @@ private void SavePathItems(bool odata) cboPath.Items.Clear(); cboPath.Items.FromString(odata ? Settings.Default.ApiPaths : Settings.Default.ApiPaths2); } - - private void MainForm_Closing(object sender, FormClosingEventArgs e) - { - Settings.Default["ApiPublicKey"] = txtPublicKey.Text; - Settings.Default["ApiSecretKey"] = txtSecretKey.Text; - Settings.Default[radioOdata.Checked ? "ApiPaths" : "ApiPaths2"] = cboPath.Items.IntoString(); - Settings.Default["ApiQuery"] = cboQuery.Items.IntoString(); - Settings.Default["ApiContent"] = cboContent.Items.IntoString(); - Settings.Default.Save(); - } private void MainForm_Shown(object sender, EventArgs e) { From 236f8a725eb7442ad37178aa09461ae4ab66836c Mon Sep 17 00:00:00 2001 From: Murat Cakir Date: Tue, 1 Dec 2015 22:50:30 +0100 Subject: [PATCH 115/707] Moved FastProperty & FastActivator to namespace SmartStore.ComponentModel --- .../Reflection => ComponentModel}/FastActivator.cs | 4 +--- .../Reflection => ComponentModel}/FastProperty.cs | 2 +- .../SmartStore.Core/ComponentModel/HybridExpando.cs | 1 - .../SmartStore.Core/Infrastructure/ComparableObject.cs | 3 +-- .../DependencyManagement/ContainerManager.cs | 2 +- src/Libraries/SmartStore.Core/SmartStore.Core.csproj | 4 ++-- src/Libraries/SmartStore.Core/Utilities/CommonHelper.cs | 4 +--- .../SmartStore.Core/Utilities/DictionaryConverter.cs | 2 +- .../SmartStore.Data/Extensions/DataReaderExtensions.cs | 2 +- .../SmartStore.Services/Configuration/SettingService.cs | 7 ------- .../SmartStore.Services/DataExchange/Import/ImportRow.cs | 2 +- .../Localization/LocalizationExtentions.cs | 2 +- .../SmartStore.Web.Framework/DependencyRegistrar.cs | 2 +- .../Settings/StoreDependingSettingHelper.cs | 2 +- .../WebApi/WebApiEntityController.cs | 2 +- .../Views/Product/ProductTemplate.Simple.cshtml | 2 +- src/Tests/SmartStore.Core.Tests/FastPropertyTests.cs | 2 +- src/Tests/SmartStore.Core.Tests/PerformanceTests.cs | 1 - 18 files changed, 16 insertions(+), 30 deletions(-) rename src/Libraries/SmartStore.Core/{Utilities/Reflection => ComponentModel}/FastActivator.cs (98%) rename src/Libraries/SmartStore.Core/{Utilities/Reflection => ComponentModel}/FastProperty.cs (99%) diff --git a/src/Libraries/SmartStore.Core/Utilities/Reflection/FastActivator.cs b/src/Libraries/SmartStore.Core/ComponentModel/FastActivator.cs similarity index 98% rename from src/Libraries/SmartStore.Core/Utilities/Reflection/FastActivator.cs rename to src/Libraries/SmartStore.Core/ComponentModel/FastActivator.cs index ce0ea4b9a2..79a4362f30 100644 --- a/src/Libraries/SmartStore.Core/Utilities/Reflection/FastActivator.cs +++ b/src/Libraries/SmartStore.Core/ComponentModel/FastActivator.cs @@ -1,13 +1,11 @@ using System; using System.Collections.Generic; using System.Linq; -using System.Text; using System.Reflection; -using System.Threading.Tasks; using System.Linq.Expressions; using System.Collections.Concurrent; -namespace SmartStore.Utilities.Reflection +namespace SmartStore.ComponentModel { public class FastActivator { diff --git a/src/Libraries/SmartStore.Core/Utilities/Reflection/FastProperty.cs b/src/Libraries/SmartStore.Core/ComponentModel/FastProperty.cs similarity index 99% rename from src/Libraries/SmartStore.Core/Utilities/Reflection/FastProperty.cs rename to src/Libraries/SmartStore.Core/ComponentModel/FastProperty.cs index 09775e9545..01c4473f51 100644 --- a/src/Libraries/SmartStore.Core/Utilities/Reflection/FastProperty.cs +++ b/src/Libraries/SmartStore.Core/ComponentModel/FastProperty.cs @@ -9,7 +9,7 @@ using System.Linq.Expressions; using System.Reflection; -namespace SmartStore.Utilities.Reflection +namespace SmartStore.ComponentModel { public enum PropertyCachingStrategy { diff --git a/src/Libraries/SmartStore.Core/ComponentModel/HybridExpando.cs b/src/Libraries/SmartStore.Core/ComponentModel/HybridExpando.cs index 9c6bc8f333..5d595bb57f 100644 --- a/src/Libraries/SmartStore.Core/ComponentModel/HybridExpando.cs +++ b/src/Libraries/SmartStore.Core/ComponentModel/HybridExpando.cs @@ -37,7 +37,6 @@ using System.Dynamic; using System.Reflection; using System.Collections; -using SmartStore.Utilities.Reflection; namespace SmartStore.ComponentModel { diff --git a/src/Libraries/SmartStore.Core/Infrastructure/ComparableObject.cs b/src/Libraries/SmartStore.Core/Infrastructure/ComparableObject.cs index 7291139dd8..940d9851aa 100644 --- a/src/Libraries/SmartStore.Core/Infrastructure/ComparableObject.cs +++ b/src/Libraries/SmartStore.Core/Infrastructure/ComparableObject.cs @@ -3,10 +3,9 @@ using System.Linq; using System.Linq.Expressions; using System.Reflection; -using System.ComponentModel; -using SmartStore.Utilities.Reflection; using SmartStore.Utilities; using System.Collections.Concurrent; +using SmartStore.ComponentModel; namespace SmartStore { diff --git a/src/Libraries/SmartStore.Core/Infrastructure/DependencyManagement/ContainerManager.cs b/src/Libraries/SmartStore.Core/Infrastructure/DependencyManagement/ContainerManager.cs index 6e314c8f0c..7b1bbc9292 100644 --- a/src/Libraries/SmartStore.Core/Infrastructure/DependencyManagement/ContainerManager.cs +++ b/src/Libraries/SmartStore.Core/Infrastructure/DependencyManagement/ContainerManager.cs @@ -5,8 +5,8 @@ using System.Reflection; using Autofac; using Autofac.Builder; +using SmartStore.ComponentModel; using SmartStore.Core.Caching; -using SmartStore.Utilities.Reflection; namespace SmartStore.Core.Infrastructure.DependencyManagement { diff --git a/src/Libraries/SmartStore.Core/SmartStore.Core.csproj b/src/Libraries/SmartStore.Core/SmartStore.Core.csproj index 6b90d23447..afe8a97f1d 100644 --- a/src/Libraries/SmartStore.Core/SmartStore.Core.csproj +++ b/src/Libraries/SmartStore.Core/SmartStore.Core.csproj @@ -570,11 +570,11 @@ - + - + diff --git a/src/Libraries/SmartStore.Core/Utilities/CommonHelper.cs b/src/Libraries/SmartStore.Core/Utilities/CommonHelper.cs index ad14f03a1a..5890760b28 100644 --- a/src/Libraries/SmartStore.Core/Utilities/CommonHelper.cs +++ b/src/Libraries/SmartStore.Core/Utilities/CommonHelper.cs @@ -1,15 +1,13 @@ -using SmartStore.Utilities.Reflection; using System; using System.Collections.Generic; -using System.ComponentModel; using System.Configuration; using System.Dynamic; using System.Globalization; using System.IO; using System.Security.Cryptography; -using System.Text; using System.Web.Hosting; using System.Web.Mvc; +using SmartStore.ComponentModel; namespace SmartStore.Utilities { diff --git a/src/Libraries/SmartStore.Core/Utilities/DictionaryConverter.cs b/src/Libraries/SmartStore.Core/Utilities/DictionaryConverter.cs index 34f4e74782..1df2547ea0 100644 --- a/src/Libraries/SmartStore.Core/Utilities/DictionaryConverter.cs +++ b/src/Libraries/SmartStore.Core/Utilities/DictionaryConverter.cs @@ -5,7 +5,7 @@ using System.Collections; using System.Reflection; using System.Runtime.Serialization; -using SmartStore.Utilities.Reflection; +using SmartStore.ComponentModel; namespace SmartStore.Utilities { diff --git a/src/Libraries/SmartStore.Data/Extensions/DataReaderExtensions.cs b/src/Libraries/SmartStore.Data/Extensions/DataReaderExtensions.cs index edd6e3dba4..09aa2eadbb 100644 --- a/src/Libraries/SmartStore.Data/Extensions/DataReaderExtensions.cs +++ b/src/Libraries/SmartStore.Data/Extensions/DataReaderExtensions.cs @@ -5,8 +5,8 @@ using System.Data; using System.Reflection; using System.Linq; -using SmartStore.Utilities.Reflection; using System.Dynamic; +using SmartStore.ComponentModel; namespace SmartStore.Data { diff --git a/src/Libraries/SmartStore.Services/Configuration/SettingService.cs b/src/Libraries/SmartStore.Services/Configuration/SettingService.cs index 58659b3386..5a03d72ea6 100644 --- a/src/Libraries/SmartStore.Services/Configuration/SettingService.cs +++ b/src/Libraries/SmartStore.Services/Configuration/SettingService.cs @@ -2,20 +2,13 @@ using System.Collections.Generic; using System.Linq; using Newtonsoft.Json; -using SmartStore.Core; using SmartStore.Core.Caching; using SmartStore.Core.Configuration; using SmartStore.Core.Data; using SmartStore.Core.Domain.Configuration; -using SmartStore.Core.Infrastructure; using SmartStore.Core.Events; -//using Fasterflect; using System.Linq.Expressions; using System.Reflection; -using SmartStore.Core.Plugins; -using System.ComponentModel; -using SmartStore.Utilities; -using SmartStore.Utilities.Reflection; using SmartStore.ComponentModel; namespace SmartStore.Services.Configuration diff --git a/src/Libraries/SmartStore.Services/DataExchange/Import/ImportRow.cs b/src/Libraries/SmartStore.Services/DataExchange/Import/ImportRow.cs index 449c771b50..b1ebde7e70 100644 --- a/src/Libraries/SmartStore.Services/DataExchange/Import/ImportRow.cs +++ b/src/Libraries/SmartStore.Services/DataExchange/Import/ImportRow.cs @@ -4,8 +4,8 @@ using System.Linq; using System.Linq.Expressions; using System.Text; +using SmartStore.ComponentModel; using SmartStore.Core; -using SmartStore.Utilities.Reflection; namespace SmartStore.Services.DataExchange.Import { diff --git a/src/Libraries/SmartStore.Services/Localization/LocalizationExtentions.cs b/src/Libraries/SmartStore.Services/Localization/LocalizationExtentions.cs index 3fb8b75d82..8bbd78cf9b 100644 --- a/src/Libraries/SmartStore.Services/Localization/LocalizationExtentions.cs +++ b/src/Libraries/SmartStore.Services/Localization/LocalizationExtentions.cs @@ -7,8 +7,8 @@ using SmartStore.Core.Plugins; using System.Xml; using SmartStore.Utilities; -using SmartStore.Utilities.Reflection; using SmartStore.Services.DataExchange.Import; +using SmartStore.ComponentModel; namespace SmartStore.Services.Localization { diff --git a/src/Presentation/SmartStore.Web.Framework/DependencyRegistrar.cs b/src/Presentation/SmartStore.Web.Framework/DependencyRegistrar.cs index 28d0b9e187..425b95bbe6 100644 --- a/src/Presentation/SmartStore.Web.Framework/DependencyRegistrar.cs +++ b/src/Presentation/SmartStore.Web.Framework/DependencyRegistrar.cs @@ -74,8 +74,8 @@ using SmartStore.Web.Framework.WebApi.Configuration; using Module = Autofac.Module; using SmartStore.Core.Domain.DataExchange; -using SmartStore.Utilities.Reflection; using SmartStore.Services.DataExchange.Import; +using SmartStore.ComponentModel; namespace SmartStore.Web.Framework { diff --git a/src/Presentation/SmartStore.Web.Framework/Settings/StoreDependingSettingHelper.cs b/src/Presentation/SmartStore.Web.Framework/Settings/StoreDependingSettingHelper.cs index 7f0f2e0096..84f64a1124 100644 --- a/src/Presentation/SmartStore.Web.Framework/Settings/StoreDependingSettingHelper.cs +++ b/src/Presentation/SmartStore.Web.Framework/Settings/StoreDependingSettingHelper.cs @@ -2,11 +2,11 @@ using System.Collections.Generic; using System.Linq; using System.Web.Mvc; +using SmartStore.ComponentModel; using SmartStore.Core.Infrastructure; using SmartStore.Services.Configuration; using SmartStore.Services.Localization; using SmartStore.Web.Framework.Localization; -using SmartStore.Utilities.Reflection; namespace SmartStore.Web.Framework.Settings { diff --git a/src/Presentation/SmartStore.Web.Framework/WebApi/WebApiEntityController.cs b/src/Presentation/SmartStore.Web.Framework/WebApi/WebApiEntityController.cs index c8889391d0..2d7a98ecda 100644 --- a/src/Presentation/SmartStore.Web.Framework/WebApi/WebApiEntityController.cs +++ b/src/Presentation/SmartStore.Web.Framework/WebApi/WebApiEntityController.cs @@ -14,9 +14,9 @@ using SmartStore.Services.Directory; using SmartStore.Services.Localization; using System.Collections.Generic; -using SmartStore.Utilities.Reflection; using SmartStore.Services; using Autofac; +using SmartStore.ComponentModel; namespace SmartStore.Web.Framework.WebApi { diff --git a/src/Presentation/SmartStore.Web/Views/Product/ProductTemplate.Simple.cshtml b/src/Presentation/SmartStore.Web/Views/Product/ProductTemplate.Simple.cshtml index a65289d3f3..8c3598444d 100644 --- a/src/Presentation/SmartStore.Web/Views/Product/ProductTemplate.Simple.cshtml +++ b/src/Presentation/SmartStore.Web/Views/Product/ProductTemplate.Simple.cshtml @@ -349,7 +349,7 @@ - - \ No newline at end of file diff --git a/src/Presentation/SmartStore.Web/Content/fonts/raw/license.txt b/src/Presentation/SmartStore.Web/Content/fonts/raw/license.txt deleted file mode 100644 index f963b349f2..0000000000 --- a/src/Presentation/SmartStore.Web/Content/fonts/raw/license.txt +++ /dev/null @@ -1,34 +0,0 @@ -Icon Set: WPZOOM Developer Icon Set -- http://www.wpzoom.com/wpzoom/new-freebie-wpzoom-developer-icon-set-154-free-icons/ -License: CC BY-SA 3.0 -- http://creativecommons.org/licenses/by-sa/3.0/ - - -Icon Set: Typicons -- http://typicons.com/ -License: CC BY-SA 3.0 -- http://creativecommons.org/licenses/by-sa/3.0/ - - -Icon Set: Entypo -- http://www.entypo.com/ -License: CC BY-SA 3.0 -- http://creativecommons.org/licenses/by-sa/3.0/ - - -Icon Set: Brankic1979 -- http://brankic1979.com/icons/ -License: Custom -- http://brankic1979.com/icons/ - - -Icon Set: Eco Ico -- http://dribbble.com/shots/665585-Eco-Ico -License: CC0 -- http://creativecommons.org/publicdomain/zero/1.0/ - - -Icon Set: Icon Minia -- http://dribbble.com/shots/598215-Icon-Minia-139-Vector-Icons -License: GPL V3 -- http://www.gnu.org/copyleft/gpl.html - - -Icon Set: IcoMoon - Free -- http://keyamoon.com/icomoon/ -License: CC BY-SA 3.0 -- http://creativecommons.org/licenses/by-sa/3.0/ - - -Icon Set: Broccolidry -- http://dribbble.com/shots/587469-Free-16px-Broccolidryiconsaniconsetitisfullof-icons -License: Aribitrary -- http://licence.visualidiot.com/ - - -Icon Set: Iconic -- http://somerandomdude.com/work/iconic/ -License: CC BY-SA 3.0 -- http://creativecommons.org/licenses/by-sa/3.0/us/ \ No newline at end of file diff --git a/src/Presentation/SmartStore.Web/Content/fonts/raw/lte-ie7.js b/src/Presentation/SmartStore.Web/Content/fonts/raw/lte-ie7.js deleted file mode 100644 index b109d62b28..0000000000 --- a/src/Presentation/SmartStore.Web/Content/fonts/raw/lte-ie7.js +++ /dev/null @@ -1,74 +0,0 @@ -/* Use this script if you need to support IE 7 and IE 6. */ - -window.onload = function() { - function addIcon(el, entity) { - var html = el.innerHTML; - el.innerHTML = '' + entity + '' + html; - } - var icons = { - 'sm-icon-database' : '!', - 'sm-icon-user' : '"', - 'sm-icon-cog' : '#', - 'sm-icon-stats-up' : '$', - 'sm-icon-gift' : '%', - 'sm-icon-cube' : '&', - 'sm-icon-help' : ''', - 'sm-icon-loop' : '(', - 'sm-icon-tag' : ')', - 'sm-icon-gift-2' : '+', - 'sm-icon-home' : '-', - 'sm-icon-earth' : '.', - 'sm-icon-loop-alt2' : '3', - 'sm-icon-layers' : '4', - 'sm-icon-tag-stroke' : '6', - 'sm-icon-archive' : '<', - 'sm-icon-cog-2' : '=', - 'sm-icon-refresh' : '>', - 'sm-icon-tag-2' : '?', - 'sm-icon-tag-3' : '@', - 'sm-icon-chart' : 'C', - 'sm-icon-cube-2' : 'D', - 'sm-icon-megaphone' : 'E', - 'sm-icon-box' : 'F', - 'sm-icon-layout' : 'G', - 'sm-icon-layout-2' : 'H', - 'sm-icon-layout-3' : 'I', - 'sm-icon-layout-4' : 'J', - 'sm-icon-stats' : 'K', - 'sm-icon-discout' : 'L', - 'sm-icon-retweet' : 'M', - 'sm-icon-tags' : 'N', - 'sm-icon-users' : 'O', - 'sm-icon-user-2' : 'P', - 'sm-icon-price' : 'Q', - 'sm-icon-retweet-2' : 'R', - 'sm-icon-download' : 'S', - 'sm-icon-upload' : 'T', - 'sm-icon-home-2' : 'U', - 'sm-icon-dots-three' : 'V', - 'sm-icon-users-2' : 'W', - 'sm-icon-contact' : '*', - 'sm-icon-camera' : ',', - 'sm-icon-cart' : '/', - 'sm-icon-bag' : '0', - 'sm-icon-shopping' : '1', - 'sm-icon-cart-2' : '2', - 'sm-icon-cart-3' : '5', - 'sm-icon-cart-4' : '7', - 'sm-icon-basket' : '8' - }, - els = document.getElementsByTagName('*'), - i, attr, html, c, el; - for (i = 0; i < els.length; i += 1) { - el = els[i]; - attr = el.getAttribute('data-icon'); - if (attr) { - addIcon(el, attr); - } - c = el.className; - c = c.match(/sm-icon-[^\s'"]+/); - if (c && icons[c[0]]) { - addIcon(el, icons[c[0]]); - } - } -}; \ No newline at end of file diff --git a/src/Presentation/SmartStore.Web/Content/fonts/raw/style.css b/src/Presentation/SmartStore.Web/Content/fonts/raw/style.css deleted file mode 100644 index cf8e62665b..0000000000 --- a/src/Presentation/SmartStore.Web/Content/fonts/raw/style.css +++ /dev/null @@ -1,180 +0,0 @@ -@font-face { - font-family: 'Fontastic'; - src:url('fonts/Fontastic.eot'); - src:url('fonts/Fontastic.eot?#iefix') format('embedded-opentype'), - url('fonts/Fontastic.svg#Fontastic') format('svg'), - url('fonts/Fontastic.woff') format('woff'), - url('fonts/Fontastic.ttf') format('truetype'); - font-weight: normal; - font-style: normal; -} - -/* Use the following CSS code if you want to use data attributes for inserting your icons */ -[data-icon]:before { - font-family: 'Fontastic'; - content: attr(data-icon); - speak: none; - font-weight: normal; - line-height: 1; - -webkit-font-smoothing: antialiased; -} - -/* Use the following CSS code if you want to have a class per icon */ -[class^="sm-icon-"]:before, [class*=" sm-icon-"]:before { - font-family: 'Fontastic'; - font-style: normal; - speak: none; - font-weight: normal; - line-height: 1; - -webkit-font-smoothing: antialiased; -} -.sm-icon-database:before { - content: "\21"; -} -.sm-icon-user:before { - content: "\22"; -} -.sm-icon-cog:before { - content: "\23"; -} -.sm-icon-stats-up:before { - content: "\24"; -} -.sm-icon-gift:before { - content: "\25"; -} -.sm-icon-cube:before { - content: "\26"; -} -.sm-icon-help:before { - content: "\27"; -} -.sm-icon-loop:before { - content: "\28"; -} -.sm-icon-tag:before { - content: "\29"; -} -.sm-icon-gift-2:before { - content: "\2b"; -} -.sm-icon-home:before { - content: "\2d"; -} -.sm-icon-earth:before { - content: "\2e"; -} -.sm-icon-loop-alt2:before { - content: "\33"; -} -.sm-icon-layers:before { - content: "\34"; -} -.sm-icon-tag-stroke:before { - content: "\36"; -} -.sm-icon-archive:before { - content: "\3c"; -} -.sm-icon-cog-2:before { - content: "\3d"; -} -.sm-icon-refresh:before { - content: "\3e"; -} -.sm-icon-tag-2:before { - content: "\3f"; -} -.sm-icon-tag-3:before { - content: "\40"; -} -.sm-icon-chart:before { - content: "\43"; -} -.sm-icon-cube-2:before { - content: "\44"; -} -.sm-icon-megaphone:before { - content: "\45"; -} -.sm-icon-box:before { - content: "\46"; -} -.sm-icon-layout:before { - content: "\47"; -} -.sm-icon-layout-2:before { - content: "\48"; -} -.sm-icon-layout-3:before { - content: "\49"; -} -.sm-icon-layout-4:before { - content: "\4a"; -} -.sm-icon-stats:before { - content: "\4b"; -} -.sm-icon-discout:before { - content: "\4c"; -} -.sm-icon-retweet:before { - content: "\4d"; -} -.sm-icon-tags:before { - content: "\4e"; -} -.sm-icon-users:before { - content: "\4f"; -} -.sm-icon-user-2:before { - content: "\50"; -} -.sm-icon-price:before { - content: "\51"; -} -.sm-icon-retweet-2:before { - content: "\52"; -} -.sm-icon-download:before { - content: "\53"; -} -.sm-icon-upload:before { - content: "\54"; -} -.sm-icon-home-2:before { - content: "\55"; -} -.sm-icon-dots-three:before { - content: "\56"; -} -.sm-icon-users-2:before { - content: "\57"; -} -.sm-icon-contact:before { - content: "\2a"; -} -.sm-icon-camera:before { - content: "\2c"; -} -.sm-icon-cart:before { - content: "\2f"; -} -.sm-icon-bag:before { - content: "\30"; -} -.sm-icon-shopping:before { - content: "\31"; -} -.sm-icon-cart-2:before { - content: "\32"; -} -.sm-icon-cart-3:before { - content: "\35"; -} -.sm-icon-cart-4:before { - content: "\37"; -} -.sm-icon-basket:before { - content: "\38"; -} diff --git a/src/Presentation/SmartStore.Web/SmartStore.Web.csproj b/src/Presentation/SmartStore.Web/SmartStore.Web.csproj index 726d057551..8fd87da6c1 100644 --- a/src/Presentation/SmartStore.Web/SmartStore.Web.csproj +++ b/src/Presentation/SmartStore.Web/SmartStore.Web.csproj @@ -909,7 +909,6 @@ - ResXFileCodeGenerator MvcLocalization.de.Designer.cs @@ -919,10 +918,6 @@ Designer - - - - @@ -944,11 +939,11 @@ Designer - - - - - + + + + + @@ -1522,14 +1517,6 @@ - - - - - - - - diff --git a/src/Presentation/SmartStore.Web/Themes/Alpha/Content/datalist.less b/src/Presentation/SmartStore.Web/Themes/Alpha/Content/datalist.less index 43fd4b4ccb..cd325675b3 100644 --- a/src/Presentation/SmartStore.Web/Themes/Alpha/Content/datalist.less +++ b/src/Presentation/SmartStore.Web/Themes/Alpha/Content/datalist.less @@ -257,6 +257,9 @@ text-decoration: none; } } + .fa { + font-size: 13px; + } } .item-box:hover .quicklinks { .opacity(100); diff --git a/src/Presentation/SmartStore.Web/Themes/Alpha/Content/product.less b/src/Presentation/SmartStore.Web/Themes/Alpha/Content/product.less index 9edce6806f..486bc2dca5 100644 --- a/src/Presentation/SmartStore.Web/Themes/Alpha/Content/product.less +++ b/src/Presentation/SmartStore.Web/Themes/Alpha/Content/product.less @@ -200,7 +200,7 @@ .product-details-page .add-to-cart { padding-top: 10px; } -.product-details-page #details-cnt .add-to-cart .fa-plus-circle { +.product-details-page #details-cnt .add-to-cart .fa-cart-plus { position: absolute; right: 6px; top: 50%; diff --git a/src/Presentation/SmartStore.Web/Themes/Alpha/Content/shopbar.less b/src/Presentation/SmartStore.Web/Themes/Alpha/Content/shopbar.less index 74d2919a7b..8213eda3d6 100644 --- a/src/Presentation/SmartStore.Web/Themes/Alpha/Content/shopbar.less +++ b/src/Presentation/SmartStore.Web/Themes/Alpha/Content/shopbar.less @@ -139,7 +139,7 @@ width: 1px; background-color: rgba(0,0,0, .15); margin: 8px; - padding: none; + padding: 0; border-right: 1px solid @shopBarBackgroundColor; .no-rgba & { @@ -172,8 +172,6 @@ position: relative; display: inline-block; margin: 2px 4px 0 0; - width: 24px; - height: 24px; span.label { position: absolute; @@ -185,19 +183,18 @@ } } -.shopbar-tool [class^="sm-icon-"] { +.shopbar-button-icon .fa { display: inline-block; - width: 24px; - height: 24px; - font-size: 24px; + font-size: 24px !important; font-style: normal; - margin-top: 5px; + line-height: 28px; + vertical-align: middle; color: @shopBarIconColor; .transition(color .1s linear); } -.shopbar-button:hover [class^="sm-icon-"] { +.shopbar-button:hover .shopbar-button-icon .fa { color: darken(@shopBarIconColor, 22%); } diff --git a/src/Presentation/SmartStore.Web/Themes/Alpha/Content/theme.less b/src/Presentation/SmartStore.Web/Themes/Alpha/Content/theme.less index 346d8148ab..a1c1b682af 100644 --- a/src/Presentation/SmartStore.Web/Themes/Alpha/Content/theme.less +++ b/src/Presentation/SmartStore.Web/Themes/Alpha/Content/theme.less @@ -7,7 +7,6 @@ // Fonts @import "typo.less"; -@import "~/Content/fonts/fontastic.less"; // Bootstrap @import "bootstrap.less"; diff --git a/src/Presentation/SmartStore.Web/Views/Catalog/CompareProductsButton.cshtml b/src/Presentation/SmartStore.Web/Views/Catalog/CompareProductsButton.cshtml index 0254f49751..0141d7c45b 100644 --- a/src/Presentation/SmartStore.Web/Views/Catalog/CompareProductsButton.cshtml +++ b/src/Presentation/SmartStore.Web/Views/Catalog/CompareProductsButton.cshtml @@ -7,7 +7,7 @@ data-href="@Url.Action("AddProductToCompare", new { id = Model.ProductId })" data-type="compare" data-action="add"> - + @T("Products.Compare.AddToCompareList") \ No newline at end of file diff --git a/src/Presentation/SmartStore.Web/Views/Catalog/_ProductBoxList.cshtml b/src/Presentation/SmartStore.Web/Views/Catalog/_ProductBoxList.cshtml index 47cf844778..855afc1ee6 100644 --- a/src/Presentation/SmartStore.Web/Views/Catalog/_ProductBoxList.cshtml +++ b/src/Presentation/SmartStore.Web/Views/Catalog/_ProductBoxList.cshtml @@ -216,7 +216,7 @@ data-form-selector="#product-details-form" data-type="wishlist" data-action="add"> - + @T("Categories.Wishlist") } @@ -228,7 +228,7 @@ rel="nofollow" data-type="compare" data-action="add"> - + @T("Categories.Compare") } @@ -250,7 +250,7 @@ data-type="cart" data-action="add"> @(Model.ProductPrice.AvailableForPreOrder ? T("ShoppingCart.PreOrder") : T("ShoppingCart.AddToCart")) - + } else diff --git a/src/Presentation/SmartStore.Web/Views/Common/AccountDropdown.cshtml b/src/Presentation/SmartStore.Web/Views/Common/AccountDropdown.cshtml index cacb881673..5384e9bb64 100644 --- a/src/Presentation/SmartStore.Web/Views/Common/AccountDropdown.cshtml +++ b/src/Presentation/SmartStore.Web/Views/Common/AccountDropdown.cshtml @@ -20,7 +20,7 @@ @Html.Widget("account_dropdown_before")
  • - + @T("Account.MyAccount")
  • @@ -28,7 +28,7 @@ {
  • - + @T("Account.Administration")
  • @@ -38,7 +38,7 @@ {
  • - + @T("PrivateMessages.Inbox") @if (Model.UnreadPrivateMessages != "") { @@ -63,7 +63,7 @@ {
  • - + @T("Wishlist") @Model.WishlistItems
  • } @@ -71,14 +71,14 @@ { }
  • - + @T("Account.Logout")
  • diff --git a/src/Presentation/SmartStore.Web/Views/Common/ShopBar.cshtml b/src/Presentation/SmartStore.Web/Views/Common/ShopBar.cshtml index ee88905a10..1c09e0a289 100644 --- a/src/Presentation/SmartStore.Web/Views/Common/ShopBar.cshtml +++ b/src/Presentation/SmartStore.Web/Views/Common/ShopBar.cshtml @@ -11,7 +11,7 @@
    - + @Model.ShoppingCartItems
    @@ -34,7 +34,7 @@
    - +
    @if (Model.IsAuthenticated) @@ -68,7 +68,7 @@
    - + @Model.WishlistItems
    @@ -91,7 +91,7 @@
    diff --git a/src/Presentation/SmartStore.Web/Views/Product/_AddToCart.cshtml b/src/Presentation/SmartStore.Web/Views/Product/_AddToCart.cshtml index d08658b85a..608a0fb93f 100644 --- a/src/Presentation/SmartStore.Web/Views/Product/_AddToCart.cshtml +++ b/src/Presentation/SmartStore.Web/Views/Product/_AddToCart.cshtml @@ -137,7 +137,7 @@ data-type="cart" data-action="add"> @(Model.AddToCart.AvailableForPreOrder ? T("ShoppingCart.PreOrder") : T("ShoppingCart.AddToCart")) - + } else diff --git a/src/Presentation/SmartStore.Web/Views/Product/_BundleItemsAddToCart.cshtml b/src/Presentation/SmartStore.Web/Views/Product/_BundleItemsAddToCart.cshtml index b7e73105af..7387dd9bce 100644 --- a/src/Presentation/SmartStore.Web/Views/Product/_BundleItemsAddToCart.cshtml +++ b/src/Presentation/SmartStore.Web/Views/Product/_BundleItemsAddToCart.cshtml @@ -28,7 +28,7 @@ data-type="cart" data-action="add"> @(Model.AddToCart.AvailableForPreOrder ? T("ShoppingCart.PreOrder") : T("ShoppingCart.AddToCart")) - + }
    diff --git a/src/Presentation/SmartStore.Web/Views/Shared/_ProductBox.cshtml b/src/Presentation/SmartStore.Web/Views/Shared/_ProductBox.cshtml index 63254eb14e..ac78138a16 100644 --- a/src/Presentation/SmartStore.Web/Views/Shared/_ProductBox.cshtml +++ b/src/Presentation/SmartStore.Web/Views/Shared/_ProductBox.cshtml @@ -30,7 +30,7 @@ data-form-selector="#product-details-form" data-type="wishlist" data-action="add"> - + @T("Categories.Wishlist") } @@ -42,7 +42,7 @@ rel="nofollow" data-type="compare" data-action="add"> - + @T("Categories.Compare") } @@ -176,7 +176,7 @@ rel="tooltip nofollow" data-type="cart" data-action="add"> - + } else diff --git a/src/Presentation/SmartStore.Web/Views/ShoppingCart/FlyoutWishlist.cshtml b/src/Presentation/SmartStore.Web/Views/ShoppingCart/FlyoutWishlist.cshtml index a2a157d2d9..58d29ed197 100644 --- a/src/Presentation/SmartStore.Web/Views/ShoppingCart/FlyoutWishlist.cshtml +++ b/src/Presentation/SmartStore.Web/Views/ShoppingCart/FlyoutWishlist.cshtml @@ -56,7 +56,7 @@ data-name="@item.ProductName" data-type="cart" data-action="addfromwishlist"> - +
    } diff --git a/src/Presentation/SmartStore.Web/Views/ShoppingCart/Wishlist.cshtml b/src/Presentation/SmartStore.Web/Views/ShoppingCart/Wishlist.cshtml index 57e67c51ad..15f94b21e3 100644 --- a/src/Presentation/SmartStore.Web/Views/ShoppingCart/Wishlist.cshtml +++ b/src/Presentation/SmartStore.Web/Views/ShoppingCart/Wishlist.cshtml @@ -313,7 +313,7 @@ @if (Model.DisplayAddToCart) { } From fe7172c42d65ec919d21149b0798ff3911f574ee Mon Sep 17 00:00:00 2001 From: Marcus Gesing Date: Sat, 5 Dec 2015 14:36:42 +0100 Subject: [PATCH 148/707] Resolves #829 Activity Log: Searching by customer email out of function Added deletion of selected customer activity logs Deletion of all activity logs now uses fast and smart truncate --- changelog.md | 1 + .../Logging/ICustomerActivityService.cs | 27 +-- .../Logging/CustomerActivityService.cs | 162 +++++++++-------- .../Controllers/ActivityLogController.cs | 108 ++++++------ .../Models/Logging/ActivityLogSearchModel.cs | 13 +- .../Views/ActivityLog/ListLogs.cshtml | 164 +++++++++++++----- .../Logging/CustomerActivityServiceTests.cs | 20 ++- 7 files changed, 305 insertions(+), 190 deletions(-) diff --git a/changelog.md b/changelog.md index 794309b733..4f370dcf36 100644 --- a/changelog.md +++ b/changelog.md @@ -77,6 +77,7 @@ * #796 Selected specification in product filter mask is displayed with default language (not localized) * #805 Product filter is reset if 'product sorting' or 'view mode' or 'amount of displayed products per page' is changed * Hide link to a topic page if it is limited to stores +* #829 Activity Log: Searching by customer email out of function ## SmartStore.NET 2.2.2 diff --git a/src/Libraries/SmartStore.Core/Logging/ICustomerActivityService.cs b/src/Libraries/SmartStore.Core/Logging/ICustomerActivityService.cs index 0c32d85236..0ee497d1f8 100644 --- a/src/Libraries/SmartStore.Core/Logging/ICustomerActivityService.cs +++ b/src/Libraries/SmartStore.Core/Logging/ICustomerActivityService.cs @@ -1,15 +1,14 @@ using System; using System.Collections.Generic; -using SmartStore.Core; using SmartStore.Core.Domain.Customers; using SmartStore.Core.Domain.Logging; namespace SmartStore.Core.Logging { - /// - /// Customer activity service interface - /// - public partial interface ICustomerActivityService + /// + /// Customer activity service interface + /// + public partial interface ICustomerActivityService { /// /// Inserts an activity log type item @@ -84,10 +83,11 @@ ActivityLog InsertActivity(string systemKeyword, /// Activity log type identifier /// Page index /// Page size + /// Customer email /// Activity log collection IPagedList GetAllActivities(DateTime? createdOnFrom, DateTime? createdOnTo, int? customerId, - int activityLogTypeId, int pageIndex, int pageSize); + int activityLogTypeId, int pageIndex, int pageSize, string email = null); /// /// Gets an activity log item @@ -96,9 +96,16 @@ IPagedList GetAllActivities(DateTime? createdOnFrom, /// Activity log item ActivityLog GetActivityById(int activityLogId); - /// - /// Clears activity log - /// - void ClearAllActivities(); + /// + /// Gets activity logs be identifier + /// + /// Activity log identifiers + /// List of activity logs + IList GetActivityByIds(int[] activityLogIds); + + /// + /// Clears activity log + /// + void ClearAllActivities(); } } diff --git a/src/Libraries/SmartStore.Services/Logging/CustomerActivityService.cs b/src/Libraries/SmartStore.Services/Logging/CustomerActivityService.cs index c84c5f7526..08d4a77083 100644 --- a/src/Libraries/SmartStore.Services/Logging/CustomerActivityService.cs +++ b/src/Libraries/SmartStore.Services/Logging/CustomerActivityService.cs @@ -1,64 +1,49 @@ using System; -using System.Collections.Generic; using System.Collections.Concurrent; +using System.Collections.Generic; using System.Linq; using SmartStore.Core; -using SmartStore.Core.Caching; using SmartStore.Core.Data; -using SmartStore.Core.Domain.Common; using SmartStore.Core.Domain.Customers; using SmartStore.Core.Domain.Logging; -using SmartStore.Data; using SmartStore.Core.Logging; namespace SmartStore.Services.Logging { - /// - /// Customer activity service - /// - public class CustomerActivityService : ICustomerActivityService + /// + /// Customer activity service + /// + public class CustomerActivityService : ICustomerActivityService { - #region Fields + #region Fields - /// - /// Cache manager - /// - private readonly ICacheManager _cacheManager; - private readonly IRepository _activityLogRepository; + private const int _deleteNumberOfEntries = 1000; + + private readonly IRepository _activityLogRepository; private readonly IRepository _activityLogTypeRepository; - private readonly IWorkContext _workContext; + private readonly IRepository _customerRepository; + private readonly IWorkContext _workContext; private readonly IDbContext _dbContext; - private readonly IDataProvider _dataProvider; - private readonly CommonSettings _commonSettings; - // codehint: sm-add + private readonly static object s_lock = new object(); private readonly static ConcurrentDictionary s_logTypes = new ConcurrentDictionary(); - #endregion - #region Ctor - /// - /// Ctor - /// - /// Cache manager - /// Activity log repository - /// Activity log type repository - /// Work context - /// DB context> - /// WeData provider - /// Common settings - public CustomerActivityService(ICacheManager cacheManager, + #endregion + + #region Ctor + + public CustomerActivityService( IRepository activityLogRepository, IRepository activityLogTypeRepository, - IWorkContext workContext, - IDbContext dbContext, IDataProvider dataProvider, CommonSettings commonSettings) + IRepository customerRepository, + IWorkContext workContext, + IDbContext dbContext) { - this._cacheManager = cacheManager; this._activityLogRepository = activityLogRepository; this._activityLogTypeRepository = activityLogTypeRepository; + this._customerRepository = customerRepository; this._workContext = workContext; this._dbContext = dbContext; - this._dataProvider = dataProvider; - this._commonSettings = commonSettings; } #endregion @@ -218,27 +203,41 @@ public virtual void DeleteActivity(ActivityLog activityLog) _activityLogRepository.Delete(activityLog); } - /// - /// Gets all activity log items - /// - /// Log item creation from; null to load all customers - /// Log item creation to; null to load all customers - /// Customer identifier; null to load all customers - /// Activity log type identifier - /// Page index - /// Page size - /// Activity log collection - public virtual IPagedList GetAllActivities(DateTime? createdOnFrom, + /// + /// Gets all activity log items + /// + /// Log item creation from; null to load all customers + /// Log item creation to; null to load all customers + /// Customer identifier; null to load all customers + /// Activity log type identifier + /// Page index + /// Page size + /// Customer email + /// Activity log collection + public virtual IPagedList GetAllActivities(DateTime? createdOnFrom, DateTime? createdOnTo, int? customerId, int activityLogTypeId, - int pageIndex, int pageSize) + int pageIndex, int pageSize, string email = null) { var query = _activityLogRepository.Table; + + if (email.HasValue()) + { + query = + from al in _activityLogRepository.Table + join c in _customerRepository.Table on al.CustomerId equals c.Id + where c.Email == email + select al; + } + if (createdOnFrom.HasValue) query = query.Where(al => createdOnFrom.Value <= al.CreatedOnUtc); + if (createdOnTo.HasValue) query = query.Where(al => createdOnTo.Value >= al.CreatedOnUtc); + if (activityLogTypeId > 0) query = query.Where(al => activityLogTypeId == al.ActivityLogTypeId); + if (customerId.HasValue) query = query.Where(al => customerId.Value == al.CustomerId); @@ -266,29 +265,54 @@ public virtual ActivityLog GetActivityById(int activityLogId) return activityLog; } - /// - /// Clears activity log - /// - public virtual void ClearAllActivities() - { - if (_commonSettings.UseStoredProceduresIfSupported && _dataProvider.StoredProceduresSupported) - { - //although it's not a stored procedure we use it to ensure that a database supports them - //we cannot wait until EF team has it implemented - http://data.uservoice.com/forums/72025-entity-framework-feature-suggestions/suggestions/1015357-batch-cud-support + public virtual IList GetActivityByIds(int[] activityLogIds) + { + if (activityLogIds == null || activityLogIds.Length == 0) + return new List(); + var query = _activityLogRepository.Table + .Where(x => activityLogIds.Contains(x.Id)) + .OrderByDescending(x => x.CreatedOnUtc); - //do all databases support "Truncate command"? - //TODO: do not hard-code the table name - _dbContext.ExecuteSqlCommand("TRUNCATE TABLE [ActivityLog]"); - } - else - { - var activityLog = _activityLogRepository.Table.ToList(); - foreach (var activityLogItem in activityLog) - _activityLogRepository.Delete(activityLogItem); - } - } - #endregion + return query.ToList(); + } + /// + /// Clears activity log + /// + public virtual void ClearAllActivities() + { + try + { + _dbContext.ExecuteSqlCommand("TRUNCATE TABLE [ActivityLog]"); + } + catch + { + try + { + for (int i = 0; i < 100000; ++i) + { + if (_dbContext.ExecuteSqlCommand("Delete Top ({0}) From [ActivityLog]", false, null, _deleteNumberOfEntries) < _deleteNumberOfEntries) + break; + } + } + catch { } + + try + { + _dbContext.ExecuteSqlCommand("DBCC CHECKIDENT('ActivityLog', RESEED, 0)"); + } + catch + { + try + { + _dbContext.ExecuteSqlCommand("Alter Table [ActivityLog] Alter Column [Id] Identity(1,1)"); + } + catch { } + } + } + } + + #endregion } } diff --git a/src/Presentation/SmartStore.Web/Administration/Controllers/ActivityLogController.cs b/src/Presentation/SmartStore.Web/Administration/Controllers/ActivityLogController.cs index 9f10684d6d..479b394285 100644 --- a/src/Presentation/SmartStore.Web/Administration/Controllers/ActivityLogController.cs +++ b/src/Presentation/SmartStore.Web/Administration/Controllers/ActivityLogController.cs @@ -1,39 +1,43 @@ using System; +using System.Collections.Generic; using System.Linq; using System.Web.Mvc; using SmartStore.Admin.Models.Logging; -using SmartStore.Services.Helpers; -using SmartStore.Services.Localization; +using SmartStore.Core.Domain.Common; using SmartStore.Core.Logging; +using SmartStore.Services.Helpers; using SmartStore.Services.Security; using SmartStore.Web.Framework.Controllers; +using SmartStore.Web.Framework.Filters; using SmartStore.Web.Framework.Security; using Telerik.Web.Mvc; namespace SmartStore.Admin.Controllers { - [AdminAuthorize] + [AdminAuthorize] public partial class ActivityLogController : AdminControllerBase { #region Fields private readonly ICustomerActivityService _customerActivityService; private readonly IDateTimeHelper _dateTimeHelper; - private readonly ILocalizationService _localizationService; private readonly IPermissionService _permissionService; + private readonly AdminAreaSettings _adminAreaSettings; - #endregion Fields + #endregion Fields - #region Constructors + #region Constructors - public ActivityLogController(ICustomerActivityService customerActivityService, - IDateTimeHelper dateTimeHelper, ILocalizationService localizationService, - IPermissionService permissionService) + public ActivityLogController( + ICustomerActivityService customerActivityService, + IDateTimeHelper dateTimeHelper, + IPermissionService permissionService, + AdminAreaSettings adminAreaSettings) { this._customerActivityService = customerActivityService; this._dateTimeHelper = dateTimeHelper; - this._localizationService = localizationService; this._permissionService = permissionService; + this._adminAreaSettings = adminAreaSettings; } #endregion  @@ -88,7 +92,8 @@ public ActionResult SaveTypes(FormCollection formCollection) } - NotifySuccess(_localizationService.GetResource("Admin.Configuration.ActivityLog.ActivityLogType.Updated")); + NotifySuccess(T("Admin.Configuration.ActivityLog.ActivityLogType.Updated")); + return RedirectToAction("ListTypes"); } @@ -101,37 +106,35 @@ public ActionResult ListLogs() if (!_permissionService.Authorize(StandardPermissionProvider.ManageActivityLog)) return AccessDeniedView(); - var activityLogSearchModel = new ActivityLogSearchModel(); - activityLogSearchModel.ActivityLogType.Add(new SelectListItem() - { - Value = "0", - Text = "All" - }); - - - foreach (var at in _customerActivityService.GetAllActivityTypes() - .OrderBy(x=>x.Name) - .Select(x => new SelectListItem - { - Value = x.Id.ToString(), - Text = x.Name - })) - activityLogSearchModel.ActivityLogType.Add(at); - - return View(activityLogSearchModel); + var model = new ActivityLogSearchModel + { + GridPageSize = _adminAreaSettings.GridPageSize + }; + + model.ActivityLogType = _customerActivityService.GetAllActivityTypes() + .OrderBy(x => x.Name) + .Select(x => new SelectListItem + { + Value = x.Id.ToString(), + Text = x.Name + }) + .ToList(); + + return View(model); } [HttpPost, GridAction(EnableCustomBinding = true)] - public JsonResult ListLogs(GridCommand command, ActivityLogSearchModel model) + public JsonResult ListActivityLogs(GridCommand command, ActivityLogSearchModel model) { DateTime? startDateValue = (model.CreatedOnFrom == null) ? null : (DateTime?)_dateTimeHelper.ConvertToUtcTime(model.CreatedOnFrom.Value, _dateTimeHelper.CurrentTimeZone); - DateTime? endDateValue = (model.CreatedOnTo == null) - ? null + DateTime? endDateValue = (model.CreatedOnTo == null) ? null : (DateTime?)_dateTimeHelper.ConvertToUtcTime(model.CreatedOnTo.Value, _dateTimeHelper.CurrentTimeZone).AddDays(1); - var activityLog = _customerActivityService.GetAllActivities(startDateValue, endDateValue,null, model.ActivityLogTypeId, command.Page - 1, command.PageSize); + var activityLog = _customerActivityService.GetAllActivities(startDateValue, endDateValue,null, model.ActivityLogTypeId, + command.Page - 1, command.PageSize, model.CustomerEmail); + var gridModel = new GridModel { Data = activityLog.Select(x => @@ -146,32 +149,35 @@ public JsonResult ListLogs(GridCommand command, ActivityLogSearchModel model) return new JsonResult { Data = gridModel}; } - [GridAction(EnableCustomBinding = true)] - public ActionResult AcivityLogDelete(int id, GridCommand command) + [HttpPost, ActionName("ListLogs")] + [FormValueRequired("clearall")] + public ActionResult ClearAll() { if (!_permissionService.Authorize(StandardPermissionProvider.ManageActivityLog)) return AccessDeniedView(); - var activityLog = _customerActivityService.GetActivityById(id); - if (activityLog == null) - throw new ArgumentException("No activity log found with the specified id"); - - _customerActivityService.DeleteActivity(activityLog); + _customerActivityService.ClearAllActivities(); - //TODO pass and return current ActivityLogSearchModel - return ListLogs(command, new ActivityLogSearchModel()); + return RedirectToAction("ListLogs"); } - public ActionResult ClearAll() - { - if (!_permissionService.Authorize(StandardPermissionProvider.ManageActivityLog)) - return AccessDeniedView(); + [HttpPost] + public ActionResult DeleteSelected(ICollection selectedIds) + { + if (!_permissionService.Authorize(StandardPermissionProvider.ManageActivityLog)) + return AccessDeniedView(); - _customerActivityService.ClearAllActivities(); - return RedirectToAction("ListLogs"); - } + if (selectedIds != null) + { + var activityLogs = _customerActivityService.GetActivityByIds(selectedIds.ToArray()); - #endregion + foreach (var activityLog in activityLogs) + _customerActivityService.DeleteActivity(activityLog); + } + + return Json(new { Result = true }); + } - } + #endregion + } } diff --git a/src/Presentation/SmartStore.Web/Administration/Models/Logging/ActivityLogSearchModel.cs b/src/Presentation/SmartStore.Web/Administration/Models/Logging/ActivityLogSearchModel.cs index 9db9865366..210b7d644a 100644 --- a/src/Presentation/SmartStore.Web/Administration/Models/Logging/ActivityLogSearchModel.cs +++ b/src/Presentation/SmartStore.Web/Administration/Models/Logging/ActivityLogSearchModel.cs @@ -1,19 +1,16 @@ using System; using System.Collections.Generic; -using System.ComponentModel.DataAnnotations; using System.Web.Mvc; using SmartStore.Web.Framework; using SmartStore.Web.Framework.Modelling; namespace SmartStore.Admin.Models.Logging { - public class ActivityLogSearchModel : ModelBase + public class ActivityLogSearchModel : ModelBase { - public ActivityLogSearchModel() - { - ActivityLogType = new List(); - } - [SmartResourceDisplayName("Admin.Configuration.ActivityLog.ActivityLog.Fields.CreatedOnFrom")] + public int GridPageSize { get; set; } + + [SmartResourceDisplayName("Admin.Configuration.ActivityLog.ActivityLog.Fields.CreatedOnFrom")] public DateTime? CreatedOnFrom { get; set; } [SmartResourceDisplayName("Admin.Configuration.ActivityLog.ActivityLog.Fields.CreatedOnTo")] @@ -25,8 +22,6 @@ public ActivityLogSearchModel() [SmartResourceDisplayName("Admin.Configuration.ActivityLog.ActivityLog.Fields.ActivityLogType")] public int ActivityLogTypeId { get; set; } - - [SmartResourceDisplayName("Admin.Configuration.ActivityLog.ActivityLog.Fields.ActivityLogType")] public IList ActivityLogType { get; set; } } } \ No newline at end of file diff --git a/src/Presentation/SmartStore.Web/Administration/Views/ActivityLog/ListLogs.cshtml b/src/Presentation/SmartStore.Web/Administration/Views/ActivityLog/ListLogs.cshtml index 6855e21c3c..bf1eb8813b 100644 --- a/src/Presentation/SmartStore.Web/Administration/Views/ActivityLog/ListLogs.cshtml +++ b/src/Presentation/SmartStore.Web/Administration/Views/ActivityLog/ListLogs.cshtml @@ -1,9 +1,6 @@ @model ActivityLogSearchModel @using Telerik.Web.Mvc; -@{ - var gridPageSize = EngineContext.Current.Resolve().GridPageSize; - - //page title +@{ ViewBag.Title = T("Admin.Configuration.ActivityLog.ActivityLog").Text; } @using (Html.BeginForm()) @@ -14,14 +11,18 @@ @T("Admin.Configuration.ActivityLog.ActivityLog")
    - -  @T("Admin.Common.Clear") - + +
    -

    -

    - + +

    + +
    @@ -66,52 +67,115 @@
    @Html.SmartLabelFor(model => model.CreatedOnFrom) @@ -51,7 +52,7 @@ @Html.SmartLabelFor(model => model.ActivityLogTypeId) - @Html.DropDownList("ActivityLogTypeId", Model.ActivityLogType) + @Html.DropDownListFor(ModelBase => ModelBase.ActivityLogTypeId, Model.ActivityLogType, T("Common.Unspecified"))
    +

    +
    @(Html.Telerik().Grid() - .Name("activityLog-grid") - .DataKeys(x => - { - x.Add(y => y.Id).RouteKey("Id"); - }) - .ClientEvents(events => events.OnDataBinding("onDataBinding")) - .Columns(columns => - { - columns.Bound(x => x.ActivityLogTypeName); - columns.Bound(x => x.CustomerId) - .Template(x => Html.ActionLink(x.CustomerEmail, "Edit", "Customer", new { id = x.CustomerId }, new { })) - .ClientTemplate("\"><#= CustomerEmail #>"); - columns.Bound(x => x.Comment); - columns.Bound(x => x.CreatedOn) - .Width(180); - columns.Command(commands => - { - commands.Delete().Localize(T); - }).Width(90); - }) - .Pageable(settings => settings.PageSize(gridPageSize).Position(GridPagerPosition.Both)) - .DataBinding(dataBinding => - { - dataBinding.Ajax().Select("ListLogs", "ActivityLog") - .Delete("AcivityLogDelete", "ActivityLog"); - }) - .PreserveGridState() - .EnableCustomBinding(true)) + .Name("activityLog-grid") + .DataKeys(x => + { + x.Add(y => y.Id).RouteKey("Id"); + }) + .ClientEvents(events => events.OnDataBinding("onDataBinding").OnDataBound("onDataBound")) + .Columns(columns => + { + columns.Bound(x => x.Id) + .ClientTemplate("") + .Title("") + .Width(50) + .HtmlAttributes(new { style = "text-align:center" }) + .HeaderHtmlAttributes(new { style = "text-align:center" }); + columns.Bound(x => x.ActivityLogTypeName); + columns.Bound(x => x.CustomerId) + .Template(x => Html.ActionLink(x.CustomerEmail, "Edit", "Customer", new { id = x.CustomerId }, new { })) + .ClientTemplate("\"><#= CustomerEmail #>"); + columns.Bound(x => x.Comment); + columns.Bound(x => x.CreatedOn) + .Width(180); + }) + .DataBinding(dataBinding => + { + dataBinding.Ajax() + .Select("ListActivityLogs", "ActivityLog"); + }) + .Pageable(settings => settings.PageSize(Model.GridPageSize).Position(GridPagerPosition.Both)) + .PreserveGridState() + .EnableCustomBinding(true))
    + } \ No newline at end of file diff --git a/src/Tests/SmartStore.Services.Tests/Logging/CustomerActivityServiceTests.cs b/src/Tests/SmartStore.Services.Tests/Logging/CustomerActivityServiceTests.cs index 77bdd50b8d..d125fdc122 100644 --- a/src/Tests/SmartStore.Services.Tests/Logging/CustomerActivityServiceTests.cs +++ b/src/Tests/SmartStore.Services.Tests/Logging/CustomerActivityServiceTests.cs @@ -1,29 +1,29 @@ using System.Collections.Generic; using System.Linq; +using NUnit.Framework; +using Rhino.Mocks; using SmartStore.Core; -using SmartStore.Core.Caching; using SmartStore.Core.Data; using SmartStore.Core.Domain.Customers; using SmartStore.Core.Domain.Logging; using SmartStore.Core.Logging; -using SmartStore.Tests; -using NUnit.Framework; -using Rhino.Mocks; using SmartStore.Services.Logging; +using SmartStore.Tests; namespace SmartStore.Services.Tests.Logging { - [TestFixture] + [TestFixture] public class CustomerActivityServiceTests : ServiceTest { - ICacheManager _cacheManager; IRepository _activityLogRepository; IRepository _activityLogTypeRepository; - IWorkContext _workContext; + IRepository _customerRepository; + IWorkContext _workContext; ICustomerActivityService _customerActivityService; ActivityLogType _activityType1, _activityType2; ActivityLog _activity1, _activity2; Customer _customer1, _customer2; + [SetUp] public new void SetUp() { @@ -69,13 +69,15 @@ public class CustomerActivityServiceTests : ServiceTest CustomerId = _customer2.Id, Customer = _customer2 }; - _cacheManager = new NullCache(); + _workContext = MockRepository.GenerateMock(); _activityLogRepository = MockRepository.GenerateMock>(); _activityLogTypeRepository = MockRepository.GenerateMock>(); + _customerRepository = MockRepository.GenerateMock>(); _activityLogTypeRepository.Expect(x => x.Table).Return(new List() { _activityType1, _activityType2 }.AsQueryable()); _activityLogRepository.Expect(x => x.Table).Return(new List() { _activity1, _activity2 }.AsQueryable()); - _customerActivityService = new CustomerActivityService(_cacheManager, _activityLogRepository, _activityLogTypeRepository, _workContext, null, null, null); + + _customerActivityService = new CustomerActivityService(_activityLogRepository, _activityLogTypeRepository, _customerRepository, _workContext, null); } [Test] From a558b3582486d02ebdd80072d9acd813527e67f6 Mon Sep 17 00:00:00 2001 From: Murat Cakir Date: Tue, 8 Dec 2015 21:29:38 +0100 Subject: [PATCH 149/707] Added ImportDataSegmenter.GetColumnIndexes() method --- .../Import/ImportDataSegmenter.cs | 42 ++++++++++++++++++- .../DataExchange/Import/ImportRow.cs | 14 ++----- .../DataExchange/ImportDataSegmenterTests.cs | 42 +++++++++++++++++++ .../SmartStore.Services.Tests.csproj | 1 + 4 files changed, 87 insertions(+), 12 deletions(-) create mode 100644 src/Tests/SmartStore.Services.Tests/DataExchange/ImportDataSegmenterTests.cs diff --git a/src/Libraries/SmartStore.Services/DataExchange/Import/ImportDataSegmenter.cs b/src/Libraries/SmartStore.Services/DataExchange/Import/ImportDataSegmenter.cs index 8a566dfbb8..4bcb355089 100644 --- a/src/Libraries/SmartStore.Services/DataExchange/Import/ImportDataSegmenter.cs +++ b/src/Libraries/SmartStore.Services/DataExchange/Import/ImportDataSegmenter.cs @@ -12,13 +12,15 @@ public class ImportDataSegmenter where T : BaseEntity { private const int BATCHSIZE = 100; - private IDataTable _table; + private readonly IDataTable _table; private ImportRow[] _currentBatch; - private IPageable _pageable; + private readonly IPageable _pageable; private bool _bof; private CultureInfo _culture; private ColumnMap _columnMap; + private readonly IDictionary _columnIndexes = new Dictionary(StringComparer.OrdinalIgnoreCase); + public ImportDataSegmenter(IDataTable table) { Guard.ArgumentNotNull(() => table); @@ -95,6 +97,42 @@ public bool HasDataColumn(string name, string index) return _table.HasColumn(_columnMap.GetMappedName(name, index)); } + /// + /// Returns an array of exisiting index names for a column + /// + /// The name of the columns without index qualification + /// An array of index names + /// + /// If following columns exist in source: Attr[Color], Attr[Size] + /// This method returns: string[] { "Color", "Size" } + /// + public string[] GetColumnIndexes(string name) + { + string[] indexes; + + if (!_columnIndexes.TryGetValue(name, out indexes)) + { + var startsWith = name + "["; + + var columns1 = _columnMap.Mappings + .Where(x => x.Key.StartsWith(startsWith, StringComparison.OrdinalIgnoreCase)) + .Select(x => x.Key); + + var columns2 = _table.Columns + .Where(x => x.Name.StartsWith(startsWith, StringComparison.OrdinalIgnoreCase)) + .Select(x => x.Name); + + indexes = columns1.Concat(columns2) + .Distinct(StringComparer.OrdinalIgnoreCase) + .Select(x => x.Substring(x.IndexOf("[", StringComparison.OrdinalIgnoreCase) + 1).TrimEnd(']')) + .ToArray(); + + _columnIndexes[name] = indexes; + } + + return indexes; + } + public void Reset() { if (_pageable.PageIndex != 0 && _currentBatch != null) diff --git a/src/Libraries/SmartStore.Services/DataExchange/Import/ImportRow.cs b/src/Libraries/SmartStore.Services/DataExchange/Import/ImportRow.cs index b1ebde7e70..9ca5ab441b 100644 --- a/src/Libraries/SmartStore.Services/DataExchange/Import/ImportRow.cs +++ b/src/Libraries/SmartStore.Services/DataExchange/Import/ImportRow.cs @@ -14,7 +14,7 @@ public class ImportRow where T : BaseEntity private bool _initialized = false; private T _entity; private string _entityDisplayName; - private int _position; + private readonly int _position; private bool _isNew; private ImportRowInfo _rowInfo; @@ -130,15 +130,9 @@ public bool SetProperty( } else { - if (value.ToString().ToUpper().Equals("NULL")) - { - // prop is set "explicitly" to null. - converted = default(TProp); - } - else - { - converted = value.Convert(_segmenter.Culture); - } + converted = value.ToString().ToUpper().Equals("NULL") + ? default(TProp) + : value.Convert(_segmenter.Culture); } fastProp.SetValue(target, converted); diff --git a/src/Tests/SmartStore.Services.Tests/DataExchange/ImportDataSegmenterTests.cs b/src/Tests/SmartStore.Services.Tests/DataExchange/ImportDataSegmenterTests.cs new file mode 100644 index 0000000000..ceb0fb3d93 --- /dev/null +++ b/src/Tests/SmartStore.Services.Tests/DataExchange/ImportDataSegmenterTests.cs @@ -0,0 +1,42 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using NUnit.Framework; +using SmartStore.Core.Domain.Catalog; +using SmartStore.Services.DataExchange.Import; +using SmartStore.Tests; + +namespace SmartStore.Services.Tests.DataExchange +{ + [TestFixture] + public class ImportDataSegmenterTests + { + [Test] + public void CanResolveColumnIndexNames() + { + var columns = new List + { + new LightweightDataColumn("Attr[Color]", typeof(string)), + new LightweightDataColumn("Attr[Size]", typeof(string)), + new LightweightDataColumn("material", typeof(string)), + new LightweightDataColumn("Name[en]", typeof(string)), + new LightweightDataColumn("Name[de]", typeof(string)), + new LightweightDataColumn("Name[fr]", typeof(string)), + new LightweightDataColumn("name_it", typeof(string)), + }; + + var table = new LightweightDataTable(columns, new List()); + var segmenter = new ImportDataSegmenter(table); + segmenter.ColumnMap.AddMapping("Attr[Material]", "material"); + segmenter.ColumnMap.AddMapping("Name[it]", "name_it"); + + var attrs = segmenter.GetColumnIndexes("Attr"); + attrs.ShouldSequenceEqual(new string[] {"Material", "Color", "Size"}); + + var langs = segmenter.GetColumnIndexes("Name"); + langs.ShouldSequenceEqual(new string[] { "it", "en", "de", "fr" }); + } + } +} diff --git a/src/Tests/SmartStore.Services.Tests/SmartStore.Services.Tests.csproj b/src/Tests/SmartStore.Services.Tests/SmartStore.Services.Tests.csproj index 1780542acc..a507b19eb5 100644 --- a/src/Tests/SmartStore.Services.Tests/SmartStore.Services.Tests.csproj +++ b/src/Tests/SmartStore.Services.Tests/SmartStore.Services.Tests.csproj @@ -106,6 +106,7 @@ + From 37eecc1bc5580bfc97264b5a96fac83106feb4cb Mon Sep 17 00:00:00 2001 From: Marcus Gesing Date: Wed, 9 Dec 2015 11:20:25 +0100 Subject: [PATCH 150/707] Display ID for primary entities on backend edit page --- .../Views/Category/_CreateOrUpdate.cshtml | 24 ++++++++++++++++--- .../Views/Customer/_CreateOrUpdate.cshtml | 14 ++++++++++- .../Views/Manufacturer/_CreateOrUpdate.cshtml | 22 +++++++++++++++-- .../Views/Product/_CreateOrUpdate.Info.cshtml | 4 ++-- 4 files changed, 56 insertions(+), 8 deletions(-) diff --git a/src/Presentation/SmartStore.Web/Administration/Views/Category/_CreateOrUpdate.cshtml b/src/Presentation/SmartStore.Web/Administration/Views/Category/_CreateOrUpdate.cshtml index 9f98f0d5a0..78b0bc549f 100644 --- a/src/Presentation/SmartStore.Web/Administration/Views/Category/_CreateOrUpdate.cshtml +++ b/src/Presentation/SmartStore.Web/Administration/Views/Category/_CreateOrUpdate.cshtml @@ -14,8 +14,25 @@ //generate an event EngineContext.Current.Resolve().Publish(new TabStripCreated(x, "category-edit", this.Html, this.Model)); }) -@helper TabInfo() { - +@helper TabInfo() +{ + if (Model.Id != 0) + { + + + + + +
    + @Html.SmartLabelFor(model => model.Id) + + @Html.DisplayFor(model => model.Id) + @Html.ValidationMessageFor(model => model.Id) +
    + +

    + } + @(Html.LocalizedEditor("category-info-localized", @ @@ -99,7 +116,8 @@
    - )) +)) +
    diff --git a/src/Presentation/SmartStore.Web/Administration/Views/Customer/_CreateOrUpdate.cshtml b/src/Presentation/SmartStore.Web/Administration/Views/Customer/_CreateOrUpdate.cshtml index 090c3da2d5..dee81edee0 100644 --- a/src/Presentation/SmartStore.Web/Administration/Views/Customer/_CreateOrUpdate.cshtml +++ b/src/Presentation/SmartStore.Web/Administration/Views/Customer/_CreateOrUpdate.cshtml @@ -36,7 +36,7 @@ EngineContext.Current.Resolve().Publish(new TabStripCreated(x, "customer-edit", this.Html, this.Model)); }) @helper TabInfo() - { +{ if (Model.CountryEnabled && Model.StateProvinceEnabled) { } + @if (Model.Id != 0) + { + + + + + } @if (Model.UsernamesEnabled) { if (Model.Id == 0 || Model.AllowUsersToChangeUsernames) diff --git a/src/Presentation/SmartStore.Web/Administration/Views/Manufacturer/_CreateOrUpdate.cshtml b/src/Presentation/SmartStore.Web/Administration/Views/Manufacturer/_CreateOrUpdate.cshtml index 44385835cb..8b0c80c9ac 100644 --- a/src/Presentation/SmartStore.Web/Administration/Views/Manufacturer/_CreateOrUpdate.cshtml +++ b/src/Presentation/SmartStore.Web/Administration/Views/Manufacturer/_CreateOrUpdate.cshtml @@ -15,7 +15,24 @@ EngineContext.Current.Resolve().Publish(new TabStripCreated(x, "manufacturer-edit", this.Html, this.Model)); }) @helper TabInfo() - { +{ + if (Model.Id != 0) + { +
    + @Html.SmartLabelFor(model => model.Id) + + @Html.DisplayFor(model => model.Id) + @Html.ValidationMessageFor(model => model.Id) +
    + + + + +
    + @Html.SmartLabelFor(model => model.Id) + + @Html.DisplayFor(model => model.Id) + @Html.ValidationMessageFor(model => model.Id) +
    + +

    + } + @(Html.LocalizedEditor("manufacturer-info-localized", @ @@ -63,7 +80,8 @@
    - )) +)) + - + @@ -45,10 +45,10 @@ @Html.SymbolForBool(profile.Enabled) - - + @@ -332,7 +331,6 @@ - + + + +
    diff --git a/src/Presentation/SmartStore.Web/Administration/Views/Product/_CreateOrUpdate.Info.cshtml b/src/Presentation/SmartStore.Web/Administration/Views/Product/_CreateOrUpdate.Info.cshtml index 8b4f0e6dba..9352203d40 100644 --- a/src/Presentation/SmartStore.Web/Administration/Views/Product/_CreateOrUpdate.Info.cshtml +++ b/src/Presentation/SmartStore.Web/Administration/Views/Product/_CreateOrUpdate.Info.cshtml @@ -191,14 +191,14 @@
    - @if (Model.Id > 0) + @if (Model.Id != 0) { From 09ad4aa3641768ace64de481d4960bf8896dff01 Mon Sep 17 00:00:00 2001 From: Marcus Gesing Date: Wed, 9 Dec 2015 17:17:03 +0100 Subject: [PATCH 151/707] Initial implementation of import framework --- .../Domain/DataExchange/ImportProfile.cs | 62 +++++ .../SmartStore.Core/SmartStore.Core.csproj | 1 + .../Mapping/DataExchange/ImportProfileMap.cs | 25 ++ .../201508091512101_ExportFramework.cs | 19 +- ...01512091408315_ImportFramework.Designer.cs | 29 +++ .../201512091408315_ImportFramework.cs | 109 +++++++++ .../201512091408315_ImportFramework.resx | 126 ++++++++++ .../SmartStore.Data/SmartStore.Data.csproj | 8 + .../DataExchange/ExportProfileService.cs | 4 - .../DataExchange/Import/DataImportTask.cs | 17 ++ .../Import/IImportProfileService.cs | 42 ++++ .../DataExchange/Import/ImportExtensions.cs | 55 +++++ .../Import/ImportProfileService.cs | 124 ++++++++++ .../Security/StandardPermissionProvider.cs | 3 + .../SmartStore.Services.csproj | 4 + .../DependencyRegistrar.cs | 1 + .../Controllers/ImportController.cs | 218 ++++++++++++++++++ .../Models/DataExchange/ExportProfileModel.cs | 8 +- .../Models/DataExchange/ImportProfileModel.cs | 46 ++++ .../Administration/SmartStore.Admin.csproj | 4 + .../DataExchange/ImportProfileValidator.cs | 22 ++ .../Administration/Views/Export/List.cshtml | 2 +- .../Administration/Views/Import/List.cshtml | 167 ++++++++++++++ .../Administration/sitemap.config | 1 + 24 files changed, 1068 insertions(+), 29 deletions(-) create mode 100644 src/Libraries/SmartStore.Core/Domain/DataExchange/ImportProfile.cs create mode 100644 src/Libraries/SmartStore.Data/Mapping/DataExchange/ImportProfileMap.cs create mode 100644 src/Libraries/SmartStore.Data/Migrations/201512091408315_ImportFramework.Designer.cs create mode 100644 src/Libraries/SmartStore.Data/Migrations/201512091408315_ImportFramework.cs create mode 100644 src/Libraries/SmartStore.Data/Migrations/201512091408315_ImportFramework.resx create mode 100644 src/Libraries/SmartStore.Services/DataExchange/Import/DataImportTask.cs create mode 100644 src/Libraries/SmartStore.Services/DataExchange/Import/IImportProfileService.cs create mode 100644 src/Libraries/SmartStore.Services/DataExchange/Import/ImportExtensions.cs create mode 100644 src/Libraries/SmartStore.Services/DataExchange/Import/ImportProfileService.cs create mode 100644 src/Presentation/SmartStore.Web/Administration/Controllers/ImportController.cs create mode 100644 src/Presentation/SmartStore.Web/Administration/Models/DataExchange/ImportProfileModel.cs create mode 100644 src/Presentation/SmartStore.Web/Administration/Validators/DataExchange/ImportProfileValidator.cs create mode 100644 src/Presentation/SmartStore.Web/Administration/Views/Import/List.cshtml diff --git a/src/Libraries/SmartStore.Core/Domain/DataExchange/ImportProfile.cs b/src/Libraries/SmartStore.Core/Domain/DataExchange/ImportProfile.cs new file mode 100644 index 0000000000..38633e4fed --- /dev/null +++ b/src/Libraries/SmartStore.Core/Domain/DataExchange/ImportProfile.cs @@ -0,0 +1,62 @@ +using SmartStore.Core.Domain.Tasks; + +namespace SmartStore.Core.Domain +{ + public class ImportProfile : BaseEntity + { + /// + /// The name of the profile + /// + public string Name { get; set; } + + /// + /// The name of the folder (file system) + /// + public string FolderName { get; set; } + + /// + /// The type of the entity + /// + public string EntityType { get; set; } + + /// + /// Whether the profile is enabled + /// + public bool Enabled { get; set; } + + /// + /// Number of records to bypass + /// + public int Skip { get; set; } + + /// + /// Maximum number of records to return + /// + public int Take { get; set; } + + /// + /// File type specific configuration + /// + public string FileTypeConfiguration { get; set; } + + /// + /// Mapping of import columns + /// + public string ColumnMapping { get; set; } + + /// + /// Whether to delete import files after import + /// + public bool Cleanup { get; set; } + + /// + /// The scheduling task identifier + /// + public int SchedulingTaskId { get; set; } + + /// + /// The scheduling task + /// + public virtual ScheduleTask ScheduleTask { get; set; } + } +} diff --git a/src/Libraries/SmartStore.Core/SmartStore.Core.csproj b/src/Libraries/SmartStore.Core/SmartStore.Core.csproj index 96cdf8c400..e876d7b408 100644 --- a/src/Libraries/SmartStore.Core/SmartStore.Core.csproj +++ b/src/Libraries/SmartStore.Core/SmartStore.Core.csproj @@ -168,6 +168,7 @@ + diff --git a/src/Libraries/SmartStore.Data/Mapping/DataExchange/ImportProfileMap.cs b/src/Libraries/SmartStore.Data/Mapping/DataExchange/ImportProfileMap.cs new file mode 100644 index 0000000000..94b9d9a46a --- /dev/null +++ b/src/Libraries/SmartStore.Data/Mapping/DataExchange/ImportProfileMap.cs @@ -0,0 +1,25 @@ +using System.Data.Entity.ModelConfiguration; +using SmartStore.Core.Domain; + +namespace SmartStore.Data.Mapping.DataExchange +{ + public partial class ImportProfileMap : EntityTypeConfiguration + { + public ImportProfileMap() + { + this.ToTable("ImportProfile"); + this.HasKey(x => x.Id); + + this.Property(x => x.Name).IsRequired().HasMaxLength(100); + this.Property(x => x.FolderName).IsRequired().HasMaxLength(100); + this.Property(x => x.EntityType).IsRequired().HasMaxLength(100); + this.Property(x => x.FileTypeConfiguration).IsMaxLength(); + this.Property(x => x.ColumnMapping).IsMaxLength(); + + this.HasRequired(x => x.ScheduleTask) + .WithMany() + .HasForeignKey(x => x.SchedulingTaskId) + .WillCascadeOnDelete(false); + } + } +} diff --git a/src/Libraries/SmartStore.Data/Migrations/201508091512101_ExportFramework.cs b/src/Libraries/SmartStore.Data/Migrations/201508091512101_ExportFramework.cs index 64bb41f4d8..74f4c865d7 100644 --- a/src/Libraries/SmartStore.Data/Migrations/201508091512101_ExportFramework.cs +++ b/src/Libraries/SmartStore.Data/Migrations/201508091512101_ExportFramework.cs @@ -142,24 +142,7 @@ public void MigrateLocaleResources(LocaleResourcesBuilder builder) "The file type of the exported data.", "Der Dateityp der exportierten Daten."); - builder.AddOrUpdate("Admin.DataExchange.Export.LastExecution", - "Last execution", - "Letzte Ausfhrung", - "Information about the last execution of the export.", - "Informationen zur letzten Ausfhrung des Exports."); - - - builder.AddOrUpdate("Admin.DataExchange.Export.Offset", - "Skip", - "berspringen", - "Specifies the number of records to be skipped.", - "Legt die Anzahl der zu berspringenden Datenstze fest."); - - builder.AddOrUpdate("Admin.DataExchange.Export.Limit", - "Limit", - "Begrenzen", - "Specifies how many records to be loaded at maximum.", - "Legt die maximale Anzahl der zu exportierenden Datenstze fest."); + builder.AddOrUpdate("Admin.DataExchange.Export.BatchSize", "Batch size", diff --git a/src/Libraries/SmartStore.Data/Migrations/201512091408315_ImportFramework.Designer.cs b/src/Libraries/SmartStore.Data/Migrations/201512091408315_ImportFramework.Designer.cs new file mode 100644 index 0000000000..2d56b77d1e --- /dev/null +++ b/src/Libraries/SmartStore.Data/Migrations/201512091408315_ImportFramework.Designer.cs @@ -0,0 +1,29 @@ +// +namespace SmartStore.Data.Migrations +{ + using System.CodeDom.Compiler; + using System.Data.Entity.Migrations; + using System.Data.Entity.Migrations.Infrastructure; + using System.Resources; + + [GeneratedCode("EntityFramework.Migrations", "6.1.3-40302")] + public sealed partial class ImportFramework : IMigrationMetadata + { + private readonly ResourceManager Resources = new ResourceManager(typeof(ImportFramework)); + + string IMigrationMetadata.Id + { + get { return "201512091408315_ImportFramework"; } + } + + string IMigrationMetadata.Source + { + get { return null; } + } + + string IMigrationMetadata.Target + { + get { return Resources.GetString("Target"); } + } + } +} diff --git a/src/Libraries/SmartStore.Data/Migrations/201512091408315_ImportFramework.cs b/src/Libraries/SmartStore.Data/Migrations/201512091408315_ImportFramework.cs new file mode 100644 index 0000000000..06901ed24c --- /dev/null +++ b/src/Libraries/SmartStore.Data/Migrations/201512091408315_ImportFramework.cs @@ -0,0 +1,109 @@ +namespace SmartStore.Data.Migrations +{ + using System.Data.Entity.Migrations; + using Core.Domain.Customers; + using Core.Domain.Security; + using Setup; + + public partial class ImportFramework : DbMigration, ILocaleResourcesProvider, IDataSeeder + { + public override void Up() + { + CreateTable( + "dbo.ImportProfile", + c => new + { + Id = c.Int(nullable: false, identity: true), + Name = c.String(nullable: false, maxLength: 100), + FolderName = c.String(nullable: false, maxLength: 100), + EntityType = c.String(nullable: false, maxLength: 100), + Enabled = c.Boolean(nullable: false), + Skip = c.Int(nullable: false), + Take = c.Int(nullable: false), + FileTypeConfiguration = c.String(), + ColumnMapping = c.String(), + Cleanup = c.Boolean(nullable: false), + SchedulingTaskId = c.Int(nullable: false), + }) + .PrimaryKey(t => t.Id) + .ForeignKey("dbo.ScheduleTask", t => t.SchedulingTaskId) + .Index(t => t.SchedulingTaskId); + + } + + public override void Down() + { + DropForeignKey("dbo.ImportProfile", "SchedulingTaskId", "dbo.ScheduleTask"); + DropIndex("dbo.ImportProfile", new[] { "SchedulingTaskId" }); + DropTable("dbo.ImportProfile"); + } + + public bool RollbackOnFailure + { + get { return false; } + } + + public void Seed(SmartObjectContext context) + { + context.MigrateLocaleResources(MigrateLocaleResources); + + var permissionMigrator = new PermissionMigrator(context); + + permissionMigrator.AddPermission(new PermissionRecord + { + Name = "Admin area. Manage Imports", + SystemName = "ManageImports", + Category = "Configuration" + }, new string[] { SystemCustomerRoleNames.Administrators }); + } + + public void MigrateLocaleResources(LocaleResourcesBuilder builder) + { + builder.AddOrUpdate("Common.Files", "Files", "Dateien"); + + builder.AddOrUpdate("Admin.Common.RecordsSkip", + "Skip", + "berspringen", + "Specifies the number of records to be skipped.", + "Legt die Anzahl der zu berspringenden Datenstze fest."); + + builder.AddOrUpdate("Admin.Common.RecordsTake", + "Limit", + "Begrenzen", + "Specifies the maximum number of records to be processed.", + "Legt die maximale Anzahl der zu verarbeitenden Datenstze fest."); + + builder.AddOrUpdate("Admin.DataExchange.Import.NoProfiles", + "There were no import profiles found.", + "Es wurden keine Importprofile gefunden."); + + builder.AddOrUpdate("Admin.DataExchange.Import.FolderName.Validate", + "Please enter a valid folder name.", + "Bitte einen gltigen Ordnernamen eingeben."); + + builder.AddOrUpdate("Admin.DataExchange.Import.Name", + "Name of profile", + "Name des Profils", + "Specifies the name of the import profile.", + "Legt den Namen des Importprofils fest."); + + builder.AddOrUpdate("Admin.DataExchange.Import.FolderName", + "Folder name", + "Ordnername", + "Specifies the name of the folder where the import files are saved.", + "Legt den Namen des Ordners fest, in den die Importdateien gespeichert werden."); + + builder.AddOrUpdate("Admin.DataExchange.Import.Cleanup", + "Clean up at the end", + "Zum Schluss aufrumen", + "Specifies whether to delete import files after an import.", + "Legt fest, ob die Importdateien nach einem Import gelscht werden sollen."); + + builder.Delete( + "Admin.DataExchange.Export.LastExecution", + "Admin.DataExchange.Export.Offset", + "Admin.DataExchange.Export.Limit" + ); + } + } +} diff --git a/src/Libraries/SmartStore.Data/Migrations/201512091408315_ImportFramework.resx b/src/Libraries/SmartStore.Data/Migrations/201512091408315_ImportFramework.resx new file mode 100644 index 0000000000..bf924882bc --- /dev/null +++ b/src/Libraries/SmartStore.Data/Migrations/201512091408315_ImportFramework.resx @@ -0,0 +1,126 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 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 + + + dbo + + \ No newline at end of file diff --git a/src/Libraries/SmartStore.Data/SmartStore.Data.csproj b/src/Libraries/SmartStore.Data/SmartStore.Data.csproj index 7e8cce3347..aee5f01421 100644 --- a/src/Libraries/SmartStore.Data/SmartStore.Data.csproj +++ b/src/Libraries/SmartStore.Data/SmartStore.Data.csproj @@ -121,6 +121,7 @@ + @@ -371,6 +372,10 @@ 201511271019577_ExportFramework3.cs + + + 201512091408315_ImportFramework.cs + @@ -694,6 +699,9 @@ 201511271019577_ExportFramework3.cs + + 201512091408315_ImportFramework.cs + diff --git a/src/Libraries/SmartStore.Services/DataExchange/ExportProfileService.cs b/src/Libraries/SmartStore.Services/DataExchange/ExportProfileService.cs index 3f2314afb1..53776a31c7 100644 --- a/src/Libraries/SmartStore.Services/DataExchange/ExportProfileService.cs +++ b/src/Libraries/SmartStore.Services/DataExchange/ExportProfileService.cs @@ -45,8 +45,6 @@ public ExportProfileService( _localizationService = localizationService; } - #region Export profiles - public virtual ExportProfile InsertExportProfile( string providerSystemName, string name, @@ -340,7 +338,5 @@ public virtual void DeleteExportDeployment(ExportDeployment deployment) _eventPublisher.EntityDeleted(deployment); } - - #endregion } } diff --git a/src/Libraries/SmartStore.Services/DataExchange/Import/DataImportTask.cs b/src/Libraries/SmartStore.Services/DataExchange/Import/DataImportTask.cs new file mode 100644 index 0000000000..ad4a21785b --- /dev/null +++ b/src/Libraries/SmartStore.Services/DataExchange/Import/DataImportTask.cs @@ -0,0 +1,17 @@ +using SmartStore.Services.Tasks; + +namespace SmartStore.Services.DataExchange.Import +{ + // note: namespace persisted in ScheduleTask.Type + public partial class DataImportTask : ITask + { + public DataImportTask() + { + } + + public void Execute(TaskExecutionContext ctx) + { + // TODO + } + } +} diff --git a/src/Libraries/SmartStore.Services/DataExchange/Import/IImportProfileService.cs b/src/Libraries/SmartStore.Services/DataExchange/Import/IImportProfileService.cs new file mode 100644 index 0000000000..85d6f64dec --- /dev/null +++ b/src/Libraries/SmartStore.Services/DataExchange/Import/IImportProfileService.cs @@ -0,0 +1,42 @@ +using System.Linq; +using SmartStore.Core.Domain; + +namespace SmartStore.Services.DataExchange.Import +{ + public interface IImportProfileService + { + /// + /// Inserts an import profile + /// + /// Profile name + /// + /// Inserted import profile + ImportProfile InsertImportProfile(string name, string entityType); + + /// + /// Updates an import profile + /// + /// Import profile + void UpdateImportProfile(ImportProfile profile); + + /// + /// Deletes an import profile + /// + /// Import profile + void DeleteImportProfile(ImportProfile profile); + + /// + /// Get queryable import profiles + /// + /// Whether to filter enabled or disabled profiles + /// Import profiles + IQueryable GetImportProfiles(bool? enabled = null); + + /// + /// Gets an import profile by identifier + /// + /// Import profile identifier + /// Import profile + ImportProfile GetImportProfileById(int id); + } +} diff --git a/src/Libraries/SmartStore.Services/DataExchange/Import/ImportExtensions.cs b/src/Libraries/SmartStore.Services/DataExchange/Import/ImportExtensions.cs new file mode 100644 index 0000000000..078a04a460 --- /dev/null +++ b/src/Libraries/SmartStore.Services/DataExchange/Import/ImportExtensions.cs @@ -0,0 +1,55 @@ +using System.Collections.Generic; +using System.IO; +using System.Linq; +using SmartStore.Core.Domain; +using SmartStore.Utilities; + +namespace SmartStore.Services.DataExchange.Import +{ + public static class ImportExtensions + { + /// + /// Get folder for import files + /// + /// Import profile + /// Folder path + public static string GetImportFolder(this ImportProfile profile, bool content = false, bool create = false) + { + var path = CommonHelper.MapPath(string.Concat("~/App_Data/ImportProfiles/", profile.FolderName, content ? "/Content" : "")); + + if (create && !System.IO.Directory.Exists(path)) + System.IO.Directory.CreateDirectory(path); + + return path; + } + + /// + /// Gets import files for an import profile + /// + /// Import profile + /// List of file paths + public static List GetImportFiles(this ImportProfile profile) + { + var folder = profile.GetImportFolder(true); + + if (System.IO.Directory.Exists(folder)) + { + return System.IO.Directory.EnumerateFiles(folder, "*", SearchOption.TopDirectoryOnly) + .OrderBy(x => x) + .ToList(); + } + + return new List(); + } + + /// + /// Get log file path for an import profile + /// + /// Import profile + /// Log file path + public static string GetImportLogPath(this ImportProfile profile) + { + return Path.Combine(profile.GetImportFolder(), "log.txt"); + } + } +} diff --git a/src/Libraries/SmartStore.Services/DataExchange/Import/ImportProfileService.cs b/src/Libraries/SmartStore.Services/DataExchange/Import/ImportProfileService.cs new file mode 100644 index 0000000000..76f7a0b083 --- /dev/null +++ b/src/Libraries/SmartStore.Services/DataExchange/Import/ImportProfileService.cs @@ -0,0 +1,124 @@ +using System; +using System.Linq; +using SmartStore.Core.Data; +using SmartStore.Core.Domain; +using SmartStore.Core.Domain.DataExchange; +using SmartStore.Core.Domain.Tasks; +using SmartStore.Core.Events; +using SmartStore.Services.Tasks; +using SmartStore.Utilities; + +namespace SmartStore.Services.DataExchange.Import +{ + public partial class ImportProfileService : IImportProfileService + { + private readonly IRepository _importProfileRepository; + private readonly IEventPublisher _eventPublisher; + private readonly IScheduleTaskService _scheduleTaskService; + private readonly DataExchangeSettings _dataExchangeSettings; + + public ImportProfileService( + IRepository importProfileRepository, + IEventPublisher eventPublisher, + IScheduleTaskService scheduleTaskService, + DataExchangeSettings dataExchangeSettings) + { + _importProfileRepository = importProfileRepository; + _eventPublisher = eventPublisher; + _scheduleTaskService = scheduleTaskService; + _dataExchangeSettings = dataExchangeSettings; + } + + public virtual ImportProfile InsertImportProfile(string name, string entityType) + { + Guard.ArgumentNotEmpty(() => name); + Guard.ArgumentNotEmpty(() => entityType); + + var task = new ScheduleTask + { + CronExpression = "0 */24 * * *", + Type = typeof(DataImportTask).AssemblyQualifiedNameWithoutVersion(), + Enabled = false, + StopOnError = false, + IsHidden = true + }; + + task.Name = string.Concat(name, " Task"); + + _scheduleTaskService.InsertTask(task); + + var profile = new ImportProfile + { + Name = name, + EntityType = entityType, + Enabled = true, + SchedulingTaskId = task.Id + }; + + profile.FolderName = SeoHelper.GetSeName(name, true, false) + .ToValidPath() + .Truncate(_dataExchangeSettings.MaxFileNameLength); + + _importProfileRepository.Insert(profile); + + task.Alias = profile.Id.ToString(); + _scheduleTaskService.UpdateTask(task); + + _eventPublisher.EntityInserted(profile); + + return profile; + } + + public virtual void UpdateImportProfile(ImportProfile profile) + { + if (profile == null) + throw new ArgumentNullException("profile"); + + _importProfileRepository.Update(profile); + + _eventPublisher.EntityUpdated(profile); + } + + public virtual void DeleteImportProfile(ImportProfile profile) + { + if (profile == null) + throw new ArgumentNullException("profile"); + + int scheduleTaskId = profile.SchedulingTaskId; + + _importProfileRepository.Delete(profile); + + var scheduleTask = _scheduleTaskService.GetTaskById(scheduleTaskId); + _scheduleTaskService.DeleteTask(scheduleTask); + + _eventPublisher.EntityDeleted(profile); + } + + public virtual IQueryable GetImportProfiles(bool? enabled = null) + { + var query = _importProfileRepository.Table + .Expand(x => x.ScheduleTask); + + if (enabled.HasValue) + { + query = query.Where(x => x.Enabled == enabled.Value); + } + + query = query.OrderBy(x => x.Name); + + return query; + } + + public virtual ImportProfile GetImportProfileById(int id) + { + if (id == 0) + return null; + + var profile = _importProfileRepository.Table + .Expand(x => x.ScheduleTask) + .FirstOrDefault(x => x.Id == id); + + return profile; + } + } +} diff --git a/src/Libraries/SmartStore.Services/Security/StandardPermissionProvider.cs b/src/Libraries/SmartStore.Services/Security/StandardPermissionProvider.cs index 886196b240..4f1032077a 100644 --- a/src/Libraries/SmartStore.Services/Security/StandardPermissionProvider.cs +++ b/src/Libraries/SmartStore.Services/Security/StandardPermissionProvider.cs @@ -50,6 +50,7 @@ public partial class StandardPermissionProvider : IPermissionProvider public static readonly PermissionRecord UploadPictures = new PermissionRecord { Name = "Admin area. Upload Pictures", SystemName = "UploadPictures", Category = "Configuration" }; public static readonly PermissionRecord ManageScheduleTasks = new PermissionRecord { Name = "Admin area. Manage Schedule Tasks", SystemName = "ManageScheduleTasks", Category = "Configuration" }; public static readonly PermissionRecord ManageExports = new PermissionRecord { Name = "Admin area. Manage Exports", SystemName = "ManageExports", Category = "Configuration" }; + public static readonly PermissionRecord ManageImports = new PermissionRecord { Name = "Admin area. Manage Imports", SystemName = "ManageImports", Category = "Configuration" }; public static readonly PermissionRecord ManageUrlRecords = new PermissionRecord { Name = "Admin area. Manage Url Records", SystemName = "ManageUrlRecords", Category = "Configuration" }; //public store permissions @@ -105,6 +106,7 @@ public virtual IEnumerable GetPermissions() UploadPictures, ManageScheduleTasks, ManageExports, + ManageImports, ManageUrlRecords, DisplayPrices, EnableShoppingCart, @@ -164,6 +166,7 @@ public virtual IEnumerable GetDefaultPermissions() UploadPictures, ManageScheduleTasks, ManageExports, + ManageImports, ManageUrlRecords, DisplayPrices, EnableShoppingCart, diff --git a/src/Libraries/SmartStore.Services/SmartStore.Services.csproj b/src/Libraries/SmartStore.Services/SmartStore.Services.csproj index b1c9cc5a3f..c61ee698c3 100644 --- a/src/Libraries/SmartStore.Services/SmartStore.Services.csproj +++ b/src/Libraries/SmartStore.Services/SmartStore.Services.csproj @@ -184,8 +184,12 @@ + + + + diff --git a/src/Presentation/SmartStore.Web.Framework/DependencyRegistrar.cs b/src/Presentation/SmartStore.Web.Framework/DependencyRegistrar.cs index eb2f5b2b1e..9536d25375 100644 --- a/src/Presentation/SmartStore.Web.Framework/DependencyRegistrar.cs +++ b/src/Presentation/SmartStore.Web.Framework/DependencyRegistrar.cs @@ -247,6 +247,7 @@ protected override void Load(ContainerBuilder builder) builder.RegisterType().As().InstancePerRequest(); builder.RegisterType().As().InstancePerRequest(); + builder.RegisterType().As().InstancePerRequest(); builder.RegisterType().As().InstancePerRequest(); builder.RegisterType().As().InstancePerRequest(); diff --git a/src/Presentation/SmartStore.Web/Administration/Controllers/ImportController.cs b/src/Presentation/SmartStore.Web/Administration/Controllers/ImportController.cs new file mode 100644 index 0000000000..2c5040e624 --- /dev/null +++ b/src/Presentation/SmartStore.Web/Administration/Controllers/ImportController.cs @@ -0,0 +1,218 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Web.Mvc; +using SmartStore.Admin.Extensions; +using SmartStore.Admin.Models.DataExchange; +using SmartStore.Core.Domain; +using SmartStore.Core.IO; +using SmartStore.Services; +using SmartStore.Services.DataExchange.Import; +using SmartStore.Services.Helpers; +using SmartStore.Services.Security; +using SmartStore.Services.Tasks; +using SmartStore.Web.Framework.Controllers; +using SmartStore.Web.Framework.Filters; +using SmartStore.Web.Framework.Security; + +namespace SmartStore.Admin.Controllers +{ + [AdminAuthorize] + public class ImportController : AdminControllerBase + { + private readonly ICommonServices _services; + private readonly IImportProfileService _importService; + private readonly IDateTimeHelper _dateTimeHelper; + private readonly ITaskScheduler _taskScheduler; + + public ImportController( + ICommonServices services, + IImportProfileService importService, + IDateTimeHelper dateTimeHelper, + ITaskScheduler taskScheduler) + { + _services = services; + _importService = importService; + _dateTimeHelper = dateTimeHelper; + _taskScheduler = taskScheduler; + } + + #region Utilities + + private void PrepareProfileModel(ImportProfileModel model, ImportProfile profile, bool forEdit) + { + model.Id = profile.Id; + model.Name = profile.Name; + model.FolderName = profile.FolderName; + model.FileNames = profile.GetImportFiles(); + model.EntityType = profile.EntityType; + model.Enabled = profile.Enabled; + model.Skip = profile.Skip; + model.Take = profile.Take; + model.Cleanup = profile.Cleanup; + model.ScheduleTaskId = profile.SchedulingTaskId; + model.ScheduleTaskName = profile.ScheduleTask.Name.NaIfEmpty(); + model.IsTaskRunning = profile.ScheduleTask.IsRunning; + model.IsTaskEnabled = profile.ScheduleTask.Enabled; + model.LogFileExists = System.IO.File.Exists(profile.GetImportLogPath()); + } + + #endregion + + public ActionResult Index() + { + return RedirectToAction("List"); + } + + public ActionResult List() + { + if (!_services.Permissions.Authorize(StandardPermissionProvider.ManageImports)) + return AccessDeniedView(); + + var profiles = _importService.GetImportProfiles().ToList(); + var model = new List(); + + foreach (var profile in profiles) + { + var profileModel = new ImportProfileModel(); + + PrepareProfileModel(profileModel, profile, false); + + profileModel.TaskModel = profile.ScheduleTask.ToScheduleTaskModel(_services.Localization, _dateTimeHelper, Url); + + model.Add(profileModel); + } + + return View(model); + } + + public ActionResult Edit(int id) + { + if (!_services.Permissions.Authorize(StandardPermissionProvider.ManageImports)) + return AccessDeniedView(); + + var profile = _importService.GetImportProfileById(id); + if (profile == null) + return RedirectToAction("List"); + + var model = new ImportProfileModel(); + + PrepareProfileModel(model, profile, true); + + return View(model); + } + + [HttpPost, ParameterBasedOnFormName("save-continue", "continueEditing")] + [FormValueRequired("save", "save-continue")] + public ActionResult Edit(ImportProfileModel model, bool continueEditing) + { + if (!_services.Permissions.Authorize(StandardPermissionProvider.ManageImports)) + return AccessDeniedView(); + + var profile = _importService.GetImportProfileById(model.Id); + if (profile == null) + return RedirectToAction("List"); + + if (!ModelState.IsValid) + { + PrepareProfileModel(model, profile, true); + return View(model); + } + + profile.Name = model.Name; + profile.FolderName = model.FolderName; + profile.Enabled = model.Enabled; + + + _importService.UpdateImportProfile(profile); + + NotifySuccess(T("Admin.Common.DataSuccessfullySaved")); + + return (continueEditing ? RedirectToAction("Edit", new { id = profile.Id }) : RedirectToAction("List")); + } + + [HttpPost, ActionName("Delete")] + public ActionResult DeleteConfirmed(int id) + { + if (!_services.Permissions.Authorize(StandardPermissionProvider.ManageImports)) + return AccessDeniedView(); + + var profile = _importService.GetImportProfileById(id); + if (profile == null) + return RedirectToAction("List"); + + try + { + _importService.DeleteImportProfile(profile); + + NotifySuccess(T("Admin.Common.TaskSuccessfullyProcessed")); + + return RedirectToAction("List"); + } + catch (Exception exception) + { + NotifyError(exception); + } + + return RedirectToAction("Edit", new { id = profile.Id }); + } + + [HttpPost] + public ActionResult Execute(int id) + { + if (!_services.Permissions.Authorize(StandardPermissionProvider.ManageImports)) + return AccessDeniedView(); + + var profile = _importService.GetImportProfileById(id); + if (profile == null) + return RedirectToAction("List"); + + _taskScheduler.RunSingleTask(profile.SchedulingTaskId, null); + + NotifyInfo(T("Admin.System.ScheduleTasks.RunNow.Progress")); + + return RedirectToAction("List"); + } + + public ActionResult DownloadLogFile(int id) + { + if (!_services.Permissions.Authorize(StandardPermissionProvider.ManageImports)) + return AccessDeniedView(); + + var profile = _importService.GetImportProfileById(id); + if (profile == null) + return RedirectToAction("List"); + + var path = profile.GetImportLogPath(); + var stream = new FileStream(path, FileMode.Open); + + var result = new FileStreamResult(stream, "text/plain; charset=utf-8"); + result.FileDownloadName = profile.Name.ToValidFileName() + "-log.txt"; + + return result; + } + + public ActionResult DownloadExportFile(int id, string name) + { + if (!_services.Permissions.Authorize(StandardPermissionProvider.ManageImports)) + return AccessDeniedView(); + + var profile = _importService.GetImportProfileById(id); + if (profile == null) + return RedirectToAction("List"); + + var path = Path.Combine(profile.GetImportFolder(true), name); + + if (!System.IO.File.Exists(path)) + path = Path.Combine(profile.GetImportFolder(false), name); + + var stream = new FileStream(path, FileMode.Open); + + var result = new FileStreamResult(stream, MimeTypes.MapNameToMimeType(path)); + result.FileDownloadName = Path.GetFileName(path); + + return result; + } + } +} \ No newline at end of file diff --git a/src/Presentation/SmartStore.Web/Administration/Models/DataExchange/ExportProfileModel.cs b/src/Presentation/SmartStore.Web/Administration/Models/DataExchange/ExportProfileModel.cs index 9c01bef987..73c26d57d2 100644 --- a/src/Presentation/SmartStore.Web/Administration/Models/DataExchange/ExportProfileModel.cs +++ b/src/Presentation/SmartStore.Web/Administration/Models/DataExchange/ExportProfileModel.cs @@ -49,14 +49,10 @@ public partial class ExportProfileModel : EntityModelBase public bool IsTaskRunning { get; set; } public bool IsTaskEnabled { get; set; } - [SmartResourceDisplayName("Admin.DataExchange.Export.LastExecution")] - [AllowHtml] - public string LastExecution { get; set; } - - [SmartResourceDisplayName("Admin.DataExchange.Export.Offset")] + [SmartResourceDisplayName("Admin.Common.RecordsSkip")] public int Offset { get; set; } - [SmartResourceDisplayName("Admin.DataExchange.Export.Limit")] + [SmartResourceDisplayName("Admin.Common.RecordsTake")] public int Limit { get; set; } [SmartResourceDisplayName("Admin.DataExchange.Export.BatchSize")] diff --git a/src/Presentation/SmartStore.Web/Administration/Models/DataExchange/ImportProfileModel.cs b/src/Presentation/SmartStore.Web/Administration/Models/DataExchange/ImportProfileModel.cs new file mode 100644 index 0000000000..a1a663f693 --- /dev/null +++ b/src/Presentation/SmartStore.Web/Administration/Models/DataExchange/ImportProfileModel.cs @@ -0,0 +1,46 @@ +using System.Collections.Generic; +using FluentValidation.Attributes; +using SmartStore.Admin.Models.Tasks; +using SmartStore.Admin.Validators.DataExchange; +using SmartStore.Web.Framework; +using SmartStore.Web.Framework.Modelling; + +namespace SmartStore.Admin.Models.DataExchange +{ + [Validator(typeof(ImportProfileValidator))] + public partial class ImportProfileModel : EntityModelBase + { + [SmartResourceDisplayName("Admin.DataExchange.Import.Name")] + public string Name { get; set; } + + [SmartResourceDisplayName("Admin.DataExchange.Import.FolderName")] + public string FolderName { get; set; } + + [SmartResourceDisplayName("Common.Files")] + public List FileNames { get; set; } + + [SmartResourceDisplayName("Admin.Common.Entity")] + public string EntityType { get; set; } + + [SmartResourceDisplayName("Common.Enabled")] + public bool Enabled { get; set; } + + [SmartResourceDisplayName("Admin.Common.RecordsSkip")] + public int Skip { get; set; } + + [SmartResourceDisplayName("Admin.Common.RecordsTake")] + public int Take { get; set; } + + [SmartResourceDisplayName("Admin.DataExchange.Import.Cleanup")] + public bool Cleanup { get; set; } + + [SmartResourceDisplayName("Common.Execution")] + public int ScheduleTaskId { get; set; } + public string ScheduleTaskName { get; set; } + public bool IsTaskRunning { get; set; } + public bool IsTaskEnabled { get; set; } + + public ScheduleTaskModel TaskModel { get; set; } + public bool LogFileExists { get; set; } + } +} \ No newline at end of file diff --git a/src/Presentation/SmartStore.Web/Administration/SmartStore.Admin.csproj b/src/Presentation/SmartStore.Web/Administration/SmartStore.Admin.csproj index 8beba42ebc..7bc7cfc138 100644 --- a/src/Presentation/SmartStore.Web/Administration/SmartStore.Admin.csproj +++ b/src/Presentation/SmartStore.Web/Administration/SmartStore.Admin.csproj @@ -181,6 +181,7 @@ + @@ -252,6 +253,7 @@ + @@ -374,6 +376,7 @@ + @@ -533,6 +536,7 @@ + diff --git a/src/Presentation/SmartStore.Web/Administration/Validators/DataExchange/ImportProfileValidator.cs b/src/Presentation/SmartStore.Web/Administration/Validators/DataExchange/ImportProfileValidator.cs new file mode 100644 index 0000000000..3760f5bae1 --- /dev/null +++ b/src/Presentation/SmartStore.Web/Administration/Validators/DataExchange/ImportProfileValidator.cs @@ -0,0 +1,22 @@ +using System.IO; +using System.Linq; +using FluentValidation; +using SmartStore.Admin.Models.DataExchange; +using SmartStore.Services.Localization; + +namespace SmartStore.Admin.Validators.DataExchange +{ + public partial class ImportProfileValidator : AbstractValidator + { + public ImportProfileValidator(ILocalizationService localization) + { + RuleFor(x => x.Name) + .NotEmpty() + .WithMessage(localization.GetResource("Admin.Validation.Name")); + + RuleFor(x => x.FolderName) + .Must(x => x.HasValue() && !x.IsCaseInsensitiveEqual("con") && !Path.GetInvalidFileNameChars().Any(y => x.Contains(y))) + .WithMessage(localization.GetResource("Admin.DataExchange.Import.FolderName.Validate")); + } + } +} \ No newline at end of file diff --git a/src/Presentation/SmartStore.Web/Administration/Views/Export/List.cshtml b/src/Presentation/SmartStore.Web/Administration/Views/Export/List.cshtml index 9ddcf27347..9405ee9369 100644 --- a/src/Presentation/SmartStore.Web/Administration/Views/Export/List.cshtml +++ b/src/Presentation/SmartStore.Web/Administration/Views/Export/List.cshtml @@ -157,7 +157,7 @@ else url: dialog.attr('data-urldelete'), ask: dialog.find('.modal-ask-delete').text(), callbackSuccess: function (resp) { - refreshGrid(forExport); + refreshGrid(); } }); return false; diff --git a/src/Presentation/SmartStore.Web/Administration/Views/Import/List.cshtml b/src/Presentation/SmartStore.Web/Administration/Views/Import/List.cshtml new file mode 100644 index 0000000000..105b8b85b4 --- /dev/null +++ b/src/Presentation/SmartStore.Web/Administration/Views/Import/List.cshtml @@ -0,0 +1,167 @@ +@using SmartStore.Core.Domain.DataExchange; +@using SmartStore.Admin.Models.DataExchange; +@using Telerik.Web.Mvc.UI; +@model List +@{ + ViewBag.Title = T("Common.Import").Text; +} + +
    +
    + + @T("Common.Import") +
    + +
    + +
    + + + +@if(Model.Count > 0) +{ +
    @Html.SmartLabelFor(model => model.Id) - @Model.Id.ToString() + @Html.DisplayFor(model => model.Id) @Html.ValidationMessageFor(model => model.Id)
    + + + + + + + + + + + + + @foreach (var profile in Model) + { + + + + + + + + + + } + +
    @T("Admin.DataExchange.Import.Name")@T("Common.Enabled")@T("Admin.Common.Entity")@T("Common.Files")@T("Admin.System.ScheduleTasks.LastStart")@T("Admin.System.ScheduleTasks.NextRun")@T("Admin.Common.Actions")
    + @profile.Name + + @Html.SymbolForBool(profile.Enabled) + + @profile.EntityType.NaIfEmpty() + + @(string.Join("
    ", profile.FileNames)) +
    +
    + @Html.Partial("~/Administration/Views/ScheduleTask/_LastRun.cshtml", profile.TaskModel) +
    +
    +
    + @Html.Partial("~/Administration/Views/ScheduleTask/_NextRun.cshtml", profile.TaskModel) +
    +
    +
    + + + + @T("Common.Cancel") + + + +  @T("Admin.Configuration.ActivityLog") + +
    +} +else +{ +
    + + @T("Admin.DataExchange.Import.NoProfiles") +
    +} + + diff --git a/src/Presentation/SmartStore.Web/Administration/sitemap.config b/src/Presentation/SmartStore.Web/Administration/sitemap.config index 573d1227b0..ac42790f6b 100644 --- a/src/Presentation/SmartStore.Web/Administration/sitemap.config +++ b/src/Presentation/SmartStore.Web/Administration/sitemap.config @@ -127,6 +127,7 @@ + From f31826e68d80543cc9dd3535843a118f9e7c3a86 Mon Sep 17 00:00:00 2001 From: Murat Cakir Date: Wed, 9 Dec 2015 18:08:48 +0100 Subject: [PATCH 152/707] Fixes #831: Message Template list page crashes --- .../Administration/Controllers/MessageTemplateController.cs | 1 + .../Administration/Models/Messages/MessageTemplateModel.cs | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/Presentation/SmartStore.Web/Administration/Controllers/MessageTemplateController.cs b/src/Presentation/SmartStore.Web/Administration/Controllers/MessageTemplateController.cs index 699dbcd4f6..be6c73a92b 100644 --- a/src/Presentation/SmartStore.Web/Administration/Controllers/MessageTemplateController.cs +++ b/src/Presentation/SmartStore.Web/Administration/Controllers/MessageTemplateController.cs @@ -171,6 +171,7 @@ public ActionResult List(GridCommand command, MessageTemplateListModel model) Data = messageTemplates.Select(x => x.ToModel()), Total = messageTemplates.Count }; + return new JsonResult { Data = gridModel diff --git a/src/Presentation/SmartStore.Web/Administration/Models/Messages/MessageTemplateModel.cs b/src/Presentation/SmartStore.Web/Administration/Models/Messages/MessageTemplateModel.cs index 4367223014..9dab2a81ba 100644 --- a/src/Presentation/SmartStore.Web/Administration/Models/Messages/MessageTemplateModel.cs +++ b/src/Presentation/SmartStore.Web/Administration/Models/Messages/MessageTemplateModel.cs @@ -2,6 +2,7 @@ using System.Web.Mvc; using System.Web.Script.Serialization; using FluentValidation.Attributes; +using Newtonsoft.Json; using SmartStore.Admin.Models.Stores; using SmartStore.Admin.Validators.Messages; using SmartStore.Collections; @@ -23,7 +24,7 @@ public MessageTemplateModel() } [SmartResourceDisplayName("Admin.ContentManagement.MessageTemplates.Fields.AllowedTokens")] - [ScriptIgnore] + [ScriptIgnore, JsonIgnore] public TreeNode TokensTree { get; set; } [SmartResourceDisplayName("Admin.ContentManagement.MessageTemplates.Fields.Name")] From e2b6680bae0c9293afc3cee2d0841ff49433cc6e Mon Sep 17 00:00:00 2001 From: Murat Cakir Date: Wed, 9 Dec 2015 20:01:03 +0100 Subject: [PATCH 153/707] Updated ua-parser (UserAgent parser) to latest version. Also updated custom mobile & bot definitions. Plus: regex file is loaded from disk now (App_Data/ua-parser.regexes.yaml) --- .../SmartStore.Services/Common/IUserAgent.cs | 18 + .../Common/UAParserUserAgent.cs | 23 +- .../SmartStore.Services.csproj | 5 +- .../SmartStore.Services/packages.config | 2 +- .../App_Data/ua-parser.regexes.yaml | 4767 +++++++++++++++++ 5 files changed, 4806 insertions(+), 9 deletions(-) create mode 100644 src/Presentation/SmartStore.Web/App_Data/ua-parser.regexes.yaml diff --git a/src/Libraries/SmartStore.Services/Common/IUserAgent.cs b/src/Libraries/SmartStore.Services/Common/IUserAgent.cs index c6530bda07..a232323b07 100644 --- a/src/Libraries/SmartStore.Services/Common/IUserAgent.cs +++ b/src/Libraries/SmartStore.Services/Common/IUserAgent.cs @@ -67,6 +67,13 @@ private static string FormatVersionString(params string[] parts) public sealed class UserAgentInfo { + private static readonly HashSet s_Bots = new HashSet(StringComparer.InvariantCultureIgnoreCase) + { + "BingPreview" + }; + + private bool? _isBot; + public UserAgentInfo(string family, string major, string minor, string patch) { this.Family = family; @@ -83,6 +90,17 @@ public override string ToString() public string Major { get; private set; } public string Minor { get; private set; } public string Patch { get; private set; } + public bool IsBot + { + get + { + if (!_isBot.HasValue) + { + _isBot = s_Bots.Contains(Family); + } + return _isBot.Value; + } + } } internal static class VersionString diff --git a/src/Libraries/SmartStore.Services/Common/UAParserUserAgent.cs b/src/Libraries/SmartStore.Services/Common/UAParserUserAgent.cs index f0726c906c..060c127d3f 100644 --- a/src/Libraries/SmartStore.Services/Common/UAParserUserAgent.cs +++ b/src/Libraries/SmartStore.Services/Common/UAParserUserAgent.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.Text.RegularExpressions; using System.Web; +using SmartStore.Utilities; using uap = UAParser; namespace SmartStore.Services.Common @@ -14,7 +15,7 @@ public class UAParserUserAgent : IUserAgent # region Mobile UAs, OS & Devices - private static readonly HashSet s_MobileOS = new HashSet + private static readonly HashSet s_MobileOS = new HashSet(StringComparer.InvariantCultureIgnoreCase) { "Android", "iOS", @@ -32,8 +33,10 @@ public class UAParserUserAgent : IUserAgent "Maemo" }; - private static readonly HashSet s_MobileBrowsers = new HashSet + private static readonly HashSet s_MobileBrowsers = new HashSet(StringComparer.InvariantCultureIgnoreCase) { + "Googlebot-Mobile", + "Baiduspider-mobile", "Android", "Firefox Mobile", "Opera Mobile", @@ -80,7 +83,7 @@ public class UAParserUserAgent : IUserAgent "Skyfire" }; - private static readonly HashSet s_MobileDevices = new HashSet + private static readonly HashSet s_MobileDevices = new HashSet(StringComparer.InvariantCultureIgnoreCase) { "BlackBerry", "MI PAD", @@ -116,7 +119,8 @@ public class UAParserUserAgent : IUserAgent static UAParserUserAgent() { - s_uap = uap.Parser.GetDefault(); + //s_uap = uap.Parser.GetDefault(); + s_uap = uap.Parser.FromYamlFile(CommonHelper.MapPath("~/App_Data/ua-parser.regexes.yaml")); } public UAParserUserAgent(HttpContextBase httpContext) @@ -176,7 +180,7 @@ public virtual DeviceInfo Device if (_device == null) { var tmp = s_uap.ParseDevice(this.RawValue); - _device = new DeviceInfo(tmp.Family, tmp.IsSpider); + _device = new DeviceInfo(tmp.Family, tmp.IsSpider()); } return _device; } @@ -201,7 +205,7 @@ public virtual bool IsBot { if (!_isBot.HasValue) { - _isBot = _httpContext.Request.Browser.Crawler || this.Device.IsBot; + _isBot = _httpContext.Request.Browser.Crawler || this.Device.IsBot || this.UserAgent.IsBot; } return _isBot.Value; } @@ -247,7 +251,14 @@ public virtual bool IsPdfConverter return _isPdfConverter.Value; } } + } + internal static class DeviceExtensions + { + internal static bool IsSpider(this UAParser.Device device) + { + return device.Family.Equals("Spider", StringComparison.InvariantCultureIgnoreCase); + } } } diff --git a/src/Libraries/SmartStore.Services/SmartStore.Services.csproj b/src/Libraries/SmartStore.Services/SmartStore.Services.csproj index b1c9cc5a3f..9276e94dc0 100644 --- a/src/Libraries/SmartStore.Services/SmartStore.Services.csproj +++ b/src/Libraries/SmartStore.Services/SmartStore.Services.csproj @@ -154,8 +154,9 @@ - - ..\..\packages\UAParser.1.2.0.0\lib\net35-Client\UAParser.dll + + ..\..\packages\UAParser.2.0.0.0\lib\net40-Client\UAParser.dll + True diff --git a/src/Libraries/SmartStore.Services/packages.config b/src/Libraries/SmartStore.Services/packages.config index 23354a2a94..7f5b29df78 100644 --- a/src/Libraries/SmartStore.Services/packages.config +++ b/src/Libraries/SmartStore.Services/packages.config @@ -16,5 +16,5 @@ - + \ No newline at end of file diff --git a/src/Presentation/SmartStore.Web/App_Data/ua-parser.regexes.yaml b/src/Presentation/SmartStore.Web/App_Data/ua-parser.regexes.yaml new file mode 100644 index 0000000000..6ef74a0d89 --- /dev/null +++ b/src/Presentation/SmartStore.Web/App_Data/ua-parser.regexes.yaml @@ -0,0 +1,4767 @@ +user_agent_parsers: + #### SPECIAL CASES TOP #### + + # @note: iOS / OSX Applications + - regex: '(CFNetwork)(?:/(\d+)\.(\d+)\.?(\d+)?)?' + family_replacement: 'CFNetwork' + + # Pingdom + - regex: '(Pingdom.com_bot_version_)(\d+)\.(\d+)' + family_replacement: 'PingdomBot' + + # Facebook + - regex: '(facebookexternalhit)/(\d+)\.(\d+)' + family_replacement: 'FacebookBot' + + # Google Plus + - regex: 'Google.*/\+/web/snippet' + family_replacement: 'GooglePlusBot' + + # Bots Pattern '/name-0.0' + - regex: '/((?:Ant-)?Nutch|[A-z]+[Bb]ot|[A-z]+[Ss]pider|Axtaris|fetchurl|Isara|ShopSalad|Tailsweep)[ \-](\d+)(?:\.(\d+)(?:\.(\d+))?)?' + # Bots Pattern 'name/0.0' + - regex: '(008|Altresium|Argus|BaiduMobaider|BoardReader|DNSGroup|DataparkSearch|EDI|Goodzer|Grub|INGRID|Infohelfer|LinkedInBot|LOOQ|Nutch|PathDefender|Peew|PostPost|Steeler|Twitterbot|VSE|WebCrunch|WebZIP|Y!J-BR[A-Z]|YahooSeeker|envolk|sproose|wminer)/(\d+)(?:\.(\d+)(?:\.(\d+))?)?' + + # MSIECrawler + - regex: '(MSIE) (\d+)\.(\d+)([a-z]\d?)?;.* MSIECrawler' + family_replacement: 'MSIECrawler' + + # Downloader ... + - regex: '(Google-HTTP-Java-Client|Apache-HttpClient|http%20client|Python-urllib|HttpMonitor|TLSProber|WinHTTP|JNLP)(?:[ /](\d+)(?:\.(\d+)(?:\.(\d+))?)?)?' + + # Bots + - regex: '(1470\.net crawler|50\.nu|8bo Crawler Bot|Aboundex|Accoona-[A-z]+-Agent|AdsBot-Google(?:-[a-z]+)?|altavista|AppEngine-Google|archive.*?\.org_bot|archiver|Ask Jeeves|[Bb]ai[Dd]u[Ss]pider(?:-[A-Za-z]+)*|bingbot|BingPreview|blitzbot|BlogBridge|BoardReader(?: [A-Za-z]+)*|boitho.com-dc|BotSeer|\b\w*favicon\w*\b|\bYeti(?:-[a-z]+)?|Catchpoint bot|[Cc]harlotte|Checklinks|clumboot|Comodo HTTP\(S\) Crawler|Comodo-Webinspector-Crawler|ConveraCrawler|CRAWL-E|CrawlConvera|Daumoa(?:-feedfetcher)?|Feed Seeker Bot|findlinks|Flamingo_SearchEngine|FollowSite Bot|furlbot|Genieo|gigabot|GomezAgent|gonzo1|(?:[a-zA-Z]+-)?Googlebot(?:-[a-zA-Z]+)?|Google SketchUp|grub-client|gsa-crawler|heritrix|HiddenMarket|holmes|HooWWWer|htdig|ia_archiver|ICC-Crawler|Icarus6j|ichiro(?:/mobile)?|IconSurf|IlTrovatore(?:-Setaccio)?|InfuzApp|Innovazion Crawler|InternetArchive|IP2[a-z]+Bot|jbot\b|KaloogaBot|Kraken|Kurzor|larbin|LEIA|LesnikBot|Linguee Bot|LinkAider|LinkedInBot|Lite Bot|Llaut|lycos|Mail\.RU_Bot|masidani_bot|Mediapartners-Google|Microsoft .*? Bot|mogimogi|mozDex|MJ12bot|msnbot(?:-media *)?|msrbot|netresearch|Netvibes|NewsGator[^/]*|^NING|Nutch[^/]*|Nymesis|ObjectsSearch|Orbiter|OOZBOT|PagePeeker|PagesInventory|PaxleFramework|Peeplo Screenshot Bot|PlantyNet_WebRobot|Pompos|Read%20Later|Reaper|RedCarpet|Retreiver|Riddler|Rival IQ|scooter|Scrapy|Scrubby|searchsight|seekbot|semanticdiscovery|Simpy|SimplePie|SEOstats|SimpleRSS|SiteCon|Slurp|snappy|Speedy Spider|Squrl Java|TheUsefulbot|ThumbShotsBot|Thumbshots\.ru|TwitterBot|URL2PNG|Vagabondo|VoilaBot|^vortex|Votay bot|^voyager|WASALive.Bot|Web-sniffer|WebThumb|WeSEE:[A-z]+|WhatWeb|WIRE|WordPress|Wotbox|www\.almaden\.ibm\.com|Xenu(?:.s)? Link Sleuth|Xerka [A-z]+Bot|yacy(?:bot)?|Yahoo[a-z]*Seeker|Yahoo! Slurp|Yandex\w+|YodaoBot(?:-[A-z]+)?|YottaaMonitor|Yowedo|^Zao|^Zao-Crawler|ZeBot_www\.ze\.bz|ZooShot|ZyBorg)(?:[ /]v?(\d+)(?:\.(\d+)(?:\.(\d+))?)?)?' + + # Bots General matcher 'name/0.0' + - regex: '(?:\/[A-Za-z0-9\.]+)? *([A-Za-z0-9 \-_\!\[\]:]*(?:[Aa]rchiver|[Ii]ndexer|[Ss]craper|[Bb]ot|[Ss]pider|[Cc]rawl[a-z]*))/(\d+)(?:\.(\d+)(?:\.(\d+))?)?' + # Bots General matcher 'name 0.0' + - regex: '(?:\/[A-Za-z0-9\.]+)? *([A-Za-z0-9 _\!\[\]:]*(?:[Aa]rchiver|[Ii]ndexer|[Ss]craper|[Bb]ot|[Ss]pider|[Cc]rawl[a-z]*)) (\d+)(?:\.(\d+)(?:\.(\d+))?)?' + # Bots containing spider|scrape|bot(but not CUBOT)|Crawl + - regex: '((?:[A-z0-9]+|[A-z\-]+ ?)?(?: the )?(?:[Ss][Pp][Ii][Dd][Ee][Rr]|[Ss]crape|[A-Za-z0-9-]*(?:[^C][^Uu])[Bb]ot|[Cc][Rr][Aa][Ww][Ll])[A-z0-9]*)(?:(?:[ /]| v)(\d+)(?:\.(\d+)(?:\.(\d+))?)?)?' + + # HbbTV standard defines what features the browser should understand. + # but it's like targeting "HTML5 browsers", effective browser support depends on the model + # See os_parsers if you want to target a specific TV + - regex: '(HbbTV)/(\d+)\.(\d+)\.(\d+) \(' + + # must go before Firefox to catch Chimera/SeaMonkey/Camino + - regex: '(Chimera|SeaMonkey|Camino)/(\d+)\.(\d+)\.?([ab]?\d+[a-z]*)?' + + # Social Networks + # Facebook + - regex: '\[FB.*;(FBAV)/(\d+)(?:\.(\d+)(?:\.(\d)+)?)?' + family_replacement: 'Facebook' + # Pinterest + - regex: '\[(Pinterest)/[^\]]+\]' + - regex: '(Pinterest)(?: for Android(?: Tablet)?)?/(\d+)(?:\.(\d+)(?:\.(\d)+)?)?' + + # Firefox + - regex: '(Pale[Mm]oon)/(\d+)\.(\d+)\.?(\d+)?' + family_replacement: 'Pale Moon (Firefox Variant)' + - regex: '(Fennec)/(\d+)\.(\d+)\.?([ab]?\d+[a-z]*)' + family_replacement: 'Firefox Mobile' + - regex: '(Fennec)/(\d+)\.(\d+)(pre)' + family_replacement: 'Firefox Mobile' + - regex: '(Fennec)/(\d+)\.(\d+)' + family_replacement: 'Firefox Mobile' + - regex: '(?:Mobile|Tablet);.*(Firefox)/(\d+)\.(\d+)' + family_replacement: 'Firefox Mobile' + - regex: '(Namoroka|Shiretoko|Minefield)/(\d+)\.(\d+)\.(\d+(?:pre)?)' + family_replacement: 'Firefox ($1)' + - regex: '(Firefox)/(\d+)\.(\d+)(a\d+[a-z]*)' + family_replacement: 'Firefox Alpha' + - regex: '(Firefox)/(\d+)\.(\d+)(b\d+[a-z]*)' + family_replacement: 'Firefox Beta' + - regex: '(Firefox)-(?:\d+\.\d+)?/(\d+)\.(\d+)(a\d+[a-z]*)' + family_replacement: 'Firefox Alpha' + - regex: '(Firefox)-(?:\d+\.\d+)?/(\d+)\.(\d+)(b\d+[a-z]*)' + family_replacement: 'Firefox Beta' + - regex: '(Namoroka|Shiretoko|Minefield)/(\d+)\.(\d+)([ab]\d+[a-z]*)?' + family_replacement: 'Firefox ($1)' + - regex: '(Firefox).*Tablet browser (\d+)\.(\d+)\.(\d+)' + family_replacement: 'MicroB' + - regex: '(MozillaDeveloperPreview)/(\d+)\.(\d+)([ab]\d+[a-z]*)?' + - regex: '(FxiOS)/(\d+)\.(\d+)(\.(\d+))?(\.(\d+))?' + family_replacement: 'Firefox iOS' + + # e.g.: Flock/2.0b2 + - regex: '(Flock)/(\d+)\.(\d+)(b\d+?)' + + # RockMelt + - regex: '(RockMelt)/(\d+)\.(\d+)\.(\d+)' + + # e.g.: Fennec/0.9pre + - regex: '(Navigator)/(\d+)\.(\d+)\.(\d+)' + family_replacement: 'Netscape' + + - regex: '(Navigator)/(\d+)\.(\d+)([ab]\d+)' + family_replacement: 'Netscape' + + - regex: '(Netscape6)/(\d+)\.(\d+)\.?([ab]?\d+)?' + family_replacement: 'Netscape' + + - regex: '(MyIBrow)/(\d+)\.(\d+)' + family_replacement: 'My Internet Browser' + + # Opera will stop at 9.80 and hide the real version in the Version string. + # see: http://dev.opera.com/articles/view/opera-ua-string-changes/ + - regex: '(Opera Tablet).*Version/(\d+)\.(\d+)(?:\.(\d+))?' + - regex: '(Opera Mini)(?:/att)?/(\d+)?(?:\.(\d+))?(?:\.(\d+))?' + - regex: '(Opera)/.+Opera Mobi.+Version/(\d+)\.(\d+)' + family_replacement: 'Opera Mobile' + - regex: '(Opera)/(\d+)\.(\d+).+Opera Mobi' + family_replacement: 'Opera Mobile' + - regex: 'Opera Mobi.+(Opera)(?:/|\s+)(\d+)\.(\d+)' + family_replacement: 'Opera Mobile' + - regex: 'Opera Mobi' + family_replacement: 'Opera Mobile' + - regex: '(Opera)/9.80.*Version/(\d+)\.(\d+)(?:\.(\d+))?' + + # Opera 14 for Android uses a WebKit render engine. + - regex: '(?:Mobile Safari).*(OPR)/(\d+)\.(\d+)\.(\d+)' + family_replacement: 'Opera Mobile' + + # Opera >=15 for Desktop is similar to Chrome but includes an "OPR" Version string. + - regex: '(?:Chrome).*(OPR)/(\d+)\.(\d+)\.(\d+)' + family_replacement: 'Opera' + + # Opera Coast + - regex: '(Coast)/(\d+).(\d+).(\d+)' + family_replacement: 'Opera Coast' + + # Opera Mini for iOS (from version 8.0.0) + - regex: '(OPiOS)/(\d+).(\d+).(\d+)' + family_replacement: 'Opera Mini' + + # Palm WebOS looks a lot like Safari. + - regex: '(hpw|web)OS/(\d+)\.(\d+)(?:\.(\d+))?' + family_replacement: 'webOS Browser' + + # LuaKit has no version info. + # http://luakit.org/projects/luakit/ + - regex: '(luakit)' + family_replacement: 'LuaKit' + + # Snowshoe + - regex: '(Snowshoe)/(\d+)\.(\d+).(\d+)' + + # Lightning (for Thunderbird) + # http://www.mozilla.org/projects/calendar/lightning/ + - regex: '(Lightning)/(\d+)\.(\d+)\.?((?:[ab]?\d+[a-z]*)|(?:\d*))' + + # Swiftfox + - regex: '(Firefox)/(\d+)\.(\d+)\.(\d+(?:pre)?) \(Swiftfox\)' + family_replacement: 'Swiftfox' + - regex: '(Firefox)/(\d+)\.(\d+)([ab]\d+[a-z]*)? \(Swiftfox\)' + family_replacement: 'Swiftfox' + + # Rekonq + - regex: '(rekonq)/(\d+)\.(\d+)\.?(\d+)? Safari' + family_replacement: 'Rekonq' + - regex: 'rekonq' + family_replacement: 'Rekonq' + + # Conkeror lowercase/uppercase + # http://conkeror.org/ + - regex: '(conkeror|Conkeror)/(\d+)\.(\d+)\.?(\d+)?' + family_replacement: 'Conkeror' + + # catches lower case konqueror + - regex: '(konqueror)/(\d+)\.(\d+)\.(\d+)' + family_replacement: 'Konqueror' + + - regex: '(WeTab)-Browser' + + - regex: '(Comodo_Dragon)/(\d+)\.(\d+)\.(\d+)' + family_replacement: 'Comodo Dragon' + + - regex: '(Symphony) (\d+).(\d+)' + + - regex: '(Minimo)' + + - regex: 'PLAYSTATION 3.+WebKit' + family_replacement: 'NetFront NX' + - regex: 'PLAYSTATION 3' + family_replacement: 'NetFront' + - regex: '(PlayStation Portable)' + family_replacement: 'NetFront' + - regex: '(PlayStation Vita)' + family_replacement: 'NetFront NX' + + - regex: 'AppleWebKit.+ (NX)/(\d+)\.(\d+)\.(\d+)' + family_replacement: 'NetFront NX' + - regex: '(Nintendo 3DS)' + family_replacement: 'NetFront NX' + + # Amazon Silk, should go before Safari and Chrome Mobile + - regex: '(Silk)/(\d+)\.(\d+)(?:\.([0-9\-]+))?' + family_replacement: 'Amazon Silk' + + + # @ref: http://www.puffinbrowser.com + - regex: '(Puffin)/(\d+)\.(\d+)(?:\.(\d+))?' + + # Edge Mobile + - regex: 'Windows Phone .*(Edge)/(\d+)\.(\d+)' + family_replacement: 'Edge Mobile' + + # Chrome Mobile + - regex: '(CrMo)/(\d+)\.(\d+)\.(\d+)\.(\d+)' + family_replacement: 'Chrome Mobile' + - regex: '(CriOS)/(\d+)\.(\d+)\.(\d+)\.(\d+)' + family_replacement: 'Chrome Mobile iOS' + - regex: '(Chrome)/(\d+)\.(\d+)\.(\d+)\.(\d+) Mobile' + family_replacement: 'Chrome Mobile' + + # Chrome Frame must come before MSIE. + - regex: '(chromeframe)/(\d+)\.(\d+)\.(\d+)' + family_replacement: 'Chrome Frame' + + # UC Browser + - regex: '(UCBrowser)[ /](\d+)\.(\d+)\.(\d+)' + family_replacement: 'UC Browser' + - regex: '(UC Browser)[ /](\d+)\.(\d+)\.(\d+)' + - regex: '(UC Browser|UCBrowser|UCWEB)(\d+)\.(\d+)\.(\d+)' + family_replacement: 'UC Browser' + + # Tizen Browser (second case included in browser/major.minor regex) + - regex: '(SLP Browser)/(\d+)\.(\d+)' + family_replacement: 'Tizen Browser' + + # Sogou Explorer 2.X + - regex: '(SE 2\.X) MetaSr (\d+)\.(\d+)' + family_replacement: 'Sogou Explorer' + + # Baidu Browsers (desktop spoofs chrome & IE, explorer is mobile) + - regex: '(baidubrowser)[/\s](\d+)' + family_replacement: 'Baidu Browser' + - regex: '(FlyFlow)/(\d+)\.(\d+)' + family_replacement: 'Baidu Explorer' + + # QQ Browsers + - regex: '(MQQBrowser/Mini)(?:(\d+)(?:\.(\d+)(?:\.(\d+))?)?)?' + family_replacement: 'QQ Browser Mini' + - regex: '(MQQBrowser)(?:/(\d+)(?:\.(\d+)(?:\.(\d+))?)?)?' + family_replacement: 'QQ Browser Mobile' + - regex: '(QQBrowser)(?:/(\d+)(?:\.(\d+)\.(\d+)(?:\.(\d+))?)?)?' + family_replacement: 'QQ Browser' + + # Rackspace Monitoring + - regex: '(Rackspace Monitoring)/(\d+)\.(\d+)' + family_replacement: 'RackspaceBot' + + # PyAMF + - regex: '(PyAMF)/(\d+)\.(\d+)\.(\d+)' + + # Yandex Browser + - regex: '(YaBrowser)/(\d+)\.(\d+)\.(\d+)' + family_replacement: 'Yandex Browser' + + # Mail.ru Amigo/Internet Browser (Chromium-based) + - regex: '(Chrome)/(\d+)\.(\d+)\.(\d+).* MRCHROME' + family_replacement: 'Mail.ru Chromium Browser' + + # AOL Browser (IE-based) + - regex: '(AOL) (\d+)\.(\d+); AOLBuild (\d+)' + + #### END SPECIAL CASES TOP #### + + #### MAIN CASES - this catches > 50% of all browsers #### + + # Browser/major_version.minor_version.beta_version + - regex: '(AdobeAIR|FireWeb|Jasmine|ANTGalio|Midori|Fresco|Lobo|PaleMoon|Maxthon|Lynx|OmniWeb|Dillo|Camino|Demeter|Fluid|Fennec|Epiphany|Shiira|Sunrise|Spotify|Flock|Netscape|Lunascape|WebPilot|NetFront|Netfront|Konqueror|SeaMonkey|Kazehakase|Vienna|Iceape|Iceweasel|IceWeasel|Iron|K-Meleon|Sleipnir|Galeon|GranParadiso|Opera Mini|iCab|NetNewsWire|ThunderBrowse|Iris|UP\.Browser|Bunjalloo|Google Earth|Raven for Mac|Openwave)/(\d+)\.(\d+)\.(\d+)' + + # Outlook 2007 + - regex: 'MSOffice 12' + family_replacement: 'Outlook' + v1_replacement: '2007' + + # Outlook 2010 + - regex: 'MSOffice 14' + family_replacement: 'Outlook' + v1_replacement: '2010' + + # Outlook 2013 + - regex: 'Microsoft Outlook 15\.\d+\.\d+' + family_replacement: 'Outlook' + v1_replacement: '2013' + + # Apple Air Mail + - regex: '(Airmail) (\d+)\.(\d+)(?:\.(\d+))?' + + # Thunderbird + - regex: '(Thunderbird)/(\d+)\.(\d+)\.(\d+(?:pre)?)' + family_replacement: 'Thunderbird' + + # Vivaldi uses "Vivaldi" + - regex: '(Vivaldi)/(\d+)\.(\d+)\.(\d+)' + + # Edge/major_version.minor_version + - regex: '(Edge)/(\d+)\.(\d+)' + + # Chrome/Chromium/major_version.minor_version.beta_version + - regex: '(Chromium|Chrome)/(\d+)\.(\d+)\.(\d+)' + + # Dolphin Browser + # @ref: http://www.dolphin.com + - regex: '\b(Dolphin)(?: |HDCN/|/INT\-)(\d+)\.(\d+)\.?(\d+)?' + + # Browser/major_version.minor_version + - regex: '(bingbot|Bolt|Jasmine|IceCat|Skyfire|Midori|Maxthon|Lynx|Arora|IBrowse|Dillo|Camino|Shiira|Fennec|Phoenix|Chrome|Flock|Netscape|Lunascape|Epiphany|WebPilot|Opera Mini|Opera|NetFront|Netfront|Konqueror|Googlebot|SeaMonkey|Kazehakase|Vienna|Iceape|Iceweasel|IceWeasel|Iron|K-Meleon|Sleipnir|Galeon|GranParadiso|iCab|iTunes|MacAppStore|NetNewsWire|Space Bison|Stainless|Orca|Dolfin|BOLT|Minimo|Tizen Browser|Polaris|Abrowser|Planetweb|ICE Browser|mDolphin|qutebrowser|Otter|QupZilla)/(\d+)\.(\d+)\.?(\d+)?' + + # Chrome/Chromium/major_version.minor_version + - regex: '(Chromium|Chrome)/(\d+)\.(\d+)' + + ########## + # IE Mobile needs to happen before Android to catch cases such as: + # Mozilla/5.0 (Mobile; Windows Phone 8.1; Android 4.0; ARM; Trident/7.0; Touch; rv:11.0; IEMobile/11.0; NOKIA; Lumia 920)... + # Mozilla/5.0 (Mobile; Windows Phone 8.1; Android 4.0; ARM; Trident/7.0; Touch; rv:11.0; IEMobile/11.0; NOKIA; Lumia 920; ANZ821)... + # Mozilla/5.0 (Mobile; Windows Phone 8.1; Android 4.0; ARM; Trident/7.0; Touch; rv:11.0; IEMobile/11.0; NOKIA; Lumia 920; Orange)... + # Mozilla/5.0 (Mobile; Windows Phone 8.1; Android 4.0; ARM; Trident/7.0; Touch; rv:11.0; IEMobile/11.0; NOKIA; Lumia 920; Vodafone)... + ########## + + # IE Mobile + - regex: '(IEMobile)[ /](\d+)\.(\d+)' + family_replacement: 'IE Mobile' + + # Browser major_version.minor_version.beta_version (space instead of slash) + - regex: '(iRider|Crazy Browser|SkipStone|iCab|Lunascape|Sleipnir|Maemo Browser) (\d+)\.(\d+)\.(\d+)' + # Browser major_version.minor_version (space instead of slash) + - regex: '(iCab|Lunascape|Opera|Android|Jasmine|Polaris) (\d+)\.(\d+)\.?(\d+)?' + + # Kindle WebKit + - regex: '(Kindle)/(\d+)\.(\d+)' + + # weird android UAs + - regex: '(Android) Donut' + v1_replacement: '1' + v2_replacement: '2' + + - regex: '(Android) Eclair' + v1_replacement: '2' + v2_replacement: '1' + + - regex: '(Android) Froyo' + v1_replacement: '2' + v2_replacement: '2' + + - regex: '(Android) Gingerbread' + v1_replacement: '2' + v2_replacement: '3' + + - regex: '(Android) Honeycomb' + v1_replacement: '3' + + # desktop mode + # http://www.anandtech.com/show/3982/windows-phone-7-review + - regex: '(MSIE) (\d+)\.(\d+).*XBLWP7' + family_replacement: 'IE Large Screen' + + #### END MAIN CASES #### + + #### SPECIAL CASES #### + - regex: '(Obigo)InternetBrowser' + - regex: '(Obigo)\-Browser' + - regex: '(Obigo|OBIGO)[^\d]*(\d+)(?:.(\d+))?' + family_replacement: 'Obigo' + + - regex: '(MAXTHON|Maxthon) (\d+)\.(\d+)' + family_replacement: 'Maxthon' + - regex: '(Maxthon|MyIE2|Uzbl|Shiira)' + v1_replacement: '0' + + - regex: '(BrowseX) \((\d+)\.(\d+)\.(\d+)' + + - regex: '(NCSA_Mosaic)/(\d+)\.(\d+)' + family_replacement: 'NCSA Mosaic' + + # Polaris/d.d is above + - regex: '(POLARIS)/(\d+)\.(\d+)' + family_replacement: 'Polaris' + - regex: '(Embider)/(\d+)\.(\d+)' + family_replacement: 'Polaris' + + - regex: '(BonEcho)/(\d+)\.(\d+)\.?([ab]?\d+)?' + family_replacement: 'Bon Echo' + + # @note: iOS / OSX Applications + - regex: '(iPod|iPhone|iPad).+Version/(\d+)\.(\d+)(?:\.(\d+))?.* Safari' + family_replacement: 'Mobile Safari' + - regex: '(iPod|iPhone|iPad).+Version/(\d+)\.(\d+)(?:\.(\d+))?' + family_replacement: 'Mobile Safari UIWebView' + - regex: '(iPod|iPhone|iPad);.*CPU.*OS (\d+)_(\d+)(?:_(\d+))?.*Mobile.* Safari' + family_replacement: 'Mobile Safari' + - regex: '(iPod|iPhone|iPad);.*CPU.*OS (\d+)_(\d+)(?:_(\d+))?.*Mobile' + family_replacement: 'Mobile Safari UIWebView' + - regex: '(iPod|iPhone|iPad).* Safari' + family_replacement: 'Mobile Safari' + - regex: '(iPod|iPhone|iPad)' + family_replacement: 'Mobile Safari UIWebView' + + - regex: '(AvantGo) (\d+).(\d+)' + + - regex: '(OneBrowser)/(\d+).(\d+)' + family_replacement: 'ONE Browser' + + - regex: '(Avant)' + v1_replacement: '1' + + # This is the Tesla Model S (see similar entry in device parsers) + - regex: '(QtCarBrowser)' + v1_replacement: '1' + + - regex: '^(iBrowser/Mini)(\d+).(\d+)' + family_replacement: 'iBrowser Mini' + - regex: '^(iBrowser|iRAPP)/(\d+).(\d+)' + + # nokia browsers + # based on: http://www.developer.nokia.com/Community/Wiki/User-Agent_headers_for_Nokia_devices + - regex: '^(Nokia)' + family_replacement: 'Nokia Services (WAP) Browser' + - regex: '(NokiaBrowser)/(\d+)\.(\d+).(\d+)\.(\d+)' + family_replacement: 'Nokia Browser' + - regex: '(NokiaBrowser)/(\d+)\.(\d+).(\d+)' + family_replacement: 'Nokia Browser' + - regex: '(NokiaBrowser)/(\d+)\.(\d+)' + family_replacement: 'Nokia Browser' + - regex: '(BrowserNG)/(\d+)\.(\d+).(\d+)' + family_replacement: 'Nokia Browser' + - regex: '(Series60)/5\.0' + family_replacement: 'Nokia Browser' + v1_replacement: '7' + v2_replacement: '0' + - regex: '(Series60)/(\d+)\.(\d+)' + family_replacement: 'Nokia OSS Browser' + - regex: '(S40OviBrowser)/(\d+)\.(\d+)\.(\d+)\.(\d+)' + family_replacement: 'Ovi Browser' + - regex: '(Nokia)[EN]?(\d+)' + + # BlackBerry devices + - regex: '(PlayBook).+RIM Tablet OS (\d+)\.(\d+)\.(\d+)' + family_replacement: 'BlackBerry WebKit' + - regex: '(Black[bB]erry|BB10).+Version/(\d+)\.(\d+)\.(\d+)' + family_replacement: 'BlackBerry WebKit' + - regex: '(Black[bB]erry)\s?(\d+)' + family_replacement: 'BlackBerry' + + - regex: '(OmniWeb)/v(\d+)\.(\d+)' + + - regex: '(Blazer)/(\d+)\.(\d+)' + family_replacement: 'Palm Blazer' + + - regex: '(Pre)/(\d+)\.(\d+)' + family_replacement: 'Palm Pre' + + # fork of Links + - regex: '(ELinks)/(\d+)\.(\d+)' + - regex: '(ELinks) \((\d+)\.(\d+)' + - regex: '(Links) \((\d+)\.(\d+)' + + - regex: '(QtWeb) Internet Browser/(\d+)\.(\d+)' + + #- regex: '\(iPad;.+(Version)/(\d+)\.(\d+)(?:\.(\d+))?.*Safari/' + # family_replacement: 'iPad' + + # Phantomjs, should go before Safari + - regex: '(PhantomJS)/(\d+)\.(\d+)\.(\d+)' + + # WebKit Nightly + - regex: '(AppleWebKit)/(\d+)\.?(\d+)?\+ .* Safari' + family_replacement: 'WebKit Nightly' + + # Safari + - regex: '(Version)/(\d+)\.(\d+)(?:\.(\d+))?.*Safari/' + family_replacement: 'Safari' + # Safari didn't provide "Version/d.d.d" prior to 3.0 + - regex: '(Safari)/\d+' + + - regex: '(OLPC)/Update(\d+)\.(\d+)' + + - regex: '(OLPC)/Update()\.(\d+)' + v1_replacement: '0' + + - regex: '(SEMC\-Browser)/(\d+)\.(\d+)' + + - regex: '(Teleca)' + family_replacement: 'Teleca Browser' + + - regex: '(Phantom)/V(\d+)\.(\d+)' + family_replacement: 'Phantom Browser' + + - regex: 'Trident(.*)rv.(\d+)\.(\d+)' + family_replacement: 'IE' + + # Espial + - regex: '(Espial)/(\d+)(?:\.(\d+))?(?:\.(\d+))?' + + # Apple Mail + + # apple mail - not directly detectable, have it after Safari stuff + - regex: '(AppleWebKit)/(\d+)\.(\d+)\.(\d+)' + family_replacement: 'AppleMail' + + # AFTER THE EDGE CASES ABOVE! + # AFTER IE11 + # BEFORE all other IE + - regex: '(Firefox)/(\d+)\.(\d+)\.(\d+)' + - regex: '(Firefox)/(\d+)\.(\d+)(pre|[ab]\d+[a-z]*)?' + + - regex: '([MS]?IE) (\d+)\.(\d+)' + family_replacement: 'IE' + + - regex: '(python-requests)/(\d+)\.(\d+)' + family_replacement: 'Python Requests' + + - regex: '(Java)[/ ]{0,1}\d+\.(\d+)\.(\d+)[_-]*([a-zA-Z0-9]+)*' + +os_parsers: + ########## + # HbbTV vendors + ########## + + # starts with the easy one : Panasonic seems consistent across years, hope it will continue + #HbbTV/1.1.1 (;Panasonic;VIERA 2011;f.532;0071-0802 2000-0000;) + #HbbTV/1.1.1 (;Panasonic;VIERA 2012;1.261;0071-3103 2000-0000;) + #HbbTV/1.2.1 (;Panasonic;VIERA 2013;3.672;4101-0003 0002-0000;) + #- regex: 'HbbTV/\d+\.\d+\.\d+ \(;(Panasonic);VIERA ([0-9]{4});' + + # Sony is consistent too but do not place year like the other + # Opera/9.80 (Linux armv7l; HbbTV/1.1.1 (; Sony; KDL32W650A; PKG3.211EUA; 2013;); ) Presto/2.12.362 Version/12.11 + # Opera/9.80 (Linux mips; U; HbbTV/1.1.1 (; Sony; KDL40HX751; PKG1.902EUA; 2012;);; en) Presto/2.10.250 Version/11.60 + # Opera/9.80 (Linux mips; U; HbbTV/1.1.1 (; Sony; KDL22EX320; PKG4.017EUA; 2011;);; en) Presto/2.7.61 Version/11.00 + #- regex: 'HbbTV/\d+\.\d+\.\d+ \(; (Sony);.*;.*; ([0-9]{4});\)' + + + # LG is consistent too, but we need to add manually the year model + #Mozilla/5.0 (Unknown; Linux armv7l) AppleWebKit/537.1+ (KHTML, like Gecko) Safari/537.1+ HbbTV/1.1.1 ( ;LGE ;NetCast 4.0 ;03.20.30 ;1.0M ;) + #Mozilla/5.0 (DirectFB; Linux armv7l) AppleWebKit/534.26+ (KHTML, like Gecko) Version/5.0 Safari/534.26+ HbbTV/1.1.1 ( ;LGE ;NetCast 3.0 ;1.0 ;1.0M ;) + - regex: 'HbbTV/\d+\.\d+\.\d+ \( ;(LG)E ;NetCast 4.0' + os_v1_replacement: '2013' + - regex: 'HbbTV/\d+\.\d+\.\d+ \( ;(LG)E ;NetCast 3.0' + os_v1_replacement: '2012' + + # Samsung is on its way of normalizing their user-agent + # HbbTV/1.1.1 (;Samsung;SmartTV2013;T-FXPDEUC-1102.2;;) WebKit + # HbbTV/1.1.1 (;Samsung;SmartTV2013;T-MST12DEUC-1102.1;;) WebKit + # HbbTV/1.1.1 (;Samsung;SmartTV2012;;;) WebKit + # HbbTV/1.1.1 (;;;;;) Maple_2011 + - regex: 'HbbTV/1.1.1 \(;;;;;\) Maple_2011' + os_replacement: 'Samsung' + os_v1_replacement: '2011' + # manage the two models of 2013 + - regex: 'HbbTV/\d+\.\d+\.\d+ \(;(Samsung);SmartTV([0-9]{4});.*FXPDEUC' + os_v2_replacement: 'UE40F7000' + - regex: 'HbbTV/\d+\.\d+\.\d+ \(;(Samsung);SmartTV([0-9]{4});.*MST12DEUC' + os_v2_replacement: 'UE32F4500' + # generic Samsung (works starting in 2012) + #- regex: 'HbbTV/\d+\.\d+\.\d+ \(;(Samsung);SmartTV([0-9]{4});' + + # Philips : not found any other way than a manual mapping + # Opera/9.80 (Linux mips; U; HbbTV/1.1.1 (; Philips; ; ; ; ) CE-HTML/1.0 NETTV/4.1.3 PHILIPSTV/1.1.1; en) Presto/2.10.250 Version/11.60 + # Opera/9.80 (Linux mips ; U; HbbTV/1.1.1 (; Philips; ; ; ; ) CE-HTML/1.0 NETTV/3.2.1; en) Presto/2.6.33 Version/10.70 + - regex: 'HbbTV/1.1.1 \(; (Philips);.*NETTV/4' + os_v1_replacement: '2013' + - regex: 'HbbTV/1.1.1 \(; (Philips);.*NETTV/3' + os_v1_replacement: '2012' + - regex: 'HbbTV/1.1.1 \(; (Philips);.*NETTV/2' + os_v1_replacement: '2011' + + # the HbbTV emulator developers use HbbTV/1.1.1 (;;;;;) firetv-firefox-plugin 1.1.20 + - regex: 'HbbTV/\d+\.\d+\.\d+.*(firetv)-firefox-plugin (\d+).(\d+).(\d+)' + os_replacement: 'FireHbbTV' + + # generic HbbTV, hoping to catch manufacturer name (always after 2nd comma) and the first string that looks like a 2011-2019 year + - regex: 'HbbTV/\d+\.\d+\.\d+ \(.*; ?([a-zA-Z]+) ?;.*(201[1-9]).*\)' + + ########## + # @note: Windows Phone needs to come before Windows NT 6.1 *and* before Android to catch cases such as: + # Mozilla/5.0 (Mobile; Windows Phone 8.1; Android 4.0; ARM; Trident/7.0; Touch; rv:11.0; IEMobile/11.0; NOKIA; Lumia 920)... + # Mozilla/5.0 (Mobile; Windows Phone 8.1; Android 4.0; ARM; Trident/7.0; Touch; rv:11.0; IEMobile/11.0; NOKIA; Lumia 920; ANZ821)... + # Mozilla/5.0 (Mobile; Windows Phone 8.1; Android 4.0; ARM; Trident/7.0; Touch; rv:11.0; IEMobile/11.0; NOKIA; Lumia 920; Orange)... + # Mozilla/5.0 (Mobile; Windows Phone 8.1; Android 4.0; ARM; Trident/7.0; Touch; rv:11.0; IEMobile/11.0; NOKIA; Lumia 920; Vodafone)... + ########## + + - regex: '(Windows Phone) (?:OS[ /])?(\d+)\.(\d+)' + + ########## + # Android + # can actually detect rooted android os. do we care? + ########## + - regex: '(Android)[ \-/](\d+)\.(\d+)(?:[.\-]([a-z0-9]+))?' + + - regex: '(Android) Donut' + os_v1_replacement: '1' + os_v2_replacement: '2' + + - regex: '(Android) Eclair' + os_v1_replacement: '2' + os_v2_replacement: '1' + + - regex: '(Android) Froyo' + os_v1_replacement: '2' + os_v2_replacement: '2' + + - regex: '(Android) Gingerbread' + os_v1_replacement: '2' + os_v2_replacement: '3' + + - regex: '(Android) Honeycomb' + os_v1_replacement: '3' + + # UCWEB + - regex: '^UCWEB.*; (Adr) (\d+)\.(\d+)(?:[.\-]([a-z0-9]+))?;' + os_replacement: 'Android' + - regex: '^UCWEB.*; (iPad OS|iPh OS) (\d+)_(\d+)(?:_(\d+))?;' + os_replacement: 'iOS' + - regex: '^UCWEB.*; (wds) (\d+)\.(\d+)(?:\.(\d+))?;' + os_replacement: 'Windows Phone' + # JUC + - regex: '^(JUC).*; ?U; ?(?:Android)?(\d+)\.(\d+)(?:[\.\-]([a-z0-9]+))?' + os_replacement: 'Android' + + ########## + # Kindle Android + ########## + - regex: '(Silk-Accelerated=[a-z]{4,5})' + os_replacement: 'Android' + + ########## + # Windows + # http://en.wikipedia.org/wiki/Windows_NT#Releases + # possibility of false positive when different marketing names share same NT kernel + # e.g. windows server 2003 and windows xp + # lots of ua strings have Windows NT 4.1 !?!?!?!? !?!? !? !????!?! !!! ??? !?!?! ? + # (very) roughly ordered in terms of frequency of occurence of regex (win xp currently most frequent, etc) + ########## + + # ie mobile desktop mode + # spoofs nt 6.1. must come before windows 7 + - regex: '(XBLWP7)' + os_replacement: 'Windows Phone' + + # @note: This needs to come before Windows NT 6.1 + - regex: '(Windows ?Mobile)' + os_replacement: 'Windows Mobile' + + - regex: '(Windows (?:NT 5\.2|NT 5\.1))' + os_replacement: 'Windows XP' + + - regex: '(Windows NT 6\.1)' + os_replacement: 'Windows 7' + + - regex: '(Windows NT 6\.0)' + os_replacement: 'Windows Vista' + + - regex: '(Win 9x 4\.90)' + os_replacement: 'Windows ME' + + - regex: '(Windows 98|Windows XP|Windows ME|Windows 95|Windows CE|Windows 7|Windows NT 4\.0|Windows Vista|Windows 2000|Windows 3.1)' + + - regex: '(Windows NT 6\.2; ARM;)' + os_replacement: 'Windows RT' + - regex: '(Windows NT 6\.2)' + os_replacement: 'Windows 8' + + - regex: '(Windows NT 6\.3; ARM;)' + os_replacement: 'Windows RT 8.1' + - regex: '(Windows NT 6\.3)' + os_replacement: 'Windows 8.1' + + - regex: '(Windows NT 6\.4)' + os_replacement: 'Windows 10' + - regex: '(Windows NT 10\.0)' + os_replacement: 'Windows 10' + + - regex: '(Windows NT 5\.0)' + os_replacement: 'Windows 2000' + + - regex: '(WinNT4.0)' + os_replacement: 'Windows NT 4.0' + + - regex: '(Windows ?CE)' + os_replacement: 'Windows CE' + + - regex: 'Win ?(95|98|3.1|NT|ME|2000)' + os_replacement: 'Windows $1' + + - regex: 'Win16' + os_replacement: 'Windows 3.1' + + - regex: 'Win32' + os_replacement: 'Windows 95' + + ########## + # Tizen OS from Samsung + # spoofs Android so pushing it above + ########## + - regex: '(Tizen)/(\d+)\.(\d+)' + + ########## + # Mac OS + # @ref: http://en.wikipedia.org/wiki/Mac_OS_X#Versions + # @ref: http://www.puredarwin.org/curious/versions + ########## + - regex: '((?:Mac ?|; )OS X)[\s/](?:(\d+)[_.](\d+)(?:[_.](\d+))?|Mach-O)' + os_replacement: 'Mac OS X' + # Leopard + - regex: ' (Dar)(win)/(9).(\d+).*\((?:i386|x86_64|Power Macintosh)\)' + os_replacement: 'Mac OS X' + os_v1_replacement: '10' + os_v2_replacement: '5' + # Snow Leopard + - regex: ' (Dar)(win)/(10).(\d+).*\((?:i386|x86_64)\)' + os_replacement: 'Mac OS X' + os_v1_replacement: '10' + os_v2_replacement: '6' + # Lion + - regex: ' (Dar)(win)/(11).(\d+).*\((?:i386|x86_64)\)' + os_replacement: 'Mac OS X' + os_v1_replacement: '10' + os_v2_replacement: '7' + # Mountain Lion + - regex: ' (Dar)(win)/(12).(\d+).*\((?:i386|x86_64)\)' + os_replacement: 'Mac OS X' + os_v1_replacement: '10' + os_v2_replacement: '8' + # Mavericks + - regex: ' (Dar)(win)/(13).(\d+).*\((?:i386|x86_64)\)' + os_replacement: 'Mac OS X' + os_v1_replacement: '10' + os_v2_replacement: '9' + # Yosemite is Darwin/14.x but patch versions are inconsistent in the Darwin string; + # more accurately covered by CFNetwork regexes downstream + + # IE on Mac doesn't specify version number + - regex: 'Mac_PowerPC' + os_replacement: 'Mac OS' + + # builds before tiger don't seem to specify version? + + # ios devices spoof (mac os x), so including intel/ppc prefixes + - regex: '(?:PPC|Intel) (Mac OS X)' + + ########## + # iOS + # http://en.wikipedia.org/wiki/IOS_version_history + ########## + # keep this above generic iOS, since AppleTV UAs contain 'CPU OS' + - regex: '(Apple\s?TV)(?:/(\d+)\.(\d+))?' + os_replacement: 'ATV OS X' + + - regex: '(CPU OS|iPhone OS|CPU iPhone) +(\d+)[_\.](\d+)(?:[_\.](\d+))?' + os_replacement: 'iOS' + + # remaining cases are mostly only opera uas, so catch opera as to not catch iphone spoofs + - regex: '(iPhone|iPad|iPod); Opera' + os_replacement: 'iOS' + + # few more stragglers + - regex: '(iPhone|iPad|iPod).*Mac OS X.*Version/(\d+)\.(\d+)' + os_replacement: 'iOS' + + # CFNetwork/Darwin - The specific CFNetwork or Darwin version determines + # whether the os maps to Mac OS, or iOS, or just Darwin. + # See: http://user-agents.me/cfnetwork-version-list + - regex: '(CFNetwork)/(5)48\.0\.3.* Darwin/11\.0\.0' + os_replacement: 'iOS' + - regex: '(CFNetwork)/(5)48\.(0)\.4.* Darwin/(1)1\.0\.0' + os_replacement: 'iOS' + - regex: '(CFNetwork)/(5)48\.(1)\.4' + os_replacement: 'iOS' + - regex: '(CFNetwork)/(4)85\.1(3)\.9' + os_replacement: 'iOS' + - regex: '(CFNetwork)/(6)09\.(1)\.4' + os_replacement: 'iOS' + - regex: '(CFNetwork)/(6)(0)9' + os_replacement: 'iOS' + - regex: '(CFNetwork)/6(7)2\.(1)\.13' + os_replacement: 'iOS' + - regex: '(CFNetwork)/6(7)2\.(1)\.(1)4' + os_replacement: 'iOS' + - regex: '(CF)(Network)/6(7)(2)\.1\.15' + os_replacement: 'iOS' + os_v1_replacement: '7' + os_v2_replacement: '1' + - regex: '(CFNetwork)/6(7)2\.(0)\.(?:2|8)' + os_replacement: 'iOS' + - regex: '(CFNetwork)/709\.1' + os_replacement: 'iOS' + os_v1_replacement: '8' + os_v2_replacement: '0.b5' + - regex: '(CF)(Network)/711\.(\d)' + os_replacement: 'iOS' + os_v1_replacement: '8' + - regex: '(CF)(Network)/(720)\.(\d)' + os_replacement: 'Mac OS X' + os_v1_replacement: '10' + os_v2_replacement: '10' + - regex: '(CF)(Network)/758\.(\d)' + os_replacement: 'iOS' + os_v1_replacement: '9' + + ########## + # CFNetwork iOS Apps + # @ref: https://en.wikipedia.org/wiki/Darwin_(operating_system)#Release_history + ########## + - regex: 'CFNetwork/.* Darwin/(9)\.\d+' + os_replacement: 'iOS' + os_v1_replacement: '1' + - regex: 'CFNetwork/.* Darwin/(10)\.\d+' + os_replacement: 'iOS' + os_v1_replacement: '4' + - regex: 'CFNetwork/.* Darwin/(11)\.\d+' + os_replacement: 'iOS' + os_v1_replacement: '5' + - regex: 'CFNetwork/.* Darwin/(13)\.\d+' + os_replacement: 'iOS' + os_v1_replacement: '6' + - regex: 'CFNetwork/6.* Darwin/(14)\.\d+' + os_replacement: 'iOS' + os_v1_replacement: '7' + - regex: 'CFNetwork/7.* Darwin/(14)\.\d+' + os_replacement: 'iOS' + os_v1_replacement: '8' + os_v2_replacement: '0' + - regex: 'CFNetwork/7.* Darwin/(15)\.\d+' + os_replacement: 'iOS' + os_v1_replacement: '9' + os_v2_replacement: '0' + # iOS Apps + - regex: '\b(iOS[ /]|iPhone(?:/| v|[ _]OS[/,]|; | OS : |\d,\d/|\d,\d; )|iPad/)(\d{1,2})[_\.](\d{1,2})(?:[_\.](\d+))?' + os_replacement: 'iOS' + + ########## + # Apple TV + ########## + - regex: '(tvOS)/(\d+).(\d+)' + os_replacement: 'tvOS' + + ########## + # Chrome OS + # if version 0.0.0, probably this stuff: + # http://code.google.com/p/chromium-os/issues/detail?id=11573 + # http://code.google.com/p/chromium-os/issues/detail?id=13790 + ########## + - regex: '(CrOS) [a-z0-9_]+ (\d+)\.(\d+)(?:\.(\d+))?' + os_replacement: 'Chrome OS' + + ########## + # Linux distros + ########## + - regex: '([Dd]ebian)' + os_replacement: 'Debian' + - regex: '(Linux Mint)(?:/(\d+))?' + - regex: '(Mandriva)(?: Linux)?/(?:[\d.-]+m[a-z]{2}(\d+).(\d))?' + + ########## + # Symbian + Symbian OS + # http://en.wikipedia.org/wiki/History_of_Symbian + ########## + - regex: '(Symbian[Oo][Ss])[/ ](\d+)\.(\d+)' + os_replacement: 'Symbian OS' + - regex: '(Symbian/3).+NokiaBrowser/7\.3' + os_replacement: 'Symbian^3 Anna' + - regex: '(Symbian/3).+NokiaBrowser/7\.4' + os_replacement: 'Symbian^3 Belle' + - regex: '(Symbian/3)' + os_replacement: 'Symbian^3' + - regex: '\b(Series 60|SymbOS|S60Version|S60V\d|S60\b)' + os_replacement: 'Symbian OS' + - regex: '(MeeGo)' + - regex: 'Symbian [Oo][Ss]' + os_replacement: 'Symbian OS' + - regex: 'Series40;' + os_replacement: 'Nokia Series 40' + - regex: 'Series30Plus;' + os_replacement: 'Nokia Series 30 Plus' + + ########## + # BlackBerry devices + ########## + - regex: '(BB10);.+Version/(\d+)\.(\d+)\.(\d+)' + os_replacement: 'BlackBerry OS' + - regex: '(Black[Bb]erry)[0-9a-z]+/(\d+)\.(\d+)\.(\d+)(?:\.(\d+))?' + os_replacement: 'BlackBerry OS' + - regex: '(Black[Bb]erry).+Version/(\d+)\.(\d+)\.(\d+)(?:\.(\d+))?' + os_replacement: 'BlackBerry OS' + - regex: '(RIM Tablet OS) (\d+)\.(\d+)\.(\d+)' + os_replacement: 'BlackBerry Tablet OS' + - regex: '(Play[Bb]ook)' + os_replacement: 'BlackBerry Tablet OS' + - regex: '(Black[Bb]erry)' + os_replacement: 'BlackBerry OS' + + ########## + # Firefox OS + ########## + - regex: '\((?:Mobile|Tablet);.+Gecko/18.0 Firefox/\d+\.\d+' + os_replacement: 'Firefox OS' + os_v1_replacement: '1' + os_v2_replacement: '0' + os_v3_replacement: '1' + + - regex: '\((?:Mobile|Tablet);.+Gecko/18.1 Firefox/\d+\.\d+' + os_replacement: 'Firefox OS' + os_v1_replacement: '1' + os_v2_replacement: '1' + + - regex: '\((?:Mobile|Tablet);.+Gecko/26.0 Firefox/\d+\.\d+' + os_replacement: 'Firefox OS' + os_v1_replacement: '1' + os_v2_replacement: '2' + + - regex: '\((?:Mobile|Tablet);.+Gecko/28.0 Firefox/\d+\.\d+' + os_replacement: 'Firefox OS' + os_v1_replacement: '1' + os_v2_replacement: '3' + + - regex: '\((?:Mobile|Tablet);.+Gecko/30.0 Firefox/\d+\.\d+' + os_replacement: 'Firefox OS' + os_v1_replacement: '1' + os_v2_replacement: '4' + + - regex: '\((?:Mobile|Tablet);.+Gecko/32.0 Firefox/\d+\.\d+' + os_replacement: 'Firefox OS' + os_v1_replacement: '2' + os_v2_replacement: '0' + + - regex: '\((?:Mobile|Tablet);.+Gecko/34.0 Firefox/\d+\.\d+' + os_replacement: 'Firefox OS' + os_v1_replacement: '2' + os_v2_replacement: '1' + + # Firefox OS Generic + - regex: '\((?:Mobile|Tablet);.+Firefox/\d+\.\d+' + os_replacement: 'Firefox OS' + + + ########## + # BREW + # yes, Brew is lower-cased for Brew MP + ########## + - regex: '(BREW)[ /](\d+)\.(\d+)\.(\d+)' + - regex: '(BREW);' + - regex: '(Brew MP|BMP)[ /](\d+)\.(\d+)\.(\d+)' + os_replacement: 'Brew MP' + - regex: 'BMP;' + os_replacement: 'Brew MP' + + ########## + # Google TV + ########## + - regex: '(GoogleTV)(?: (\d+)\.(\d+)(?:\.(\d+))?|/[\da-z]+)' + + - regex: '(WebTV)/(\d+).(\d+)' + + ########## + # Misc mobile + ########## + - regex: '(hpw|web)OS/(\d+)\.(\d+)(?:\.(\d+))?' + os_replacement: 'webOS' + - regex: '(VRE);' + + ########## + # Generic patterns + # since the majority of os cases are very specific, these go last + ########## + - regex: '(Fedora|Red Hat|PCLinuxOS|Puppy|Ubuntu|Kindle|Bada|Lubuntu|BackTrack|Slackware|(?:Free|Open|Net|\b)BSD)[/ ](\d+)\.(\d+)(?:\.(\d+)(?:\.(\d+))?)?' + + # Gentoo Linux + Kernel Version + - regex: '(Linux)[ /](\d+)\.(\d+)(?:\.(\d+))?.*gentoo' + os_replacement: 'Gentoo' + + # Opera Mini Bada + - regex: '\((Bada);' + + # just os + - regex: '(Windows|Android|WeTab|Maemo)' + - regex: '(Ubuntu|Kubuntu|Arch Linux|CentOS|Slackware|Gentoo|openSUSE|SUSE|Red Hat|Fedora|PCLinuxOS|Mageia|(?:Free|Open|Net|\b)BSD)' + # Linux + Kernel Version + - regex: '(Linux)(?:[ /](\d+)\.(\d+)(?:\.(\d+))?)?' + - regex: 'SunOS' + os_replacement: 'Solaris' + +device_parsers: + + ######### + # Mobile Spiders + # Catch the mobile crawler before checking for iPhones / Androids. + ######### + - regex: '(?:(?:iPhone|Windows CE|Android).*(?:(?:Bot|Yeti)-Mobile|YRSpider|bots?/\d|(?:bot|spider)\.html)|AdsBot-Google-Mobile.*iPhone)' + regex_flag: 'i' + device_replacement: 'Spider' + brand_replacement: 'Spider' + model_replacement: 'Smartphone' + - regex: '(?:DoCoMo|\bMOT\b|\bLG\b|Nokia|Samsung|SonyEricsson).*(?:(?:Bot|Yeti)-Mobile|bots?/\d|(?:bot|crawler)\.html|(?:jump|google|Wukong)bot|ichiro/mobile|/spider|YahooSeeker)' + regex_flag: 'i' + device_replacement: 'Spider' + brand_replacement: 'Spider' + model_replacement: 'Feature Phone' + + ######### + # WebBrowser for SmartWatch + # @ref: https://play.google.com/store/apps/details?id=se.vaggan.webbrowser&hl=en + ######### + - regex: '\bSmartWatch *\( *([^;]+) *; *([^;]+) *;' + device_replacement: '$1 $2' + brand_replacement: '$1' + model_replacement: '$2' + + ###################################################################### + # Android parsers + # + # @ref: https://support.google.com/googleplay/answer/1727131?hl=en + ###################################################################### + + # Android Application + - regex: 'Android Application[^\-]+ - (Sony) ?(Ericsson)? (.+) \w+ - ' + device_replacement: '$1 $2' + brand_replacement: '$1$2' + model_replacement: '$3' + - regex: 'Android Application[^\-]+ - (?:HTC|HUAWEI|LGE|LENOVO|MEDION|TCT) (HTC|HUAWEI|LG|LENOVO|MEDION|ALCATEL)[ _\-](.+) \w+ - ' + regex_flag: 'i' + device_replacement: '$1 $2' + brand_replacement: '$1' + model_replacement: '$2' + - regex: 'Android Application[^\-]+ - ([^ ]+) (.+) \w+ - ' + device_replacement: '$1 $2' + brand_replacement: '$1' + model_replacement: '$2' + + ######### + # 3Q + # @ref: http://www.3q-int.com/ + ######### + - regex: '; *([BLRQ]C\d{4}[A-Z]+) +Build/' + device_replacement: '3Q $1' + brand_replacement: '3Q' + model_replacement: '$1' + - regex: '; *(?:3Q_)([^;/]+) +Build' + device_replacement: '3Q $1' + brand_replacement: '3Q' + model_replacement: '$1' + + ######### + # Acer + # @ref: http://us.acer.com/ac/en/US/content/group/tablets + ######### + - regex: 'Android [34].*; *(A100|A101|A110|A200|A210|A211|A500|A501|A510|A511|A700(?: Lite| 3G)?|A701|B1-A71|A1-\d{3}|B1-\d{3}|V360|V370|W500|W500P|W501|W501P|W510|W511|W700|Slider SL101|DA22[^;/]+) Build' + device_replacement: '$1' + brand_replacement: 'Acer' + model_replacement: '$1' + - regex: '; *Acer Iconia Tab ([^;/]+) Build' + device_replacement: '$1' + brand_replacement: 'Acer' + model_replacement: '$1' + - regex: '; *(Z1[1235]0|E320[^/]*|S500|S510|Liquid[^;/]*|Iconia A\d+) Build' + device_replacement: '$1' + brand_replacement: 'Acer' + model_replacement: '$1' + - regex: '; *(Acer |ACER )([^;/]+) Build' + device_replacement: '$1$2' + brand_replacement: 'Acer' + model_replacement: '$2' + + ######### + # Advent + # @ref: https://en.wikipedia.org/wiki/Advent_Vega + # @note: VegaBean and VegaComb (names derived from jellybean, honeycomb) are + # custom ROM builds for Vega + ######### + - regex: '; *(Advent )?(Vega(?:Bean|Comb)?).* Build' + device_replacement: '$1$2' + brand_replacement: 'Advent' + model_replacement: '$2' + + ######### + # Ainol + # @ref: http://www.ainol.com/plugin.php?identifier=ainol&module=product + ######### + - regex: '; *(Ainol )?((?:NOVO|[Nn]ovo)[^;/]+) Build' + device_replacement: '$1$2' + brand_replacement: 'Ainol' + model_replacement: '$2' + + ######### + # Airis + # @ref: http://airis.es/Tienda/Default.aspx?idG=001 + ######### + - regex: '; *AIRIS[ _\-]?([^/;\)]+) *(?:;|\)|Build)' + regex_flag: 'i' + device_replacement: '$1' + brand_replacement: 'Airis' + model_replacement: '$1' + - regex: '; *(OnePAD[^;/]+) Build' + regex_flag: 'i' + device_replacement: '$1' + brand_replacement: 'Airis' + model_replacement: '$1' + + ######### + # Airpad + # @ref: ?? + ######### + - regex: '; *Airpad[ \-]([^;/]+) Build' + device_replacement: 'Airpad $1' + brand_replacement: 'Airpad' + model_replacement: '$1' + + ######### + # Alcatel - TCT + # @ref: http://www.alcatelonetouch.com/global-en/products/smartphones.html + ######### + - regex: '; *(one ?touch) (EVO7|T10|T20) Build' + device_replacement: 'Alcatel One Touch $2' + brand_replacement: 'Alcatel' + model_replacement: 'One Touch $2' + - regex: '; *(?:alcatel[ _])?(?:(?:one[ _]?touch[ _])|ot[ \-])([^;/]+);? Build' + regex_flag: 'i' + device_replacement: 'Alcatel One Touch $1' + brand_replacement: 'Alcatel' + model_replacement: 'One Touch $1' + - regex: '; *(TCL)[ _]([^;/]+) Build' + device_replacement: '$1 $2' + brand_replacement: '$1' + model_replacement: '$2' + # operator specific models + - regex: '; *(Vodafone Smart II|Optimus_Madrid) Build' + device_replacement: 'Alcatel $1' + brand_replacement: 'Alcatel' + model_replacement: '$1' + - regex: '; *BASE_Lutea_3 Build' + device_replacement: 'Alcatel One Touch 998' + brand_replacement: 'Alcatel' + model_replacement: 'One Touch 998' + - regex: '; *BASE_Varia Build' + device_replacement: 'Alcatel One Touch 918D' + brand_replacement: 'Alcatel' + model_replacement: 'One Touch 918D' + + ######### + # Allfine + # @ref: http://www.myallfine.com/Products.asp + ######### + - regex: '; *((?:FINE|Fine)\d[^;/]+) Build' + device_replacement: '$1' + brand_replacement: 'Allfine' + model_replacement: '$1' + + ######### + # Allview + # @ref: http://www.allview.ro/produse/droseries/lista-tablete-pc/ + ######### + - regex: '; *(ALLVIEW[ _]?|Allview[ _]?)((?:Speed|SPEED).*) Build/' + device_replacement: '$1$2' + brand_replacement: 'Allview' + model_replacement: '$2' + - regex: '; *(ALLVIEW[ _]?|Allview[ _]?)?(AX1_Shine|AX2_Frenzy) Build' + device_replacement: '$1$2' + brand_replacement: 'Allview' + model_replacement: '$2' + - regex: '; *(ALLVIEW[ _]?|Allview[ _]?)([^;/]*) Build' + device_replacement: '$1$2' + brand_replacement: 'Allview' + model_replacement: '$2' + + ######### + # Allwinner + # @ref: http://www.allwinner.com/ + # @models: A31 (13.3"),A20,A10, + ######### + - regex: '; *(A13-MID) Build' + device_replacement: '$1' + brand_replacement: 'Allwinner' + model_replacement: '$1' + - regex: '; *(Allwinner)[ _\-]?([^;/]+) Build' + device_replacement: '$1 $2' + brand_replacement: 'Allwinner' + model_replacement: '$1' + + ######### + # Amaway + # @ref: http://www.amaway.cn/ + ######### + - regex: '; *(A651|A701B?|A702|A703|A705|A706|A707|A711|A712|A713|A717|A722|A785|A801|A802|A803|A901|A902|A1002|A1003|A1006|A1007|A9701|A9703|Q710|Q80) Build' + device_replacement: '$1' + brand_replacement: 'Amaway' + model_replacement: '$1' + + ######### + # Amoi + # @ref: http://www.amoi.com/en/prd/prd_index.jspx + ######### + - regex: '; *(?:AMOI|Amoi)[ _]([^;/]+) Build' + device_replacement: 'Amoi $1' + brand_replacement: 'Amoi' + model_replacement: '$1' + - regex: '^(?:AMOI|Amoi)[ _]([^;/]+) Linux' + device_replacement: 'Amoi $1' + brand_replacement: 'Amoi' + model_replacement: '$1' + + ######### + # Aoc + # @ref: http://latin.aoc.com/media_tablet + ######### + - regex: '; *(MW(?:0[789]|10)[^;/]+) Build' + device_replacement: '$1' + brand_replacement: 'Aoc' + model_replacement: '$1' + + ######### + # Aoson + # @ref: http://www.luckystar.com.cn/en/mid.aspx?page=1 + # @ref: http://www.luckystar.com.cn/en/mobiletel.aspx?page=1 + # @note: brand owned by luckystar + ######### + - regex: '; *(G7|M1013|M1015G|M11[CG]?|M-?12[B]?|M15|M19[G]?|M30[ACQ]?|M31[GQ]|M32|M33[GQ]|M36|M37|M38|M701T|M710|M712B|M713|M715G|M716G|M71(?:G|GS|T)?|M72[T]?|M73[T]?|M75[GT]?|M77G|M79T|M7L|M7LN|M81|M810|M81T|M82|M92|M92KS|M92S|M717G|M721|M722G|M723|M725G|M739|M785|M791|M92SK|M93D) Build' + device_replacement: 'Aoson $1' + brand_replacement: 'Aoson' + model_replacement: '$1' + - regex: '; *Aoson ([^;/]+) Build' + regex_flag: 'i' + device_replacement: 'Aoson $1' + brand_replacement: 'Aoson' + model_replacement: '$1' + + ######### + # Apanda + # @ref: http://www.apanda.com.cn/ + ######### + - regex: '; *[Aa]panda[ _\-]([^;/]+) Build' + device_replacement: 'Apanda $1' + brand_replacement: 'Apanda' + model_replacement: '$1' + + ######### + # Archos + # @ref: http://www.archos.com/de/products/tablets.html + # @ref: http://www.archos.com/de/products/smartphones/index.html + ######### + - regex: '; *(?:ARCHOS|Archos) ?(GAMEPAD.*?)(?: Build|[;/\(\)\-])' + device_replacement: 'Archos $1' + brand_replacement: 'Archos' + model_replacement: '$1' + - regex: 'ARCHOS; GOGI; ([^;]+);' + device_replacement: 'Archos $1' + brand_replacement: 'Archos' + model_replacement: '$1' + - regex: '(?:ARCHOS|Archos)[ _]?(.*?)(?: Build|[;/\(\)\-]|$)' + device_replacement: 'Archos $1' + brand_replacement: 'Archos' + model_replacement: '$1' + - regex: '; *(AN(?:7|8|9|10|13)[A-Z0-9]{1,4}) Build' + device_replacement: 'Archos $1' + brand_replacement: 'Archos' + model_replacement: '$1' + - regex: '; *(A28|A32|A43|A70(?:BHT|CHT|HB|S|X)|A101(?:B|C|IT)|A7EB|A7EB-WK|101G9|80G9) Build' + device_replacement: 'Archos $1' + brand_replacement: 'Archos' + model_replacement: '$1' + + ######### + # A-rival + # @ref: http://www.a-rival.de/de/ + ######### + - regex: '; *(PAD-FMD[^;/]+) Build' + device_replacement: '$1' + brand_replacement: 'Arival' + model_replacement: '$1' + - regex: '; *(BioniQ) ?([^;/]+) Build' + device_replacement: '$1 $2' + brand_replacement: 'Arival' + model_replacement: '$1 $2' + + ######### + # Arnova + # @ref: http://arnovatech.com/ + ######### + - regex: '; *(AN\d[^;/]+|ARCHM\d+) Build' + device_replacement: 'Arnova $1' + brand_replacement: 'Arnova' + model_replacement: '$1' + - regex: '; *(?:ARNOVA|Arnova) ?([^;/]+) Build' + device_replacement: 'Arnova $1' + brand_replacement: 'Arnova' + model_replacement: '$1' + + ######### + # Assistant + # @ref: http://www.assistant.ua + ######### + - regex: '; *(?:ASSISTANT )?(AP)-?([1789]\d{2}[A-Z]{0,2}|80104) Build' + device_replacement: 'Assistant $1-$2' + brand_replacement: 'Assistant' + model_replacement: '$1-$2' + + ######### + # Asus + # @ref: http://www.asus.com/uk/Tablets_Mobile/ + ######### + - regex: '; *(ME17\d[^;/]*|ME3\d{2}[^;/]+|K00[A-Z]|Nexus 10|Nexus 7(?: 2013)?|PadFone[^;/]*|Transformer[^;/]*|TF\d{3}[^;/]*|eeepc) Build' + device_replacement: 'Asus $1' + brand_replacement: 'Asus' + model_replacement: '$1' + - regex: '; *ASUS[ _]*([^;/]+) Build' + device_replacement: 'Asus $1' + brand_replacement: 'Asus' + model_replacement: '$1' + + ######### + # Garmin-Asus + ######### + - regex: '; *Garmin-Asus ([^;/]+) Build' + device_replacement: 'Garmin-Asus $1' + brand_replacement: 'Garmin-Asus' + model_replacement: '$1' + - regex: '; *(Garminfone) Build' + device_replacement: 'Garmin $1' + brand_replacement: 'Garmin-Asus' + model_replacement: '$1' + + ######### + # Attab + # @ref: http://www.theattab.com/ + ######### + - regex: '; (@TAB-[^;/]+) Build' + device_replacement: '$1' + brand_replacement: 'Attab' + model_replacement: '$1' + + ######### + # Audiosonic + # @ref: ?? + # @note: Take care with Docomo T-01 Toshiba + ######### + - regex: '; *(T-(?:07|[^0]\d)[^;/]+) Build' + device_replacement: '$1' + brand_replacement: 'Audiosonic' + model_replacement: '$1' + + ######### + # Axioo + # @ref: http://www.axiooworld.com/ww/index.php + ######### + - regex: '; *(?:Axioo[ _\-]([^;/]+)|(picopad)[ _\-]([^;/]+)) Build' + regex_flag: 'i' + device_replacement: 'Axioo $1$2 $3' + brand_replacement: 'Axioo' + model_replacement: '$1$2 $3' + + ######### + # Azend + # @ref: http://azendcorp.com/index.php/products/portable-electronics + ######### + - regex: '; *(V(?:100|700|800)[^;/]*) Build' + device_replacement: '$1' + brand_replacement: 'Azend' + model_replacement: '$1' + + ######### + # Bak + # @ref: http://www.bakinternational.com/produtos.php?cat=80 + ######### + - regex: '; *(IBAK\-[^;/]*) Build' + regex_flag: 'i' + device_replacement: '$1' + brand_replacement: 'Bak' + model_replacement: '$1' + + ######### + # Bedove + # @ref: http://www.bedove.com/product.html + # @models: HY6501|HY5001|X12|X21|I5 + ######### + - regex: '; *(HY5001|HY6501|X12|X21|I5) Build' + device_replacement: 'Bedove $1' + brand_replacement: 'Bedove' + model_replacement: '$1' + + ######### + # Benss + # @ref: http://www.benss.net/ + ######### + - regex: '; *(JC-[^;/]*) Build' + device_replacement: 'Benss $1' + brand_replacement: 'Benss' + model_replacement: '$1' + + ######### + # Blackberry + # @ref: http://uk.blackberry.com/ + # @note: Android Apps seams to be used here + ######### + - regex: '; *(BB) ([^;/]+) Build' + device_replacement: '$1 $2' + brand_replacement: 'Blackberry' + model_replacement: '$2' + + ######### + # Blackbird + # @ref: http://iblackbird.co.kr + ######### + - regex: '; *(BlackBird)[ _](I8.*) Build' + device_replacement: '$1 $2' + brand_replacement: '$1' + model_replacement: '$2' + - regex: '; *(BlackBird)[ _](.*) Build' + device_replacement: '$1 $2' + brand_replacement: '$1' + model_replacement: '$2' + + ######### + # Blaupunkt + # @ref: http://www.blaupunkt.com + ######### + # Endeavour + - regex: '; *([0-9]+BP[EM][^;/]*|Endeavour[^;/]+) Build' + device_replacement: 'Blaupunkt $1' + brand_replacement: 'Blaupunkt' + model_replacement: '$1' + + ######### + # Blu + # @ref: http://bluproducts.com + ######### + - regex: '; *((?:BLU|Blu)[ _\-])([^;/]+) Build' + device_replacement: '$1$2' + brand_replacement: 'Blu' + model_replacement: '$2' + # BMOBILE = operator branded device + - regex: '; *(?:BMOBILE )?(Blu|BLU|DASH [^;/]+|VIVO 4\.3|TANK 4\.5) Build' + device_replacement: '$1' + brand_replacement: 'Blu' + model_replacement: '$1' + + ######### + # Blusens + # @ref: http://www.blusens.com/es/?sg=1&sv=al&roc=1 + ######### + # tablet + - regex: '; *(TOUCH\d[^;/]+) Build' + device_replacement: '$1' + brand_replacement: 'Blusens' + model_replacement: '$1' + + ######### + # Bmobile + # @ref: http://bmobile.eu.com/?categoria=smartphones-2 + # @note: Might collide with Maxx as AX is used also there. + ######### + # smartphone + - regex: '; *(AX5\d+) Build' + device_replacement: '$1' + brand_replacement: 'Bmobile' + model_replacement: '$1' + + ######### + # bq + # @ref: http://bqreaders.com + ######### + - regex: '; *([Bb]q) ([^;/]+);? Build' + device_replacement: '$1 $2' + brand_replacement: 'bq' + model_replacement: '$2' + - regex: '; *(Maxwell [^;/]+) Build' + device_replacement: '$1' + brand_replacement: 'bq' + model_replacement: '$1' + + ######### + # Braun Phototechnik + # @ref: http://www.braun-phototechnik.de/en/products/list/~pcat.250/Tablet-PC.html + ######### + - regex: '; *((?:B-Tab|B-TAB) ?\d[^;/]+) Build' + device_replacement: '$1' + brand_replacement: 'Braun' + model_replacement: '$1' + + ######### + # Broncho + # @ref: http://www.broncho.cn/ + ######### + - regex: '; *(Broncho) ([^;/]+) Build' + device_replacement: '$1 $2' + brand_replacement: '$1' + model_replacement: '$2' + + ######### + # Captiva + # @ref: http://www.captiva-power.de + ######### + - regex: '; *CAPTIVA ([^;/]+) Build' + device_replacement: 'Captiva $1' + brand_replacement: 'Captiva' + model_replacement: '$1' + + ######### + # Casio + # @ref: http://www.casiogzone.com/ + ######### + - regex: '; *(C771|CAL21|IS11CA) Build' + device_replacement: '$1' + brand_replacement: 'Casio' + model_replacement: '$1' + + ######### + # Cat + # @ref: http://www.cat-sound.com + ######### + - regex: '; *(?:Cat|CAT) ([^;/]+) Build' + device_replacement: 'Cat $1' + brand_replacement: 'Cat' + model_replacement: '$1' + - regex: '; *(?:Cat)(Nova.*) Build' + device_replacement: 'Cat $1' + brand_replacement: 'Cat' + model_replacement: '$1' + - regex: '; *(INM8002KP|ADM8000KP_[AB]) Build' + device_replacement: '$1' + brand_replacement: 'Cat' + model_replacement: 'Tablet PHOENIX 8.1J0' + + ######### + # Celkon + # @ref: http://www.celkonmobiles.com/?_a=products + # @models: A10, A19Q, A101, A105, A107, A107\+, A112, A118, A119, A119Q, A15, A19, A20, A200, A220, A225, A22 Race, A27, A58, A59, A60, A62, A63, A64, A66, A67, A69, A75, A77, A79, A8\+, A83, A85, A86, A87, A89 Ultima, A9\+, A90, A900, A95, A97i, A98, AR 40, AR 45, AR 50, ML5 + ######### + - regex: '; *(?:[Cc]elkon[ _\*]|CELKON[ _\*])([^;/\)]+) ?(?:Build|;|\))' + device_replacement: '$1' + brand_replacement: 'Celkon' + model_replacement: '$1' + - regex: 'Build/(?:[Cc]elkon)+_?([^;/_\)]+)' + device_replacement: '$1' + brand_replacement: 'Celkon' + model_replacement: '$1' + - regex: '; *(CT)-?(\d+) Build' + device_replacement: '$1$2' + brand_replacement: 'Celkon' + model_replacement: '$1$2' + # smartphones + - regex: '; *(A19|A19Q|A105|A107[^;/\)]*) ?(?:Build|;|\))' + device_replacement: '$1' + brand_replacement: 'Celkon' + model_replacement: '$1' + + ######### + # ChangJia + # @ref: http://www.cjshowroom.com/eproducts.aspx?classcode=004001001 + # @brief: China manufacturer makes tablets for different small brands + # (eg. http://www.zeepad.net/index.html) + ######### + - regex: '; *(TPC[0-9]{4,5}) Build' + device_replacement: '$1' + brand_replacement: 'ChangJia' + model_replacement: '$1' + + ######### + # Cloudfone + # @ref: http://www.cloudfonemobile.com/ + ######### + - regex: '; *(Cloudfone)[ _](Excite)([^ ][^;/]+) Build' + device_replacement: '$1 $2 $3' + brand_replacement: 'Cloudfone' + model_replacement: '$1 $2 $3' + - regex: '; *(Excite|ICE)[ _](\d+[^;/]+) Build' + device_replacement: 'Cloudfone $1 $2' + brand_replacement: 'Cloudfone' + model_replacement: 'Cloudfone $1 $2' + - regex: '; *(Cloudfone|CloudPad)[ _]([^;/]+) Build' + device_replacement: '$1 $2' + brand_replacement: 'Cloudfone' + model_replacement: '$1 $2' + + ######### + # Cmx + # @ref: http://cmx.at/de/ + ######### + - regex: '; *((?:Aquila|Clanga|Rapax)[^;/]+) Build' + regex_flag: 'i' + device_replacement: '$1' + brand_replacement: 'Cmx' + model_replacement: '$1' + + ######### + # CobyKyros + # @ref: http://cobykyros.com + # @note: Be careful with MID\d{3} from MpMan or Manta + ######### + - regex: '; *(?:CFW-|Kyros )?(MID[0-9]{4}(?:[ABC]|SR|TV)?)(\(3G\)-4G| GB 8K| 3G| 8K| GB)? *(?:Build|[;\)])' + device_replacement: 'CobyKyros $1$2' + brand_replacement: 'CobyKyros' + model_replacement: '$1$2' + + ######### + # Coolpad + # @ref: ?? + ######### + - regex: '; *([^;/]*)Coolpad[ _]([^;/]+) Build' + device_replacement: '$1$2' + brand_replacement: 'Coolpad' + model_replacement: '$1$2' + + ######### + # Cube + # @ref: http://www.cube-tablet.com/buy-products.html + ######### + - regex: '; *(CUBE[ _])?([KU][0-9]+ ?GT.*|A5300) Build' + regex_flag: 'i' + device_replacement: '$1$2' + brand_replacement: 'Cube' + model_replacement: '$2' + + ######### + # Cubot + # @ref: http://www.cubotmall.com/ + ######### + - regex: '; *CUBOT ([^;/]+) Build' + regex_flag: 'i' + device_replacement: '$1' + brand_replacement: 'Cubot' + model_replacement: '$1' + - regex: '; *(BOBBY) Build' + regex_flag: 'i' + device_replacement: '$1' + brand_replacement: 'Cubot' + model_replacement: '$1' + + ######### + # Danew + # @ref: http://www.danew.com/produits-tablette.php + ######### + - regex: '; *(Dslide [^;/]+) Build' + device_replacement: '$1' + brand_replacement: 'Danew' + model_replacement: '$1' + + ######### + # Dell + # @ref: http://www.dell.com + # @ref: http://www.softbank.jp/mobile/support/product/101dl/ + # @ref: http://www.softbank.jp/mobile/support/product/001dl/ + # @ref: http://developer.emnet.ne.jp/android.html + # @ref: http://www.dell.com/in/p/mobile-xcd28/pd + # @ref: http://www.dell.com/in/p/mobile-xcd35/pd + ######### + - regex: '; *(XCD)[ _]?(28|35) Build' + device_replacement: 'Dell $1$2' + brand_replacement: 'Dell' + model_replacement: '$1$2' + - regex: '; *(001DL) Build' + device_replacement: 'Dell $1' + brand_replacement: 'Dell' + model_replacement: 'Streak' + - regex: '; *(?:Dell|DELL) (Streak) Build' + device_replacement: 'Dell $1' + brand_replacement: 'Dell' + model_replacement: 'Streak' + - regex: '; *(101DL|GS01|Streak Pro[^;/]*) Build' + device_replacement: 'Dell $1' + brand_replacement: 'Dell' + model_replacement: 'Streak Pro' + - regex: '; *([Ss]treak ?7) Build' + device_replacement: 'Dell $1' + brand_replacement: 'Dell' + model_replacement: 'Streak 7' + - regex: '; *(Mini-3iX) Build' + device_replacement: 'Dell $1' + brand_replacement: 'Dell' + model_replacement: '$1' + - regex: '; *(?:Dell|DELL)[ _](Aero|Venue|Thunder|Mini.*|Streak[ _]Pro) Build' + device_replacement: 'Dell $1' + brand_replacement: 'Dell' + model_replacement: '$1' + - regex: '; *Dell[ _]([^;/]+) Build' + device_replacement: 'Dell $1' + brand_replacement: 'Dell' + model_replacement: '$1' + - regex: '; *Dell ([^;/]+) Build' + device_replacement: 'Dell $1' + brand_replacement: 'Dell' + model_replacement: '$1' + + ######### + # Denver + # @ref: http://www.denver-electronics.com/tablets1/ + ######### + - regex: '; *(TA[CD]-\d+[^;/]*) Build' + device_replacement: '$1' + brand_replacement: 'Denver' + model_replacement: '$1' + + ######### + # Dex + # @ref: http://dex.ua/ + ######### + - regex: '; *(iP[789]\d{2}(?:-3G)?|IP10\d{2}(?:-8GB)?) Build' + device_replacement: '$1' + brand_replacement: 'Dex' + model_replacement: '$1' + + ######### + # DNS AirTab + # @ref: http://www.dns-shop.ru/ + ######### + - regex: '; *(AirTab)[ _\-]([^;/]+) Build' + device_replacement: '$1 $2' + brand_replacement: 'DNS' + model_replacement: '$1 $2' + + ######### + # Docomo (Operator Branded Device) + # @ref: http://www.ipentec.com/document/document.aspx?page=android-useragent + ######### + - regex: '; *(F\-\d[^;/]+) Build' + device_replacement: '$1' + brand_replacement: 'Fujitsu' + model_replacement: '$1' + - regex: '; *(HT-03A) Build' + device_replacement: '$1' + brand_replacement: 'HTC' + model_replacement: 'Magic' + - regex: '; *(HT\-\d[^;/]+) Build' + device_replacement: '$1' + brand_replacement: 'HTC' + model_replacement: '$1' + - regex: '; *(L\-\d[^;/]+) Build' + device_replacement: '$1' + brand_replacement: 'LG' + model_replacement: '$1' + - regex: '; *(N\-\d[^;/]+) Build' + device_replacement: '$1' + brand_replacement: 'Nec' + model_replacement: '$1' + - regex: '; *(P\-\d[^;/]+) Build' + device_replacement: '$1' + brand_replacement: 'Panasonic' + model_replacement: '$1' + - regex: '; *(SC\-\d[^;/]+) Build' + device_replacement: '$1' + brand_replacement: 'Samsung' + model_replacement: '$1' + - regex: '; *(SH\-\d[^;/]+) Build' + device_replacement: '$1' + brand_replacement: 'Sharp' + model_replacement: '$1' + - regex: '; *(SO\-\d[^;/]+) Build' + device_replacement: '$1' + brand_replacement: 'SonyEricsson' + model_replacement: '$1' + - regex: '; *(T\-0[12][^;/]+) Build' + device_replacement: '$1' + brand_replacement: 'Toshiba' + model_replacement: '$1' + + ######### + # DOOV + # @ref: http://www.doov.com.cn/ + ######### + - regex: '; *(DOOV)[ _]([^;/]+) Build' + device_replacement: '$1 $2' + brand_replacement: 'DOOV' + model_replacement: '$2' + + ######### + # Enot + # @ref: http://www.enot.ua/ + ######### + - regex: '; *(Enot|ENOT)[ -]?([^;/]+) Build' + device_replacement: '$1 $2' + brand_replacement: 'Enot' + model_replacement: '$2' + + ######### + # Evercoss + # @ref: http://evercoss.com/android/ + ######### + - regex: '; *[^;/]+ Build/(?:CROSS|Cross)+[ _\-]([^\)]+)' + device_replacement: 'CROSS $1' + brand_replacement: 'Evercoss' + model_replacement: 'Cross $1' + - regex: '; *(CROSS|Cross)[ _\-]([^;/]+) Build' + device_replacement: '$1 $2' + brand_replacement: 'Evercoss' + model_replacement: 'Cross $2' + + ######### + # Explay + # @ref: http://explay.ru/ + ######### + - regex: '; *Explay[_ ](.+?)(?:[\)]| Build)' + device_replacement: '$1' + brand_replacement: 'Explay' + model_replacement: '$1' + + ######### + # Fly + # @ref: http://www.fly-phone.com/ + ######### + - regex: '; *(IQ.*) Build' + device_replacement: '$1' + brand_replacement: 'Fly' + model_replacement: '$1' + - regex: '; *(Fly|FLY)[ _](IQ[^;]+|F[34]\d+[^;]*);? Build' + device_replacement: '$1 $2' + brand_replacement: 'Fly' + model_replacement: '$2' + + ######### + # Fujitsu + # @ref: http://www.fujitsu.com/global/ + ######### + - regex: '; *(M532|Q572|FJL21) Build/' + device_replacement: '$1' + brand_replacement: 'Fujitsu' + model_replacement: '$1' + + ######### + # Galapad + # @ref: http://www.galapad.net/product.html + ######### + - regex: '; *(G1) Build' + device_replacement: '$1' + brand_replacement: 'Galapad' + model_replacement: '$1' + + ######### + # Geeksphone + # @ref: http://www.geeksphone.com/ + ######### + - regex: '; *(Geeksphone) ([^;/]+) Build' + device_replacement: '$1 $2' + brand_replacement: '$1' + model_replacement: '$2' + + ######### + # Gfive + # @ref: http://www.gfivemobile.com/en + ######### + #- regex: '; *(G\'?FIVE) ([^;/]+) Build' # there is a problem with python yaml parser here + - regex: '; *(G[^F]?FIVE) ([^;/]+) Build' + device_replacement: '$1 $2' + brand_replacement: 'Gfive' + model_replacement: '$2' + + ######### + # Gionee + # @ref: http://www.gionee.com/ + ######### + - regex: '; *(Gionee)[ _\-]([^;/]+)(?:/[^;/]+)? Build' + regex_flag: 'i' + device_replacement: '$1 $2' + brand_replacement: 'Gionee' + model_replacement: '$2' + - regex: '; *(GN\d+[A-Z]?|INFINITY_PASSION|Ctrl_V1) Build' + device_replacement: 'Gionee $1' + brand_replacement: 'Gionee' + model_replacement: '$1' + - regex: '; *(E3) Build/JOP40D' + device_replacement: 'Gionee $1' + brand_replacement: 'Gionee' + model_replacement: '$1' + + ######### + # GoClever + # @ref: http://www.goclever.com + ######### + - regex: '; *((?:FONE|QUANTUM|INSIGNIA) \d+[^;/]*|PLAYTAB) Build' + device_replacement: 'GoClever $1' + brand_replacement: 'GoClever' + model_replacement: '$1' + - regex: '; *GOCLEVER ([^;/]+) Build' + device_replacement: 'GoClever $1' + brand_replacement: 'GoClever' + model_replacement: '$1' + + ######### + # Google + # @ref: http://www.google.de/glass/start/ + ######### + - regex: '; *(Glass \d+) Build' + device_replacement: '$1' + brand_replacement: 'Google' + model_replacement: '$1' + + ######### + # Gigabyte + # @ref: http://gsmart.gigabytecm.com/en/ + ######### + - regex: '; *(GSmart)[ -]([^/]+) Build' + device_replacement: '$1 $2' + brand_replacement: 'Gigabyte' + model_replacement: '$1 $2' + + ######### + # Freescale development boards + # @ref: http://www.freescale.com/webapp/sps/site/prod_summary.jsp?code=IMX53QSB + ######### + - regex: '; *(imx5[13]_[^/]+) Build' + device_replacement: 'Freescale $1' + brand_replacement: 'Freescale' + model_replacement: '$1' + + ######### + # Haier + # @ref: http://www.haier.com/ + # @ref: http://www.haier.com/de/produkte/tablet/ + ######### + - regex: '; *Haier[ _\-]([^/]+) Build' + device_replacement: 'Haier $1' + brand_replacement: 'Haier' + model_replacement: '$1' + - regex: '; *(PAD1016) Build' + device_replacement: 'Haipad $1' + brand_replacement: 'Haipad' + model_replacement: '$1' + + ######### + # Haipad + # @ref: http://www.haipad.net/ + # @models: V7P|M7SM7S|M9XM9X|M7XM7X|M9|M8|M7-M|M1002|M7|M701 + ######### + - regex: '; *(M701|M7|M8|M9) Build' + device_replacement: 'Haipad $1' + brand_replacement: 'Haipad' + model_replacement: '$1' + + ######### + # Hannspree + # @ref: http://www.hannspree.eu/ + # @models: SN10T1|SN10T2|SN70T31B|SN70T32W + ######### + - regex: '; *(SN\d+T[^;\)/]*)(?: Build|[;\)])' + device_replacement: 'Hannspree $1' + brand_replacement: 'Hannspree' + model_replacement: '$1' + + ######### + # HCLme + # @ref: http://www.hclmetablet.com/india/ + ######### + - regex: 'Build/HCL ME Tablet ([^;\)]+)[\);]' + device_replacement: 'HCLme $1' + brand_replacement: 'HCLme' + model_replacement: '$1' + - regex: '; *([^;\/]+) Build/HCL' + device_replacement: 'HCLme $1' + brand_replacement: 'HCLme' + model_replacement: '$1' + + ######### + # Hena + # @ref: http://www.henadigital.com/en/product/index.asp?id=6 + ######### + - regex: '; *(MID-?\d{4}C[EM]) Build' + device_replacement: 'Hena $1' + brand_replacement: 'Hena' + model_replacement: '$1' + + ######### + # Hisense + # @ref: http://www.hisense.com/ + ######### + - regex: '; *(EG\d{2,}|HS-[^;/]+|MIRA[^;/]+) Build' + device_replacement: 'Hisense $1' + brand_replacement: 'Hisense' + model_replacement: '$1' + - regex: '; *(andromax[^;/]+) Build' + regex_flag: 'i' + device_replacement: 'Hisense $1' + brand_replacement: 'Hisense' + model_replacement: '$1' + + ######### + # hitech + # @ref: http://www.hitech-mobiles.com/ + ######### + - regex: '; *(?:AMAZE[ _](S\d+)|(S\d+)[ _]AMAZE) Build' + device_replacement: 'AMAZE $1$2' + brand_replacement: 'hitech' + model_replacement: 'AMAZE $1$2' + + ######### + # HP + # @ref: http://www.hp.com/ + ######### + - regex: '; *(PlayBook) Build' + device_replacement: 'HP $1' + brand_replacement: 'HP' + model_replacement: '$1' + - regex: '; *HP ([^/]+) Build' + device_replacement: 'HP $1' + brand_replacement: 'HP' + model_replacement: '$1' + - regex: '; *([^/]+_tenderloin) Build' + device_replacement: 'HP TouchPad' + brand_replacement: 'HP' + model_replacement: 'TouchPad' + + ######### + # Huawei + # @ref: http://www.huaweidevice.com + # @note: Needs to be before HTC due to Desire HD Build on U8815 + ######### + - regex: '; *(HUAWEI |Huawei-)?([UY][^;/]+) Build/(?:Huawei|HUAWEI)([UY][^\);]+)\)' + device_replacement: '$1$2' + brand_replacement: 'Huawei' + model_replacement: '$2' + - regex: '; *([^;/]+) Build[/ ]Huawei(MT1-U06|[A-Z]+\d+[^\);]+)[^\);]*\)' + device_replacement: '$1' + brand_replacement: 'Huawei' + model_replacement: '$2' + - regex: '; *(S7|M860) Build' + device_replacement: '$1' + brand_replacement: 'Huawei' + model_replacement: '$1' + - regex: '; *((?:HUAWEI|Huawei)[ \-]?)(MediaPad) Build' + device_replacement: '$1$2' + brand_replacement: 'Huawei' + model_replacement: '$2' + - regex: '; *((?:HUAWEI[ _]?|Huawei[ _])?Ascend[ _])([^;/]+) Build' + device_replacement: '$1$2' + brand_replacement: 'Huawei' + model_replacement: '$2' + - regex: '; *((?:HUAWEI|Huawei)[ _\-]?)((?:G700-|MT-)[^;/]+) Build' + device_replacement: '$1$2' + brand_replacement: 'Huawei' + model_replacement: '$2' + - regex: '; *((?:HUAWEI|Huawei)[ _\-]?)([^;/]+) Build' + device_replacement: '$1$2' + brand_replacement: 'Huawei' + model_replacement: '$2' + - regex: '; *(MediaPad[^;]+|SpringBoard) Build/Huawei' + device_replacement: '$1' + brand_replacement: 'Huawei' + model_replacement: '$1' + - regex: '; *([^;]+) Build/Huawei' + device_replacement: '$1' + brand_replacement: 'Huawei' + model_replacement: '$1' + - regex: '; *([Uu])([89]\d{3}) Build' + device_replacement: '$1$2' + brand_replacement: 'Huawei' + model_replacement: 'U$2' + - regex: '; *(?:Ideos |IDEOS )(S7) Build' + device_replacement: 'Huawei Ideos$1' + brand_replacement: 'Huawei' + model_replacement: 'Ideos$1' + - regex: '; *(?:Ideos |IDEOS )([^;/]+\s*|\s*)Build' + device_replacement: 'Huawei Ideos$1' + brand_replacement: 'Huawei' + model_replacement: 'Ideos$1' + - regex: '; *(Orange Daytona|Pulse|Pulse Mini|Vodafone 858|C8500|C8600|C8650|C8660) Build' + device_replacement: 'Huawei $1' + brand_replacement: 'Huawei' + model_replacement: '$1' + + ######### + # HTC + # @ref: http://www.htc.com/www/products/ + # @ref: http://en.wikipedia.org/wiki/List_of_HTC_phones + ######### + + - regex: '; *HTC[ _]([^;]+); Windows Phone' + device_replacement: 'HTC $1' + brand_replacement: 'HTC' + model_replacement: '$1' + + # Android HTC with Version Number matcher + # ; HTC_0P3Z11/1.12.161.3 Build + # ;HTC_A3335 V2.38.841.1 Build + - regex: '; *(?:HTC[ _/])+([^ _/]+)(?:[/\\]1\.0 | V|/| +)\d+\.\d[\d\.]*(?: *Build|\))' + device_replacement: 'HTC $1' + brand_replacement: 'HTC' + model_replacement: '$1' + - regex: '; *(?:HTC[ _/])+([^ _/]+)(?:[ _/]([^ _/]+))?(?:[/\\]1\.0 | V|/| +)\d+\.\d[\d\.]*(?: *Build|\))' + device_replacement: 'HTC $1 $2' + brand_replacement: 'HTC' + model_replacement: '$1 $2' + - regex: '; *(?:HTC[ _/])+([^ _/]+)(?:[ _/]([^ _/]+)(?:[ _/]([^ _/]+))?)?(?:[/\\]1\.0 | V|/| +)\d+\.\d[\d\.]*(?: *Build|\))' + device_replacement: 'HTC $1 $2 $3' + brand_replacement: 'HTC' + model_replacement: '$1 $2 $3' + - regex: '; *(?:HTC[ _/])+([^ _/]+)(?:[ _/]([^ _/]+)(?:[ _/]([^ _/]+)(?:[ _/]([^ _/]+))?)?)?(?:[/\\]1\.0 | V|/| +)\d+\.\d[\d\.]*(?: *Build|\))' + device_replacement: 'HTC $1 $2 $3 $4' + brand_replacement: 'HTC' + model_replacement: '$1 $2 $3 $4' + + # Android HTC without Version Number matcher + - regex: '; *(?:(?:HTC|htc)(?:_blocked)*[ _/])+([^ _/;]+)(?: *Build|[;\)]| - )' + device_replacement: 'HTC $1' + brand_replacement: 'HTC' + model_replacement: '$1' + - regex: '; *(?:(?:HTC|htc)(?:_blocked)*[ _/])+([^ _/]+)(?:[ _/]([^ _/;\)]+))?(?: *Build|[;\)]| - )' + device_replacement: 'HTC $1 $2' + brand_replacement: 'HTC' + model_replacement: '$1 $2' + - regex: '; *(?:(?:HTC|htc)(?:_blocked)*[ _/])+([^ _/]+)(?:[ _/]([^ _/]+)(?:[ _/]([^ _/;\)]+))?)?(?: *Build|[;\)]| - )' + device_replacement: 'HTC $1 $2 $3' + brand_replacement: 'HTC' + model_replacement: '$1 $2 $3' + - regex: '; *(?:(?:HTC|htc)(?:_blocked)*[ _/])+([^ _/]+)(?:[ _/]([^ _/]+)(?:[ _/]([^ _/]+)(?:[ _/]([^ /;]+))?)?)?(?: *Build|[;\)]| - )' + device_replacement: 'HTC $1 $2 $3 $4' + brand_replacement: 'HTC' + model_replacement: '$1 $2 $3 $4' + + # HTC Streaming Player + - regex: 'HTC Streaming Player [^\/]*/[^\/]*/ htc_([^/]+) /' + device_replacement: 'HTC $1' + brand_replacement: 'HTC' + model_replacement: '$1' + # general matcher for anything else + - regex: '(?:[;,] *|^)(?:htccn_chs-)?HTC[ _-]?([^;]+?)(?: *Build|clay|Android|-?Mozilla| Opera| Profile| UNTRUSTED|[;/\(\)]|$)' + regex_flag: 'i' + device_replacement: 'HTC $1' + brand_replacement: 'HTC' + model_replacement: '$1' + # Android matchers without HTC + - regex: '; *(A6277|ADR6200|ADR6300|ADR6350|ADR6400[A-Z]*|ADR6425[A-Z]*|APX515CKT|ARIA|Desire[^_ ]*|Dream|EndeavorU|Eris|Evo|Flyer|HD2|Hero|HERO200|Hero CDMA|HTL21|Incredible|Inspire[A-Z0-9]*|Legend|Liberty|Nexus ?(?:One|HD2)|One|One S C2|One[ _]?(?:S|V|X\+?)\w*|PC36100|PG06100|PG86100|S31HT|Sensation|Wildfire)(?: Build|[/;\(\)])' + regex_flag: 'i' + device_replacement: 'HTC $1' + brand_replacement: 'HTC' + model_replacement: '$1' + - regex: '; *(ADR6200|ADR6400L|ADR6425LVW|Amaze|DesireS?|EndeavorU|Eris|EVO|Evo\d[A-Z]+|HD2|IncredibleS?|Inspire[A-Z0-9]*|Inspire[A-Z0-9]*|Sensation[A-Z0-9]*|Wildfire)[ _-](.+?)(?:[/;\)]|Build|MIUI|1\.0)' + regex_flag: 'i' + device_replacement: 'HTC $1 $2' + brand_replacement: 'HTC' + model_replacement: '$1 $2' + + ######### + # Hyundai + # @ref: http://www.hyundaitechnologies.com + ######### + - regex: '; *HYUNDAI (T\d[^/]*) Build' + device_replacement: 'Hyundai $1' + brand_replacement: 'Hyundai' + model_replacement: '$1' + - regex: '; *HYUNDAI ([^;/]+) Build' + device_replacement: 'Hyundai $1' + brand_replacement: 'Hyundai' + model_replacement: '$1' + # X900? http://www.amazon.com/Hyundai-X900-Retina-Android-Bluetooth/dp/B00AO07H3O + - regex: '; *(X700|Hold X|MB-6900) Build' + device_replacement: 'Hyundai $1' + brand_replacement: 'Hyundai' + model_replacement: '$1' + + ######### + # iBall + # @ref: http://www.iball.co.in/Category/Mobiles/22 + ######### + - regex: '; *(?:iBall[ _\-])?(Andi)[ _]?(\d[^;/]*) Build' + regex_flag: 'i' + device_replacement: '$1 $2' + brand_replacement: 'iBall' + model_replacement: '$1 $2' + - regex: '; *(IBall)(?:[ _]([^;/]+)|) Build' + regex_flag: 'i' + device_replacement: '$1 $2' + brand_replacement: 'iBall' + model_replacement: '$2' + + ######### + # IconBIT + # @ref: http://www.iconbit.com/catalog/tablets/ + ######### + - regex: '; *(NT-\d+[^ ;/]*|Net[Tt]AB [^;/]+|Mercury [A-Z]+|iconBIT)(?: S/N:[^;/]+)? Build' + device_replacement: '$1' + brand_replacement: 'IconBIT' + model_replacement: '$1' + + ######### + # IMO + # @ref: http://www.ponselimo.com/ + ######### + - regex: '; *(IMO)[ _]([^;/]+) Build' + regex_flag: 'i' + device_replacement: '$1 $2' + brand_replacement: 'IMO' + model_replacement: '$2' + + ######### + # i-mobile + # @ref: http://www.i-mobilephone.com/ + ######### + - regex: '; *i-?mobile[ _]([^/]+) Build/' + regex_flag: 'i' + device_replacement: 'i-mobile $1' + brand_replacement: 'imobile' + model_replacement: '$1' + - regex: '; *(i-(?:style|note)[^/]*) Build/' + regex_flag: 'i' + device_replacement: 'i-mobile $1' + brand_replacement: 'imobile' + model_replacement: '$1' + + ######### + # Impression + # @ref: http://impression.ua/planshetnye-kompyutery + ######### + - regex: '; *(ImPAD) ?(\d+(?:.)*) Build' + device_replacement: '$1 $2' + brand_replacement: 'Impression' + model_replacement: '$1 $2' + + ######### + # Infinix + # @ref: http://www.infinixmobility.com/index.html + ######### + - regex: '; *(Infinix)[ _]([^;/]+) Build' + device_replacement: '$1 $2' + brand_replacement: 'Infinix' + model_replacement: '$2' + + ######### + # Informer + # @ref: ?? + ######### + - regex: '; *(Informer)[ \-]([^;/]+) Build' + device_replacement: '$1 $2' + brand_replacement: 'Informer' + model_replacement: '$2' + + ######### + # Intenso + # @ref: http://www.intenso.de + # @models: 7":TAB 714,TAB 724;8":TAB 814,TAB 824;10":TAB 1004 + ######### + - regex: '; *(TAB) ?([78][12]4) Build' + device_replacement: 'Intenso $1' + brand_replacement: 'Intenso' + model_replacement: '$1 $2' + + ######### + # Intex + # @ref: http://intexmobile.in/index.aspx + # @note: Zync also offers a "Cloud Z5" device + ######### + # smartphones + - regex: '; *(?:Intex[ _])?(AQUA|Aqua)([ _\.\-])([^;/]+) *(?:Build|;)' + device_replacement: '$1$2$3' + brand_replacement: 'Intex' + model_replacement: '$1 $3' + # matches "INTEX CLOUD X1" + - regex: '; *(?:INTEX|Intex)(?:[_ ]([^\ _;/]+))(?:[_ ]([^\ _;/]+))? *(?:Build|;)' + device_replacement: '$1 $2' + brand_replacement: 'Intex' + model_replacement: '$1 $2' + # tablets + - regex: '; *([iI]Buddy)[ _]?(Connect)(?:_|\?_| )?([^;/]*) *(?:Build|;)' + device_replacement: '$1 $2 $3' + brand_replacement: 'Intex' + model_replacement: 'iBuddy $2 $3' + - regex: '; *(I-Buddy)[ _]([^;/]+) *(?:Build|;)' + device_replacement: '$1 $2' + brand_replacement: 'Intex' + model_replacement: 'iBuddy $2' + + ######### + # iOCEAN + # @ref: http://www.iocean.cc/ + ######### + - regex: '; *(iOCEAN) ([^/]+) Build' + regex_flag: 'i' + device_replacement: '$1 $2' + brand_replacement: 'iOCEAN' + model_replacement: '$2' + + ######### + # i.onik + # @ref: http://www.i-onik.de/ + ######### + - regex: '; *(TP\d+(?:\.\d+)?\-\d[^;/]+) Build' + device_replacement: 'ionik $1' + brand_replacement: 'ionik' + model_replacement: '$1' + + ######### + # IRU.ru + # @ref: http://www.iru.ru/catalog/soho/planetable/ + ######### + - regex: '; *(M702pro) Build' + device_replacement: '$1' + brand_replacement: 'Iru' + model_replacement: '$1' + + ######### + # Ivio + # @ref: http://www.ivio.com/mobile.php + # @models: DG80,DG20,DE38,DE88,MD70 + ######### + - regex: '; *(DE88Plus|MD70) Build' + device_replacement: '$1' + brand_replacement: 'Ivio' + model_replacement: '$1' + - regex: '; *IVIO[_\-]([^;/]+) Build' + device_replacement: '$1' + brand_replacement: 'Ivio' + model_replacement: '$1' + + ######### + # Jaytech + # @ref: http://www.jay-tech.de/jaytech/servlet/frontend/ + ######### + - regex: '; *(TPC-\d+|JAY-TECH) Build' + device_replacement: '$1' + brand_replacement: 'Jaytech' + model_replacement: '$1' + + ######### + # Jiayu + # @ref: http://www.ejiayu.com/en/Product.html + ######### + - regex: '; *(JY-[^;/]+|G[234]S?) Build' + device_replacement: '$1' + brand_replacement: 'Jiayu' + model_replacement: '$1' + + ######### + # JXD + # @ref: http://www.jxd.hk/ + ######### + - regex: '; *(JXD)[ _\-]([^;/]+) Build' + device_replacement: '$1 $2' + brand_replacement: 'JXD' + model_replacement: '$2' + + ######### + # Karbonn + # @ref: http://www.karbonnmobiles.com/products_tablet.php + ######### + - regex: '; *Karbonn[ _]?([^;/]+) *(?:Build|;)' + regex_flag: 'i' + device_replacement: '$1' + brand_replacement: 'Karbonn' + model_replacement: '$1' + - regex: '; *([^;]+) Build/Karbonn' + device_replacement: '$1' + brand_replacement: 'Karbonn' + model_replacement: '$1' + - regex: '; *(A11|A39|A37|A34|ST8|ST10|ST7|Smart Tab3|Smart Tab2|Titanium S\d) +Build' + device_replacement: '$1' + brand_replacement: 'Karbonn' + model_replacement: '$1' + + ######### + # KDDI (Operator Branded Device) + # @ref: http://www.ipentec.com/document/document.aspx?page=android-useragent + ######### + - regex: '; *(IS01|IS03|IS05|IS\d{2}SH) Build' + device_replacement: '$1' + brand_replacement: 'Sharp' + model_replacement: '$1' + - regex: '; *(IS04) Build' + device_replacement: '$1' + brand_replacement: 'Regza' + model_replacement: '$1' + - regex: '; *(IS06|IS\d{2}PT) Build' + device_replacement: '$1' + brand_replacement: 'Pantech' + model_replacement: '$1' + - regex: '; *(IS11S) Build' + device_replacement: '$1' + brand_replacement: 'SonyEricsson' + model_replacement: 'Xperia Acro' + - regex: '; *(IS11CA) Build' + device_replacement: '$1' + brand_replacement: 'Casio' + model_replacement: 'GzOne $1' + - regex: '; *(IS11LG) Build' + device_replacement: '$1' + brand_replacement: 'LG' + model_replacement: 'Optimus X' + - regex: '; *(IS11N) Build' + device_replacement: '$1' + brand_replacement: 'Medias' + model_replacement: '$1' + - regex: '; *(IS11PT) Build' + device_replacement: '$1' + brand_replacement: 'Pantech' + model_replacement: 'MIRACH' + - regex: '; *(IS12F) Build' + device_replacement: '$1' + brand_replacement: 'Fujitsu' + model_replacement: 'Arrows ES' + # @ref: https://ja.wikipedia.org/wiki/IS12M + - regex: '; *(IS12M) Build' + device_replacement: '$1' + brand_replacement: 'Motorola' + model_replacement: 'XT909' + - regex: '; *(IS12S) Build' + device_replacement: '$1' + brand_replacement: 'SonyEricsson' + model_replacement: 'Xperia Acro HD' + - regex: '; *(ISW11F) Build' + device_replacement: '$1' + brand_replacement: 'Fujitsu' + model_replacement: 'Arrowz Z' + - regex: '; *(ISW11HT) Build' + device_replacement: '$1' + brand_replacement: 'HTC' + model_replacement: 'EVO' + - regex: '; *(ISW11K) Build' + device_replacement: '$1' + brand_replacement: 'Kyocera' + model_replacement: 'DIGNO' + - regex: '; *(ISW11M) Build' + device_replacement: '$1' + brand_replacement: 'Motorola' + model_replacement: 'Photon' + - regex: '; *(ISW11SC) Build' + device_replacement: '$1' + brand_replacement: 'Samsung' + model_replacement: 'GALAXY S II WiMAX' + - regex: '; *(ISW12HT) Build' + device_replacement: '$1' + brand_replacement: 'HTC' + model_replacement: 'EVO 3D' + - regex: '; *(ISW13HT) Build' + device_replacement: '$1' + brand_replacement: 'HTC' + model_replacement: 'J' + - regex: '; *(ISW?[0-9]{2}[A-Z]{0,2}) Build' + device_replacement: '$1' + brand_replacement: 'KDDI' + model_replacement: '$1' + - regex: '; *(INFOBAR [^;/]+) Build' + device_replacement: '$1' + brand_replacement: 'KDDI' + model_replacement: '$1' + + ######### + # Kingcom + # @ref: http://www.e-kingcom.com + ######### + - regex: '; *(JOYPAD|Joypad)[ _]([^;/]+) Build/' + device_replacement: '$1 $2' + brand_replacement: 'Kingcom' + model_replacement: '$1 $2' + + ######### + # Kobo + # @ref: https://en.wikipedia.org/wiki/Kobo_Inc. + # @ref: http://www.kobo.com/devices#tablets + ######### + - regex: '; *(Vox|VOX|Arc|K080) Build/' + regex_flag: 'i' + device_replacement: '$1' + brand_replacement: 'Kobo' + model_replacement: '$1' + - regex: '\b(Kobo Touch)\b' + device_replacement: '$1' + brand_replacement: 'Kobo' + model_replacement: '$1' + + ######### + # K-Touch + # @ref: ?? + ######### + - regex: '; *(K-Touch)[ _]([^;/]+) Build' + regex_flag: 'i' + device_replacement: '$1 $2' + brand_replacement: 'Ktouch' + model_replacement: '$2' + + ######### + # KT Tech + # @ref: http://www.kttech.co.kr + ######### + - regex: '; *((?:EV|KM)-S\d+[A-Z]?) Build' + regex_flag: 'i' + device_replacement: '$1' + brand_replacement: 'KTtech' + model_replacement: '$1' + + ######### + # Kyocera + # @ref: http://www.android.com/devices/?country=all&m=kyocera + ######### + - regex: '; *(Zio|Hydro|Torque|Event|EVENT|Echo|Milano|Rise|URBANO PROGRESSO|WX04K|WX06K|WX10K|KYL21|101K|C5[12]\d{2}) Build/' + device_replacement: '$1' + brand_replacement: 'Kyocera' + model_replacement: '$1' + + ######### + # Lava + # @ref: http://www.lavamobiles.com/ + ######### + - regex: '; *(?:LAVA[ _])?IRIS[ _\-]?([^/;\)]+) *(?:;|\)|Build)' + regex_flag: 'i' + device_replacement: 'Iris $1' + brand_replacement: 'Lava' + model_replacement: 'Iris $1' + - regex: '; *LAVA[ _]([^;/]+) Build' + device_replacement: '$1' + brand_replacement: 'Lava' + model_replacement: '$1' + + ######### + # Lemon + # @ref: http://www.lemonmobiles.com/products.php?type=1 + ######### + - regex: '; *(?:(Aspire A1)|(?:LEMON|Lemon)[ _]([^;/]+))_? Build' + device_replacement: 'Lemon $1$2' + brand_replacement: 'Lemon' + model_replacement: '$1$2' + + ######### + # Lenco + # @ref: http://www.lenco.com/c/tablets/ + ######### + - regex: '; *(TAB-1012) Build/' + device_replacement: 'Lenco $1' + brand_replacement: 'Lenco' + model_replacement: '$1' + - regex: '; Lenco ([^;/]+) Build/' + device_replacement: 'Lenco $1' + brand_replacement: 'Lenco' + model_replacement: '$1' + + ######### + # Lenovo + # @ref: http://support.lenovo.com/en_GB/downloads/default.page?# + ######### + - regex: '; *(A1_07|A2107A-H|S2005A-H|S1-37AH0) Build' + device_replacement: '$1' + brand_replacement: 'Lenovo' + model_replacement: '$1' + - regex: '; *(Idea[Tp]ab)[ _]([^;/]+);? Build' + device_replacement: 'Lenovo $1 $2' + brand_replacement: 'Lenovo' + model_replacement: '$1 $2' + - regex: '; *(Idea(?:Tab|pad)) ?([^;/]+) Build' + device_replacement: 'Lenovo $1 $2' + brand_replacement: 'Lenovo' + model_replacement: '$1 $2' + - regex: '; *(ThinkPad) ?(Tablet) Build/' + device_replacement: 'Lenovo $1 $2' + brand_replacement: 'Lenovo' + model_replacement: '$1 $2' + - regex: '; *(?:LNV-)?(?:=?[Ll]enovo[ _\-]?|LENOVO[ _])+(.+?)(?:Build|[;/\)])' + device_replacement: 'Lenovo $1' + brand_replacement: 'Lenovo' + model_replacement: '$1' + - regex: '[;,] (?:Vodafone )?(SmartTab) ?(II) ?(\d+) Build/' + device_replacement: 'Lenovo $1 $2 $3' + brand_replacement: 'Lenovo' + model_replacement: '$1 $2 $3' + - regex: '; *(?:Ideapad )?K1 Build/' + device_replacement: 'Lenovo Ideapad K1' + brand_replacement: 'Lenovo' + model_replacement: 'Ideapad K1' + - regex: '; *(3GC101|3GW10[01]|A390) Build/' + device_replacement: '$1' + brand_replacement: 'Lenovo' + model_replacement: '$1' + - regex: '\b(?:Lenovo|LENOVO)+[ _\-]?([^,;:/ ]+)' + device_replacement: 'Lenovo $1' + brand_replacement: 'Lenovo' + model_replacement: '$1' + + ######### + # Lexibook + # @ref: http://www.lexibook.com/fr + ######### + - regex: '; *(MFC\d+)[A-Z]{2}([^;,/]*),? Build' + device_replacement: '$1$2' + brand_replacement: 'Lexibook' + model_replacement: '$1$2' + + ######### + # LG + # @ref: http://www.lg.com/uk/mobile + ######### + - regex: '; *(E[34][0-9]{2}|LS[6-8][0-9]{2}|VS[6-9][0-9]+[^;/]+|Nexus [45]|GT540f?|Optimus (?:2X|G|4X HD)|OptimusX4HD) *(?:Build|;)' + device_replacement: '$1' + brand_replacement: 'LG' + model_replacement: '$1' + - regex: '[;:] *(L-\d+[A-Z]|LGL\d+[A-Z]?)(?:/V\d+)? *(?:Build|[;\)])' + device_replacement: '$1' + brand_replacement: 'LG' + model_replacement: '$1' + - regex: '; *(LG-)([A-Z]{1,2}\d{2,}[^,;/\)\(]*?)(?:Build| V\d+|[,;/\)\(]|$)' + device_replacement: '$1$2' + brand_replacement: 'LG' + model_replacement: '$2' + - regex: '; *(LG[ \-]|LG)([^;/]+)[;/]? Build' + device_replacement: '$1$2' + brand_replacement: 'LG' + model_replacement: '$2' + - regex: '^(LG)-([^;/]+)/ Mozilla/.*; Android' + device_replacement: '$1 $2' + brand_replacement: 'LG' + model_replacement: '$2' + + ######### + # Malata + # @ref: http://www.malata.com/en/products.aspx?classid=680 + ######### + - regex: '; *((?:SMB|smb)[^;/]+) Build/' + device_replacement: '$1' + brand_replacement: 'Malata' + model_replacement: '$1' + - regex: '; *(?:Malata|MALATA) ([^;/]+) Build/' + device_replacement: '$1' + brand_replacement: 'Malata' + model_replacement: '$1' + + ######### + # Manta + # @ref: http://www.manta.com.pl/en + ######### + - regex: '; *(MS[45][0-9]{3}|MID0[568][NS]?|MID[1-9]|MID[78]0[1-9]|MID970[1-9]|MID100[1-9]) Build/' + device_replacement: '$1' + brand_replacement: 'Manta' + model_replacement: '$1' + + ######### + # Match + # @ref: http://www.match.net.cn/products.asp + ######### + - regex: '; *(M1052|M806|M9000|M9100|M9701|MID100|MID120|MID125|MID130|MID135|MID140|MID701|MID710|MID713|MID727|MID728|MID731|MID732|MID733|MID735|MID736|MID737|MID760|MID800|MID810|MID820|MID830|MID833|MID835|MID860|MID900|MID930|MID933|MID960|MID980) Build/' + device_replacement: '$1' + brand_replacement: 'Match' + model_replacement: '$1' + + ######### + # Maxx + # @ref: http://www.maxxmobile.in/ + # @models: Maxx MSD7-Play, Maxx MX245+ Trance, Maxx AX8 Race, Maxx MSD7 3G- AX50, Maxx Genx Droid 7 - AX40, Maxx AX5 Duo, + # Maxx AX3 Duo, Maxx AX3, Maxx AX8 Note II (Note 2), Maxx AX8 Note I, Maxx AX8, Maxx AX5 Plus, Maxx MSD7 Smarty, + # Maxx AX9Z Race, + # Maxx MT150, Maxx MQ601, Maxx M2020, Maxx Sleek MX463neo, Maxx MX525, Maxx MX192-Tune, Maxx Genx Droid 7 AX353, + # @note: Need more User-Agents!!! + ######### + - regex: '; *(GenxDroid7|MSD7.*|AX\d.*|Tab 701|Tab 722) Build/' + device_replacement: 'Maxx $1' + brand_replacement: 'Maxx' + model_replacement: '$1' + + ######### + # Mediacom + # @ref: http://www.mediacomeurope.it/ + ######### + - regex: '; *(M-PP[^;/]+|PhonePad ?\d{2,}[^;/]+) Build' + device_replacement: 'Mediacom $1' + brand_replacement: 'Mediacom' + model_replacement: '$1' + - regex: '; *(M-MP[^;/]+|SmartPad ?\d{2,}[^;/]+) Build' + device_replacement: 'Mediacom $1' + brand_replacement: 'Mediacom' + model_replacement: '$1' + + ######### + # Medion + # @ref: http://www.medion.com/en/ + ######### + - regex: '; *(?:MD_)?LIFETAB[ _]([^;/]+) Build' + regex_flag: 'i' + device_replacement: 'Medion Lifetab $1' + brand_replacement: 'Medion' + model_replacement: 'Lifetab $1' + - regex: '; *MEDION ([^;/]+) Build' + device_replacement: 'Medion $1' + brand_replacement: 'Medion' + model_replacement: '$1' + + ######### + # Meizu + # @ref: http://www.meizu.com + ######### + - regex: '; *(M030|M031|M035|M040|M065|m9) Build' + device_replacement: 'Meizu $1' + brand_replacement: 'Meizu' + model_replacement: '$1' + - regex: '; *(?:meizu_|MEIZU )(.+?) *(?:Build|[;\)])' + device_replacement: 'Meizu $1' + brand_replacement: 'Meizu' + model_replacement: '$1' + + ######### + # Micromax + # @ref: http://www.micromaxinfo.com + ######### + - regex: '; *(?:Micromax[ _](A111|A240)|(A111|A240)) Build' + regex_flag: 'i' + device_replacement: 'Micromax $1$2' + brand_replacement: 'Micromax' + model_replacement: '$1$2' + - regex: '; *Micromax[ _](A\d{2,3}[^;/]*) Build' + regex_flag: 'i' + device_replacement: 'Micromax $1' + brand_replacement: 'Micromax' + model_replacement: '$1' + # be carefull here with Acer e.g. A500 + - regex: '; *(A\d{2}|A[12]\d{2}|A90S|A110Q) Build' + regex_flag: 'i' + device_replacement: 'Micromax $1' + brand_replacement: 'Micromax' + model_replacement: '$1' + - regex: '; *Micromax[ _](P\d{3}[^;/]*) Build' + regex_flag: 'i' + device_replacement: 'Micromax $1' + brand_replacement: 'Micromax' + model_replacement: '$1' + - regex: '; *(P\d{3}|P\d{3}\(Funbook\)) Build' + regex_flag: 'i' + device_replacement: 'Micromax $1' + brand_replacement: 'Micromax' + model_replacement: '$1' + + ######### + # Mito + # @ref: http://new.mitomobile.com/ + ######### + - regex: '; *(MITO)[ _\-]?([^;/]+) Build' + regex_flag: 'i' + device_replacement: '$1 $2' + brand_replacement: 'Mito' + model_replacement: '$2' + + ######### + # Mobistel + # @ref: http://www.mobistel.com/ + ######### + - regex: '; *(Cynus)[ _](F5|T\d|.+?) *(?:Build|[;/\)])' + regex_flag: 'i' + device_replacement: '$1 $2' + brand_replacement: 'Mobistel' + model_replacement: '$1 $2' + + ######### + # Modecom + # @ref: http://www.modecom.eu/tablets/portal/ + ######### + - regex: '; *(MODECOM )?(FreeTab) ?([^;/]+) Build' + regex_flag: 'i' + device_replacement: '$1$2 $3' + brand_replacement: 'Modecom' + model_replacement: '$2 $3' + - regex: '; *(MODECOM )([^;/]+) Build' + regex_flag: 'i' + device_replacement: '$1 $2' + brand_replacement: 'Modecom' + model_replacement: '$2' + + ######### + # Motorola + # @ref: http://www.motorola.com/us/shop-all-mobile-phones/ + ######### + - regex: '; *(MZ\d{3}\+?|MZ\d{3} 4G|Xoom|XOOM[^;/]*) Build' + device_replacement: 'Motorola $1' + brand_replacement: 'Motorola' + model_replacement: '$1' + - regex: '; *(Milestone )(XT[^;/]*) Build' + device_replacement: 'Motorola $1$2' + brand_replacement: 'Motorola' + model_replacement: '$2' + - regex: '; *(Motoroi ?x|Droid X|DROIDX) Build' + regex_flag: 'i' + device_replacement: 'Motorola $1' + brand_replacement: 'Motorola' + model_replacement: 'DROID X' + - regex: '; *(Droid[^;/]*|DROID[^;/]*|Milestone[^;/]*|Photon|Triumph|Devour|Titanium) Build' + device_replacement: 'Motorola $1' + brand_replacement: 'Motorola' + model_replacement: '$1' + - regex: '; *(A555|A85[34][^;/]*|A95[356]|ME[58]\d{2}\+?|ME600|ME632|ME722|MB\d{3}\+?|MT680|MT710|MT870|MT887|MT917|WX435|WX453|WX44[25]|XT\d{3,4}[A-Z\+]*|CL[iI]Q|CL[iI]Q XT) Build' + device_replacement: '$1' + brand_replacement: 'Motorola' + model_replacement: '$1' + - regex: '; *(Motorola MOT-|Motorola[ _\-]|MOT\-?)([^;/]+) Build' + device_replacement: '$1$2' + brand_replacement: 'Motorola' + model_replacement: '$2' + - regex: '; *(Moto[_ ]?|MOT\-)([^;/]+) Build' + device_replacement: '$1$2' + brand_replacement: 'Motorola' + model_replacement: '$2' + + ######### + # MpMan + # @ref: http://www.mpmaneurope.com + ######### + - regex: '; *((?:MP[DQ]C|MPG\d{1,4}|MP\d{3,4}|MID(?:(?:10[234]|114|43|7[247]|8[24]|7)C|8[01]1))[^;/]*) Build' + device_replacement: '$1' + brand_replacement: 'Mpman' + model_replacement: '$1' + + ######### + # MSI + # @ref: http://www.msi.com/product/windpad/ + ######### + - regex: '; *(?:MSI[ _])?(Primo\d+|Enjoy[ _\-][^;/]+) Build' + regex_flag: 'i' + device_replacement: '$1' + brand_replacement: 'Msi' + model_replacement: '$1' + + ######### + # Multilaser + # http://www.multilaser.com.br/listagem_produtos.php?cat=5 + ######### + - regex: '; *Multilaser[ _]([^;/]+) Build' + device_replacement: '$1' + brand_replacement: 'Multilaser' + model_replacement: '$1' + + ######### + # MyPhone + # @ref: http://myphone.com.ph/ + ######### + - regex: '; *(My)[_]?(Pad)[ _]([^;/]+) Build' + device_replacement: '$1$2 $3' + brand_replacement: 'MyPhone' + model_replacement: '$1$2 $3' + - regex: '; *(My)\|?(Phone)[ _]([^;/]+) Build' + device_replacement: '$1$2 $3' + brand_replacement: 'MyPhone' + model_replacement: '$3' + - regex: '; *(A\d+)[ _](Duo)? Build' + regex_flag: 'i' + device_replacement: '$1 $2' + brand_replacement: 'MyPhone' + model_replacement: '$1 $2' + + ######### + # Mytab + # @ref: http://www.mytab.eu/en/category/mytab-products/ + ######### + - regex: '; *(myTab[^;/]*) Build' + device_replacement: '$1' + brand_replacement: 'Mytab' + model_replacement: '$1' + + ######### + # Nabi + # @ref: https://www.nabitablet.com + ######### + - regex: '; *(NABI2?-)([^;/]+) Build/' + device_replacement: '$1$2' + brand_replacement: 'Nabi' + model_replacement: '$2' + + ######### + # Nec Medias + # @ref: http://www.n-keitai.com/ + ######### + - regex: '; *(N-\d+[CDE]) Build/' + device_replacement: '$1' + brand_replacement: 'Nec' + model_replacement: '$1' + - regex: '; ?(NEC-)(.*) Build/' + device_replacement: '$1$2' + brand_replacement: 'Nec' + model_replacement: '$2' + - regex: '; *(LT-NA7) Build/' + device_replacement: '$1' + brand_replacement: 'Nec' + model_replacement: 'Lifetouch Note' + + ######### + # Nextbook + # @ref: http://nextbookusa.com + ######### + - regex: '; *(NXM\d+[A-z0-9_]*|Next\d[A-z0-9_ \-]*|NEXT\d[A-z0-9_ \-]*|Nextbook [A-z0-9_ ]*|DATAM803HC|M805)(?: Build|[\);])' + device_replacement: '$1' + brand_replacement: 'Nextbook' + model_replacement: '$1' + + ######### + # Nokia + # @ref: http://www.nokia.com + ######### + - regex: '; *(Nokia)([ _\-]*)([^;/]*) Build' + regex_flag: 'i' + device_replacement: '$1$2$3' + brand_replacement: 'Nokia' + model_replacement: '$3' + + ######### + # Nook + # @ref: + # TODO nook browser/1.0 + ######### + - regex: '; *(Nook ?|Barnes & Noble Nook |BN )([^;/]+) Build' + device_replacement: '$1$2' + brand_replacement: 'Nook' + model_replacement: '$2' + - regex: '; *(NOOK )?(BNRV200|BNRV200A|BNTV250|BNTV250A|BNTV400|BNTV600|LogicPD Zoom2) Build' + device_replacement: '$1$2' + brand_replacement: 'Nook' + model_replacement: '$2' + - regex: '; Build/(Nook)' + device_replacement: '$1' + brand_replacement: 'Nook' + model_replacement: 'Tablet' + + ######### + # Olivetti + # @ref: http://www.olivetti.de/EN/Page/t02/view_html?idp=348 + ######### + - regex: '; *(OP110|OliPad[^;/]+) Build' + device_replacement: 'Olivetti $1' + brand_replacement: 'Olivetti' + model_replacement: '$1' + + ######### + # Omega + # @ref: http://omega-technology.eu/en/produkty/346/tablets + # @note: MID tablets might get matched by CobyKyros first + # @models: (T107|MID(?:700[2-5]|7031|7108|7132|750[02]|8001|8500|9001|971[12]) + ######### + - regex: '; *OMEGA[ _\-](MID[^;/]+) Build' + device_replacement: 'Omega $1' + brand_replacement: 'Omega' + model_replacement: '$1' + - regex: '^(MID7500|MID\d+) Mozilla/5\.0 \(iPad;' + device_replacement: 'Omega $1' + brand_replacement: 'Omega' + model_replacement: '$1' + + ######### + # OpenPeak + # @ref: https://support.google.com/googleplay/answer/1727131?hl=en + ######### + - regex: '; *((?:CIUS|cius)[^;/]*) Build' + device_replacement: 'Openpeak $1' + brand_replacement: 'Openpeak' + model_replacement: '$1' + + ######### + # Oppo + # @ref: http://en.oppo.com/products/ + ######### + - regex: '; *(Find ?(?:5|7a)|R8[012]\d{1,2}|T703\d{0,1}|U70\d{1,2}T?|X90\d{1,2}) Build' + device_replacement: 'Oppo $1' + brand_replacement: 'Oppo' + model_replacement: '$1' + - regex: '; *OPPO ?([^;/]+) Build/' + device_replacement: 'Oppo $1' + brand_replacement: 'Oppo' + model_replacement: '$1' + + ######### + # Odys + # @ref: http://odys.de + ######### + - regex: '; *(?:Odys\-|ODYS\-|ODYS )([^;/]+) Build' + device_replacement: 'Odys $1' + brand_replacement: 'Odys' + model_replacement: '$1' + - regex: '; *(SELECT) ?(7) Build' + device_replacement: 'Odys $1 $2' + brand_replacement: 'Odys' + model_replacement: '$1 $2' + - regex: '; *(PEDI)_(PLUS)_(W) Build' + device_replacement: 'Odys $1 $2 $3' + brand_replacement: 'Odys' + model_replacement: '$1 $2 $3' + # Weltbild - Tablet PC 4 = Cat Phoenix = Odys Tablet PC 4? + - regex: '; *(AEON|BRAVIO|FUSION|FUSION2IN1|Genio|EOS10|IEOS[^;/]*|IRON|Loox|LOOX|LOOX Plus|Motion|NOON|NOON_PRO|NEXT|OPOS|PEDI[^;/]*|PRIME[^;/]*|STUDYTAB|TABLO|Tablet-PC-4|UNO_X8|XELIO[^;/]*|Xelio ?\d+ ?[Pp]ro|XENO10|XPRESS PRO) Build' + device_replacement: 'Odys $1' + brand_replacement: 'Odys' + model_replacement: '$1' + + ######### + # Orion + # @ref: http://www.orion.ua/en/products/computer-products/tablet-pcs.html + ######### + - regex: '; *(TP-\d+) Build/' + device_replacement: 'Orion $1' + brand_replacement: 'Orion' + model_replacement: '$1' + + ######### + # PackardBell + # @ref: http://www.packardbell.com/pb/en/AE/content/productgroup/tablets + ######### + - regex: '; *(G100W?) Build/' + device_replacement: 'PackardBell $1' + brand_replacement: 'PackardBell' + model_replacement: '$1' + + ######### + # Panasonic + # @ref: http://panasonic.jp/mobile/ + # @models: T11, T21, T31, P11, P51, Eluga Power, Eluga DL1 + # @models: (tab) Toughpad FZ-A1, Toughpad JT-B1 + ######### + - regex: '; *(Panasonic)[_ ]([^;/]+) Build' + device_replacement: '$1 $2' + brand_replacement: '$1' + model_replacement: '$2' + # Toughpad + - regex: '; *(FZ-A1B|JT-B1) Build' + device_replacement: 'Panasonic $1' + brand_replacement: 'Panasonic' + model_replacement: '$1' + # Eluga Power + - regex: '; *(dL1|DL1) Build' + device_replacement: 'Panasonic $1' + brand_replacement: 'Panasonic' + model_replacement: '$1' + + ######### + # Pantech + # @href: http://www.pantech.co.kr/en/prod/prodList.do?gbrand=PANTECH + # @href: http://www.pantech.co.kr/en/prod/prodList.do?gbrand=VEGA + # @models: ADR8995, ADR910L, ADR930VW, C790, CDM8992, CDM8999, IS06, IS11PT, P2000, P2020, P2030, P4100, P5000, P6010, P6020, P6030, P7000, P7040, P8000, P8010, P9020, P9050, P9060, P9070, P9090, PT001, PT002, PT003, TXT8040, TXT8045, VEGA PTL21 + ######### + - regex: '; *(SKY[ _])?(IM\-[AT]\d{3}[^;/]+).* Build/' + device_replacement: 'Pantech $1$2' + brand_replacement: 'Pantech' + model_replacement: '$1$2' + - regex: '; *((?:ADR8995|ADR910L|ADR930L|ADR930VW|PTL21|P8000)(?: 4G)?) Build/' + device_replacement: '$1' + brand_replacement: 'Pantech' + model_replacement: '$1' + - regex: '; *Pantech([^;/]+).* Build/' + device_replacement: 'Pantech $1' + brand_replacement: 'Pantech' + model_replacement: '$1' + + ######### + # Papayre + # @ref: http://grammata.es/ + ######### + - regex: '; *(papyre)[ _\-]([^;/]+) Build/' + regex_flag: 'i' + device_replacement: '$1 $2' + brand_replacement: 'Papyre' + model_replacement: '$2' + + ######### + # Pearl + # @ref: http://www.pearl.de/c-1540.shtml + ######### + - regex: '; *(?:Touchlet )?(X10\.[^;/]+) Build/' + device_replacement: 'Pearl $1' + brand_replacement: 'Pearl' + model_replacement: '$1' + + ######### + # Phicomm + # @ref: http://www.phicomm.com.cn/ + ######### + - regex: '; PHICOMM (i800) Build/' + device_replacement: 'Phicomm $1' + brand_replacement: 'Phicomm' + model_replacement: '$1' + - regex: '; PHICOMM ([^;/]+) Build/' + device_replacement: 'Phicomm $1' + brand_replacement: 'Phicomm' + model_replacement: '$1' + - regex: '; *(FWS\d{3}[^;/]+) Build/' + device_replacement: 'Phicomm $1' + brand_replacement: 'Phicomm' + model_replacement: '$1' + + ######### + # Philips + # @ref: http://www.support.philips.com/support/catalog/products.jsp?_dyncharset=UTF-8&country=&categoryid=MOBILE_PHONES_SMART_SU_CN_CARE&userLanguage=en&navCount=2&groupId=PC_PRODUCTS_AND_PHONES_GR_CN_CARE&catalogType=&navAction=push&userCountry=cn&title=Smartphones&cateId=MOBILE_PHONES_CA_CN_CARE + # @TODO: Philips Tablets User-Agents missing! + # @ref: http://www.support.philips.com/support/catalog/products.jsp?_dyncharset=UTF-8&country=&categoryid=ENTERTAINMENT_TABLETS_SU_CN_CARE&userLanguage=en&navCount=0&groupId=&catalogType=&navAction=push&userCountry=cn&title=Entertainment+Tablets&cateId=TABLETS_CA_CN_CARE + ######### + # @note: this a best guess according to available philips models. Need more User-Agents + - regex: '; *(D633|D822|D833|T539|T939|V726|W335|W336|W337|W3568|W536|W5510|W626|W632|W6350|W6360|W6500|W732|W736|W737|W7376|W820|W832|W8355|W8500|W8510|W930) Build' + device_replacement: '$1' + brand_replacement: 'Philips' + model_replacement: '$1' + - regex: '; *(?:Philips|PHILIPS)[ _]([^;/]+) Build' + device_replacement: 'Philips $1' + brand_replacement: 'Philips' + model_replacement: '$1' + + ######### + # Pipo + # @ref: http://www.pipo.cn/En/ + ######### + - regex: 'Android 4\..*; *(M[12356789]|U[12368]|S[123])\ ?(pro)? Build' + device_replacement: 'Pipo $1$2' + brand_replacement: 'Pipo' + model_replacement: '$1$2' + + ######### + # Ployer + # @ref: http://en.ployer.cn/ + ######### + - regex: '; *(MOMO[^;/]+) Build' + device_replacement: '$1' + brand_replacement: 'Ployer' + model_replacement: '$1' + + ######### + # Polaroid/ Acho + # @ref: http://polaroidstore.com/store/start.asp?category_id=382&category_id2=0&order=title&filter1=&filter2=&filter3=&view=all + ######### + - regex: '; *(?:Polaroid[ _])?((?:MIDC\d{3,}|PMID\d{2,}|PTAB\d{3,})[^;/]*)(\/[^;/]*)? Build/' + device_replacement: '$1' + brand_replacement: 'Polaroid' + model_replacement: '$1' + - regex: '; *(?:Polaroid )(Tablet) Build/' + device_replacement: '$1' + brand_replacement: 'Polaroid' + model_replacement: '$1' + + ######### + # Pomp + # @ref: http://pompmobileshop.com/ + ######### + #~ TODO + - regex: '; *(POMP)[ _\-](.+?) *(?:Build|[;/\)])' + device_replacement: '$1 $2' + brand_replacement: 'Pomp' + model_replacement: '$2' + + ######### + # Positivo + # @ref: http://www.positivoinformatica.com.br/www/pessoal/tablet-ypy/ + ######### + - regex: '; *(TB07STA|TB10STA|TB07FTA|TB10FTA) Build/' + device_replacement: '$1' + brand_replacement: 'Positivo' + model_replacement: '$1' + - regex: '; *(?:Positivo )?((?:YPY|Ypy)[^;/]+) Build/' + device_replacement: '$1' + brand_replacement: 'Positivo' + model_replacement: '$1' + + ######### + # POV + # @ref: http://www.pointofview-online.com/default2.php + # @TODO: Smartphone Models MOB-3515, MOB-5045-B missing + ######### + - regex: '; *(MOB-[^;/]+) Build/' + device_replacement: '$1' + brand_replacement: 'POV' + model_replacement: '$1' + - regex: '; *POV[ _\-]([^;/]+) Build/' + device_replacement: 'POV $1' + brand_replacement: 'POV' + model_replacement: '$1' + - regex: '; *((?:TAB-PLAYTAB|TAB-PROTAB|PROTAB|PlayTabPro|Mobii[ _\-]|TAB-P)[^;/]*) Build/' + device_replacement: 'POV $1' + brand_replacement: 'POV' + model_replacement: '$1' + + ######### + # Prestigio + # @ref: http://www.prestigio.com/catalogue/MultiPhones + # @ref: http://www.prestigio.com/catalogue/MultiPads + ######### + - regex: '; *(?:Prestigio )?((?:PAP|PMP)\d[^;/]+) Build/' + device_replacement: 'Prestigio $1' + brand_replacement: 'Prestigio' + model_replacement: '$1' + + ######### + # Proscan + # @ref: http://www.proscanvideo.com/products-search.asp?itemClass=TABLET&itemnmbr= + ######### + - regex: '; *(PLT[0-9]{4}.*) Build/' + device_replacement: '$1' + brand_replacement: 'Proscan' + model_replacement: '$1' + + ######### + # QMobile + # @ref: http://www.qmobile.com.pk/ + ######### + - regex: '; *(A2|A5|A8|A900)_?(Classic)? Build' + device_replacement: '$1 $2' + brand_replacement: 'Qmobile' + model_replacement: '$1 $2' + - regex: '; *(Q[Mm]obile)_([^_]+)_([^_]+) Build' + device_replacement: 'Qmobile $2 $3' + brand_replacement: 'Qmobile' + model_replacement: '$2 $3' + - regex: '; *(Q\-?[Mm]obile)[_ ](A[^;/]+) Build' + device_replacement: 'Qmobile $2' + brand_replacement: 'Qmobile' + model_replacement: '$2' + + ######### + # Qmobilevn + # @ref: http://qmobile.vn/san-pham.html + ######### + - regex: '; *(Q\-Smart)[ _]([^;/]+) Build/' + device_replacement: '$1 $2' + brand_replacement: 'Qmobilevn' + model_replacement: '$2' + - regex: '; *(Q\-?[Mm]obile)[ _\-](S[^;/]+) Build/' + device_replacement: '$1 $2' + brand_replacement: 'Qmobilevn' + model_replacement: '$2' + + ######### + # Quanta + # @ref: ? + ######### + - regex: '; *(TA1013) Build' + device_replacement: '$1' + brand_replacement: 'Quanta' + model_replacement: '$1' + + ######### + # Rockchip + # @ref: http://www.rock-chips.com/a/cn/product/index.html + # @note: manufacturer sells chipsets - I assume that these UAs are dev-boards + ######### + - regex: '; *(RK\d+),? Build/' + device_replacement: '$1' + brand_replacement: 'Rockchip' + model_replacement: '$1' + - regex: ' Build/(RK\d+)' + device_replacement: '$1' + brand_replacement: 'Rockchip' + model_replacement: '$1' + + ######### + # Samsung Android Devices + # @ref: http://www.samsung.com/us/mobile/cell-phones/all-products + ######### + - regex: '; *(SAMSUNG |Samsung )?((?:Galaxy (?:Note II|S\d)|GT-I9082|GT-I9205|GT-N7\d{3}|SM-N9005)[^;/]*)\/?[^;/]* Build/' + device_replacement: 'Samsung $1$2' + brand_replacement: 'Samsung' + model_replacement: '$2' + - regex: '; *(Google )?(Nexus [Ss](?: 4G)?) Build/' + device_replacement: 'Samsung $1$2' + brand_replacement: 'Samsung' + model_replacement: '$2' + - regex: '; *(SAMSUNG |Samsung )([^\/]*)\/[^ ]* Build/' + device_replacement: 'Samsung $2' + brand_replacement: 'Samsung' + model_replacement: '$2' + - regex: '; *(Galaxy(?: Ace| Nexus| S ?II+|Nexus S| with MCR 1.2| Mini Plus 4G)?) Build/' + device_replacement: 'Samsung $1' + brand_replacement: 'Samsung' + model_replacement: '$1' + - regex: '; *(SAMSUNG[ _\-] *)+([^;/]+) Build' + device_replacement: 'Samsung $2' + brand_replacement: 'Samsung' + model_replacement: '$2' + - regex: '; *(SAMSUNG-)?(GT\-[BINPS]\d{4}[^\/]*)(\/[^ ]*) Build' + device_replacement: 'Samsung $1$2$3' + brand_replacement: 'Samsung' + model_replacement: '$2' + - regex: '(?:; *|^)((?:GT\-[BIiNPS]\d{4}|I9\d{2}0[A-Za-z\+]?\b)[^;/\)]*?)(?:Build|Linux|MIUI|[;/\)])' + device_replacement: 'Samsung $1' + brand_replacement: 'Samsung' + model_replacement: '$1' + - regex: '; (SAMSUNG-)([A-Za-z0-9\-]+).* Build/' + device_replacement: 'Samsung $1$2' + brand_replacement: 'Samsung' + model_replacement: '$2' + - regex: '; *((?:SCH|SGH|SHV|SHW|SPH|SC|SM)\-[A-Za-z0-9 ]+)(/?[^ ]*)? Build' + device_replacement: 'Samsung $1' + brand_replacement: 'Samsung' + model_replacement: '$1' + - regex: ' ((?:SCH)\-[A-Za-z0-9 ]+)(/?[^ ]*)? Build' + device_replacement: 'Samsung $1' + brand_replacement: 'Samsung' + model_replacement: '$1' + - regex: '; *(Behold ?(?:2|II)|YP\-G[^;/]+|EK-GC100|SCL21|I9300) Build' + device_replacement: 'Samsung $1' + brand_replacement: 'Samsung' + model_replacement: '$1' + + ######### + # Sharp + # @ref: http://www.sharp-phone.com/en/index.html + # @ref: http://www.android.com/devices/?country=all&m=sharp + ######### + - regex: '; *(SH\-?\d\d[^;/]+|SBM\d[^;/]+) Build' + device_replacement: '$1' + brand_replacement: 'Sharp' + model_replacement: '$1' + - regex: '; *(SHARP[ -])([^;/]+) Build' + device_replacement: '$1$2' + brand_replacement: 'Sharp' + model_replacement: '$2' + + ######### + # Simvalley + # @ref: http://www.simvalley-mobile.de/ + ######### + - regex: '; *(SPX[_\-]\d[^;/]*) Build/' + device_replacement: '$1' + brand_replacement: 'Simvalley' + model_replacement: '$1' + - regex: '; *(SX7\-PEARL\.GmbH) Build/' + device_replacement: '$1' + brand_replacement: 'Simvalley' + model_replacement: '$1' + - regex: '; *(SP[T]?\-\d{2}[^;/]*) Build/' + device_replacement: '$1' + brand_replacement: 'Simvalley' + model_replacement: '$1' + + ######### + # SK Telesys + # @ref: http://www.sk-w.com/phone/phone_list.jsp + # @ref: http://www.android.com/devices/?country=all&m=sk-telesys + ######### + - regex: '; *(SK\-.*) Build/' + device_replacement: '$1' + brand_replacement: 'SKtelesys' + model_replacement: '$1' + + ######### + # Skytex + # @ref: http://skytex.com/android + ######### + - regex: '; *(?:SKYTEX|SX)-([^;/]+) Build' + device_replacement: '$1' + brand_replacement: 'Skytex' + model_replacement: '$1' + - regex: '; *(IMAGINE [^;/]+) Build' + device_replacement: '$1' + brand_replacement: 'Skytex' + model_replacement: '$1' + + ######### + # SmartQ + # @ref: http://en.smartdevices.com.cn/Products/ + # @models: Z8, X7, U7H, U7, T30, T20, Ten3, V5-II, T7-3G, SmartQ5, K7, S7, Q8, T19, Ten2, Ten, R10, T7, R7, V5, V7, SmartQ7 + ######### + - regex: '; *(SmartQ) ?([^;/]+) Build/' + device_replacement: '$1 $2' + brand_replacement: '$1' + model_replacement: '$2' + + ######### + # Smartbitt + # @ref: http://www.smartbitt.com/ + # @missing: SBT Useragents + ######### + - regex: '; *(WF7C|WF10C|SBT[^;/]+) Build' + device_replacement: '$1' + brand_replacement: 'Smartbitt' + model_replacement: '$1' + + ######### + # Softbank (Operator Branded Devices) + # @ref: http://www.ipentec.com/document/document.aspx?page=android-useragent + ######### + - regex: '; *(SBM(?:003SH|005SH|006SH|007SH|102SH)) Build' + device_replacement: '$1' + brand_replacement: 'Sharp' + model_replacement: '$1' + - regex: '; *(003P|101P|101P11C|102P) Build' + device_replacement: '$1' + brand_replacement: 'Panasonic' + model_replacement: '$1' + - regex: '; *(00\dZ) Build/' + device_replacement: '$1' + brand_replacement: 'ZTE' + model_replacement: '$1' + - regex: '; HTC(X06HT) Build' + device_replacement: '$1' + brand_replacement: 'HTC' + model_replacement: '$1' + - regex: '; *(001HT|X06HT) Build' + device_replacement: '$1' + brand_replacement: 'HTC' + model_replacement: '$1' + - regex: '; *(201M) Build' + device_replacement: '$1' + brand_replacement: 'Motorola' + model_replacement: 'XT902' + + ######### + # Trekstor + # @ref: http://www.trekstor.co.uk/surftabs-en.html + # @note: Must come before SonyEricsson + ######### + - regex: '; *(ST\d{4}.*)Build/ST' + device_replacement: 'Trekstor $1' + brand_replacement: 'Trekstor' + model_replacement: '$1' + - regex: '; *(ST\d{4}.*) Build/' + device_replacement: 'Trekstor $1' + brand_replacement: 'Trekstor' + model_replacement: '$1' + + ######### + # SonyEricsson + # @note: Must come before nokia since they also use symbian + # @ref: http://www.android.com/devices/?country=all&m=sony-ericssons + # @TODO: type! + ######### + # android matchers + - regex: '; *(Sony ?Ericsson ?)([^;/]+) Build' + device_replacement: '$1$2' + brand_replacement: 'SonyEricsson' + model_replacement: '$2' + - regex: '; *((?:SK|ST|E|X|LT|MK|MT|WT)\d{2}[a-z0-9]*(?:-o)?|R800i|U20i) Build' + device_replacement: '$1' + brand_replacement: 'SonyEricsson' + model_replacement: '$1' + # TODO X\d+ is wrong + - regex: '; *(Xperia (?:A8|Arc|Acro|Active|Live with Walkman|Mini|Neo|Play|Pro|Ray|X\d+)[^;/]*) Build' + regex_flag: 'i' + device_replacement: '$1' + brand_replacement: 'SonyEricsson' + model_replacement: '$1' + + ######### + # Sony + # @ref: http://www.sonymobile.co.jp/index.html + # @ref: http://www.sonymobile.com/global-en/products/phones/ + # @ref: http://www.sony.jp/tablet/ + ######### + - regex: '; Sony (Tablet[^;/]+) Build' + device_replacement: 'Sony $1' + brand_replacement: 'Sony' + model_replacement: '$1' + - regex: '; Sony ([^;/]+) Build' + device_replacement: 'Sony $1' + brand_replacement: 'Sony' + model_replacement: '$1' + - regex: '; *(Sony)([A-Za-z0-9\-]+) Build' + device_replacement: '$1 $2' + brand_replacement: '$1' + model_replacement: '$2' + - regex: '; *(Xperia [^;/]+) Build' + device_replacement: '$1' + brand_replacement: 'Sony' + model_replacement: '$1' + - regex: '; *(C(?:1[0-9]|2[0-9]|53|55|6[0-9])[0-9]{2}|D[25]\d{3}|D6[56]\d{2}) Build' + device_replacement: '$1' + brand_replacement: 'Sony' + model_replacement: '$1' + - regex: '; *(SGP\d{3}|SGPT\d{2}) Build' + device_replacement: '$1' + brand_replacement: 'Sony' + model_replacement: '$1' + - regex: '; *(NW-Z1000Series) Build' + device_replacement: '$1' + brand_replacement: 'Sony' + model_replacement: '$1' + + ########## + # Sony PlayStation + # @ref: http://playstation.com + # The Vita spoofs the Kindle + ########## + - regex: 'PLAYSTATION 3' + device_replacement: 'PlayStation 3' + brand_replacement: 'Sony' + model_replacement: 'PlayStation 3' + - regex: '(PlayStation (?:Portable|Vita|\d+))' + device_replacement: '$1' + brand_replacement: 'Sony' + model_replacement: '$1' + + ######### + # Spice + # @ref: http://www.spicemobilephones.co.in/ + ######### + - regex: '; *((?:CSL_Spice|Spice|SPICE|CSL)[ _\-]?)?([Mm][Ii])([ _\-])?(\d{3}[^;/]*) Build/' + device_replacement: '$1$2$3$4' + brand_replacement: 'Spice' + model_replacement: 'Mi$4' + + ######### + # Sprint (Operator Branded Devices) + # @ref: + ######### + - regex: '; *(Sprint )(.+?) *(?:Build|[;/])' + device_replacement: '$1$2' + brand_replacement: 'Sprint' + model_replacement: '$2' + - regex: '\b(Sprint)[: ]([^;,/ ]+)' + device_replacement: '$1$2' + brand_replacement: 'Sprint' + model_replacement: '$2' + + ######### + # Tagi + # @ref: ?? + ######### + - regex: '; *(TAGI[ ]?)(MID) ?([^;/]+) Build/' + device_replacement: '$1$2$3' + brand_replacement: 'Tagi' + model_replacement: '$2$3' + + ######### + # Tecmobile + # @ref: http://www.tecmobile.com/ + ######### + - regex: '; *(Oyster500|Opal 800) Build' + device_replacement: 'Tecmobile $1' + brand_replacement: 'Tecmobile' + model_replacement: '$1' + + ######### + # Tecno + # @ref: www.tecno-mobile.com/‎ + ######### + - regex: '; *(TECNO[ _])([^;/]+) Build/' + device_replacement: '$1$2' + brand_replacement: 'Tecno' + model_replacement: '$2' + + ######### + # Telechips, Techvision evaluation boards + # @ref: + ######### + - regex: '; *Android for (Telechips|Techvision) ([^ ]+) ' + regex_flag: 'i' + device_replacement: '$1 $2' + brand_replacement: '$1' + model_replacement: '$2' + + ######### + # Telstra + # @ref: http://www.telstra.com.au/home-phone/thub-2/ + # @ref: https://support.google.com/googleplay/answer/1727131?hl=en + ######### + - regex: '; *(T-Hub2) Build/' + device_replacement: '$1' + brand_replacement: 'Telstra' + model_replacement: '$1' + + ######### + # Terra + # @ref: http://www.wortmann.de/ + ######### + - regex: '; *(PAD) ?(100[12]) Build/' + device_replacement: 'Terra $1$2' + brand_replacement: 'Terra' + model_replacement: '$1$2' + + ######### + # Texet + # @ref: http://www.texet.ru/tablet/ + ######### + - regex: '; *(T[BM]-\d{3}[^;/]+) Build/' + device_replacement: '$1' + brand_replacement: 'Texet' + model_replacement: '$1' + + ######### + # Thalia + # @ref: http://www.thalia.de/shop/tolino-shine-ereader/show/ + ######### + - regex: '; *(tolino [^;/]+) Build' + device_replacement: '$1' + brand_replacement: 'Thalia' + model_replacement: '$1' + - regex: '; *Build/.* (TOLINO_BROWSER)' + device_replacement: '$1' + brand_replacement: 'Thalia' + model_replacement: 'Tolino Shine' + + ######### + # Thl + # @ref: http://en.thl.com.cn/Mobile + # @ref: http://thlmobilestore.com + ######### + - regex: '; *(?:CJ[ -])?(ThL|THL)[ -]([^;/]+) Build/' + device_replacement: '$1 $2' + brand_replacement: 'Thl' + model_replacement: '$2' + - regex: '; *(T100|T200|T5|W100|W200|W8s) Build/' + device_replacement: '$1' + brand_replacement: 'Thl' + model_replacement: '$1' + + ######### + # T-Mobile (Operator Branded Devices) + ######### + # @ref: https://en.wikipedia.org/wiki/HTC_Hero + - regex: '; *(T-Mobile[ _]G2[ _]Touch) Build' + device_replacement: '$1' + brand_replacement: 'HTC' + model_replacement: 'Hero' + # @ref: https://en.wikipedia.org/wiki/HTC_Desire_Z + - regex: '; *(T-Mobile[ _]G2) Build' + device_replacement: '$1' + brand_replacement: 'HTC' + model_replacement: 'Desire Z' + - regex: '; *(T-Mobile myTouch Q) Build' + device_replacement: '$1' + brand_replacement: 'Huawei' + model_replacement: 'U8730' + - regex: '; *(T-Mobile myTouch) Build' + device_replacement: '$1' + brand_replacement: 'Huawei' + model_replacement: 'U8680' + - regex: '; *(T-Mobile_Espresso) Build' + device_replacement: '$1' + brand_replacement: 'HTC' + model_replacement: 'Espresso' + - regex: '; *(T-Mobile G1) Build' + device_replacement: '$1' + brand_replacement: 'HTC' + model_replacement: 'Dream' + - regex: '\b(T-Mobile ?)?(myTouch)[ _]?([34]G)[ _]?([^\/]*) (?:Mozilla|Build)' + device_replacement: '$1$2 $3 $4' + brand_replacement: 'HTC' + model_replacement: '$2 $3 $4' + - regex: '\b(T-Mobile)_([^_]+)_(.*) Build' + device_replacement: '$1 $2 $3' + brand_replacement: 'Tmobile' + model_replacement: '$2 $3' + - regex: '\b(T-Mobile)[_ ]?(.*?)Build' + device_replacement: '$1 $2' + brand_replacement: 'Tmobile' + model_replacement: '$2' + + ######### + # Tomtec + # @ref: http://www.tom-tec.eu/pages/tablets.php + ######### + - regex: ' (ATP[0-9]{4}) Build' + device_replacement: '$1' + brand_replacement: 'Tomtec' + model_replacement: '$1' + + ######### + # Tooky + # @ref: http://www.tookymobile.com/ + ######### + - regex: ' *(TOOKY)[ _\-]([^;/]+) ?(?:Build|;)' + regex_flag: 'i' + device_replacement: '$1 $2' + brand_replacement: 'Tooky' + model_replacement: '$2' + + ######### + # Toshiba + # @ref: http://www.toshiba.co.jp/ + # @missing: LT170, Thrive 7, TOSHIBA STB10 + ######### + - regex: '\b(TOSHIBA_AC_AND_AZ|TOSHIBA_FOLIO_AND_A|FOLIO_AND_A)' + device_replacement: '$1' + brand_replacement: 'Toshiba' + model_replacement: 'Folio 100' + - regex: '; *([Ff]olio ?100) Build/' + device_replacement: '$1' + brand_replacement: 'Toshiba' + model_replacement: 'Folio 100' + - regex: '; *(AT[0-9]{2,3}(?:\-A|LE\-A|PE\-A|SE|a)?|AT7-A|AT1S0|Hikari-iFrame/WDPF-[^;/]+|THRiVE|Thrive) Build/' + device_replacement: 'Toshiba $1' + brand_replacement: 'Toshiba' + model_replacement: '$1' + + ######### + # Touchmate + # @ref: http://touchmatepc.com/new/ + ######### + - regex: '; *(TM-MID\d+[^;/]+|TOUCHMATE|MID-750) Build' + device_replacement: '$1' + brand_replacement: 'Touchmate' + model_replacement: '$1' + # @todo: needs verification user-agents missing + - regex: '; *(TM-SM\d+[^;/]+) Build' + device_replacement: '$1' + brand_replacement: 'Touchmate' + model_replacement: '$1' + + ######### + # Treq + # @ref: http://www.treq.co.id/product + ######### + - regex: '; *(A10 [Bb]asic2?) Build/' + device_replacement: '$1' + brand_replacement: 'Treq' + model_replacement: '$1' + - regex: '; *(TREQ[ _\-])([^;/]+) Build' + regex_flag: 'i' + device_replacement: '$1$2' + brand_replacement: 'Treq' + model_replacement: '$2' + + ######### + # Umeox + # @ref: http://umeox.com/ + # @models: A936|A603|X-5|X-3 + ######### + # @todo: guessed markers + - regex: '; *(X-?5|X-?3) Build/' + device_replacement: '$1' + brand_replacement: 'Umeox' + model_replacement: '$1' + # @todo: guessed markers + - regex: '; *(A502\+?|A936|A603|X1|X2) Build/' + device_replacement: '$1' + brand_replacement: 'Umeox' + model_replacement: '$1' + + ######### + # Versus + # @ref: http://versusuk.com/support.html + ######### + - regex: '(TOUCH(?:TAB|PAD).+?) Build/' + regex_flag: 'i' + device_replacement: 'Versus $1' + brand_replacement: 'Versus' + model_replacement: '$1' + + ######### + # Vertu + # @ref: http://www.vertu.com/ + ######### + - regex: '(VERTU) ([^;/]+) Build/' + device_replacement: '$1 $2' + brand_replacement: 'Vertu' + model_replacement: '$2' + + ######### + # Videocon + # @ref: http://www.videoconmobiles.com + ######### + - regex: '; *(Videocon)[ _\-]([^;/]+) *(?:Build|;)' + device_replacement: '$1 $2' + brand_replacement: 'Videocon' + model_replacement: '$2' + - regex: ' (VT\d{2}[A-Za-z]*) Build' + device_replacement: '$1' + brand_replacement: 'Videocon' + model_replacement: '$1' + + ######### + # Viewsonic + # @ref: http://viewsonic.com + ######### + - regex: '; *((?:ViewPad|ViewPhone|VSD)[^;/]+) Build/' + device_replacement: '$1' + brand_replacement: 'Viewsonic' + model_replacement: '$1' + - regex: '; *(ViewSonic-)([^;/]+) Build/' + device_replacement: '$1$2' + brand_replacement: 'Viewsonic' + model_replacement: '$2' + - regex: '; *(GTablet.*) Build/' + device_replacement: '$1' + brand_replacement: 'Viewsonic' + model_replacement: '$1' + + ######### + # vivo + # @ref: http://vivo.cn/ + ######### + - regex: '; *([Vv]ivo)[ _]([^;/]+) Build' + device_replacement: '$1 $2' + brand_replacement: 'vivo' + model_replacement: '$2' + + ######### + # Vodafone (Operator Branded Devices) + # @ref: ?? + ######### + - regex: '(Vodafone) (.*) Build/' + device_replacement: '$1 $2' + brand_replacement: '$1' + model_replacement: '$2' + + ######### + # Walton + # @ref: http://www.waltonbd.com/ + ######### + - regex: '; *(?:Walton[ _\-])?(Primo[ _\-][^;/]+) Build' + regex_flag: 'i' + device_replacement: 'Walton $1' + brand_replacement: 'Walton' + model_replacement: '$1' + + ######### + # Wiko + # @ref: http://fr.wikomobile.com/collection.php?s=Smartphones + ######### + - regex: '; *(?:WIKO[ \-])?(CINK\+?|BARRY|BLOOM|DARKFULL|DARKMOON|DARKNIGHT|DARKSIDE|FIZZ|HIGHWAY|IGGY|OZZY|RAINBOW|STAIRWAY|SUBLIM|WAX|CINK [^;/]+) Build/' + regex_flag: 'i' + device_replacement: 'Wiko $1' + brand_replacement: 'Wiko' + model_replacement: '$1' + + ######### + # WellcoM + # @ref: ?? + ######### + - regex: '; *WellcoM-([^;/]+) Build' + device_replacement: 'Wellcom $1' + brand_replacement: 'Wellcom' + model_replacement: '$1' + + ########## + # WeTab + # @ref: http://wetab.mobi/ + ########## + - regex: '(?:(WeTab)-Browser|; (wetab) Build)' + device_replacement: '$1' + brand_replacement: 'WeTab' + model_replacement: 'WeTab' + + ######### + # Wolfgang + # @ref: http://wolfgangmobile.com/ + ######### + - regex: '; *(AT-AS[^;/]+) Build' + device_replacement: 'Wolfgang $1' + brand_replacement: 'Wolfgang' + model_replacement: '$1' + + ######### + # Woxter + # @ref: http://www.woxter.es/es-es/categories/index + ######### + - regex: '; *(?:Woxter|Wxt) ([^;/]+) Build' + device_replacement: 'Woxter $1' + brand_replacement: 'Woxter' + model_replacement: '$1' + + ######### + # Yarvik Zania + # @ref: http://yarvik.com + ######### + - regex: '; *(?:Xenta |Luna )?(TAB[234][0-9]{2}|TAB0[78]-\d{3}|TAB0?9-\d{3}|TAB1[03]-\d{3}|SMP\d{2}-\d{3}) Build/' + device_replacement: 'Yarvik $1' + brand_replacement: 'Yarvik' + model_replacement: '$1' + + ######### + # Yifang + # @note: Needs to be at the very last as manufacturer builds for other brands. + # @ref: http://www.yifangdigital.com/ + # @models: M1010, M1011, M1007, M1008, M1005, M899, M899LP, M909, M8000, + # M8001, M8002, M8003, M849, M815, M816, M819, M805, M878, M780LPW, + # M778, M7000, M7000AD, M7000NBD, M7001, M7002, M7002KBD, M777, M767, + # M789, M799, M769, M757, M755, M753, M752, M739, M729, M723, M712, M727 + ######### + - regex: '; *([A-Z]{2,4})(M\d{3,}[A-Z]{2})([^;\)\/]*)(?: Build|[;\)])' + device_replacement: 'Yifang $1$2$3' + brand_replacement: 'Yifang' + model_replacement: '$2' + + ######### + # XiaoMi + # @ref: http://www.xiaomi.com/event/buyphone + ######### + - regex: '; *((MI|HM|MI-ONE|Redmi)[ -](NOTE |Note )?[^;/]*) Build/' + device_replacement: 'XiaoMi $1' + brand_replacement: 'XiaoMi' + model_replacement: '$1' + + ######### + # Xolo + # @ref: http://www.xolo.in/ + ######### + - regex: '; *XOLO[ _]([^;/]*tab.*) Build' + regex_flag: 'i' + device_replacement: 'Xolo $1' + brand_replacement: 'Xolo' + model_replacement: '$1' + - regex: '; *XOLO[ _]([^;/]+) Build' + regex_flag: 'i' + device_replacement: 'Xolo $1' + brand_replacement: 'Xolo' + model_replacement: '$1' + - regex: '; *(q\d0{2,3}[a-z]?) Build' + regex_flag: 'i' + device_replacement: 'Xolo $1' + brand_replacement: 'Xolo' + model_replacement: '$1' + + ######### + # Xoro + # @ref: http://www.xoro.de/produkte/ + ######### + - regex: '; *(PAD ?[79]\d+[^;/]*|TelePAD\d+[^;/]) Build' + device_replacement: 'Xoro $1' + brand_replacement: 'Xoro' + model_replacement: '$1' + + ######### + # Zopo + # @ref: http://www.zopomobiles.com/products.html + ######### + - regex: '; *(?:(?:ZOPO|Zopo)[ _]([^;/]+)|(ZP ?(?:\d{2}[^;/]+|C2))|(C[2379])) Build' + device_replacement: '$1$2$3' + brand_replacement: 'Zopo' + model_replacement: '$1$2$3' + + ######### + # ZiiLabs + # @ref: http://www.ziilabs.com/products/platforms/androidreferencetablets.php + ######### + - regex: '; *(ZiiLABS) (Zii[^;/]*) Build' + device_replacement: '$1 $2' + brand_replacement: 'ZiiLabs' + model_replacement: '$2' + - regex: '; *(Zii)_([^;/]*) Build' + device_replacement: '$1 $2' + brand_replacement: 'ZiiLabs' + model_replacement: '$2' + + ######### + # ZTE + # @ref: http://www.ztedevices.com/ + ######### + - regex: '; *(ARIZONA|(?:ATLAS|Atlas) W|D930|Grand (?:[SX][^;]*|Era|Memo[^;]*)|JOE|(?:Kis|KIS)\b[^;]*|Libra|Light [^;]*|N8[056][01]|N850L|N8000|N9[15]\d{2}|N9810|NX501|Optik|(?:Vip )Racer[^;]*|RacerII|RACERII|San Francisco[^;]*|V9[AC]|V55|V881|Z[679][0-9]{2}[A-z]?) Build' + device_replacement: '$1' + brand_replacement: 'ZTE' + model_replacement: '$1' + - regex: '; *([A-Z]\d+)_USA_[^;]* Build' + device_replacement: '$1' + brand_replacement: 'ZTE' + model_replacement: '$1' + - regex: '; *(SmartTab\d+)[^;]* Build' + device_replacement: '$1' + brand_replacement: 'ZTE' + model_replacement: '$1' + - regex: '; *(?:Blade|BLADE|ZTE-BLADE)([^;/]*) Build' + device_replacement: 'ZTE Blade$1' + brand_replacement: 'ZTE' + model_replacement: 'Blade$1' + - regex: '; *(?:Skate|SKATE|ZTE-SKATE)([^;/]*) Build' + device_replacement: 'ZTE Skate$1' + brand_replacement: 'ZTE' + model_replacement: 'Skate$1' + - regex: '; *(Orange |Optimus )(Monte Carlo|San Francisco) Build' + device_replacement: '$1$2' + brand_replacement: 'ZTE' + model_replacement: '$1$2' + - regex: '; *(?:ZXY-ZTE_|ZTE\-U |ZTE[\- _]|ZTE-C[_ ])([^;/]+) Build' + device_replacement: 'ZTE $1' + brand_replacement: 'ZTE' + model_replacement: '$1' + # operator specific + - regex: '; (BASE) (lutea|Lutea 2|Tab[^;]*) Build' + device_replacement: '$1 $2' + brand_replacement: 'ZTE' + model_replacement: '$1 $2' + - regex: '; (Avea inTouch 2|soft stone|tmn smart a7|Movistar[ _]Link) Build' + regex_flag: 'i' + device_replacement: '$1' + brand_replacement: 'ZTE' + model_replacement: '$1' + - regex: '; *(vp9plus)\)' + device_replacement: '$1' + brand_replacement: 'ZTE' + model_replacement: '$1' + + ########## + # Zync + # @ref: http://www.zync.in/index.php/our-products/tablet-phablets + ########## + - regex: '; ?(Cloud[ _]Z5|z1000|Z99 2G|z99|z930|z999|z990|z909|Z919|z900) Build/' + device_replacement: '$1' + brand_replacement: 'Zync' + model_replacement: '$1' + + ########## + # Kindle + # @note: Needs to be after Sony Playstation Vita as this UA contains Silk/3.2 + # @ref: https://developer.amazon.com/sdk/fire/specifications.html + # @ref: http://amazonsilk.wordpress.com/useful-bits/silk-user-agent/ + ########## + - regex: '; ?(KFOT|Kindle Fire) Build\b' + device_replacement: 'Kindle Fire' + brand_replacement: 'Amazon' + model_replacement: 'Kindle Fire' + - regex: '; ?(KFOTE|Amazon Kindle Fire2) Build\b' + device_replacement: 'Kindle Fire 2' + brand_replacement: 'Amazon' + model_replacement: 'Kindle Fire 2' + - regex: '; ?(KFTT) Build\b' + device_replacement: 'Kindle Fire HD' + brand_replacement: 'Amazon' + model_replacement: 'Kindle Fire HD 7"' + - regex: '; ?(KFJWI) Build\b' + device_replacement: 'Kindle Fire HD 8.9" WiFi' + brand_replacement: 'Amazon' + model_replacement: 'Kindle Fire HD 8.9" WiFi' + - regex: '; ?(KFJWA) Build\b' + device_replacement: 'Kindle Fire HD 8.9" 4G' + brand_replacement: 'Amazon' + model_replacement: 'Kindle Fire HD 8.9" 4G' + - regex: '; ?(KFSOWI) Build\b' + device_replacement: 'Kindle Fire HD 7" WiFi' + brand_replacement: 'Amazon' + model_replacement: 'Kindle Fire HD 7" WiFi' + - regex: '; ?(KFTHWI) Build\b' + device_replacement: 'Kindle Fire HDX 7" WiFi' + brand_replacement: 'Amazon' + model_replacement: 'Kindle Fire HDX 7" WiFi' + - regex: '; ?(KFTHWA) Build\b' + device_replacement: 'Kindle Fire HDX 7" 4G' + brand_replacement: 'Amazon' + model_replacement: 'Kindle Fire HDX 7" 4G' + - regex: '; ?(KFAPWI) Build\b' + device_replacement: 'Kindle Fire HDX 8.9" WiFi' + brand_replacement: 'Amazon' + model_replacement: 'Kindle Fire HDX 8.9" WiFi' + - regex: '; ?(KFAPWA) Build\b' + device_replacement: 'Kindle Fire HDX 8.9" 4G' + brand_replacement: 'Amazon' + model_replacement: 'Kindle Fire HDX 8.9" 4G' + - regex: '; ?Amazon ([^;/]+) Build\b' + device_replacement: '$1' + brand_replacement: 'Amazon' + model_replacement: '$1' + - regex: '; ?(Kindle) Build\b' + device_replacement: 'Kindle' + brand_replacement: 'Amazon' + model_replacement: 'Kindle' + - regex: '; ?(Silk)/(\d+)\.(\d+)(?:\.([0-9\-]+))? Build\b' + device_replacement: 'Kindle Fire' + brand_replacement: 'Amazon' + model_replacement: 'Kindle Fire$2' + - regex: ' (Kindle)/(\d+\.\d+)' + device_replacement: 'Kindle' + brand_replacement: 'Amazon' + model_replacement: '$1 $2' + - regex: ' (Silk|Kindle)/(\d+)\.' + device_replacement: 'Kindle' + brand_replacement: 'Amazon' + model_replacement: 'Kindle' + + ######### + # Devices from chinese manufacturer(s) + # @note: identified by x-wap-profile http://218.249.47.94/Xianghe/.* + ######### + - regex: '(sprd)\-([^/]+)/' + device_replacement: '$1 $2' + brand_replacement: '$1' + model_replacement: '$2' + # @ref: http://eshinechina.en.alibaba.com/ + - regex: '; *(H\d{2}00\+?) Build' + device_replacement: '$1' + brand_replacement: 'Hero' + model_replacement: '$1' + - regex: '; *(iphone|iPhone5) Build/' + device_replacement: 'Xianghe $1' + brand_replacement: 'Xianghe' + model_replacement: '$1' + - regex: '; *(e\d{4}[a-z]?_?v\d+|v89_[^;/]+)[^;/]+ Build/' + device_replacement: 'Xianghe $1' + brand_replacement: 'Xianghe' + model_replacement: '$1' + + ######### + # Cellular + # @ref: + # @note: Operator branded devices + ######### + - regex: '\bUSCC[_\-]?([^ ;/\)]+)' + device_replacement: '$1' + brand_replacement: 'Cellular' + model_replacement: '$1' + + ###################################################################### + # Windows Phone Parsers + ###################################################################### + + ######### + # Alcatel Windows Phones + ######### + - regex: 'Windows Phone [^;]+; .*?IEMobile/[^;\)]+[;\)] ?(?:ARM; ?Touch; ?|Touch; ?)?(?:ALCATEL)[^;]*; *([^;,\)]+)' + device_replacement: 'Alcatel $1' + brand_replacement: 'Alcatel' + model_replacement: '$1' + + ######### + # Asus Windows Phones + ######### + #~ - regex: 'Windows Phone [^;]+; .*?IEMobile/[^;\)]+[;\)] ?(?:ARM; ?Touch; ?|Touch; ?|WpsLondonTest; ?)?(?:ASUS|Asus)[^;]*; *([^;,\)]+)' + - regex: 'Windows Phone [^;]+; .*?IEMobile/[^;\)]+[;\)] ?(?:ARM; ?Touch; ?|Touch; ?|WpsLondonTest; ?)?(?:ASUS|Asus)[^;]*; *([^;,\)]+)' + device_replacement: 'Asus $1' + brand_replacement: 'Asus' + model_replacement: '$1' + + ######### + # Dell Windows Phones + ######### + - regex: 'Windows Phone [^;]+; .*?IEMobile/[^;\)]+[;\)] ?(?:ARM; ?Touch; ?|Touch; ?)?(?:DELL|Dell)[^;]*; *([^;,\)]+)' + device_replacement: 'Dell $1' + brand_replacement: 'Dell' + model_replacement: '$1' + + ######### + # HTC Windows Phones + ######### + - regex: 'Windows Phone [^;]+; .*?IEMobile/[^;\)]+[;\)] ?(?:ARM; ?Touch; ?|Touch; ?|WpsLondonTest; ?)?(?:HTC|Htc|HTC_blocked[^;]*)[^;]*; *(?:HTC)?([^;,\)]+)' + device_replacement: 'HTC $1' + brand_replacement: 'HTC' + model_replacement: '$1' + + ######### + # Huawei Windows Phones + ######### + - regex: 'Windows Phone [^;]+; .*?IEMobile/[^;\)]+[;\)] ?(?:ARM; ?Touch; ?|Touch; ?)?(?:HUAWEI)[^;]*; *(?:HUAWEI )?([^;,\)]+)' + device_replacement: 'Huawei $1' + brand_replacement: 'Huawei' + model_replacement: '$1' + + ######### + # LG Windows Phones + ######### + - regex: 'Windows Phone [^;]+; .*?IEMobile/[^;\)]+[;\)] ?(?:ARM; ?Touch; ?|Touch; ?)?(?:LG|Lg)[^;]*; *(?:LG[ \-])?([^;,\)]+)' + device_replacement: 'LG $1' + brand_replacement: 'LG' + model_replacement: '$1' + + ######### + # Noka Windows Phones + ######### + - regex: 'Windows Phone [^;]+; .*?IEMobile/[^;\)]+[;\)] ?(?:ARM; ?Touch; ?|Touch; ?)?(?:NOKIA|Nokia)[^;]*; *(?:NOKIA ?|Nokia ?|LUMIA ?|[Ll]umia ?)*(\d{3,}[^;\)]*)' + device_replacement: 'Lumia $1' + brand_replacement: 'Nokia' + model_replacement: 'Lumia $1' + - regex: 'Windows Phone [^;]+; .*?IEMobile/[^;\)]+[;\)] ?(?:ARM; ?Touch; ?|Touch; ?)?(?:NOKIA|Nokia)[^;]*; *(RM-\d{3,})' + device_replacement: 'Nokia $1' + brand_replacement: 'Nokia' + model_replacement: '$1' + - regex: '(?:Windows Phone [^;]+; .*?IEMobile/[^;\)]+[;\)]|WPDesktop;) ?(?:ARM; ?Touch; ?|Touch; ?)?(?:NOKIA|Nokia)[^;]*; *(?:NOKIA ?|Nokia ?|LUMIA ?|[Ll]umia ?)*([^;\)]+)' + device_replacement: 'Nokia $1' + brand_replacement: 'Nokia' + model_replacement: '$1' + + ######### + # Microsoft Windows Phones + ######### + - regex: 'Windows Phone [^;]+; .*?IEMobile/[^;\)]+[;\)] ?(?:ARM; ?Touch; ?|Touch; ?)?(?:Microsoft(?: Corporation)?)[^;]*; *([^;,\)]+)' + device_replacement: 'Microsoft $1' + brand_replacement: 'Microsoft' + model_replacement: '$1' + + ######### + # Samsung Windows Phones + ######### + - regex: 'Windows Phone [^;]+; .*?IEMobile/[^;\)]+[;\)] ?(?:ARM; ?Touch; ?|Touch; ?|WpsLondonTest; ?)?(?:SAMSUNG)[^;]*; *(?:SAMSUNG )?([^;,\.\)]+)' + device_replacement: 'Samsung $1' + brand_replacement: 'Samsung' + model_replacement: '$1' + + ######### + # Toshiba Windows Phones + ######### + - regex: 'Windows Phone [^;]+; .*?IEMobile/[^;\)]+[;\)] ?(?:ARM; ?Touch; ?|Touch; ?|WpsLondonTest; ?)?(?:TOSHIBA|FujitsuToshibaMobileCommun)[^;]*; *([^;,\)]+)' + device_replacement: 'Toshiba $1' + brand_replacement: 'Toshiba' + model_replacement: '$1' + + ######### + # Generic Windows Phones + ######### + - regex: 'Windows Phone [^;]+; .*?IEMobile/[^;\)]+[;\)] ?(?:ARM; ?Touch; ?|Touch; ?|WpsLondonTest; ?)?([^;]+); *([^;,\)]+)' + device_replacement: '$1 $2' + brand_replacement: '$1' + model_replacement: '$2' + + ###################################################################### + # Other Devices Parser + ###################################################################### + + ######### + # Samsung Bada Phones + ######### + - regex: '(?:^|; )SAMSUNG\-([A-Za-z0-9\-]+).* Bada/' + device_replacement: 'Samsung $1' + brand_replacement: 'Samsung' + model_replacement: '$1' + + ######### + # Firefox OS + ######### + - regex: '\(Mobile; ALCATEL ?(One|ONE) ?(Touch|TOUCH) ?([^;/]+)(?:/[^;]+)?; rv:[^\)]+\) Gecko/[^\/]+ Firefox/' + device_replacement: 'Alcatel $1 $2 $3' + brand_replacement: 'Alcatel' + model_replacement: 'One Touch $3' + - regex: '\(Mobile; (?:ZTE([^;]+)|(OpenC)); rv:[^\)]+\) Gecko/[^\/]+ Firefox/' + device_replacement: 'ZTE $1$2' + brand_replacement: 'ZTE' + model_replacement: '$1$2' + + ########## + # NOKIA + # @note: NokiaN8-00 comes before iphone. Sometimes spoofs iphone + ########## + - regex: 'Nokia(N[0-9]+)([A-z_\-][A-z0-9_\-]*)' + device_replacement: 'Nokia $1' + brand_replacement: 'Nokia' + model_replacement: '$1$2' + - regex: '(?:NOKIA|Nokia)(?:\-| *)(?:([A-Za-z0-9]+)\-[0-9a-f]{32}|([A-Za-z0-9\-]+)(?:UCBrowser)|([A-Za-z0-9\-]+))' + device_replacement: 'Nokia $1$2$3' + brand_replacement: 'Nokia' + model_replacement: '$1$2$3' + - regex: 'Lumia ([A-Za-z0-9\-]+)' + device_replacement: 'Lumia $1' + brand_replacement: 'Nokia' + model_replacement: 'Lumia $1' + # UCWEB Browser on Symbian + - regex: '\(Symbian; U; S60 V5; [A-z]{2}\-[A-z]{2}; (SonyEricsson|Samsung|Nokia|LG)([^;/]+)\)' + device_replacement: '$1 $2' + brand_replacement: '$1' + model_replacement: '$2' + # Nokia Symbian + - regex: '\(Symbian(?:/3)?; U; ([^;]+);' + device_replacement: 'Nokia $1' + brand_replacement: 'Nokia' + model_replacement: '$1' + + ########## + # BlackBerry + # @ref: http://www.useragentstring.com/pages/BlackBerry/ + ########## + - regex: 'BB10; ([A-Za-z0-9\- ]+)\)' + device_replacement: 'BlackBerry $1' + brand_replacement: 'BlackBerry' + model_replacement: '$1' + - regex: 'Play[Bb]ook.+RIM Tablet OS' + device_replacement: 'BlackBerry Playbook' + brand_replacement: 'BlackBerry' + model_replacement: 'Playbook' + - regex: 'Black[Bb]erry ([0-9]+);' + device_replacement: 'BlackBerry $1' + brand_replacement: 'BlackBerry' + model_replacement: '$1' + - regex: 'Black[Bb]erry([0-9]+)' + device_replacement: 'BlackBerry $1' + brand_replacement: 'BlackBerry' + model_replacement: '$1' + - regex: 'Black[Bb]erry;' + device_replacement: 'BlackBerry' + brand_replacement: 'BlackBerry' + + ########## + # PALM / HP + # @note: some palm devices must come before iphone. sometimes spoofs iphone in ua + ########## + - regex: '(Pre|Pixi)/\d+\.\d+' + device_replacement: 'Palm $1' + brand_replacement: 'Palm' + model_replacement: '$1' + - regex: 'Palm([0-9]+)' + device_replacement: 'Palm $1' + brand_replacement: 'Palm' + model_replacement: '$1' + - regex: 'Treo([A-Za-z0-9]+)' + device_replacement: 'Palm Treo $1' + brand_replacement: 'Palm' + model_replacement: 'Treo $1' + - regex: 'webOS.*(P160U(?:NA)?)/(\d+).(\d+)' + device_replacement: 'HP Veer' + brand_replacement: 'HP' + model_replacement: 'Veer' + - regex: '(Touch[Pp]ad)/\d+\.\d+' + device_replacement: 'HP TouchPad' + brand_replacement: 'HP' + model_replacement: 'TouchPad' + - regex: 'HPiPAQ([A-Za-z0-9]+)/\d+.\d+' + device_replacement: 'HP iPAQ $1' + brand_replacement: 'HP' + model_replacement: 'iPAQ $1' + - regex: 'PDA; (PalmOS)/sony/model ([a-z]+)/Revision' + device_replacement: '$1' + brand_replacement: 'Sony' + model_replacement: '$1 $2' + + ########## + # AppleTV + # No built in browser that I can tell + # Stack Overflow indicated iTunes-AppleTV/4.1 as a known UA for app available and I'm seeing it in live traffic + ########## + - regex: '(Apple\s?TV)' + device_replacement: 'AppleTV' + brand_replacement: 'Apple' + model_replacement: 'AppleTV' + + ######### + # Tesla Model S + ######### + - regex: '(QtCarBrowser)' + device_replacement: 'Tesla Model S' + brand_replacement: 'Tesla' + model_replacement: 'Model S' + + ########## + # iSTUFF + # @note: complete but probably catches spoofs + # ipad and ipod must be parsed before iphone + # cannot determine specific device type from ua string. (3g, 3gs, 4, etc) + ########## + # @note: on some ua the device can be identified e.g. iPhone5,1 + - regex: '((?:iPhone|iPad|iPod)\d+,\d+)' + device_replacement: '$1' + brand_replacement: 'Apple' + model_replacement: '$1' + # @note: iPad needs to be before iPhone + - regex: '(iPad)(?:;| Simulator;)' + device_replacement: '$1' + brand_replacement: 'Apple' + model_replacement: '$1' + - regex: '(iPod)(?:;| touch;| Simulator;)' + device_replacement: '$1' + brand_replacement: 'Apple' + model_replacement: '$1' + - regex: '(iPhone)(?:;| Simulator;)' + device_replacement: '$1' + brand_replacement: 'Apple' + model_replacement: '$1' + # @note: desktop applications show device info + - regex: 'CFNetwork/.* Darwin/\d.*\(((?:Mac|iMac|PowerMac|PowerBook)[^\d]*)(\d+)(?:,|%2C)(\d+)' + device_replacement: '$1$2,$3' + brand_replacement: 'Apple' + model_replacement: '$1$2,$3' + # @note: iOS applications do not show device info + - regex: 'CFNetwork/.* Darwin/\d' + device_replacement: 'iOS-Device' + brand_replacement: 'Apple' + model_replacement: 'iOS-Device' + + ########## + # Acer + ########## + - regex: 'acer_([A-Za-z0-9]+)_' + device_replacement: 'Acer $1' + brand_replacement: 'Acer' + model_replacement: '$1' + + ########## + # Alcatel + ########## + - regex: '(?:ALCATEL|Alcatel)-([A-Za-z0-9\-]+)' + device_replacement: 'Alcatel $1' + brand_replacement: 'Alcatel' + model_replacement: '$1' + + ########## + # Amoi + ########## + - regex: '(?:Amoi|AMOI)\-([A-Za-z0-9]+)' + device_replacement: 'Amoi $1' + brand_replacement: 'Amoi' + model_replacement: '$1' + + ########## + # Asus + ########## + - regex: '(?:; |\/|^)((?:Transformer (?:Pad|Prime) |Transformer |PadFone[ _]?)[A-Za-z0-9]*)' + device_replacement: 'Asus $1' + brand_replacement: 'Asus' + model_replacement: '$1' + - regex: '(?:asus.*?ASUS|Asus|ASUS|asus)[\- ;]*((?:Transformer (?:Pad|Prime) |Transformer |Padfone |Nexus[ _])?[A-Za-z0-9]+)' + device_replacement: 'Asus $1' + brand_replacement: 'Asus' + model_replacement: '$1' + + + ########## + # Bird + ########## + - regex: '\bBIRD[ \-\.]([A-Za-z0-9]+)' + device_replacement: 'Bird $1' + brand_replacement: 'Bird' + model_replacement: '$1' + + ########## + # Dell + ########## + - regex: '\bDell ([A-Za-z0-9]+)' + device_replacement: 'Dell $1' + brand_replacement: 'Dell' + model_replacement: '$1' + + ########## + # DoCoMo + ########## + - regex: 'DoCoMo/2\.0 ([A-Za-z0-9]+)' + device_replacement: 'DoCoMo $1' + brand_replacement: 'DoCoMo' + model_replacement: '$1' + - regex: '([A-Za-z0-9]+)_W;FOMA' + device_replacement: 'DoCoMo $1' + brand_replacement: 'DoCoMo' + model_replacement: '$1' + - regex: '([A-Za-z0-9]+);FOMA' + device_replacement: 'DoCoMo $1' + brand_replacement: 'DoCoMo' + model_replacement: '$1' + + ########## + # htc + ########## + - regex: '\b(?:HTC/|HTC/[a-z0-9]+/)?HTC[ _\-;]? *(.*?)(?:-?Mozilla|fingerPrint|[;/\(\)]|$)' + device_replacement: 'HTC $1' + brand_replacement: 'HTC' + model_replacement: '$1' + + ########## + # Huawei + ########## + - regex: 'Huawei([A-Za-z0-9]+)' + device_replacement: 'Huawei $1' + brand_replacement: 'Huawei' + model_replacement: '$1' + - regex: 'HUAWEI-([A-Za-z0-9]+)' + device_replacement: 'Huawei $1' + brand_replacement: 'Huawei' + model_replacement: '$1' + - regex: 'vodafone([A-Za-z0-9]+)' + device_replacement: 'Huawei Vodafone $1' + brand_replacement: 'Huawei' + model_replacement: 'Vodafone $1' + + ########## + # i-mate + ########## + - regex: 'i\-mate ([A-Za-z0-9]+)' + device_replacement: 'i-mate $1' + brand_replacement: 'i-mate' + model_replacement: '$1' + + ########## + # kyocera + ########## + - regex: 'Kyocera\-([A-Za-z0-9]+)' + device_replacement: 'Kyocera $1' + brand_replacement: 'Kyocera' + model_replacement: '$1' + - regex: 'KWC\-([A-Za-z0-9]+)' + device_replacement: 'Kyocera $1' + brand_replacement: 'Kyocera' + model_replacement: '$1' + + ########## + # lenovo + ########## + - regex: 'Lenovo[_\-]([A-Za-z0-9]+)' + device_replacement: 'Lenovo $1' + brand_replacement: 'Lenovo' + model_replacement: '$1' + + ########## + # HbbTV (European and Australian standard) + # written before the LG regexes, as LG is making HbbTV too + ########## + - regex: '(HbbTV)/[0-9]+\.[0-9]+\.[0-9]+ \([^;]*; *(LG)E *; *([^;]*) *;[^;]*;[^;]*;\)' + device_replacement: '$1' + brand_replacement: '$2' + model_replacement: '$3' + - regex: '(HbbTV)/1\.1\.1.*CE-HTML/1\.\d;(Vendor/)*(THOM[^;]*?)[;\s](?:.*SW-Version/.*)*(LF[^;]+);?' + device_replacement: '$1' + brand_replacement: 'Thomson' + model_replacement: '$4' + - regex: '(HbbTV)(?:/1\.1\.1)?(?: ?\(;;;;;\))?; *CE-HTML(?:/1\.\d)?; *([^ ]+) ([^;]+);' + device_replacement: '$1' + brand_replacement: '$2' + model_replacement: '$3' + - regex: '(HbbTV)/1\.1\.1 \(;;;;;\) Maple_2011' + device_replacement: '$1' + brand_replacement: 'Samsung' + - regex: '(HbbTV)/[0-9]+\.[0-9]+\.[0-9]+ \([^;]*; *(?:CUS:([^;]*)|([^;]+)) *; *([^;]*) *;.*;' + device_replacement: '$1' + brand_replacement: '$2$3' + model_replacement: '$4' + - regex: '(HbbTV)/[0-9]+\.[0-9]+\.[0-9]+' + device_replacement: '$1' + + ########## + # LGE NetCast TV + ########## + - regex: 'LGE; (?:Media\/)?([^;]*);[^;]*;[^;]*;?\); "?LG NetCast(\.TV|\.Media|)-\d+' + device_replacement: 'NetCast$2' + brand_replacement: 'LG' + model_replacement: '$1' + + ########## + # InettvBrowser + ########## + - regex: 'InettvBrowser/[0-9]+\.[0-9A-Z]+ \([^;]*;(Sony)([^;]*);[^;]*;[^\)]*\)' + device_replacement: 'Inettv' + brand_replacement: '$1' + model_replacement: '$2' + - regex: 'InettvBrowser/[0-9]+\.[0-9A-Z]+ \([^;]*;([^;]*);[^;]*;[^\)]*\)' + device_replacement: 'Inettv' + brand_replacement: 'Generic_Inettv' + model_replacement: '$1' + - regex: '(?:InettvBrowser|TSBNetTV|NETTV|HBBTV)' + device_replacement: 'Inettv' + brand_replacement: 'Generic_Inettv' + + ########## + # lg + ########## + # LG Symbian Phones + - regex: 'Series60/\d\.\d (LG)[\-]?([A-Za-z0-9 \-]+)' + device_replacement: '$1 $2' + brand_replacement: '$1' + model_replacement: '$2' + # other LG phones + - regex: '\b(?:LGE[ \-]LG\-(?:AX)?|LGE |LGE?-LG|LGE?[ \-]|LG[ /\-]|lg[\-])([A-Za-z0-9]+)\b' + device_replacement: 'LG $1' + brand_replacement: 'LG' + model_replacement: '$1' + - regex: '(?:^LG[\-]?|^LGE[\-/]?)([A-Za-z]+[0-9]+[A-Za-z]*)' + device_replacement: 'LG $1' + brand_replacement: 'LG' + model_replacement: '$1' + - regex: '^LG([0-9]+[A-Za-z]*)' + device_replacement: 'LG $1' + brand_replacement: 'LG' + model_replacement: '$1' + + ########## + # microsoft + ########## + - regex: '(KIN\.[^ ]+) (\d+)\.(\d+)' + device_replacement: 'Microsoft $1' + brand_replacement: 'Microsoft' + model_replacement: '$1' + - regex: '(?:MSIE|XBMC).*\b(Xbox)\b' + device_replacement: '$1' + brand_replacement: 'Microsoft' + model_replacement: '$1' + - regex: '; ARM; Trident/6\.0; Touch[\);]' + device_replacement: 'Microsoft Surface RT' + brand_replacement: 'Microsoft' + model_replacement: 'Surface RT' + + ########## + # motorola + ########## + - regex: 'Motorola\-([A-Za-z0-9]+)' + device_replacement: 'Motorola $1' + brand_replacement: 'Motorola' + model_replacement: '$1' + - regex: 'MOTO\-([A-Za-z0-9]+)' + device_replacement: 'Motorola $1' + brand_replacement: 'Motorola' + model_replacement: '$1' + - regex: 'MOT\-([A-z0-9][A-z0-9\-]*)' + device_replacement: 'Motorola $1' + brand_replacement: 'Motorola' + model_replacement: '$1' + + ########## + # nintendo + ########## + - regex: 'Nintendo WiiU' + device_replacement: 'Nintendo Wii U' + brand_replacement: 'Nintendo' + model_replacement: 'Wii U' + - regex: 'Nintendo (DS|3DS|DSi|Wii);' + device_replacement: 'Nintendo $1' + brand_replacement: 'Nintendo' + model_replacement: '$1' + + ########## + # pantech + ########## + - regex: '(?:Pantech|PANTECH)[ _-]?([A-Za-z0-9\-]+)' + device_replacement: 'Pantech $1' + brand_replacement: 'Pantech' + model_replacement: '$1' + + ########## + # philips + ########## + - regex: 'Philips([A-Za-z0-9]+)' + device_replacement: 'Philips $1' + brand_replacement: 'Philips' + model_replacement: '$1' + - regex: 'Philips ([A-Za-z0-9]+)' + device_replacement: 'Philips $1' + brand_replacement: 'Philips' + model_replacement: '$1' + + ########## + # Samsung + ########## + # Samsung Symbian Devices + - regex: 'SymbianOS/9\.\d.* Samsung[/\-]([A-Za-z0-9 \-]+)' + device_replacement: 'Samsung $1' + brand_replacement: 'Samsung' + model_replacement: '$1' + - regex: '(Samsung)(SGH)(i[0-9]+)' + device_replacement: '$1 $2$3' + brand_replacement: '$1' + model_replacement: '$2-$3' + - regex: 'SAMSUNG-ANDROID-MMS/([^;/]+)' + device_replacement: '$1' + brand_replacement: 'Samsung' + model_replacement: '$1' + # Other Samsung + #- regex: 'SAMSUNG(?:; |-)([A-Za-z0-9\-]+)' + - regex: 'SAMSUNG(?:; |[ -/])([A-Za-z0-9\-]+)' + regex_flag: 'i' + device_replacement: 'Samsung $1' + brand_replacement: 'Samsung' + model_replacement: '$1' + + ########## + # Sega + ########## + - regex: '(Dreamcast)' + device_replacement: 'Sega $1' + brand_replacement: 'Sega' + model_replacement: '$1' + + ########## + # Siemens mobile + ########## + - regex: '^SIE-([A-Za-z0-9]+)' + device_replacement: 'Siemens $1' + brand_replacement: 'Siemens' + model_replacement: '$1' + + ########## + # Softbank + ########## + - regex: 'Softbank/[12]\.0/([A-Za-z0-9]+)' + device_replacement: 'Softbank $1' + brand_replacement: 'Softbank' + model_replacement: '$1' + + ########## + # SonyEricsson + ########## + - regex: 'SonyEricsson ?([A-Za-z0-9\-]+)' + device_replacement: 'Ericsson $1' + brand_replacement: 'SonyEricsson' + model_replacement: '$1' + + ########## + # Sony + ########## + - regex: 'Android [^;]+; ([^ ]+) (Sony)/' + device_replacement: '$2 $1' + brand_replacement: '$2' + model_replacement: '$1' + - regex: '(Sony)(?:BDP\/|\/)?([^ /;\)]+)[ /;\)]' + device_replacement: '$1 $2' + brand_replacement: '$1' + model_replacement: '$2' + + ######### + # Puffin Browser Device detect + # A=Android, I=iOS, P=Phone, T=Tablet + # AT=Android+Tablet + ######### + - regex: 'Puffin/[\d\.]+IT' + device_replacement: 'iPad' + brand_replacement: 'Apple' + model_replacement: 'iPad' + - regex: 'Puffin/[\d\.]+IP' + device_replacement: 'iPhone' + brand_replacement: 'Apple' + model_replacement: 'iPhone' + - regex: 'Puffin/[\d\.]+AT' + device_replacement: 'Generic Tablet' + brand_replacement: 'Generic' + model_replacement: 'Tablet' + - regex: 'Puffin/[\d\.]+AP' + device_replacement: 'Generic Smartphone' + brand_replacement: 'Generic' + model_replacement: 'Smartphone' + + ######### + # Android General Device Matching (far from perfect) + ######### + - regex: 'Android[\- ][\d]+\.[\d]+; [A-Za-z]{2}\-[A-Za-z]{0,2}; WOWMobile (.+) Build' + brand_replacement: 'Generic_Android' + model_replacement: '$1' + - regex: 'Android[\- ][\d]+\.[\d]+\-update1; [A-Za-z]{2}\-[A-Za-z]{0,2} *; *(.+?) Build' + brand_replacement: 'Generic_Android' + model_replacement: '$1' + - regex: 'Android[\- ][\d]+(?:\.[\d]+){1,2}; *[A-Za-z]{2}[_\-][A-Za-z]{0,2}\-? *; *(.+?) Build' + brand_replacement: 'Generic_Android' + model_replacement: '$1' + - regex: 'Android[\- ][\d]+(?:\.[\d]+){1,2}; *[A-Za-z]{0,2}\- *; *(.+?) Build' + brand_replacement: 'Generic_Android' + model_replacement: '$1' + # No build info at all - "Build" follows locale immediately + - regex: 'Android[\- ][\d]+(?:\.[\d]+){1,2}; *[a-z]{0,2}[_\-]?[A-Za-z]{0,2};? Build' + device_replacement: 'Generic Smartphone' + brand_replacement: 'Generic' + model_replacement: 'Smartphone' + - regex: 'Android[\- ][\d]+(?:\.[\d]+){1,2}; *\-?[A-Za-z]{2}; *(.+?) Build' + brand_replacement: 'Generic_Android' + model_replacement: '$1' + - regex: 'Android[\- ][\d]+(?:\.[\d]+){1,2}(?:;.*)?; *(.+?) Build' + brand_replacement: 'Generic_Android' + model_replacement: '$1' + + ########## + # Google TV + ########## + - regex: '(GoogleTV)' + brand_replacement: 'Generic_Inettv' + model_replacement: '$1' + + ########## + # WebTV + ########## + - regex: '(WebTV)/\d+.\d+' + brand_replacement: 'Generic_Inettv' + model_replacement: '$1' + + ########## + # Generic Tablet + ########## + - regex: '(Android 3\.\d|Opera Tablet|Tablet; .+Firefox/|Android.*(?:Tab|Pad))' + regex_flag: 'i' + device_replacement: 'Generic Tablet' + brand_replacement: 'Generic' + model_replacement: 'Tablet' + + ########## + # Generic Smart Phone + ########## + - regex: '(Symbian|\bS60(Version|V\d)|\bS60\b|\((Series 60|Windows Mobile|Palm OS|Bada); Opera Mini|Windows CE|Opera Mobi|BREW|Brew|Mobile; .+Firefox/|iPhone OS|Android|MobileSafari|Windows *Phone|\(webOS/|PalmOS)' + device_replacement: 'Generic Smartphone' + brand_replacement: 'Generic' + model_replacement: 'Smartphone' + - regex: '(hiptop|avantgo|plucker|xiino|blazer|elaine)' + regex_flag: 'i' + device_replacement: 'Generic Smartphone' + brand_replacement: 'Generic' + model_replacement: 'Smartphone' + + ########## + # Spiders (this is hack...) + ########## + - regex: '(bot|zao|borg|DBot|oegp|silk|Xenu|zeal|^NING|CCBot|crawl|htdig|lycos|slurp|teoma|voila|yahoo|Sogou|CiBra|Nutch|^Java/|^JNLP/|Daumoa|Genieo|ichiro|larbin|pompos|Scrapy|snappy|speedy|spider|msnbot|msrbot|vortex|^vortex|crawler|favicon|indexer|Riddler|scooter|scraper|scrubby|WhatWeb|WinHTTP|bingbot|openbot|gigabot|furlbot|polybot|seekbot|^voyager|archiver|Icarus6j|mogimogi|Netvibes|blitzbot|altavista|charlotte|findlinks|Retreiver|TLSProber|WordPress|SeznamBot|ProoXiBot|wsr\-agent|Squrl Java|EtaoSpider|PaperLiBot|SputnikBot|A6\-Indexer|netresearch|searchsight|baiduspider|YisouSpider|ICC\-Crawler|http%20client|Python-urllib|dataparksearch|converacrawler|Screaming Frog|AppEngine-Google|YahooCacheSystem|fast\-webcrawler|Sogou Pic Spider|semanticdiscovery|Innovazion Crawler|facebookexternalhit|Google.*/\+/web/snippet|Google-HTTP-Java-Client|BlogBridge|IlTrovatore-Setaccio|InternetArchive|GomezAgent|WebThumbnail|heritrix|NewsGator|PagePeeker|Reaper|ZooShot|holmes)' + regex_flag: 'i' + device_replacement: 'Spider' + brand_replacement: 'Spider' + model_replacement: 'Desktop' + + ########## + # Generic Feature Phone + # take care to do case insensitive matching + ########## + - regex: '^(1207|3gso|4thp|501i|502i|503i|504i|505i|506i|6310|6590|770s|802s|a wa|acer|acs\-|airn|alav|asus|attw|au\-m|aur |aus |abac|acoo|aiko|alco|alca|amoi|anex|anny|anyw|aptu|arch|argo|bmobile|bell|bird|bw\-n|bw\-u|beck|benq|bilb|blac|c55/|cdm\-|chtm|capi|comp|cond|dall|dbte|dc\-s|dica|ds\-d|ds12|dait|devi|dmob|doco|dopo|dorado|el(?:38|39|48|49|50|55|58|68)|el[3456]\d{2}dual|erk0|esl8|ex300|ez40|ez60|ez70|ezos|ezze|elai|emul|eric|ezwa|fake|fly\-|fly_|g\-mo|g1 u|g560|gf\-5|grun|gene|go.w|good|grad|hcit|hd\-m|hd\-p|hd\-t|hei\-|hp i|hpip|hs\-c|htc |htc\-|htca|htcg)' + regex_flag: 'i' + device_replacement: 'Generic Feature Phone' + brand_replacement: 'Generic' + model_replacement: 'Feature Phone' + - regex: '^(htcp|htcs|htct|htc_|haie|hita|huaw|hutc|i\-20|i\-go|i\-ma|i\-mobile|i230|iac|iac\-|iac/|ig01|im1k|inno|iris|jata|kddi|kgt|kgt/|kpt |kwc\-|klon|lexi|lg g|lg\-a|lg\-b|lg\-c|lg\-d|lg\-f|lg\-g|lg\-k|lg\-l|lg\-m|lg\-o|lg\-p|lg\-s|lg\-t|lg\-u|lg\-w|lg/k|lg/l|lg/u|lg50|lg54|lge\-|lge/|leno|m1\-w|m3ga|m50/|maui|mc01|mc21|mcca|medi|meri|mio8|mioa|mo01|mo02|mode|modo|mot |mot\-|mt50|mtp1|mtv |mate|maxo|merc|mits|mobi|motv|mozz|n100|n101|n102|n202|n203|n300|n302|n500|n502|n505|n700|n701|n710|nec\-|nem\-|newg|neon)' + regex_flag: 'i' + device_replacement: 'Generic Feature Phone' + brand_replacement: 'Generic' + model_replacement: 'Feature Phone' + - regex: '^(netf|noki|nzph|o2 x|o2\-x|opwv|owg1|opti|oran|ot\-s|p800|pand|pg\-1|pg\-2|pg\-3|pg\-6|pg\-8|pg\-c|pg13|phil|pn\-2|pt\-g|palm|pana|pire|pock|pose|psio|qa\-a|qc\-2|qc\-3|qc\-5|qc\-7|qc07|qc12|qc21|qc32|qc60|qci\-|qwap|qtek|r380|r600|raks|rim9|rove|s55/|sage|sams|sc01|sch\-|scp\-|sdk/|se47|sec\-|sec0|sec1|semc|sgh\-|shar|sie\-|sk\-0|sl45|slid|smb3|smt5|sp01|sph\-|spv |spv\-|sy01|samm|sany|sava|scoo|send|siem|smar|smit|soft|sony|t\-mo|t218|t250|t600|t610|t618|tcl\-|tdg\-|telm|tim\-|ts70|tsm\-|tsm3|tsm5|tx\-9|tagt)' + regex_flag: 'i' + device_replacement: 'Generic Feature Phone' + brand_replacement: 'Generic' + model_replacement: 'Feature Phone' + - regex: '^(talk|teli|topl|tosh|up.b|upg1|utst|v400|v750|veri|vk\-v|vk40|vk50|vk52|vk53|vm40|vx98|virg|vertu|vite|voda|vulc|w3c |w3c\-|wapj|wapp|wapu|wapm|wig |wapi|wapr|wapv|wapy|wapa|waps|wapt|winc|winw|wonu|x700|xda2|xdag|yas\-|your|zte\-|zeto|aste|audi|avan|blaz|brew|brvw|bumb|ccwa|cell|cldc|cmd\-|dang|eml2|fetc|hipt|http|ibro|idea|ikom|ipaq|jbro|jemu|jigs|keji|kyoc|kyok|libw|m\-cr|midp|mmef|moto|mwbp|mywa|newt|nok6|o2im|pant|pdxg|play|pluc|port|prox|rozo|sama|seri|smal|symb|treo|upsi|vx52|vx53|vx60|vx61|vx70|vx80|vx81|vx83|vx85|wap\-|webc|whit|wmlb|xda\-|xda_)' + regex_flag: 'i' + device_replacement: 'Generic Feature Phone' + brand_replacement: 'Generic' + model_replacement: 'Feature Phone' + - regex: '^(Ice)$' + device_replacement: 'Generic Feature Phone' + brand_replacement: 'Generic' + model_replacement: 'Feature Phone' + - regex: '(wap[\-\ ]browser|maui|netfront|obigo|teleca|up\.browser|midp|Opera Mini)' + regex_flag: 'i' + device_replacement: 'Generic Feature Phone' + brand_replacement: 'Generic' + model_replacement: 'Feature Phone' From 892f29455d64fc3e0c9470e4f15101dac7b643fd Mon Sep 17 00:00:00 2001 From: Marcus Gesing Date: Thu, 10 Dec 2015 14:56:34 +0100 Subject: [PATCH 154/707] Creating an import profile --- .../Domain/DataExchange/ImportEnums.cs | 12 + .../Domain/DataExchange/ImportProfile.cs | 22 +- .../SmartStore.Core/SmartStore.Core.csproj | 1 + .../Mapping/DataExchange/ImportProfileMap.cs | 3 +- .../201512091408315_ImportFramework.resx | 126 ---------- ...1512101150534_ImportFramework.Designer.cs} | 2 +- ....cs => 201512101150534_ImportFramework.cs} | 24 +- .../201512101150534_ImportFramework.resx | 126 ++++++++++ .../SmartStore.Data/SmartStore.Data.csproj | 10 +- .../Import/IImportProfileService.cs | 3 +- .../Import/ImportProfileService.cs | 3 +- .../Controllers/ImportController.cs | 122 ++++++++-- .../Models/DataExchange/ImportProfileModel.cs | 13 +- .../Administration/SmartStore.Admin.csproj | 2 + .../DataExchange/ImportProfileValidator.cs | 8 +- .../Administration/Views/Import/Create.cshtml | 24 ++ .../Administration/Views/Import/List.cshtml | 8 +- .../Views/Import/_CreateOrUpdate.cshtml | 124 ++++++++++ .../Content/1-165-0001-produktcsvexport.csv | 219 ++++++++++++++++++ 19 files changed, 677 insertions(+), 175 deletions(-) create mode 100644 src/Libraries/SmartStore.Core/Domain/DataExchange/ImportEnums.cs delete mode 100644 src/Libraries/SmartStore.Data/Migrations/201512091408315_ImportFramework.resx rename src/Libraries/SmartStore.Data/Migrations/{201512091408315_ImportFramework.Designer.cs => 201512101150534_ImportFramework.Designer.cs} (92%) rename src/Libraries/SmartStore.Data/Migrations/{201512091408315_ImportFramework.cs => 201512101150534_ImportFramework.cs} (79%) create mode 100644 src/Libraries/SmartStore.Data/Migrations/201512101150534_ImportFramework.resx create mode 100644 src/Presentation/SmartStore.Web/Administration/Views/Import/Create.cshtml create mode 100644 src/Presentation/SmartStore.Web/Administration/Views/Import/_CreateOrUpdate.cshtml create mode 100644 src/Presentation/SmartStore.Web/App_Data/ImportProfiles/produkte-importieren/Content/1-165-0001-produktcsvexport.csv diff --git a/src/Libraries/SmartStore.Core/Domain/DataExchange/ImportEnums.cs b/src/Libraries/SmartStore.Core/Domain/DataExchange/ImportEnums.cs new file mode 100644 index 0000000000..498c39b3d2 --- /dev/null +++ b/src/Libraries/SmartStore.Core/Domain/DataExchange/ImportEnums.cs @@ -0,0 +1,12 @@ +namespace SmartStore.Core.Domain.DataExchange +{ + /// + /// Supported entity types + /// + public enum ImportEntityType + { + Product = 0, + Customer, + NewsLetterSubscription + } +} diff --git a/src/Libraries/SmartStore.Core/Domain/DataExchange/ImportProfile.cs b/src/Libraries/SmartStore.Core/Domain/DataExchange/ImportProfile.cs index 38633e4fed..ccff94629c 100644 --- a/src/Libraries/SmartStore.Core/Domain/DataExchange/ImportProfile.cs +++ b/src/Libraries/SmartStore.Core/Domain/DataExchange/ImportProfile.cs @@ -1,4 +1,5 @@ -using SmartStore.Core.Domain.Tasks; +using SmartStore.Core.Domain.DataExchange; +using SmartStore.Core.Domain.Tasks; namespace SmartStore.Core.Domain { @@ -15,9 +16,24 @@ public class ImportProfile : BaseEntity public string FolderName { get; set; } /// - /// The type of the entity + /// The identifier of the entity type /// - public string EntityType { get; set; } + public int EntityTypeId { get; set; } + + /// + /// The entity type + /// + public ImportEntityType EntityType + { + get + { + return (ImportEntityType)EntityTypeId; + } + set + { + EntityTypeId = (int)value; + } + } /// /// Whether the profile is enabled diff --git a/src/Libraries/SmartStore.Core/SmartStore.Core.csproj b/src/Libraries/SmartStore.Core/SmartStore.Core.csproj index e876d7b408..6ca1700faa 100644 --- a/src/Libraries/SmartStore.Core/SmartStore.Core.csproj +++ b/src/Libraries/SmartStore.Core/SmartStore.Core.csproj @@ -168,6 +168,7 @@ + diff --git a/src/Libraries/SmartStore.Data/Mapping/DataExchange/ImportProfileMap.cs b/src/Libraries/SmartStore.Data/Mapping/DataExchange/ImportProfileMap.cs index 94b9d9a46a..c390eff79d 100644 --- a/src/Libraries/SmartStore.Data/Mapping/DataExchange/ImportProfileMap.cs +++ b/src/Libraries/SmartStore.Data/Mapping/DataExchange/ImportProfileMap.cs @@ -12,10 +12,11 @@ public ImportProfileMap() this.Property(x => x.Name).IsRequired().HasMaxLength(100); this.Property(x => x.FolderName).IsRequired().HasMaxLength(100); - this.Property(x => x.EntityType).IsRequired().HasMaxLength(100); this.Property(x => x.FileTypeConfiguration).IsMaxLength(); this.Property(x => x.ColumnMapping).IsMaxLength(); + this.Ignore(x => x.EntityType); + this.HasRequired(x => x.ScheduleTask) .WithMany() .HasForeignKey(x => x.SchedulingTaskId) diff --git a/src/Libraries/SmartStore.Data/Migrations/201512091408315_ImportFramework.resx b/src/Libraries/SmartStore.Data/Migrations/201512091408315_ImportFramework.resx deleted file mode 100644 index bf924882bc..0000000000 --- a/src/Libraries/SmartStore.Data/Migrations/201512091408315_ImportFramework.resx +++ /dev/null @@ -1,126 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - text/microsoft-resx - - - 2.0 - - - System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - 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 - - - dbo - - \ No newline at end of file diff --git a/src/Libraries/SmartStore.Data/Migrations/201512091408315_ImportFramework.Designer.cs b/src/Libraries/SmartStore.Data/Migrations/201512101150534_ImportFramework.Designer.cs similarity index 92% rename from src/Libraries/SmartStore.Data/Migrations/201512091408315_ImportFramework.Designer.cs rename to src/Libraries/SmartStore.Data/Migrations/201512101150534_ImportFramework.Designer.cs index 2d56b77d1e..8f8b2e1554 100644 --- a/src/Libraries/SmartStore.Data/Migrations/201512091408315_ImportFramework.Designer.cs +++ b/src/Libraries/SmartStore.Data/Migrations/201512101150534_ImportFramework.Designer.cs @@ -13,7 +13,7 @@ public sealed partial class ImportFramework : IMigrationMetadata string IMigrationMetadata.Id { - get { return "201512091408315_ImportFramework"; } + get { return "201512101150534_ImportFramework"; } } string IMigrationMetadata.Source diff --git a/src/Libraries/SmartStore.Data/Migrations/201512091408315_ImportFramework.cs b/src/Libraries/SmartStore.Data/Migrations/201512101150534_ImportFramework.cs similarity index 79% rename from src/Libraries/SmartStore.Data/Migrations/201512091408315_ImportFramework.cs rename to src/Libraries/SmartStore.Data/Migrations/201512101150534_ImportFramework.cs index 06901ed24c..dda44fb555 100644 --- a/src/Libraries/SmartStore.Data/Migrations/201512091408315_ImportFramework.cs +++ b/src/Libraries/SmartStore.Data/Migrations/201512101150534_ImportFramework.cs @@ -16,7 +16,7 @@ public override void Up() Id = c.Int(nullable: false, identity: true), Name = c.String(nullable: false, maxLength: 100), FolderName = c.String(nullable: false, maxLength: 100), - EntityType = c.String(nullable: false, maxLength: 100), + EntityTypeId = c.Int(nullable: false), Enabled = c.Boolean(nullable: false), Skip = c.Int(nullable: false), Take = c.Int(nullable: false), @@ -59,14 +59,15 @@ public void Seed(SmartObjectContext context) public void MigrateLocaleResources(LocaleResourcesBuilder builder) { - builder.AddOrUpdate("Common.Files", "Files", "Dateien"); - builder.AddOrUpdate("Admin.Common.RecordsSkip", "Skip", "berspringen", "Specifies the number of records to be skipped.", "Legt die Anzahl der zu berspringenden Datenstze fest."); + builder.AddOrUpdate("Admin.Common.ImportFile", "Import file", "Importdatei"); + builder.AddOrUpdate("Admin.Common.ImportFiles", "Import files", "Importdateien"); + builder.AddOrUpdate("Admin.Common.RecordsTake", "Limit", "Begrenzen", @@ -77,10 +78,6 @@ public void MigrateLocaleResources(LocaleResourcesBuilder builder) "There were no import profiles found.", "Es wurden keine Importprofile gefunden."); - builder.AddOrUpdate("Admin.DataExchange.Import.FolderName.Validate", - "Please enter a valid folder name.", - "Bitte einen gltigen Ordnernamen eingeben."); - builder.AddOrUpdate("Admin.DataExchange.Import.Name", "Name of profile", "Name des Profils", @@ -99,6 +96,19 @@ public void MigrateLocaleResources(LocaleResourcesBuilder builder) "Specifies whether to delete import files after an import.", "Legt fest, ob die Importdateien nach einem Import gelscht werden sollen."); + builder.AddOrUpdate("Enums.SmartStore.Core.Domain.DataExchange.ImportEntityType.Product", "Product", "Produkt"); + builder.AddOrUpdate("Enums.SmartStore.Core.Domain.DataExchange.ImportEntityType.Customer", "Customer", "Kunde"); + builder.AddOrUpdate("Enums.SmartStore.Core.Domain.DataExchange.ImportEntityType.NewsLetterSubscription", "Newsletter Subscribers", "Newsletter Abonnenten"); + + builder.AddOrUpdate("Admin.DataExchange.Import.FileUpload", + "Upload import file...", + "Importdatei hochladen..."); + + builder.AddOrUpdate("Admin.DataExchange.Import.MissingImportFile", + "Please upload an import file.", + "Bitte laden Sie eine Importdatei hoch."); + + builder.Delete( "Admin.DataExchange.Export.LastExecution", "Admin.DataExchange.Export.Offset", diff --git a/src/Libraries/SmartStore.Data/Migrations/201512101150534_ImportFramework.resx b/src/Libraries/SmartStore.Data/Migrations/201512101150534_ImportFramework.resx new file mode 100644 index 0000000000..641f298bd8 --- /dev/null +++ b/src/Libraries/SmartStore.Data/Migrations/201512101150534_ImportFramework.resx @@ -0,0 +1,126 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + H4sIAAAAAAAEAOy923LcuLIo+D4R8w8OP50zsY/ddq+OWLuje05IsmQrti9akmzvvV4UFAuSuMwiq3nRpSfmy+ZhPun8wgHAGwgk7iBZpa4Xu0QkEkAiM5FIJBL/6//7/3/7n4/r9MU9Ksokz35/+ebVTy9foCzOV0l2+/vLurr5H39/+T//7//z//jteLV+fPGtg/uZwOGaWfn7y7uq2vz6+nUZ36F1VL5aJ3GRl/lN9SrO16+jVf767U8//fvrN29eI4ziJcb14sVv53VWJWtE/8B/HuVZjDZVHaWf8hVKy/Y7LrmgWF98jtao3EQx+v3lxToqqosqL9Crd1EVvXxxkCYR7sYFSm9evoiyLK+iCnfy168luqiKPLu92OAPUXr5tEEY7iZKS9R2/tcB3HQcP70l43g9VOxQxXVZ5WtLhG9+bgnzmq/uRN6XPeEw6Y4xiasnMmpKvt9fXuabJH75gm/p16O0IFAj0h5R+mKwJHtF65XNf//2ggP6t54p3r56++qnVz/924ujOq3qAv2eoboqovTfXpzV12kS/wd6usx/oOz3rE5Ttqe4r7hs9AF/OivyDSqqp3N00/b/dPXyxetxvdd8xb4aU6cZ3GlW/fz25YvPuPHoOkU9IzCEoKN6jzJURBVanUVVhYqM4ECUlELrXFsXT2WF1uR31ybmPyxHL198ih4/ouy2uvv9Jf758sVJ8ohW3Ze2H1+zBIsdrlQVNdI1dZrFab1Cp9lFgpuMNl2Dh3meoigDhqnBV55FZfmQFytcUKEYD98XZYdwclpcJlU6PcUP89XT5I18QlWEOZqQrZylsXeojItk0yicGdqbZ64+JmssFqvLnAp06cvJ5yhboeKg/J6sblHli63B8s88m54OTVPfi2iDF9gKKzGh7yb1L+7yh9G8+Y38EDM3KgLolyLJC6qV1frdQHlcRreB5+K318Pqq16To8cjvNjc5sWTy8ocPb5iMOwXZ3lbmmX5bz/9ZDTJluz1Lik3afT0hbC8DaMa888Fqio6FmvewSrhJrmtCwr9qsWz5yBnDno7DQd9i9I6xEph2SyllZ66Tjz7MY+jNPkTrbo2Hbi3xdEwr4Bwz8bytprpsJtawMSKsts6urVkEQAPmTqE6fO+yOvN/Aq6b3+ppueS78/RfXJLGUgyky9fnKOUApR3yabxp4iSdTWAnxT5+jxPIYHuoa4u8rqIyfhyLehlVFDz2k2n9N3yVCUtnr0GkbelWQjfTCQu7cy0VFeuxFO0j2v/UaMLlB9hHKrWA2zcTtLo9nSNB3uSpEhD7l/MRqvZ4lap734s8KabylJ5579PdDXBlTqTqu5mMs5RSXVcKVegHKRch8oAe904UqNS6E7pultnHOogBhqHc69h9brO17rqaL3M1qVrfaEtzGlJpOssrW+TTFAiuqqXeR1DyiecVeWvFEDbSqtCnJTCGSrWSUmE8xzF1KlvrRAuUFwTf90rHtdeEcjbCnSYZLv5NznIevvLL1O0PXhDJ29ZKrxHlLdRQcQKXtZ5Hr7iqgwirIYUZFgD7iXELCoXh2FbvXzFItpLr7P0TiRBJwVCF5hVN7Q9P+P5Mno8fkTrjfepF0bUGuIEDzcF6qoHcZXcex8+nZaNVmuY3w9XUP1oqpR4zTCxYuJ3HIZ6zM26yLH82yskUq2k/+6VkLytUHuJJU2RNiZi8gPzYE4Hcmb+JfuA5eOMmvR+2A7SNH94X6OywvuSb3nljdDDJyKcE2G5e4cZ82sVd5jIn5fJWlv3OFs51vT1Nblt24imAbdpowLRpBuVQhacUu3j2gdZ+YDVmbRTTflVo0bH3WKKRJXOlXvr8AaZlyZvUOz1uUJHYSrtpi7/XK+vUfHlhmiw0m8AUzh1G/HxEzFI9iERtOkTJhd16CiMPg7qihXGcWclYKBukMF66wkWsZe2YBEF0xkvDqMStR0g1O0M3S6GTiudDZmsZdRgCZhq9iG21XGKlwsiiPthv0rI2+po9L5O+lab37bHniVuV3cCGeII8hjPcjp5KwZR6WEbOsmLdVT5LtgdtosorSbv+sFqnWRH+XrNRAxPd5OhDOZjOri5SdIEi4svtcN4nN6hFAW4R9E5rg7iOK+BEO4pfFdh+OhjVFanm4PVCm/RVNcZTANGNBqvQERTfsnA/aR1sElZfcxvk8x1g4rrUy7CqlqKwtkgaEkqOZvoVP8VAzaYAWKpsPoDILZ262GSpnia+7lXdZOHBfo6BpF3mIOz7TVv6am63cJcDRaN2G8eRrCypYCQie13YtWjljqEYQg5sfUnU6oeHz8SgyZKD+rqjpg0MQVS7XJUNcBpMKogzIlZLdsJwmZAvT7LywoeW18MDkQsFXoNgDh1sbnrKe8jLZd3clwM95KDse0m3fPDPaRFYOfGJUK/uGLbLp0jvMfALPIHddGCXRuBgF2EIYSuSsDsu/wQFauzPMmq8kOCkZATd7DfApyk93I4YAwKYNuRdEedRmuNAAyoPw5GrgB5QFsVeHGX0/pHeBN7io0yuO88FEh+KZBAezmkl1unJ6jDPaT1Os9etQj2e3p5WydJUVaBXLd683WWhnSb/jCtYBbbRNn017ePyAatEO/WaI/QKoS/3SdZLG5dNS0yF2AnG1Yrmm/maujt5A39M9kQWylKNbH8gU6V7/IMNYcfk7d1Ej3O1JLfflu+k2lkCFwKu4W2hxkWQK5IWLT5cuu1mhVSZec4SLGLIwBpR8dQfk73jlzWa/O7pEAxMc9etTj2y7O8Lc2COdG1KBobUraOjyCBJmWw4MGH/CMiRDwt57g0dXlXIGTa4M8BGsSKFhVJzDXmGEdTX/8Li9pl/i3ydvFuw9WpuQJ2zvEuGM8Bxt1x7SdU3eUSF9IY5mqo3Ki3ZOwQ00MDuyttFev9LbsQSIY1WiuA1REEEDsPQnltC8f0cLk10iLgpm6/DinUknodmirTyYyZpMLppdPbDNP66I5IwiRaiVEsc+gj3pq0UGFu8j02dj0MzBGmvXjL25I5GcKGAE5lrV5fF+g+iTRqIsyJ8DbYQU77XMf1XBB+5arvFb/Vn5AGCONqce1lXiHzLal8hd4kGsP0MrguauVgs8Gs5y98QeM6vm5Wkzit+iOZ0BEDssMnaWiBk1gfpvltH/BlLdKkdvmKwbEdobhtZy7R4/RRbGTwxKMcLui3wwiyFEPrqwFwYCeoXGAlEMibjZquePAQQbBfC+RthbrPFyoVr2WzgfIouzg2W2b3Tk3UrWwtviM2LNPRGM+r8Egvo9vpk0gvc//PME+2qatD39i25ckOM7LAKbsmOhFk1inYi+K0GvLOT+WSGeT6aI8VukIqFILL9RjCL6NPka/quDrHu3H04LKPi6oI9+jVCM92GH5tl7ZlgVS30hBuFiP1PKqYUz03onxA6eamTv8LlZeYU9IgyD7nLrjk1+Wa6YfvyrHcetVDMrfkIADxfhwIZX25k8XS0iLDm/NjhcdYVueKk2fJiKQ1xAugZtX87oJ29PfVPvv9glYbkub8b6EVuE2aqZkm8A2hZb8lZYKhT7NVcp+s6ihNn3ztkGUOwC7ucmwJz2gnnuD+zdnerNcCO65F600a4EZf2HwsHZ5w55D7DU2Ym6t0m9/dS6IrVLDdfmM9XdTrYFv9QBg7dNSI4gbt3cdwSPsIp4N423JNX/yopxe6KKtvopiYIAVeRyttlG6YZt9XiUrAwzRyWr5PbqqjqPA+7OnwhLBWyB2ppEBfqjtM8WY5CfAUGMU5GD+ae81BlFpNbGNyERHbRgerFdcH7zGdlu/yhyzNI/9z8haP78x9zdJGwDuE3mP81IXFf7kRcDpmIGrRHD9ukuYNpXfRE4/TDAW9KE5RhGD7D1F5EWGrCYWa1TE2ywsquDckg8jBbYEQazi6dmaEbBavyWl5TjJXFwEContER09xippO+eo4FuMZKpLcW/p6nHTtp4g9ZeWUhpQfZ6RKgHwYIRPcYn2aEMmL0g5jEwzY+69RnKyJb+qswL/aR5L//vLFBUm1jtdPh+4Hy3dyWh6X3uRkng/0ZRxs4pBzyeweiyZG18Qceu/cqjz+8Y86an0dXiq72a5RjAf3UYLrJimD1TM8DOyp84KVZAFH/jF/aEbdpiTxDh7Mq+TmiToETvKi6+MhwrsvP8SHUfyDvg9K3gH3TuNDdoME42lDS7wD6Te93hYF3fTjWUrW9TrMJDUYo8dwGCkB0KpFlqAZjFUsC6SDh/XTYV1Vg3PBQ7YI9PekvEuTsgqDtBX+FGHmxXp95L9xPvzE1jlFl8Te/qURkuAr0Jd0NW0D7cbkiB7DTtTGxQbjiVLLgZjj7OMayOG1Q4QCi6uNc3DE1LmzjrMKFWUQ/mrV1ggzmpgpWsU2a5t483GZoEYmvRU+XkNRWR1UWHVe1xU6ytfXSdYe6wVkQtxnrPNoqjcSQpsm/hbzd5Tc3k0niuN9THD035PVhNg/TEubfqXx1Sc9Ij9lEu7EItzlijBpErcoTFwcYHKPiidS2dJ70pmB2AQTD1p1lnSJ2tUnyLa7x/cJRWVdINIlhTkZ5FXKvs2DNRsO6atie7Tkxxi1GWnrbJUieqKl8UCFca837Z2hguRrCuX4GCEl1AiNk000ZY1YnvqyWRL7JRIMkulKr1roy3zwlQ+BMXIoIRhGAWobIshqA1WEz9UYUIjnGZXLApTGQI7xSc2syhOUCWBXLR9Io6tkoLIgJCm8LfG7nUnj8NLEWHVuMUWYGA8iG4AA59hx9hBR2XcWUNF/CEw2BhDWcRxnCcWjHEILo+g9ByHrOA/m2Of+EDxcWKEy5s63v3QHetOmL+23Lcr+w1UU41FXkI1PU8txvM11B4VCHcGJ+pQplqpTFsZRm36LigQbddA+Utl9RT3FBBnUks2SSVXHqeJRWw3cYrS2Q3QeF2unK3lwDCgyIVsu5cIRkHUiM+5sWNFZHlTs7hhC2mEOzLbLrA8H6G5fDHGGUCjwggjhFdPcmYpOyTBao7b/tY9rlrelifKd6E3zbmZCRGp8LcleKcbDDRCT2nVMxBjcqdU1Zbsrtz75XeJqYRtdVR7l9SbP2MRuzp4pAdNkGU+6maHxkVTKfHl0wESIZxsHotvGX+aarZi48WYrqPbyA5ywLCmBbRcnwMUwhUdCPwbBeWHskWhRtZwvv2fZtwnXAMYBAcqHAkL7pavpH5N3vmHUodgvxfK2NEvxRBduyP2XQC3rHPjz3ZU4zCvMp7Ne60mTaIbXmVoxCnWhZ39hJtArdeRGX6gAwNbTZnlSRW5SXSR/Ir+2R1d/ysscr1gornjczhE5LZ4v4+CxydJn0Q3peZTdKmO2wvBA4Ltx4eMXtvjm0Ladgoc739/m8/SbCBta3xL08GmS5xtCHz46bFn0B5DA/sbYC9uoaThZXX9S1QExSeq4MjE5HQ/gl6Gk64G17f4JrZLoVVt/b7gr1FdDosMki4ohZL39y0SQdHGGa5rERbmETXIXH+UnSYoy9e7g50CXHz+jB1+9fVpeFlFWJiFuSE2T4tLl5FZUITCE9uSW0zdu6mSE0z/nyF69mKYemWpbMZ9t5LSUOkuD5BhNJjSWEhw25kLXV0VqJOsjNcYvGOR0jcG3l2Kl3FByBZA/nuzndYqMHiQPlKxygyY/tWpfYgqUpb+/lBoG3fD+A95AMM83W3psBjS9hp8+0yjTaPREmKd/6Ge2hrvZ0HuBQrfc+iss5+n4ESsqbPtFM+6Rh/iH6U6QpLtj5XmT29ozisL1eN+ERbRfbeRtaRYCw3sF1kf0aV58QI/forSev/XWMP2YkzVn6jsVrlaw7T5riNn232oNuPaSI28r0G5rFGHviyxY4oY45AUgeazUwikntQc1M2eYTFLMgmyYrufZULJCl3f1+jpjXv12RdYmDt2eE5znePQiPwrpmKLhEcObQVytK3aRUNwSklfT3xhS1LU9N+GuNU17FUriWNFenQroDWLaMhqAedeDuIV0Ux3S7uBQ780QeVsD0bzz93RED4aI2vfej6iV2OxowkscVg2Ndml04TK6VCu3BnrYR5IDRGtymPZyKm8rkIUfKnbstDzBVk895DVd0B6Tv/PXc6jBteEBWH5vuP8hkT0RcIJ13uWis66/IVd49uaxv25gse31w+T6gSX3X0JHjLnV8Ir+uJL6nv7oD4kcyitMoD98kg2Y9D+ILgmkRPbaY5uvhMwapM9wwv5Ww3bdatjfQ9jBewj70Pxn5B9WBcaNF3cxLA4qFwwFECjEbgPOTuO/74Dx7m0IlfIJsgOBCd9o0CApxhtvWID8ec1NrHbYIS5jTRLyqt8QhM4jJdkkGGafMh2Yik8cRqtGZ0oCFRZLuihReWlO9VCdFacK7V5v2io87zcfwkTobo8GC5cgbwZRt0ulZ6Q1/PQiSCZ1uxI8A30cqgs60AXHBMovuNrbK7y/gmpScS+smRYQOV4X+Yitz07tMrr135ZhJHvRchatUH5c3VodLLOrZB0Fs7/68KYie6o/zyqQ73lZ3tYcz/zO8t7uQm8JB33nxvbVGDU2y0diNGHKlm/CaOLhtvMRi4OyTG4zLEXdWckcj8Mt8hLKaUmfPfQ/ewnjjhx2mv+5TgNYrRqdF+4RSerr/FJXX24oUmr32p/SeD+MocpLrnkzw7SqzLFmXH+CIIvp8r87DNbVxWqaJ13VtiaFumlVl2FrE68bW4njQXhcK2UR7W0/eVuafcxEFzuNoitCXuvc7juk0NrcZnOzW0d8d2Pht2B72ZO3FchwatEEO9Agb7fhT8xD7JNZYadlm5HAO4qEWZeyqshTgm0rEyPZWzQuD7sYLuLOBgvPcy7jAf2upnVsR6g+1DAYKo+YXpmyeqCH1riSal4tDZT1TZ/yUSMJ4eELuJjsVxGDVWSePOULHSVNFobraym1GVFCm0sU7Z7b5W1J6OYfr7ZDQqSJgiU5ey7+qKMClee315MPqvHhrv6FJWGNJkwg17zWPkNDfveYJ9sSUtUQwqz9mGQ/mAx1iySysbW2tsfOMrQ7zYw1pxVpeHjQMQF4h2C/zijktqXR+zrpW21+294jKPsHHr8W3sl9AFSTLSRdW1NlQSc7ddS8GDj5WAyynodp6PgRj6kMb69Cy9Szya9urPr6N0k9LO8ex179ydsKZB3AyVltr3W5J+QNc8BrGd/hnkWDGajmRd8xKPSsLwshGC0SsJDHs5avD8t7qHJR2u7imxfkP6B0c1OnGSpL/x28gDKYWnlBIljartAnaNqpatfNlyYC3PTOVwK/R2U7wHBhDaMOqsx7gcBXXFXBoNfUkJnwumpeDIjX6vIoXzvm6Ce1XzEotoPH2s7o7q6Hcms0jaHH6Y+lCKWdErVJub3DCDI6M7FXA+DA1lC5wMQgkDfLOuYp7vl1n5tY44uJsts6uvU/sw0kg/YXc4sQ4mjZ7AlVXXO3GixxwjIPuDcJOBoN4Z1E4mCzKfJ7tGrxHQFhtrbXKPMqPNLAqTOCJpjY57RxG5l0je10qXSNpUviADVeYEeF4Oo6hrDdKzHrMxw14GQF8Kf+SlPByQogDq0ii9KDuroja1pzYe0cxZhvXXZPXQagVyrEe5NBoYRaCvqaDMdrJtn8pP5QMsvN6G4S5XWcsE22R28ztvyF8DLlvnmaOohjvE2dp0H8532yQsWUz5JpPWOg4lQpkquh5qBJjSoIS4BZLa8d10le1OuzvHRxEdC65asexV6Fytu6zDdJHMotHSLcdv7NzOnZwWpVUA/oxPEhu5CVTalfepEClYlYKmgOAMTWeqQoKNtqusgCQp0cyhXdZID89VnbGS+FRnHsNZq8LUqlrdFoZLZCRCpd1Nf/QrFKO/5tmgtKnxtBKP26/y3BOzBPB0ZUVqQn3jFfLZ5QU9zha/SunSPqeSwIjXqUrgjjYljXcjBOa4Kugy0Q2Dv6U9W1BsB/CfDU/nvFL2+LEuh9kdebifPYmeZN3poIf1CrU7721MlhFgeiQYPsQ57jEvHXygk9yLBcm1+xQJw2Z8pgbc4C+GvzthNeKp3i2Ot1hZJ59tr4Wcp44PNHtcqAz5Gs1AV/fiTVJ07qop1ba03RpNBp/tsrCXlblEDaJGeBDhxIW963IYIGBHu/6J2kKSZW6wj1dlZgEdwo0BmQ9wKzRR2sI2GwnUVP5DQ5KLJPqLrLV1OeJEk45qguCpTFT0e45gyNNo2dR9VgAKujx//uLAuX0WO7oIZwvH2L9LkTA6qVi/q6wioxPc3i9JKgDRVqr2rs+HGexi5JY3huYhLONNcIR43OM9JW68wzwraxWUeGG7IQZfvGRsoRryIJMRGi9AShqWkqb3lqAstbnpraLX7V+WdADTc5k3ayPm0rVK1M1gQ2vOtshVa2CWGtm3mIitVZnmRV+R0VCLOdf0zv0R2Kf+T1cMd7zq200PgsKVQ70yNUDPvBzU2SJgFei+z3B5vJaUCDqsmmBqM/KhDWX0eYt8a2kzNLYUwEw/QTSbo8ixku0GbCV0jLH2glm5JJR3h0f/92loaOHzdJQR0Jn/JsSPM9U5v/haLp6cnKV5Pc9R26TgK8b92jOojpuvkhT1cz8IfY8EyMyTR8GGU/ZtkAc23OomLYNk+P5myOXlcZ8mTM0eTpdTSDcdGuptQA7K+wTi33Nd4QFMmfVNPQFBVRTH4OpsHsTc8iMrLGz1HJJAOeUMNviCN9XoKLjc402ov6urfR5x3yWV3Ed1GJ5nTgn0WJ69XBzgPSbNOnn5e2ObI/xwpnUzenJbN7jQM9cL29x5PsTvgckaM35rFeo2OLDxHJQtR6cT7nVf+iWbijzvEpDXjkScXoigccjj2hciFSAgSyjclTxg02LUAhg+MSSdecAwU739DXEu/SPyQleSAB7CAEeNUe4g6dlUMJx8kKUNvXNt8nN3Qjpx0EBHj1tUSr70l1JwxGDy0MyqCK7eBoLXJXU8Hf9Cqn0H+uSOgsX+7UMyzYklTXfbGkZ0MR3DOm3LZn52iF0BqtWCV23FjgQEdZKC1TaIGFwehrWL8ui/suvyzclYpkH5eIb1KOi116tTHSxgIkr+04AInS46H8MmeCitDhlZkGTQkqzH3Airyt/hjU08PbaDVfN7GXXaZdbc1X2KGGZpHtPgqyooa2tRdanTKFgWDU8bHmcpJ02FpwDUSDsO3FXN5WRy9fCR2toCGQtVn7JzpYnEihdNQ0t3aHGhpDt/soyKUa2lahcIbWHEa70YBgm85L4fgrmb1ikbfV+c0YrQCl6TPTTiEC5SYOVTgtu87Sp1qjAN6oDuFRXm9mcmqfY2JsSIrpWbx2fWvzJLi5QBnZx84xsqapeYb1CW+2aJasidshL8B13EHdh0v7WydyQNkvyUZuJ2EBNx0NrEmV47mS1RFHJAGVrsoyeK8lmemh1w2UfQ5Tk804JpL37ZAgdv7Zog/b8JZvllQ0jfnUIbx9Q5NH7M4xmllGMnWEcefbaGzEqUk2bm1q2i0S5jpveGv3/E2ANLSnZYcsmBn/EQtINjwtZLkFItq6eU/NnEM0d+nqbJUibGZF0wcyNAr+iObJC8XfUkPpoCzzmEQlrzpjBT71CGglySw/nVXl79+1OGgEj2uAg0hjg1TxlsiA+0x8S0QoVHTtLMRbIv3BpaddSVDs7Up5W0GswWaevDWS/WJMr2LmQ7DHVu5pNZrA7GAfFDfg4N9J2ICDda+s0wC+vQwq+C7QVfuG4CFwHEZplA3PcbmfBU3sup3LgTaRZlAGskHRLlBYmwpOUBtK4PAnToEDgkxGE/C4qQvjcdCFXURNH0O013/ytoLYIJdFFP/AFJ8p0Jte0g27u6M8g1zDx9+hNLlHxZNj9dltH+PgOl7oJbF3tiF/8kBQFuJq0AFiB0cA0iDAMZRXqicWZQiltHe66yWS0ilIJJ3LW3dh/OVaYQgpBzJ5haXFcb+C2TE7R3/UyOkZh9ZBMEKzlwOFHIRIKBZMCEJtl8IcPp2jqMyzk7xouGl+N0jLv4i6vYMcEPh1QH15ymxq+Rf0pov2qKKbm/bmxdQHK6t1kumv9v7tpyAPgox0W5i8clt0xc51R83QRLKXhiCAfScI5rnZzKlxdoQXIb94Ch7TfmVTyX+Ale0sKlr7xvKEsDnPc6jITnGICMtgHsgwYSHLpFjCIokKzEMkLGIyj2UYo2MXVPHA3JLdxVhLXbHw7B5DCgbsNOSwQe8YCw1Ba4kUSN9vZ4+s6nxXaAU45pXB6Lsc5NBXSLHmvggKqParoLwtTWC16RvCth5b9FjhT+vN9ElISAD0H3VSBHhWnPjQCHzL8KHwnpaX0ePxI2Ko4YoKIzrCbHCbF0/BFuKjPKuKPA1ha4R7kuC0pJFeyJpgcq3Paw16lw12E8OwV4AOG/SraR3BmWxc0cu/DLcSUAlTfHtNLG9LoNjED05NpNqpDX2w+hfmG9bdEdyabg7gZmjotMSYsNijOEBYqYcGNNdc8+ss3ka0VnaOZwFxXRC+bvMjed9DlyDcay15WzzJnnPmCX6sEk8jyENXYmXW92hWB/BGGlYMKmfhBGwvWQomfopT1CzNntJAEJ2hIsm9E0bQ0BeKzzPW8KLC0y6NV5lrMyDG0YTIR3iaJVUSpdusydguGmmxq3ENueoaAWr11Rja1uUlXf/nVstitjJLfe6klinT408f81sHjYxr3ZKAIAbLXhvL22LItE2nLuHyRW+HYuLIDIoyA3MlwA/SqwAT9JIKNujxAdsQdHIAlSt7G+YEWiBjCHVC4PcqRd5Wk2kZ9+ghL1RJn99M46jRuIcmegH3OCPAljaWMR/7LYX7JVDZFibPR3SPUv/3M/OiCnd9x7L1Eww+W/KdTZ+d1VvOHO0JXfjKLfpaTB9ngZkcFQUq5mhrxgAJDacVJEosi30DPvKsInuIqFS9QPQ3Jy5yM2JkxovSaAlnrNDXs9m3JRxUfvO+9ysB1V7/y9ti6eSdiijUBojOoL9ba5PEW+qqUUqiwL+gXMqhBClVgHrJ7FlB07L0C6+rwI7x7KVVIa0hwlsJD4WS1CFZg7cBWV//C8XKSPpfJgtbmt9iJRFMUYAoo9a9ffjUPIIVEGGfYtIX50Q6lGVjUI+O1crVGH5QpAowQZOqYG1dSmyeE33vWWhp3wcgXc8ZSD8fU/f8rIP27+uWw8+98pe31W47veP1whyIhQ7VUz2O0rPHFfAwilAoulYFCL+bPfEdWtUpuozKHw5sT6qVr1gke6aXt6VxaP4yjUPzALOLyr9j2qxuYcyz48cN4Uj1Rc83Ye4QNqcA0lb+vkXOYdD03XzJjovC38j5jC2+89rF+/Mxopcvi8qx7nG2cm21jmPMJ67tsmSbjsFOyw/JCgu27wThP2+JVJwhrMeFPKJmdfXu4ECDPs8fWm3dDzvJIhKxcJRnJDSAeAs/UXS0rbHMwR1wUKjNm59o5WrIxSk2+HOntzguSAQERveqR7Jf0eRtNaT3teIaLMtEg3dbB2Jd+Y7jFNuzaUAzku2b5LC+5dGrMSh7XA9BAAf2IJiXafm18JHC/FVffy+Az1kAL9L6dv5WQ0Vkfoyy2xovzXYzYP6oFGGMJPa5c0oCsPLsFY9pL1RTCxUe0fsirzfzMzduef5GRy/rzed7djhFMJa+yzu0Rt+iIiGoXLwjpH75aoRmL3fytiihAnDuLLcO/aThbZj92pTcT3G72G7kS9n8t+f2yfnQNl5IGeA0lY1XpqE8Z2R7rokICyPBH/JSmeMtkMflY36bnyUxkYDtSV7woVqnh/mKMYGmC4Zrgse6DMGfUfWQFz8mn92zIsGK6YmK8FHr1/JPMEVxHj/Gd3hXgMjTUs6oFVl0pI3AmXXICK+UtZgUOzpgMdeOtoZ9miBxZvQj48AlQxpBqccyBvXLHNR3y3otfZcUKCY3s151SPYrqrwt7fnaNA7EZmI0D+n+Mkl2U/PX6/7uupx8zAkCf7KauGFP8mKNJ522MG17H5N1glnsMm+sVe9DHiJg5d2i6TeWizK3HSPVbcfZCs9scAvLbnvzKaKZ4jx3OS2WvWqWt/UM/NQTbrUPo/jHaYZbiH94Xhs4iqoozW9fSTDuWTToBIMn9iGSzAa7fb1AyL+E9cDAfx2sYKNrK4TMSipr7ExMTqoBNR7HWYhUpZ+irL6JqE+huERrbFC4nRy1ugRCt1ck8raWWZ++JegBd1V9BW+Sll1tVvMNdJsxNAAv86j2fLzn49n4uFXuAdiYw7Tn4j0Xz8bF1FAiTxG0RpAzE48R7XlY3la/q3gTaHfydpmTJvMVv8jLEtvgqT+X8aj2fLatfGa+jjbJ6T6h6i53iS5t65evRoj2jKGYUJZQTVoo/bo6yfJGsuO8Q4yLzL8HTjz4jxrVaHWM+Sk9qKoovnPMO9te7ShfgQj3PClviyGY93193BM8CeSoa8RUxAnEzYgAaqsa1UZhoKiSkwS4zaBZ0/F6yV/6MYn28LK+J8rh9ilZI9LmDC3Lr/QnkksboKBfNeCDQ1EOJfgSFaC23lAGlUXfR7V0Q2C+Go6EreHlFx31M4im3utnhaYrkrzwfk2OsNP8d6ZJq9pokiDXmPP5B3eZzzK0c7RJn4KMz6idWcZ0dDR5E4dxPHkb+vxEgewQEkQ6fQhpyEiXC6zcLovE+/kAjMYpJ2Oz+MVxXvs/VYI7sSKHd1Ga9rMQILlJvzLDCU4C2wh86npzq8J0QCzJdSO6GgODAxnBqGycMaCXaTPulrttw+LZGzcaMVVtL36ZJOCzdbzqdlWGjesvQMw/wrO84HNk2MYqlngmwxDIem9flppU6RO13NyuuShTazUvEu8duomwVONVlcoCrmWH1OJYf72JkluXMLdeX3U49rpK3pZGW0x1MVdrY07UcCCbc8lwa6/odPMwsUaIPMIRejHkUO2l0VkaJ/KI4l1lY9o1SQPR9An/n9ceM1S+kJDbu8B3WLx2i9I94huHo4ih9luv2j9raxvrys/oofyIiKh7Buj3KhPGuNec8rZginkn+l9oKxdGn4T1fU14xeUTikrMtM2j2F43YUeY9vKikBe1pTHRq10LPxp2Tkg39Z3Y6QLfWuZ+h8U3K91WGEFSemR7YdkLy3MSltP1Ji8q3OpN4pSfa1R/LxzbJhwneYo5Z5m2B17zv7McJvHRj2Tj15HL6Afyw0C2U6T+UZ7dJLd1MQ6Wmy5DUFqvs/6m/tStkdkZkjY6T1fzJALuI3kUIVz6n/F7DcBZ5UinXY3Bh9NKOZRwXqkA9Xt54imL3dMvkGjFLt3QKwbVXovrdJp3UAHlD3WK0TfTpNoxSv8w0YJA85Q9VguZiZTmkzywyQ+TCuKp5TsFTa2uT1NraNoYUcyCktYZ21ns5ioxD8N4JMryHdqk+ZPjhQAexV6jydtqVyVflbaUiRnEMDwtm8kO40n8Z+Jt+gysG8J8NojmCJQRUh+8EaYhbfLSINlLq2pzWURZuU7og0whpgLCOb4qQ1UXDOaw1WicI4FuUZscyxmcjQaaHtqewSuhAQcX5syRSElyjz4xyQ49Qo1cApZUmXxuZHdu+EX1qgce9kQyGGFHJAX0i+B89HNmjervjQZ5W389ZxZRpuRXS6rJFY7pBeEgeZzz+wQTdtE7yadlu1R1wusZIxLIY+jnghJ5CPPOHPs7/CdZFudwLXbc0zg02RuwkzV5jkqsd0+zG9XFqDBNfbm5KZFnMDWNMfJDcRhV8d1F8qen8/kMC3nzIsX2RGCRdwrpA8Q29mOwG094r3ZQxHchokgcnd5SW2wwjuA7Ql72GH8jSGu4BXOuj2wsqXNdDiUxJQM41+s1a0pqUhaclidpdFv2s+p7XUjWUjArFEsH1tLpE1nLGHEdT+sntL5GRad00vz65Qv6Cs/vL38SWGAES8wjbL4iksYd9ZXeqCs129IWFogqbCZENUmKzbL3BI2OR+QtLThBFwlRnWf0jpHZNH3CHUk2uLskSzwZ4KjyG5MpOCjLPE4oCbv1jWa3bxQ1XpqpeF51j/px/T/OVi8asVXWGoR88IxAFfC6QEeEiYlF+veX/5cwfNMGe4XINNgNgWvkzXhMuJEv2TtE1rAXB9TmItdyyjhaiWoTU3Q1/tIKDbkjhC2oErNHklXiBjHJYjxvqc1QOCSG+0zSyb45vgSvDygjW0SbOTTpB/sEpNifvlmOmDra/faaYVYDHsb21arrmyEDg1Wk3MtCW7Mu3NTu8a1yHHMxrXLedoJjsS3frkLAq8OllGvV1SDO5WvYMK6mNYB5x48wK1uyIVaepnqJHkGBpMjJOm0x/BHCnRJVsOszSCc4B7shkLjnB1n5gIoryicqpmDgZHzWgNhyG4sY4DeIgbeD14COz8RtwFyYtEzgF+O1C7yfJqFaTTLJK2x7YRssrtDqiLhkaOoVGZfoq0IcOa5lw5UG7UHLAC3UGUk2FMO7PkR9lXiDetWhl3YaggbpwgJakQVswZwSy0utcgQzyK5yjkzab6ssJsStr1PLjBwcxIYtiA0D8ljNWe+nV69Ex44TC0n6MAPzSGi6S2wzVj26aR5LS1gWGuMGGEmpJcOzE9ifGZkKpLVJ+6OKizFY/w7UcBgj4wARFGKt4dUqc94CMAOMZca0LmM/TFJy7Ns1oO3mGD44FTj05qQQpcuBGu0D08PzY7r+8hVU9GhhXcgiNKNwKGyfAaUbxQwaSzdfRush887eIvrqMM1vyTmG3sEjQEJ82QHZMKSIeKecPdLuz8CC0jnZCacP6f1RvqZH5j3jqLiEB5ZxYAtny4QCeoAPZQy+HXwoG8FMrCibH5PmuzrLuSCbN2POEvrQ5FX7v9wTCYKDDskRpJVTEm4D8k3CyJfnSvUQ5vBSKufJyFnZVNkaxmxfpDJlGv4B2CkYk3s0Vmxj+xlzPIQFGHM8T0aMObz1vMxet33LVKsreUBwR9PCWG1leLzmmjGc40TWiTl2IBK67oJWe5eUTdrxgw2eFJJFsB2N6vxFVQliqg7ehqmUbUB7ZDPG9SJNK+k2hOmqTEeWvgVztR+AJt2Pc/RHnRSoCfHVdhqqZUOZoOuVaf8AugJw+kl0UmtGpJtBxxmRyKQfXf2l7bgrzDfJPSqe6L1/jYU1AlbYcA7G2xg1xGtsPydbPlW9mc8KA+lsxFVMvaU567DOVik6rdD6oKqK5LquUHNr6moo0TGcCQ4FH0qrOzCoUVfkaw8z5m3dfNiMcD5ZsGEBI89OX2t7BKQdiuFeWlbPSBC8OJ9rbwc32LqxLMHX8Cya8/LSG29xQPaMPB8LuzBvSNNC3pVFeG8HHT1t+727od/yaphAqKDgNhf/j7QZi2361ihK6Sjm41LpfJl0oauzNVxqqBN5+Il5dIeXctkYFmDQHVSi5GmTm4g6XQutxxwChhiThbPhShD/Et5zVUdm4CsVnXfBi94y9WgYI57QqCVpRYUWdOU5bZMA/6na2hq9qB3RfApSO58mXWHrbRVnG67oUJ2Z+HmHV3fVOBZi4B1c5dv2LzYoTm6SJg1J70YzZWB1bQUrwxUdmFrTgx1kb7MRzcfoZnO8CywPj+QLfRztSsKRMvZzwAXeLFSgsbpo6NAd6AqPkVguLyoew51BcDx4w6R3MIYtXUiUDO6m29XkXWzJUXbLWNZg0V9e4vzHvviKZcI37vLX4FlaCrtl+TK6VWSHEWEDR2ywmOUmGC4OmPylwfktKpIoq/ppOcrX10lGAa3iWUzxKAinQOFAU+MOLR0gY9vR+fSC7Zya9GybwmpU4zPc0Bmg2AqO3+H9ncWwtkM0dnCnZzCqf9QRzRD7NUu8pILFsxWiMeoQIB+jgS+5GEAd3Q6Oh+bUpGdsvW3jfdcVwEHtB2Do56Tgt0erPyNV3g1F76kzRbAMgyvdccIYd43ll/C+2c63hRBsjbONHxxN7X0l41ZL1lQis5ASiieAqKj7IxcbndRurfQYDXg5STLiDwup4lEsLVxWWwNT+9/Fi7ZVlvzC5vqzsMmvLiLylsO7/CFL82il5a0xeGDu4pBDbsOun5PzFtyXGbkLprTRacCo5mIcdpmgAo+a5Ehlc6vLmAAGhzish7ThMQl6y0zwlM+WXqPVQ5mBRdVTZdIBtt4WMKjOESFATsCWu+hekPZ+VibcXRfCObpP0IOpH2wMrVh7G0CHFZhrYZdYUTmC+ZZteI52jiU/oHRzU6cZyfk6ZiojDpJW1zItU9OZf+WtyxkaFpktY2vtwObmc+08WzB+U3Ex9v+MHkp6x1SbzFWAhJi6A7JhYhHxTiVzlXZ/Bq6UzolJ24sncyW97/J/9oyj4hIeWMaBDslcQfQAH8oYfDv4UDaCmVhRNj8mzXd1lk/Db/awGwwePBH9Qg+4HT9WqMii9KCu7gh5mxBL7lE5KW2MakOkUlW0IZ9ZB3Yqe73VkGaQd6s5tvGNLKYATvKiXtMc1FoGF0Ehbu6hbFgXQG3Fp0G8wfJOzMBZcuLuDhtd5pskNuSjMayUkSiYNSdxyBdiJbgXc/ESTODdYaYr+u/7Iq83ak5iAKVsZM1BLFKAfZi+bd2aKev/XIwHzIdJ00OtbVBiDdcYKJlmyFOorwazjPm2lO+Ars+r8EbzYcx3W2B+Mfyit5KYAYc3wRjkMu4D+XpLWFAyhlltOHF+TJqnFRZjxS/FyvxJOggYYkUKZ8OGIGLzl+gC2W+qXszASCrqmjQ/rrkwR2n3A2OwgFy0mz4PuO+zcd1O7hi6nPVfy+gWfUhwb4qnPhG+lPGUtVSvHrAVXN6GgBtUPGOwfVxqNJQZmNZoDk36sfizB+BIGs1nxU+NGM/FvU1rAOuCOntL+XY0iKWYdjRvJp2gFZZd3Ol5l5pHOTjp8m57gM7j3R0WlPR8rhVenItdYjZd+JwAOQHD7WLInLT3s7LdDobKvU9uqqOoWF2d4S7fRSVafU+qu4GDZOyiqQexZVfFhit1zcjUIsT94S5WGPZqBt4znAYjTgQxLM6YIyOiZyEdv4C1VEzpajWqGwTYUyYFy+tQo6HMyNPKOTTpR1dnu3j4Kytidow8qjobN49b3R1D1HwwSzE1OJ8mnRlVXNZs/ZxXyGSPNMBJTVYCYm2yMnh3hzUlPZ/LWBXnYvv3SOfoAYvPWY4RlJ38aH3vqkoQGwLwNgypbG6nvPQmI5mBW03mbyc8+NBAzAwBbU1jtQfuf2wachMYsVmbpOJ3yYaGn6uJNAYDU4G3EFZpv8dYd2d5gTs+g7zC87D9i0vX72bP3LGKji9G0Cqms/XFwQ1AWa4lXL09LAgOYUZOBOfIpP0ewbLhBaQbG+OIFQ46YLABj9k8ZiWc203Zk7lsZxmNTXlqswWRK+eoqovsHP1RI5ObETA4bA4wkHaWM9jEjtnMqjHMYi2r5mkn7OSh04Z6T1Yh+KW9kArQyjLJabNHUVExb1Yrz2YUdWArZQxuZ6nIm5KfH8qflA63WBj0bBYzRDsVJr0Yai1oInMj0S4b0hqTM+Furh/aYSzBrzu5igij0IVVyCpMzqm7GGuhG8QSbLqDkRdneZp+yys8ivaCNflwkJUPqud65XXAdEQcuFUaIkVTELcOnd86hjUYygw8azB3Rmzb11rOSL9D8Y+85nMWC5/lRrshAtCIB+tamfSmrUPWgzDGreN22+HNwPq2821kZPCVF/SmxHWBSXF7Fj1RL+NplhC8unMdRS3YtzKuYOdeUTVmfrARZGdm1JlZ3CUGM2DUD6be1nBhd4QnsI0pj8gQmPCm09m5YfMAt+pEY3mlbDu6BdhfN98mXeLrLiYNZFrv8dx/zG+vmN+EZ6QCoKgD8TwDYsPnqlYgnyLX+a3jbIPxzMDMBnNn0guu6lawr9bPBgFPxLC76VhTjWBm3txJd5oRF+q4z5LrXLltK141WIjRdpbBaD6Ri/q6jIukeTDcLMsaWEWaMoaFtk4dAze1UOo1ZWdmYDQ98XeC7fB476MKfUIlCcq/OinytZbvFHXghPAsuF0aeHlD87OdQW/mcKHqiW/SC7betjDfZW7LekONSRmPaWZxthP7Mj/TiWQ36cNQa7k9xc1NkuIv6EoXUyNAgruJDshqLyFgnj33lbQLc+wEZIQ12psuHDR4EKdcJmgyKMWuFAKH96Wp/fGkBL1lMvXltwrqccyyO1XNk40dR+otF/JR5QV5PitZR8XT8WN8F2W36ByL2lFd4CbiJ3nsh64mGARCKllFfmhbAVm37fs0qtC4TzOwofEsmPRFgWY7GJT+YceZoyrhWXKMfmFeBDszNxOCBLfgvlH9xdjuMIp/nGa4L/EPOweLriLEgpI6NkypbXanPM+mo5mBt03ncyc8N7LB6OI8NfVm5uldDP40HMuCDL2DoaD/qFGNVsfrKEkPqiqK7+i5+0mi2F7Jq0BMDELbsLCiOdunzZfmYP1QZmBe/fQZOTKTBXdczBCumoHE6nzEsgoahnVk03ETAJOO+rx1elY3knl5FJwvky6w9baBUxlhY1nMTu2xhJlP2bKtAuyskJit4mb1iBZTvcCcmvSFqbYYe5+uN3lR4b7d0OUjvkOrOkWXUflDytfyKhBDj6BtGFnRDJTMgu35NF4GfYdmYEA98U060dZLsltSczHmO360Zj55Ffj5UEfmUzSzDPPpOzQD8+mJv3PMhxtK8yZUuWMTNU+IFeSMN8Da8x7QDmSHqhh8+aVbN5TZeFY+a4Zb/Jv5dkvHuE71hOtUuAYqOqlZR0X15fpfKK5IEXrEjBBTV1qUZXlFsfz6tURHaUH4o/z9ZVXUIjMT1BeoYl/VKl++aL4zfNU+YibwKFc9ejyKKnSbFwkCsfTlT1pc+Be53gihaYu0KD7mcZQmf6JVO4Nwp3gofdc+RtltHd3C2Noys86hi6qgdzhLynzS7nFwWuRnqFgnZZl07y1DiHkYLdLxs+ciwvHZuK6HeZqCvcLfjSo311ZlKLrbw4ZDUg1Hi6SNpQBp0oef6DpC9rQSqWnKDCSmTSrzCVV3OTjlYwg9QqxFEJaKe6xawZ6NAIyJTdVVVqlo3oJoUR6m+S15RBDC1ZXpualx2IKs1HnONSi6R2ogHMO7VDr6qFSnsd48S+KqLkAcbZEpQVSYRhDG5CHZpJICrSWzD4DpUaM0uUfF02WyBnvKlpsOfEiQoxg7m3bIFm1/zfgkSSuJEtPUMW1UyVRjGAPeauA/RVl9E9GpV/WdBdOi1uG0QtZ24GKD4uQmiakt1NNP0WO4gl5PgtW+0BMkUG0q4B0bM2/GlHiXEWh7DaWmiL5FRRJlw9X6o3x9nWSRjDj6WtqG/1FH9MvXLAH1DFvuOgqLrps2YYLbGinfGZoswaLzbUIMnRZuz+hADdyf3+l2Dwkq8DYONjX6Qi2az+ihlOnurkyL5PgR69gsSg/q6o7s2RohkhvTKnhtY/1byBBm5oFqEzTSHRz7FrUeUSTDYNYL+ja9tBe0VIuIZkCAcLTpJAxtDuaNDHgRhJ961GAHXuCAscOPqBhiVyE0o59MEJh3rUzQkDcepGialzY0aMTc7jC9wBzwBhsfmU05JLU2RCKj2Dj9tna0TPJUeJij3Lbavo0zlMH94zPJ6bYbfM4bcNshpiiyRStdcWTJl7S0hVJNyLhJkkrEsg0T3Ho/wXB1G3QVsDfqzVFR554aXZPrQeuPAntl0hvhBqdU84+D3rQWDHtXCrZZxvfSdFTrbsyA9BquIOmkkTnnACVxdPqjnclUblUwl1k0aL4WCjR9oX7hQRnCRpZSJfAwervuDm/lqV15DTsORwAGXqkcdkq0MetaLxQNopZ4Wfq4dJNOfIqoxpX2pS3Xe7Hg4EPQqSULILXYXl+i9SaVSAEEZ+q4elIh5mGMt6EKnByIgVYnYCuFv28MoR94kZclrpgqUPIw+oE3y4ncizsCMNgMAxEq8K4YjDQyR69Bqt9zMeFd4B5rFGOn5cn1JkpuQSHqyvRS0ywsSoEZgxjtTj+iCu8WdaIOQxr0OSqx9H5Hye0dSMYRgCm6dwnmhlLSUx5Gi3QUtAJh5IKEdMr4KYtVungoNtj3j0+H4b0+f5ZvhFQxXO7UnkPHHAurjw+vhsNHpo7iHHGowJ9is7lzFPX6UId+yNKDTeGg3LSJLsqBbWI4gOXjFMbEMiUke/yrpyIMrRkfWElKP/7UWkc9GPvEpONPkK+4E2KRfJoa8kGqK0JkBI7AFUTU4AcIyY3Vn5h5mipZbwygGAoLB1KmOXpXUWOEYmouGjJXN4f/8NBZEHXPGUjZ8PvgAQ0RWFQAGUBKOpBgfC5/hXUg1oUxNkSZsACRKga15KPTV4ZoJ4QYKOhn0AIkVsOI/cnKhidc9WEUACVBQMXQIHiQXlwEhYpcIM6JKdRlDlHQhgeRj4CDhOjBhMooSMEjmokIXDSLnBRjQP04xlPrTZYxOoA4aq5zoFB/rZfpqEgeAEo+GBEYIgwTn6UgDIALoIqUyD4EOUzSlHlYTEUVDtRgOOMaAejDIZyJSG0w15AlQEElAVY/Kr6Kik5D6JkBuQTECiswBL26gDWlFSgCyQciwEKkYULoFDQRUU1sFZIGj/I1jdAeIvlgeghw6nHw4N4MAyIF6CMltYvVPIrAu+oj8QDjGYZUGL5gBdCU5gMFVeY0jBWyqiXoAlCpc8HqqQTlflCOh0v6EIhKXFIHEWsQRd365lVcJMAo9CcHCsoXE5aoUsU8qmnZpQsFuTrYbNIErS5ztp8iUZTw8lGpqkHEYqKLFbRSYoWWLukUBKHcwJ8mdOuhbcbXVQpJsx7ntCLXNwyHRitIBlYwGCFULwDhQLQA7eBxhlLwV+Mwb6l6H8Np1fAIXKHajXT6GBlEonEoeyjaSEPI2dd/5SQzqq4dvAkWBYFVofN6yhs1Lpf30XWA8LPSdkJvm0irWBBgXNOI4pYk5lqYVo2KrVuR0YWAU5JuVqL1ttVw/UNKMxFWOyyhioJihtagFPPU1g3fsJ7JBFDzUekZzJFc83AXG0Gk2lCAcPLBQOAQibh7RArygBhn2Y6OWh5fbJIylLyOlgGkVRUsZk5GbSMASZXYA9FVL6MguN1A9bLqR8hZFwT4vpgBITUVtUNW11cQV3oXTk9mTZvTElx1AfBKdm0POLZ0QKM4gLTHBh55qi9Dqk5AHToAnX6ZMUVwOVHf6rQVHiU2V+5WU3hGMVN2xHhOJUzl4UboIorp3Ve5F4EF0+/7GWhvHwKLS66jmv6HooriKq6p38UYhZYCppgUlFZfSNZPgnEX5vPxqLqkX79NantRRb+STzknsxpRqo6M7507TccIhRdVWEwLTcyoC8DscPf4p5oiBwlxFwsHWXCi87Jc37WuNF+N6zoPXmmoTkFtpWHKw0xIf3qT9kpSaDEXajzWZFKis5ij7kqx/USpeyCfNC2XeBidhsuCpe43VfBmdudCqvrqIlpvUjSkEJFTh4PUD2lcwZtCHDrI9huSpHjTp0+HMn4/D6CPBFI+ILgCRB82YYuCQhKEM9ypGFpWLPEikMlQFMu4NVlmXarP0X2CHgxsHg5QKwFjeO+gOhjrjCT6gNLNTZ1mJFJ2VKClmbym4XClCMJSVd6MQjZlzTiQu8vGpAx4FYHkoxNgIXox+aEUhBJRTRzwShrsgkiHNFUwPQQ49Th4cG8uApEC9JGS2ifkXnvJUAKpiDIEKwSIt5/9EqEqDZky/t6sonzIRvUhimoSrSmobNbkxDH7fXY2JXUBKPm4RGCIbmzOOAWRAGRzUITmmdOThAPTDGMMLSVKlwFPRxUO3RxkuWLT30lowsJoRsCASqgR6cnAIgFoMErnF5I52myCSs5oYIzmsRlLGJ5ocMHEECjqpTTYpIwqtcHAmcg6M5YQqoNBJ+MQmMAOtKEZBQ2u1YFw8sFA4BBtuqSTCrqAqCa+Ste0qdKnHISu+yotakyDuXQnlKHzakirLg+WhyvIh6WspwqW59OAGkTOw20oIucno2SbT9WQjA205fgafpmQgE0DAPVgZnYVQbrRkdKLB9HIzwAplUL9PpXHNA8JFN4jEcik8wqvkTUh5vEVdXl4r85wj++iEq2+J9Udk1dXJI2uinxwmpoQ2Zgcwgqq6RDL2CnUrh5Kj3w1pDiW0xCuoB8oWE9FPwvNpG4DIKV0jkJR8is7ocbkHNeyHO+o8pSEHTc0ud4jWa41qp8B0eipAVKq8dqU2zqNx2CakgRAWm6lOaqElw9JVQ2ilCSruIJoyhYmtmOhtrUSqq9kN1hHsbHE6zpXjsmzqCdaSkIOQj6uMaAsARZ4d1WFZ0rBZNPSXw3J7uVEGAPqxzCCV5FEb6LBKKFwXxmVnbfOXTIyrUeBB9TtgTl4r/00j2tip8LoDQKNNgchVQoCqgBrhfFLCUqtAyKdWGkPndezkBTW4KzIgJEsT59mZif+AQrN9XIVuEqFSGvBukl4OEOpn+TI57oeLvRBJZdyYItBqqTTk35zyajQsMI/IYW1GJfCW+FJsZniXPI0/ZZXNN0yPS5ln0wFglsU4IpQE3kt/zAWBW5JnlZJyleXFQF8t+YKeCoHWCFM6yr0uyEKkMiyx3lU64lpe5CQA28MBbBbxg/vXJ1mCXlVW7GFUlVQGRyKerAxIzwbpLRnVOin3c2DzyJdiU8a6YkprWs+cBkKExKb7voNWwSorp1Ul5Szw+NMV8JDTSLNVeDyQStqgUloR89TKYipwgvZmMJbVUHJp7KPQDizgamsIidKzWUL6WhiSAsdDbRjn3PMwtti+tAjGFoTDQFWkoZYcA+86EItYOQTU278gtrVSZGvVaRTgSusNXkt+NoF9+6bMp5Zjnpe0l3mFoRjgI3HNtQJTDQG8cQk69/Yu1I4UUQghYLlYUF1zTz7p1LWAq6JHSb9637aOzwSSNXCA1WA17LUJNhWgnCGkOYL8pIe3hcn66h4On6M76LsFp3jaRre6gM2+dpKij25ri780EOuS+2rxwtSc3itMCwp6R/GNBxDGw5yVCkE1cYIpyaX5K1FpW2hrSMfqa4qmLxd+nKkgqTahqbOcy9pX+G001WxH6zChReUqPM49MC3G69OEng5UUDLByivBNFQ9uqkgoKKBia+TMu0fDV+ZFJJuzGs0cBGVTR0M6bWGClAK+5hzYm4bfTUpynTsZVsWYMlwZQsyLYDXn2XT5kDcUdPX16N35IWqaqAlg9TXgmiI/9Yp4J+CsTQKf/4He0Al99sKKeAlg9QXgm+22ZMOQXi2Sg3vGh6ddY9RSqjGwCrG5xYRU6z0QOsWrIBmCEtqJwNBdV+e91gISdTUZKhoi/77TWZiXXUfvjtNQaJ0aaqo/RTvkJp2RV0r9MONdsvLy42UUwOWf7HxcsXj+s0K39/eVdVm19fvy4p6vLVOomLvMxvqldxvn4drfLXb3/66d9fv3nzet3geB2Ptsi/cb3tW8LGM97uc6XkKbUVOkmKsnoXVdF1VOL5OFqtBbALbIBXX67/heKKHtE9ckvebz2puwbbHAzNzSBxDgk0cQh34OR3u08hTVFb/xXp0yvw4tNAwxM8LDL5dISImXFJPVzzIo7SqDhrH0ztNO8KjzxP63U2/M3znrz2xVNZoTX5PcbCfjfHdprFab1C2KJMcO1ow/VMKLXAXJ5FZfmAt/K4oELkQUYOOQRgjr+rPEY6fDXHdJlUKUfM9pM5jsN89TRG0Xwxx/AJVdF/oKeHxkXCYhqX2GF8h5gXvXmko0I7vADNmM/muD4ma8xaq8u826KzGIVCc7znKFuh4qD8nqyofmbR8mXmWJsa/8wzbujsd1ts34to08YiQEhHxba4L+7yB2CmhEJbvIc5OSHmBZovs5DlIskLrE05We6/WsryZXQLiDP9KmL67TWn3vkV5LWwhHALOr8gmS1X0aPyDSeLVavHJDjMTNYuVe1pVjBx7bJdtd4l5SaNntpADBbTuGRrZht/IEFEfhPdInGYZGnNbZ1gGvozRtF+sjCUCBH4gfQft4Y1Pua488mfaNV231cd8PhclIIBjmk4p+kDj2P4amFYtCmTeFzsdwtshCAIG2FtTo0RRq7MAasEoT0uQG5GBdvD9X1GKy9el6TqMmFxadVt1Yldj4/qtHnrBmLrvtAc79cs+aNGFygnG/QxVq7IHOdJGt2ernF/iFtdHDpQbGHaVylnz5MPy285zurrNCnveKuY+fyMDZxGy1xUBQ2VLqm/LcA6xmF0Xcq0aKaR+bBrUNd7UZzGJfYYgVWDK7Jx+5DYqLO0vk04j8O4xAbjZV7Hglwxn7dGCs5QsU7KMhkSy/lIAI/Ngfv1KLZ1tQvr5hyeHmRxDV+3hoN0qSTNuUcVwWXAOerq28o1JwVC3XVEzuQYlVg4lKLH40e03nDOOeazFa52+W4C8DmEozJzrDT4m8PWfbPRso1kNaGBY0XLlkwtwUtp7jxNPbU1xuCiocFqu2CPhNLx7dEGxCR90TJWOPGQf8k+YDV4RpNGjzrIlVnIa5rmD+/pNfTL/Fte8aIrFs+xb5B70TCbYwZHX6uYd6WxJTY+nhWIj/0+325uQX3T3RT11TrwDVlD3SOrPI0GIi3yGLpvc2qez/X6GhVfbr41yY9GqMZFz3jPLtyE9mVE9qa0IzuqUUzHlI0YQKw5lISfOA2N8RYX//5y899ktn07c//dw77vzpZnonXXLI+F/W5htG76+z2jLg2fbQzgg82myO9FP8Pw3WKcBcJr2epLJixz4xILN+1mJcE4LpmdS3nmPEzz2/bRBge+VNaeiCeb5i5JqNl4qtgCi1ggPASSz5rvFft98VlSvhdjoqzV9SfS1E2jgpoePs8b9dWMXmQc9rsFtqgS3BbdN3Ms7WM7/4Xw9qGKuKMSodAa7+dcjrYv2y7uZp4f8mV0JapJeb5pX8L5Q6FFJFdUtqPhoriY74vPI/MAkMPUKWtPu5aIymVcstzq1L2VxI+T/b51W5QwrnAPM3lu+/h9nUgs5KbEwm4syetF/IZ5+GrhuGmuXI18Ns2nJaK2uzonebGORJNAKLXHfBGlFYy1KbFw+a3WSdZporG3b1RidSgKH0yMCix62CUl4Ak5Kpj7UOIdSpFwb6D/aH+40d+3hM43+sKlDik/RnhvAO9ouaIl96GkKx/z2yQDnbhiqR3mLpORFLkAsDVr1ZCyw2etkuQiMViqpDWnWanoVS6R9ZnPdjMvohq+zrtGYXW8iTI+VqD7aIMHq5NCiGZlPlsdw1QIf7tPshgIauYKLfoo3Lo4srxx0bLdG35d675aY3oLYnprg+mfyYY4WqJUDGnkiiysgrs8Q83hAGcUsAUW8hM9QtiYz3No+aXseioDvqHurSS5mPWymtPoSlG32eo1eipcto/BAQfGQ5EtTjhchi+z8Ks95B9RVaHitAQiisVSC8x3BUIq3EC51ZEgKpIYxMyXWejtmt5kvsy/RZzZOS7ZtTDjZ3Yc3zH6J1Td5Z5hm2NcLre1NAi2VUdJ7xo73jMOz52ntxlJ7HVHkjbwZ4bjou3hTNa282RMFpULX6rrT+VQDWdEB1iGr68LdN8k7+AWzFHJrqnzhZi7OxH14+sOi+NpM1x1Gm4OG4G5HYkrqKnYujBLwIociixwtiEXbd0j0WsHQ1jogrzSNyIFson5vuWI0nx5PhGY+8QlIW8R7txW/qzLLhngvN79eH7m03gyEslZfFdkc95U4JHR2+P0xj0Y4iKBMW/lW1Im1yk6zVbJfbKqozTl9D4IMOt1gDuaY00i92Kpha+tTlMpYqFwyXO9jonQGttr4mkcULz0dYaujtz4hCH2C4yGt6jt1N3CowE+oHXFQ9gbWU2M2UW9hi0sptjJvJKghyHse09DzmD6gBBOY5A3IgVy8BEexNzR1bhkeePk4kfNdZB8sJCPKKtvophkqCjwilZBByAyGPNW3lf81fPmi028wPA0/DhUYPhu0Z+2DmQ08GU2sad/1EmBvlR3qOhtMC4KFYKwbmEwN2D8o3IL+a2x3sKCHxND42C14rDxsqyFtpndLqk3P7vDdwunS1uHn1n2u0W0VpY24snkHR/FbQHlNvL32F1vkuCHIeypcfy4SQrqDHsXPZUwZXgY+1ZoMAjFAMmWHMrCuonKiwgbWwhmGaDYQpuOagqH+kKpVa9JgN/BbYGQaJuKpXbRhH1FMSYVKLaRy/4JPF4wmQIb/dVWOnqKU/QRZbfVHa/BIAjXFs5QkeTCPMpgHFqhBgZFI2hiCMIqPu4u2RxnEd7/CUpxVGSDU56MgS+zihFJiCRHaVe7ObIRYkYkUMtFWJ6Wx6VAW/rJxpnYJ+vk2YwrsrLJiOM5u8cSiys3h448dimQjRszj3/8o46o64b3Y46KrA88aP2D+yhJo+skFdDLodxaggcBQ1jMQ5IpsIulFruB/KEZexs6KRw+AOVWu6Tk5on6O07youvfIcJ7U2GnJAe0OLCI4h80xTDJfC9cseMLLffb8id5hI23+es98japKwRPbbKu1/C8wxC2LUSPuhZ4CEu6oVVbNeGXJqDYSurIunNYPx3WVSWEFQil1pi/J+VdmpSVAj0PYkGZRtekCLP7Gd6HiZ4xGMLisADvhmjVJOZvG41KbPyPAiprHF/SFYBm+GrtDT0iJ7SQH7QpsFiDNihOohTo3bjEDWN/HHeZrIHDOiWkW4vtgZ22PR7OgsNa9+JxVqGihBgNArBa9YjiGWFBEPsoAa12wIbtqQCtdmKXCWrkkNOMXJHVeo7K4an7o3x9nWR0fwuMQwtsNRasE5vXvQ42mzTh9woggDn+7yi5veMfQWi/WVAH2OfZ7+y+JyseSfvJgl7AeD5Yj6dfI9TqRQHm0JZKsUiBlozsCxpGFejW2TblAFGMNblHxROZRMF/xpWZY+3syK9ZIpxk82U2ln+J2uUMcFSIpQ6YP6GorAtE+ibBPoJwaOFgLYYZCYUOeMkPJW4WwAJ/na1SRA8vRW+fUGiL9wwV5Mo57CSSgDi2QWigbqKHcB5F3riasP5VjoQF25ownn7h9orj6bA4BPLIq04TyUP+9Yx3b3sMnj1wZVYedswpMSaREKTBFdn3VIYYKrfHDqkfvuz5hD22J5DlUV5v8ky8MwSVW4W9g1jdsHWzQI/+qfEv49cxhGXEQXPGhq0FKOKALdwarRfoCS6P97d27/EtEi8nYhm+2hifYS8MHeYV3qxLsQLFNm7OJBJcm/STjbuumWtZdB9Uvg+TU+NqAmNlp2JiqQXmhAYhCSiHzza9vEUXyZ+8Z7X/6hgWWF7mF3hfGlcwfh2sff+/QMchQqGlu/k8yoTreKOCxUNcJ3Z87U4A4Da6WcI7k3bDcXMT1Wn1LUEPnwQrUSjcGoOr1Z6et0UaJC63RWQ1pzG22uYOkyzi357himxOTNZIfD5k+GqhdlBO3l/LBFtuVGAT4fIZcWf+7SerqJsiyspECFobFcwheMtepwojJyNc7per5paagFl+QxpxO3e9urNJWldEcws3hHuPQejh6VNimYa1uqZl7g83bMxAzusUybICGoBbhQHAHrdRgcXeuckfJEm3IJba2ORtCCaMGii2ccKVFd4pUGuWfbFMDMKVw7m0dia9EgFBOLUQPREG6RLSyFrhoFxa6iYA3NspwNxmCXyVGwSwcOw+VkVEFBTn1x0+b49KZs5UPXUxg8lFCSurb6vvEdfNiw/oEXixlCuyXtabh2LBdb0resamQquumpNKckwZxPIc0Lkbnyoc229/tke/MEah0D7CAo6tcDFiYFtle04Z/ZXHhPkFkrRCRR9kx62hYqmF6zFZocu7en2dCXltuSJznG2ihzG2/uNCzsBn7cTbFqXe82DDkoF1PIc9hMrXopxmBRg6AKts+TsZ0mObbiBCfn22wAEfNXekSPtSGw/cWYGakyLxLuCoaNv4PNBh/hiby5m+FsP22y2yA1W3o9TT8gSr3Hq4r8/zlVD8/E1tNs9FEIZlEbozrRrL9jMu23/gFuuobM/ATgwcjnM9WXYJXvXfhoSOemKpIIssksHso4vUuPYxQLsXA7SPfdlvm8flbgYavUB7k8Q0cJnx3gQw1WDU7kabKb7tN9/gkTRaRTg51MBaKtTGxSDcEeLLbIMRuxgKSTziqPgZG42qyfJ81kCB2eWVAyt000gU3Acz/l/gFtRz4MQpeDAY9+3Q5mbXuKHVvzQpf4CVHeNxX8bBykvP9LLz8i0qkigD81cEmS8Ffvd5tEI60QrimanXP4fuPLl+Q+Qrem4ZQ3Y118BBWSa3GVr13hX+vh1QbrXl3plMF6cl9H728HWZvdlgK/3nmotF4Ios9NQEWSHpju1LXX25oSioxQFlpRNBtmb1Y1nHb51jMTmsaOrqS9smc7nYtytEUK412ntfvNroP28Nf0sMpUlMunB23C461NpKUicCVG6OnaT9wZ+EHMnsdxsG7tL68xw8fHdYro7yrCryFErTIoN5/hvesDIXQNhml7IQGR2WW6q2S3HTOLNJtHcTzh9MhUvQTarH+T5IVDAEtmvcTC9hXPxRRwUqz2+vgRsabKHlNv9g9a+6rMT3LIRCi0073VzLEIul84RRzmcyUnGAFsZRgc3Ze/ZD+oahUDjldYel7nf1j+b46ML+NRl7vSevOo2O69p7Xye8U2VUYhEvUPav3nwtOD8DX2bfTwGlJz4otwNfZqM/swo1WQN53ckUWF1MAfI7uCR3OH7E7ZeClcJ8ttGN+0QRYrmlpmFyh/uomh6Ng65R1N3+jTF4Ednh8rHq2rn7VfNw9/tsTkgWYmUs+qX/ndMOiwMjy6tOw8cfo+y2Jg8q8RYS893CCSMGu1oHutLbj8CFSKvFpk65tbX5skyI5bbnj20Cc5sXosGHffsiC5ztS7Rt3SPxiA6GsNgiDs/dyhuRAi0fxBs+vPV5B8YvtCIQs7LIovSgru5wo2081DmKKS19VgkVZoeVww7dNKtJZ2XIrA/LZCpr4aZ5+8lus0CocroiNLlJeHcFVG6PvXV66BoBwMzb+kIm9jL/gTgxZL9bYjuIsc1eynCOSq0s4/tkhQpZ7imofGuk/SQv6vVZXnoedfdoHORYUXcaob3MN0nMo+g/LiX84hsf1o/4nh2sVnhR5tZC5vP+LoqtaFC2CCAbFI+rcEgqTyMdtEUeRf9xMekgJIC85aMCiy1Kk92Z2510Hy2M8k57jq3w/qvFeUCCd8LcSUDzyWZzW1akYXFzO3y3xyabSajcHjvNggbibUr2OstOZ0X+yspVT82qot4Xeb0B9VRfsgvBBArF0q49vGbpPi+hpIhogubTqGCvsAx5Zn+FeCKzjaqAAGYbxeOqDiWVp9GJ26fBnjd3T+U9XUhq2jB8H4FpptNeViT1phET2hh0H2pUYIlPDMBgPi93LBpm59XmH299CEJSPqHU5uCrSWstQQ0UW87LRRVVtYCXK7LvL4xWLLVwITa5xGHEQqE13iZHudQ/KQOy57ijuihQFj8BjyeCEDYtNPXOsVLmMbMl9n2+jB7b9QhyL8ihbCL9wBuYzGdbvq6vq7yK0tMsTnHHIPbmIRxbOH7UtdBD2LdwSer3zz+oxgJDeraoHBsMadtiqxIUY+MhHFtQjIWHcGwB1xVlD4Zw1E9YzyfExozSE4RAkhmAh2gbJKYBeIi2QTIbgFt4UpsqnGU6fLXkD5jrXDgNzobOFdn2jogx1L/muzm2c3RTZyu0gu5e82U2WB+iYnWWJ1lVfkcFwnPLB+BIQCzWuTsU/8jr4XKDdJ+nhvRoUby0LAGxX71l4VxQuUUwz81NkiZAMsdRgYNFvpFY5Bvr8CWyL8BKF298sTo4wiwCmRhqSIv+41pAYHT/1Q6TaIIOXy0xAWN2G+GnqPyBVmpqymDs+nx0f/9W7HHz1Q7T8eMmKWjQy6c84xNggACu+P8LRQCV+XI3Dn6XFCiu3qHrhI+XkwHZuKD6agcxXUE+5CngjpJB+bQEcZAcyqmlwyj7IW61QABn/KKwggBu+E+P5KhJmRPW9jUzKea+3An76XXEu0f5Qvt1gdokbbwmvEKMISwkrcY2Y5H8ScWU3s6IYiihowrOvzWRSdWQ/i2eo1LIxqCDtdGOG5IGR0FPGMKnBWhEciirSIjeylMMSAFmE2RexHdRiaReWBDAZl+VwHHiowJ7j1+z84L9fV2ZPVay4cIivamrZo1WeumMK9kc+ITJhLwLxzLsNuocraMkE7LNSkDM2/gQkZt07Wb9c171ySTH7SjAtuY4qNtwfy3x3ulDUlb+b7sAKF0eeDFDM83hUdgnbKmOAw8nLJcKZ/FbiLneJzd0/xSQuQCULsxlhmYa5ura5rGw3y00aIlW35PqDmQyodAOL/ACKPP5L8C4YXjVgz9nu/TbmmMMtwAPs8mh7LkfOoPjyyx2B4C31t5Le1p2PaBJICMgqwgAYD92vDHdQHslqNzG8omTDbmSL9qUXJEDTuDGEl9mYRejjFj9ounLfLfFBnRwVGDhIURlKTwk0H+04aaB7NT4g1KuCQDPWKv2GiNA+JHjJXRF3QnDkEiDktChoWh+e/IsYKaHcLkUSBZUmjwBPBkWSx0wg+e+YqkNJWX9de2rvJ+ufQQPnB2Olbs9ULO8goOWgLi2AZJBAmJhMmiPSX2PR6fI5dylPQIyAnBFNgtVV1Vq9gAANpGyMcqGpFJiyjKh2KLvWH9+BzK6s98tQiDpy8NkleGCH5nv1vr1iNx4hTRsU7BdyzM2RDx36D0a1+UZrjvl8uy/lNI+j4Pyc2u1SoMO8+4gCIykZ4ufsaXIemjD+I1EjC5uIyMs03Bq2FjvZgicVmq/2WI5xCWZkP5qXGTnd4J28+z3+fdyOydB5BSpSW3kIzUdFpdHtqRVt1uTXxZR/AMPDDq05MsssJIwRMhOGRVYniwi+AiUL7M6J6RPtIBohcK/gPT4OytYTB5SNKfLom8TOAfvvjs4QGDZtPYf70yW4nNU1UVGHlVAvkl3RqiczBZl/YnYKNAlt9AMFNaQCuf3OkdRmWcnedHMFu9r5wpt8NJpR3Tvzrs4hEJnvPJIDiWg/bzB6RzFUhtOjW5umo0vx6zDdwuvz2qdZGCI37jEhtKM+MJXByUguxnas9iin9M/j7DyDbHwj7E5Lf46FNutuc+iojVdxJuubImtfw7COC6xMXYGGkNH0lD5Ypv2LX9nsBsVZmFUkEcohKTYMMQSq+1e3wFXs7wUnoDOQeMZ4JhG5ZF/Of9tZBeFsM2vtFGPQHSdolZVwLjlUDb9vowejx+RQIZRgdWh5RGWndu8eBLyAY6LHFTflr5ZJ6et7YO126JYArxcBuMMoWJmfa1MaF2wDCCAOfXY/hUwP+ldzNsU1wW5QNleNwh1agZhdTs5M8Q0jdzxzYv7Z7F8H+BvzXVhuS0Am82m15/iFH1E2a1wO5stsMR3hookF8JluCLLMyham08JwhZYuc0CP/5ib+EoTrKC3Hg7zZIqiVJQwPmyZyzndAJwwcf81k/EGUQO0q2sPY1gM02C+wSxeCnvEHyr3N7bvMvMSTAHY1Ca8cSLSWEMEzlt6c3g9ikkTh2Pi+bcTRxnxKHA9af/uDUs5K3X3PTZjHoMN/UR3aNUCL5lvlt5zYsKjK0al5hjJK/YgQhHBRYL9wZ+ImXj8kRKWC8+HonwQG7/0WZLc4OKAhUCrlHBbnrEpVxSkBPOLOYOAJjPNuslfe33Q1TyJjtbsDUqiiYaZ3NzBEh6zqJzzX2uxjHRWse0Kd6rEkuXEvVQL+wEe8dq10y7s4LeNmn1vx/Hj3E5sLsOwXYfxp8U+VrG3XyZDWfKcI5LrGQ7yHtNAV5ZK89RBJy/RZYnYq3b4fCpSUslXK3ii51w9zeJpegZiGesMfq8nZ7bwA6NywZQXnciHwWcVt8pnX4oxxnkyNu6g8qL+A6t6hRdRuUPz2gvBpNLpJey+jRc47+5P8BcLryqTT/ZKJg8O37cEEYV0xRzZRbKX0hha5u+1tZxoVi+N1+y46LgFf+owGLW8CJ2XovqmP1u4RWIaLRoUQn4xiV2GI+zFYiv+27Zv5q+1gv3kCmz7KM4I8xnmyX4Q7Ja8a8MD1+tovtuCaufoSIGDt65Qnu8oHdFKLTwP+QP31AhSi37fWs0/UGchnjYvEfj5BeW1p1GwTdt8ziGr7aYxAWD/W6/xz7PU2k2967MRhBPV6lwcth82xo2/FoEYcMejQMbKur+tdjwIq25vKDNlyWOq2WPG6gfNVgqOR7KUJHEgcKGeWwuyfK0KLads/8DPTVvSI4wDV+tMAlIbOoDKR+t0z3auqwW4uPLO7RG36IiIUa9HxOPUDlwsKb+NOxLG+V2Sc2nOTeRfyGGa98C9fIzkJ8uDga43rZ6FoQzTcuzzIsyBTfw7HcLbCSoUDyzZT6b4/ogPs/9wfpt7vw2P0ti8iAAcJzPFi15XeFDtU4P85WwPrLfrU9ruyQUn1H1kBc/wINbAcYq+B0L3BOVlu65SfG6HQxj3crxY3yH7TtEE/2rG5OBbo1qazvlG2/ejc3lXoe06rYqOdUbqm5vp4r5HR2SOxJh/5jjQuE1oFGR7X7/JC/WUVUl/GMMYqmFIvR8glsqoPV1mpR3/OrBfF5Sse5CoM67nDyrcZyt8Ixy88IVbY0Ko2zSfgpgpLVgrraatPq2b2UDO2l2w7I/jOIfpxnuV/wjXIiWBKkDRxljmoa5guWTCJj/IHDs/a6FSXyKsvomovuE4hKt8Trk68eDMDqwqhmabTXpviXkvSf+DtjwdQ6zYakdQHsXPww38dhcNgRaFHsu2jouanV5GCbikDmFfGow7Flo61joHJGpWrVT53sjmcXldB9ZjWAa/uktojcSS+mNE7a3EmxW71nvHD8dFXlZXqA0DcJRPDaXhU2L4vly1VLLUpNNoHmD1XNRYlG5LEnq+hNNPduo7OFaKZDdLUDpcyxC4dawxz9qVKMVfWjsoKqi+M4/FwaI0oFdDPFMwzZM4zwirsjOmRDdIuKGFllEKLRhcd5asrWUThIxnq37ZrE+Co/P2D474289fkrWSAyhHr5uo+AFEzc/IZtvMU7yIuEzYQ5f7S6GidfBbDGITDd8tblOxl8is6st9qL7ZnGIhjbpE9+R/qM1HrFLowILH+MR51k8sql9GHOOSfph/mt55OSf6wj9suTx1wWW6UuaK42L7+g/2+ECusZ8tjhKoat2DL5EzpdZ9XBFvKxRmj4JnWRKtkbJs0P10/IsJgc1r64+0cGc+Kyt9YO27cZa1ESjArsYJjGEyWr1ygv+ggv9YnFkXaIiEwY0fLUx/MpSzJkzfLW9M3ZR8vM1fLYa3zt0E9VphbXaCnNjEqWlMFgIZGvk9ihab6Lk1vMUtMPidAIgq7qtbtvnvMr6BussdVLa3IwLdEg6RuZyPqrDsK2sje3NZv1sbqXzDAAU76LYhLsSNI3xN1XEnLtRKcM4eKveQI4VoNgF91s17rc+uH9W4/5ZjnshVfcZPZQfUVWhIlwQE4zTQfGZIppI/4Gti7mnVHDzGv12CThm3GzvRkTfJxSVdYGavPS+iz6DymnJV9bf1gV/ioSk58StL0S4J1Z+uZ07gG7n/12Cmyy9FTKPzZ0hFSj2PPnMefJ0vckL8q7RTeJ7d3aEyoEbNfW3lRVP8hRPqYiH/W4bdQ9lKB+X2DqzAiRA+pFw19qbLxbHOtEP/lCHfrE7mSUUOMqzm+S2LoCTYwmIzQVFgqy7tsHdSxwVWeBMEd45ceTrP1rMQZNeDLdOEowJxpdQujVq5uIpi8NcyRkQudzIUdWeyO8f7ELORV4XMRLyQjCfl7rcQ+/rPlYiulGB7UjFhM7sd9sbIqfCiwrDZ1tcF1Uhuf7YldhiPMzzFMLXfLexi7IY3OWNCrZGLRw/kiX/HdqkeYBnh3hsLieDWhTTaInW6gFuRN1YO678TZpQJsNpSW/acqw4fLV1X/yTt0CYzxY2ej+7kJkllu72WaZvBo4PVbW5LKKsXCc0eydEMxmMXyv6NmxNx2ZrKAYI8mW2zn34JMT9GITWBM9CxiVLH0IQfkzu0Sch78GowEp+hEP37tuWrVlBdswjVM6r1V98x0yEl/zColthRStK9qjQ1sUk9tItIB7/eZ/g0Ulj7oFym4W2VV8tK3DrLVe4gO/Ae9+qmH08sYI1zny2miOiVwWXAvvdfsYbR4QYDQ6V2wSllnVanWY3Qnzr8N0c25ebmxJxS033zfJMGjiJtjq5j6r47iL5k+Nh5rPFDGBxounSxnTvvy69fB7l6w3Nx6+yIqRADsbzQRHfCWeJYul0fq2pl+yDsszjhLr8xKtfqGhNxyZt7hWbohjTU3HTS1NTuNnFwbPggL2wEtlW0dxV4wQBrAWjtV5ADrEsIXPfK+8OX0bFLYI240YdZnFZdva31yA/mLPMxV1C/2xuwl1h3VoVCXmB/IgIexNRrnBVGtQWHJSjOg2gkAkNmAJ9W558wzUQgGsMuuzJOQ315maajmGvGF2tSpQnQosZ8RqY7sVDPW1FrJ7T3yMMMPFA5/wmusWz2EQfJikxXvsHKQ1mm68im3KbuR7j9KQphyzktHOo/RjTumPY3F4lZD5fnJaf6zT9/eVNlJa8uakbvTfzvEtKajFeHWw2aUJiNds0N5pFRV2PZ6MOukuhY8BOqgY856pHHYCblN30XDdaYs2tT8QhnXWJKqwYYqglY4czON+EEZk77FvNC30n/TihRTM3I3TNtv9fRrfq7QkELkmANMCYbERExL67DyeCGncuyGxjTItZEsZbUlkNmR1huQWF0W+jDflctprn6CEqVmd5klXlhwT3A68/X0u0+p5Ud23MoCq7lbaymM9KqGLAF9qGPGdgjCsAn+g7vI3mp44M4RROtwm32bsIdUJsXjiknnzEYwupcXjc28hA+vHrWajztZIYrijJUMGD9M7c9kv/d9l9aLP4kGPgtBzqkfOedUQJUm6imLpqVugkKcqKcNp1VKIG5OWL7pCkO3ZrPWt/pEdp8wJyB/ApypIbVFaX+Q+U/f7y7U9v3r58QR8xJTfX0puXLx7XaVb+GtNpjLIsr+jQf395V1WbX1+/LmmL5at1Ehd5md9Ur+J8/Tpa5a8xrp9fv3nzGq3Wr/nqLVojLD/9e4elLFej/DLMoXEXKkvehB/z1G//gQRm6JjkHN28kPHTb6/5ir8BPEna/v1lQkhKxZk+xUUzHjYnpwQK0V6+fEHYjhwB9qz3WomePdJsmsnuoyK+i4r/to4e/zuLryrE94KE3mZxWq/QaXaRYLTRpkN6TQ6aLLt2WnYhNbigQjF9G9kd3RCfE2Ccl0mVhqFYc/c1AKJPqIraixVlMISjTHCBcIajnXCV1p07zlGGFdVB+T1ZkaXNA1OD4Z95FmaMDbrvRbRpH96R9M0c18Vd/jCaA/dRHubECPKUyz6bFqPmLHHQ4ZB9sz3F2VNNtdaPHmFP3c7qfkjrv3zxKXr8iLLb6u73l3/76SdrpOOrVKZTajwL2BqqhAsCz3cG3jrMQPuwn0YSzKyD7sZw8HmkDxwlf6LelH4mMzrcHWEa4Q3TX0/xYvP4+8v/h1b69cXpf14J9LgisSV5na3+7QWVpV9fvHnx/1p3h33aNniH/ubSIfqw1fDmKs/7YXr2M+mZpyLrezpVJ98G66SzxJuLa8tHz0RKtXr3jctctDQ6qlPysIpGr1uj/5olf9ToAuXNe3Uq5LZ24Uka3Z6ucde7iFwl+l9+ssV/XqU+FmJAM595XM4dycQmTiPTzWW1c1QCHqydlTuP5aiv2evPnxyWn46ekxheHfKABthpSRL8nqX1bZJ5bPxOy8u8juVs77Et4uMLnwmnGnnEPD1sY4b75Rdr1P1+1A+x8VzLDyqf1Tx7z8tJgVDn5fdZaC6jx+NHtN54+aMwknbBam7lgeuViRLp8lr5eHQbYaD844HHTaR8lFyeps+E4RdfgkNr1j6ZUABnaxDzkPhXv2QfcnKx7daLzw/SNH94X6Oywuv3t7zyQuZmtUI+oaggR4GIZito8JDni6uEzKsdvY+zVSBMznsEKx1wkJUP/NH5zmoCMiB7LdDU2hIN8LleX6Piyw2RjdKHqSfe0vWRXu0RzvNgIPYVXzsmGmp6MdLpZhQaY7aVM9svHWw2RX7vtxCMk3fK9ZuZ+2f0RrwVMms2fWb82SSGbRqqqRctoShvEiLstvPQJwxRusisWa5NPRsWqSzmIRTek7xYR5XNAZEc10WUVqH7ebBaJ9lRvl4z5+Z+8S1lkD3Zwc1NkiaYy/1I578je4fo9eURCrn+dtDQ7Y6ve89lok2fsst+LPQxKiuzdeaNPfKgKwTp6cf8NslCmdQYH+UwrHsNUBr1Ebi7ZWc5CAhkBoTJCKFITLvuiBjM+2O8LINXS3d2VaahpEZbAFMmDYYMXIOdMJHD3igLE9jXXpV2sLK7il4ygtEjGsibxQ5OI666T0+OmCAxL4K28vQmJLK3QZD9M9mc5WUVpdAZr5tH6y7PULNNDoLvJHoMiM1j/TPf1EB5GnZWe04SuUD9jGW7tHo7LMsgRx8PefPCx2k5QcDD5V2BkDn+n23xYxFBRRJzuJ28rU06wcv8W+RlPS8Y+LCEs3acv+SvIvtO8bqBI/xD8cjpbYapd3RHrppNwiGsYfJMGGQ6S3HBten6ukD3SQQxqO/2exeiwQ7T/JbYhM+ERRc/fja7fWTmzDC5umVuN7V+Sq/4xu7YosV1xDrdXLTw57wKjXLImOG50mznQbTqGp5qsd66G3m+nQ0YtTvHNvEMSruzs2q2HQ1pwfd0psBdoJc16F0GgtUP47ekTDA0VvDJfbJqXyx1541JjOKLO/rQRFhJO8HQoXEGP+DqGKd9+dhvqsNFQnU4Qu0u9lp6ZHl0cb3Y0EYPQQwQ8jhfdntRrwNZH0HwdcgusZWZcoP17F8olL2/5yDeljszFz/q4CISZfVNFJNrUgVeYSrYpezbyvsqUW8ZHXCelu+Tm+ooKrz2jB0O//X5HP1RJwX6Ut2h4myUkdA1DwLFNyz12jNve5VTk61elcRk6T9Yrbgmvbp/Wr7LH7I0j/y29C0Ov6n5mqWNEHbovEb2qTt4+XIj4HOKeGyRHD9ukuYdxnfRkwyjkeOvRUhDBihCf+7+EJUXEUmxH2JWx5gcjjK5+j5nmXhgJJDs4LZAiLXdXMY1QnSJHkNFOp2juC4Kz3OcHsnRU5yiRm346TsW3xkqktxTTHuMdAmnaL0E65Sef/XvsPjoslD3iLCSpVnJorTD1vjV+700ipN1lJKEXfhXSTNvvfk73pWSi6h4mXToepAwudPyuPQiIZOzxY9JsMFCXI/ZPRYxjKw5VvLcHFV5/OMfddRu8D00ebMnovgO7qME101SBqeHUxvso9PqlWTBxvsxf2jG2sam+U0DtuGTmye6jz7Ji65/hwhvi3zQHkbxD5ocieTX84zyJFs0gu+0oSHeIvSbSy+Tgi5feGaSdb0OMTENvugxFD46cLRqUSUovCmK2ZwAH9ZPh3VV5bIr1qYiQ6C/J+VdmpSVP8JWllOE+RIr5pHPw8mLiu1tiiqJvXwxIwTBl44v6WraBtptxhE5U5uqjYsNxhOlzgMxOv5g2uiPQi6TdYhDDBZ3ezQSCHPnajrOKlSU3rzYaq8RVjQxA7UabtY28X7hMkGN7HrpfLx4orI6qKoiua4rdJSvr5OM7ngmZVbc/+4hgLJ9CMBnFN9Rcns3nfiOtynB0X9PVhNi/zAtbfpVKbTO6RGHVTihTgzCxIpMfN1mW24cgiNP7lHxRGbV3vUyru3jeOns0q9Zwp9jGvRjXNunH4dRidrl1dtR0OP6hKKyLhDpndJUts/g1TdxsGbjP0IvE30z5Me4KQeP5GGdrVLU5IYF3GK+RwEN+jNUnFZoHcJNM0JIyBAS38Vd3nh+sNaeIJyyW92fSfyENqrAJT9YRyN/v/jXkkxrjAfnea7ePzolYAtuOHRNuWuQHU5P0p5xlUd5vckz9lKA005ewBIqIrabJHp8TFdBP0Yd8JCl28Kvbn69Z5+TW4uURB7ZIjbilsBRLod5hS2w4DFS5KGR0ILSsV2YQKl9ONIo3DDMmc1ZQgNMHFIcdRV9DHwSrXaR/Il8RjAKziov8wu8fYwrHrPbYygNji/jU4RQ+XOoDX8eZbcan70DhwSMKQzrk9rCyK2d8FmEctBss+/jJqrT6luCHj653es2j2JvVNczMYba0RwmWTQkucVUu6Yf3FYuPIEEj0Yt2Us/ykny9ExnZf3sEnL4GT34SPBpeVlEWZnwcUYGS2EvB1cMEq8XKdSS5d0l/ZUw2xshz0ykwCscJkZRV9Hr9t10Ntk23NXszIl2t79+Pqkeu5E5uO77mr4zx5P2vE5R4OcLLzZocgdVm2YDvqttu+p04XwhkJ2jssJ2O7U92UzvUqxmjq8O6Zk0otxpqhjE0RNhhyYmLzTyjsKSjZIn9tbI96Lw8WNVROTl1SntSvYA7pmoNK1D7Bd7K/AoT/PiA3oEXwDxRd4uXs3zMIHP9yZeGFvZbw6kyGnUM+Ghha2p9oDPtRNcda+uBApkjqc8XZYfds1x8djQuTXBveMkxWzeh3x5eZQ+JCt0eVevrzMmU6ILovYW+PLerWfmfXJXyT2DNPzyTDT0MD5X/djU9VKOPWk9LwJ0aKh54YfrtMRKtTlPsBEgW/Z6ZqezC6/3knMxkwRffU2/BxfKE6zm6uGy7vyq15YD2avmey4MwYUsRe37MK79l+HGZ8iGk4SqBI9UYOi+j9UIG6uxj6/Q9m734iv24Qd/rQ0gvep3k8SUkP0O45ksUQtbSjBtG53gkH9Eic1vg0oUYbPv97xz0IRndUfn/tHpU9pkKoI+EwGAhxiK97bmHchFGOWZsMjOzEKrVC6j22dMecsNlC3xvkVFEmXg/e9nQtQJshVOkUdwngyIk97pd78lb4Ld+ZK8UToC5zvyz/ay7EFZJrcZlsBucz5Btp39HXDOf+n/gOfCO5zhVPk/12FezguWJozuab7U1ZcbipIOcoqHZFh+eCZr6BShUQq3ZpjYpS2Ki4JEvb0EMt1RK2/aPRNe9FVw3f89Xa4+RTSic9CAV+wse11u4Nty7nWoLTbJe4E/MXk4vZPCNsmafdYsZveRVUWeEkx+ZzJSMZ2BT94Gv3Hy3ER4kgvYAd0WXgduvmq6CRV+HhMtGaKzFgRpJSsMqceX41izB6HTvLj4o44KVJ7fXofuZ7N1Xf0LTxObmjx8Gjy6CZ+hIcdYt0mWmSAsrV9yxL7ThvxX2o9J9iPQQ1D2mzzz6yrdcwHPQ692w3lfJ31DdZb8UaOEorxJCD+GPBX/WvYPHXwtvAK9ATR+78u2+EJeCid2KGrycoWKuAdvgjshO37EfStDRQPtL5Mvc5m8z977TFTS0pEVymuTZgE78iuuJgHVo9ohvNE+YwmZfNqYpbEiKZ/RXb7n9DIxvUcWBhXJHRcGU5BwwO1M7/hXer95O971BU7U/5px2cbqmtiRRRalB3V1R1RkE810jmJMsGeiwrtF2X0591Thx2vmWqy31U9m65TZ4AVE27oVAmP/QnjrMv+BwkgIRXcQx6gswyHFf97jXXPhlTnGWOhO8qJen5GnZp6HhF3mmyS2F6+2mt/lx6WF2+hpRbM99NnBaoXXzvBZaXftEgKVD8odz0RA6IDsWbSttuMCQubR38XcJlJVm0UOESifG03s9bjnN9/3vT9GZUV64emFb7FIptwRG03u5LkT2k0N9JyUz/sirzeOGqitG/xWh//TGYE3X5/bVcdLlkMoFCJ7kFG1VyuTxOHtpnqiYvlMdNROqIfnxm4BvXjGnNsQ73kwLR0LfEXHzbNB8KlP85c7EFts/9Bmxm33xg75urj6fieMbeJX594ICHwOCWnNC9xWzffEcVghcLWJdwOianL4Bk7q3HHnUV0UKIufoHezHBE3CM+xkjE8fP27s1ReRo/tquS/w/4WSe4buiszvGmvsCykp1mc4q5OFss3auz4cZ7GLkljfSLzmUY4anSekba6YZ4Rto3NOjLckIWw2jc2UmNY8SdkbYjSE4Smpqm85akJLG95amq3+MMkZad8Mjkj+qQ4Nm+Fqo7JmsCWeo2tndXE7ySco4eoWJ3leIErv6MCYdbyCx05ukPxj7wewqtD7xqFBoJdiu2MAEmMkm2Qyc1NkibeifB6q38TZIw0hoZsY8h7FgXCeuQIz//YTnGadoyF1A4zEaRLwQxTYXyeqQ7LH2glI513T4/u798GQ3b8uEkKunP6lGdDnoeAeP8LRWHGzvLluwQrt+oduh4eWHe7R9KjOYjpevAhT1eB5kpEHpARGOSHUfYj2FaKwxtMxFi8p0ehUbbP7oRGe3odBVqQWg1NjYI2/i+MTNTY2CuSP5uXnUncfBSPk9pNgj4Yu8kaOEclc0ffUxttSB6V8MQREQfsNd539jZR+K6f1aRuiUK7U8+iJFQkb7dTbLYzYWjaoiR7FSyEm7pxGU7i65o6W+r2Hmiw24VztI6SjMlk6ZAP6UNEbkq1m9vPedXn/5vgqKTbFX4tsW3/IcHT9WxeTFj84UBa1b71tppfQJa7sBizzvvkhhr7z5B1uqHZT95Q02v+vpZo9T2p7hxZiKvu3ZXRo3LB3S1zMuszYdDOnGFm2emdIRkenwPDjtT+h0UTu/lOy66rNBle5JmioUOGt2abgBuGczzYDbkbHMxS6zGGuzNygTJiV4fqYYMuXPc+obJkEoJ7J6LqZoTaZp6u4RmUXy/Yz0T79eMJGseyoLl2tuyV9hD3wEkOSnoXfOrjxr6hyU8X5xjNLCOZ+jS02y816/XUJBu3NjXtJjuyC39U1+Wn8b5nfVp2qIIYRh8xi2dDVh+vJ8eJ1v8+bQpt+vSm46vmUtV+RC5ihuFRu2Uf2yjPJfHLggs0paKOHWwSuV3m3QnJthuPrHfzeXl5Fo86bojqFbxKMRxGaZQNWXiczLdy8qiakJuwsIcBrP/jytPbdmXjPDF/Bugu2dAj1OcheQtq8ssiin8k2W3AM0Aa8zatUUIP8lCok8buPYtA6OZYhToBeEZejH5ITvc7mpoBzqdEv/Hk3gML26Oqi4wkfkfPJo9JgOtSgSZucfsnhN/pHEVlnp3kRcMrYYz0luMQ3f8a7PddkJqGIFjdM+LywHk+hxPd3JCNTxh0B6t1kkkiwfi8Y9bZZ0aKIsStsG2JNrFYIHMa6nMUFc9qkfTXlmdR0RoOXp6nxi/kdszK1vU5WmUn2f94dXH9v/Cxx3SXJbB0ooLkqg+XG3ea1XPn1Jxw0eWZ6Dno6NzyQVZgY7qNTzDRrSyBb4U4BM7T8jJ6PH5EzEhd0GAkR3g6b/PiyTNwZb5npqwpZfvwo7toPqf3hYTBOSyaIopps125qIz9CzxhJdDC1RHXBbno1cZ9P6+jFn509tIjYggem72Vh2/jUT8Tdjh6ilM0fsTbaQYImjNUJLk8qMBs4ScefIrN6zTO9IWAiVZq0NEv3Mmx7UaWVEn0v9u7tt64cSX9VwbzuFicbGZxgMUiZwHbcSYGkonHdjLYfRGUbrotRC31SuokPsD+96WoGy/Fq0jdkpeZuFksVhU/8VqsSh1vbNjai3/SQCyOf3qXHzbypVEaAYtQgx4UGKw7ULDpU9QlQrL+dSOwbN4etjkzlIvYlw6LWO3K2CXQ43VWE1uMpcZdvJ3RBmvyDn1F6dhAcXlRmXqLGHGsMwl5fQNwMomi/5tDFP2A46PZc+YD8pUuESMVFQUqfPGb5azSKOdiUd87ZbtxJ7FNIsi3cSmEJOE29Z5cikh4X/rR/UbGIFolr+9DZl+7QAkerDc6o+N9T7HouS2I13k3ZG8EmOOvMt8U+dEdhmztkfk23MWg646LkxsoW4fHbDvlHYpH3my0e/jL5yZyjCdm/RvGpbuf9xHjNjIKOAd19hNb2sOJULALpPvdE9qfU/QQl1820tvanejfHXaiF/h7UO88/u6SvyvPrr+faogBHm/8ltyaPTm7EJiazBY1Pv6Paf8/PO3eDVr/A08Fd+csaquPyhiOsXX6kF0XxbhBvBXJNe24TCOHzWKdZYUcebvK0jMg/7rORkuDWfiX5aWjZc4kfaSH/SURiIaNt6/ypnyb7PfIIrAUdGOcH+pR4xYVO2o94eBh13GSnNSM1vYu//YJFfTwVuTfvna/SIb+JmxaPXL4Os9NN5X4tlFw3Lam4RHEn6HbatzlqYvLBlN71MLrBq/c0hCrpo/FT0BNCKj79HzwztTHXa9LgG7z8Fl1/ya7rXld+sAaVqFJkuYbFJixd55MILdxZxvWx1nGYHt4Qkf0KS6SmtVGkEZ0sulOo1SSlgOcCU8QIfy1ljXXcGAhnDcCkiATFnD9Nn4SLFPr63CAS+3cBl03jsXwWzo1qrftw7v8kN8muzoC9jJ8ud9Wx/Qy31Pz17j71eYGsnsc/geqvuXFF999c1skx7h4Jp9Ol8XM5QEQxGXkYyTC8vo71jI7IBIye6x8MDMLMc2d71vuP8pI6HCto0rCx/K2d28OmYavHS7e5TUDC6OY+5u8yYsj7jIqarkn9s6pXoHP8/w5TcqnOXz4vV58ARO0z1j0r/M6/vx1tsedOXYKtFuDvY/J09SNDEBLP4UItp6+jHdfbjLMf/dli85BHp6Tz/toeXYvpCku/d/H2fkxJkvt4gEd8Zi9mSOnIMPBp6TOFyImMxvNOPCjt+617c8+3m4ft8Pezy7ebhffoZRYtenpjfRwP12/9LJa+G0Ml9DDcJGX5T1K05896KcHzQdHOoP1VsxO6yRPMqeM+WX8qkcRld0yqJhxn/15Rme0J8lJLqoq3j1t6GE2pZv9BoOpPM6zG6sVH1B95EX3rFv0L8186nIV8CZx8SZpao3xcaOj0mNdPidZXDw7HfZrv0iXJ5Lv8RYQdvS0YuzyJW7k+7stkrwYGdOrfubh3ee4ZmpwKG/vF5x7F/UhDyHoHTqlz3bSWrANIfGVkHR6LMfL3c43S5M3PC4jdH0v6udW1OdR/z0eFh6KZGSUEczEy7vVZgmzc0ySytYeN92jbF8f+cVp2neaRw9JWtKNzBNgajx2mv27/TVmu83Urw1Y3qYuGd7lvc0Lmb+52c1biXvBUlnDRWdZaiNbuDBuvG7uy9T8MwHVfo0e43Na4cGNIBDXCvDdXcXHU5wctnJ3BH0Wjq6T8KTnxsxoppv+Vtv56t/8kqh5JvKjHSy7bMzwwq2ZBJs3pGJE97FxSxa/jPPhYa9YL031cfhaO4l8hqOsl8Dphp2xB16/eeT175a8jAeSP9C38h2qP9wNejzAynkNjCJZjBo9Rv1WpoJwzdYian012HeYI9dP4wcBv/tBwB3Ft9l+8+dk+h7F5blAbaqrjXwfuvnWJQBd2PB2dzUuQrubhrprbDH0Gn8uWbmhYfYnjCaF0c3xhDf/uM3HZDNvxIJg6E2e1lmAQ7AeOmWsn+z4p0RfktMYER7iL2hM/XppWte+yrPH5HAuYuhC2vFVTno+Zp1ztReOKcL7hdMoczeRerBEdawe+wUMXz/Ei5j752z3A/ikm1h7sER0+dxwGSz+r7/clB/JFuA/f3nA8HE5v8/PxQ6B75WtxWt4qcWjxy2Hh0Aqv/yx5nwpymuqKlB19BBN3vR9r8Lo+pu7rkDV8asl0sToAKqAEYmdbkbFtml43FeFt1GcMLzMc9lVgNGxHe6jwK7819/rhdprdErzLWWwaFeeTq9AHpV+QPMtFT2sw25K8k5vN4ZHc8LyP8moFcoAuPHrU6NrQpen0Ca3hA58DV7U2z+pr6rTQxFn5TEhAQLHWxXiOHYJ3myYbV3ozX0ljK5PXMxL2BvFs3UV3ce1RQ3Y5Ct6Tz2gdrx/trrBtpxrfh4KzHkoUH+G9b9azX2D2dyf3Ho0LvKvCbZKSI/1m7IdoVqIjrmM9HBoMt8uHsQNxouv1TH+sx5KfR3CdNhojndoL+yRGTLKc1rdZI+CW6kTuw+PjyUa5RBF7qXHMLiMq93TffLPUTP5Lf4ISVSnRdzV1wFAScxsuyWAm58pXvVeYHZj7yhtT/jM3yuhol2uNTEn6QCZLhMuzy8SZ2CwHt0uUEc/a4MNW+7kRBZeXvb3OtmJw1UPcqRap27GQ3TztOuq/rbcMpSyjIw7vWnQqb+BFi0nO57ByDR0gyqW3dzXDBNGqgFRl97KoW87Fqa92jbl1KtMW26fy9iepMW3k2CoGaInXyclmfy6EAsuXdnxMP5A27ac+pJpzM6SVNVxXyUtvyWchqohe/PW/YG2bWe2Ta21L2nxrU9o25oherLl3v7vIXa6nJT3jYocN+a2VprWlFIBOvmdZGgqh5wzx66FbSfO0WvgBcyey1/z3uZp+imvYyPOGmXfJNf2yI8MK3qRld9cQovRdUN0Qu3w2mVu3qr9W/0ekkqM8unoOdQwNMlmZxQyAHfCTYX4DJSG/spNzRDguEzzw48CDl99WdvsNi8dnv0ONQOuju7Q1wR9e4vS0+M5zRw3oqvoWEZh58VNV32UKH/FZWvxEAeHtKBb7825YoP6mzuafvI23NSu5sPNjpO3QIPM/0blA7Zi6oHVH7klJxnWL8oy3yWkZ7trFBKqu3H2ukMl8UuLuvw8HPivs/0v9fJ1SODTSXSP0se/DT++P6dVckqTHRbhH7++/JX/ZD5kTW7PXy7IvVd9mlHu4r1oDqzGXioDIDkrD0jAyvYvQpMkFXzz0Pwqz8qqiLG5xW8+yXbJKU55e3CEhsNDrWnPki95jU4oq6/kVXqbtEtnXRLb75vhekBnj1cvKFAZYC35J4m+SGRbEdBosUWUsaXbgBij0yrwJdxy0XvuMroHPhWqm/naTC+LhZNAT3mHqZKPJQwCSMEkEwDT/E5X0r7ZJe4CwPoQFwfEbxIHYEiBoOr4HxCk1gCZG6Cak9KpwJmn6Tom51pSFmTkh9VPwUSNdcy6/YFqJApt21MBUdLIKEjQ/RxmjjTtRQ9oaRUxmgUx+Wx44bxT8BYGb2V2FWqddBL9So3lwPQoXzQJumBfI7lYPUUQzHEmmAB9Br5WkoZNnKsWgkndggzodUk//xAotEHBbPCTe+lNhbsqrhDx2M52KIK9FBeFMVpeFltsyeoxxahjgaXZoNS56HkE0b/97W8vhZ4bOHWOlzSn/re1AwD0Kl141ytAO/4bXhwY7D/RCSHBCDcbMHrXp/4piG5p3dUAz5QmmmR4x25IlMDjTKfwBKhSurFLmlS7382ELM0C2WKA2CyubPp4BljJnzdMjarLJK3fasJPO5wwpZm+rMa99aLBqC3W+POjgQQGyqoIVmKhk1crNChKX7aZyavTyGbymg1XnVvgOi44OmkZGYYfV3/R0ati0tb8lx3tk5iEJHyO2v/L7zzacubSofttmpsPRmBWEK4ozA0IZKEwSOL0MWmxpV0MnMAnc0JnQr34o8AJstBy4DT41M6zYupednocl3QL5+7NLrPQ6X9c+5gCP0mWdf/Mo0n/HvXihE1e5+xoxTe4U+3qMv04/DjJ4CK8A4dkCYytXuUJwKV+9y5pU/02enaY6a5JbYaLDcPMqsvngJkiPsJsMGun11WNZdCSTSjbzEhmszxb4kDWI0wzjM2/EJ8fXxMuxV3gpYw7MSm6un/cof89JwWqH8fKj7SXNHZRAoPiMOWbGcNorWzGsbkPESLc88lXVDw/1CHRpX1LEzGdyhRY7QEtRkNfuJCqGgYbVvMaJdvcmLg8Z/sU1fEMLqqqSD6fK9QEL42GEt0kR1ECHUyXTnkCJdVMLaRAHHJqlNk4KEbluprIMNReDnRbrK7mcNT1g1nfuswN50x3LghmXgGmnS1/okTd6ELw0Z+DSIJTLutoixMaQtaGDrZ4jWzOtRaDq9VMazOCavrByu7eZ+ahqs6p/hiTu6diwqs/ulmGHVuw9itARhsjOCzDqYBBhVyJsR0adtCRigSWB4Gadf/7GYGsm6UrLAp7q5nhFgC26Wc6++FtGQvz+xPaJY/JjhT1Rx3rARssPySXjHIjAJSotwYowqJ/ONV/RiZ60c/y9HgwA0Kop78KXQ2k7AjDPAV0h9DYd8IqZU3ahxksdHA11zY0cH7IsXk02GYfsFUazI15KvuCPlbgUlYRg8ygLzZVupHVAqWSxQphxkhqALjMnIskfQp05o8AMdMOnxNlcNKaaYH2KS6SOKv6sfUqP35OMkI4u4OIQjYIWkryLbmVqBQ1kWJJHicq/K1mb754oE4/747F6NxbdQN4/nmOSdD8j1kixyhDRGOBLdjk8Cg30KKhR4u9NPytd0w0geRmR781D3kd5PRHkgIh0OVTH0MuFo2THjt6gOVizhp5JT7F6bkHqVrDMLiYFrlEXRMxW8KQGHbCUxgoN9pa4JlnMDesZ19OTvgcY6aF4epWf9F9fDyl6HX+LUvzmM/PSp3BdATM+Uv/48LRAKs3PxJY48+GhYcEFVi/Ot6zPAsz5VbskumFYCLILNZLz8hC/bqJNC6DPiaN0dItAFbL31LOA6IJt412+Jl7o9jlPF5HQLxOWkaG4cfVB8TrVTFpa/aAeH3IVqtce4uK1KmbYCdMUzZJSCtILZtpbv6IsOvNlbdE0E21qBoNvLrCfOC7/l6hIovTi3P1VHNsnJi45I2LHvFUGjByqQlXPwIq1bMB5GxYfJMX5yOJYewbePKDhL5NhhP16+pxMeiyHhA85KdkNzUKSKMiDNqft4GDRpn1ACEi//29yM8nKQooEqHz2p8nmYhIg6IIgaAjM0xA8Bg1NMi1hCEEkNu+x0LiZYZBx7wvpx1xCPkCFh8yscd0XUgITb56sezXSdcvRKzZQPSh2AfJ86Nau5A2GSbtL2tP79OoYdIQa/CZe38Vm+ZpQTPlMtccNbOvcLsYmx/L+IDeJlia4jmCg4MuNJYqLTkoD0uwmWiqjFom7c4eThXEGvCt2I8RPwDEzMeUufBFJJx34iN3rUtGVC+lKEHAS9bJsDMosibALN+tYx7YTOjWYQecud06fk8eq6u42Ee352L3FJdo/1dSPUl0cO9Gjf9hJwXDbPgx3EgyVdzlXhcjTIBdMTtEmLUOrJBrlwYaayDJQXkmWPRYIcAT2qzXPV3FZWHtI/0pLHQ1tCSoTbZGcsYZ06PzLpv+yCu0/HV2LaUoQfPrujE0KLL8dfYd+obRfptjBmU3OK3ifBIQnBEHLF/92SWk1SpOMiGceZ0ENcvx5cBlsmHIFStMt8znd3j/lJzqZFSLnsk6IdmAfv2P6wZQr8fyp7FOVHJiBMvt2muBkSMcOLAFYQIq2nSsJxAZH0v0Fea9pK3FOPm9o9dMUT+v6X/ljD7jaqU6F1mdEREF8DUOtB6mROaWNkzJBtbAtD6rWP32D3imH1WssLm+scUKeJz151zb5kSQq7ioqFR/IdNSamDCS8QtSfjC7aSPFHQzaXMB6SIFCK1illoCzKacq5zQNft0JWBr+XfwSwDWhDfyTria+2L+6gntvuRnPuSZ8LN8BBMomaFMLJ3mbTOollq0kEHNNPYMA0iJhkbDHV91xm3f7lxgjQ+38TM5erzJkpqvpxNI1ek02zC3f+ML132sKOhj1CbVE4vBR3eRodbIVz8HOzgAlVKKFvaGxA0gfkFpc2HC150NnzUMvuKeeJcfIurfdUfKTxo4OubEgS+bBJBUqzJpQp1bqGwWBne0UibNcSIuAmqr2HnOh6op95u2cJp9q+kfP+FiQPLQ2QZkVgMV8sz3/vy53BVJk2py4vAfdNvic2q2dPWwEHVaBUiwfl/jCr1HZe3AGb0p8uN0KGEb507D2KLV44NTyKRFujOWApCH/Cc8FgKPoSvmW9U+PiYp/gVFE4Vm6BtkGQ2/rv1+dlDFaHczs9/HxS7lAhvWWmhHBkI0c4TNXnRud5NOEr5QNFMgOPX62KxG6rrzXaZVeVEHJ0+OcfF8/X33FGcHdIe/iKtzgZvYPSvg1RKw0Op+NB9liAjsjVjzSyBMQHqFwUOjh0lDig5YBjTIHz8xMQMmGMvPBobLePflJsOy7L4E3eQGmX0kwjMiSWlWv9iVabaKHbMMd8v3+Vge6Cb0ABmDubkdQf48ozPaXx/jJL2oqnj3RC7b3ySKpbZ9aqggkAMl5xKYgRSrzzgF62V07JPMuPqmxI4a4Xfq4GkMERMcnimYZICjhJdhLBCy5KYKji6j5mj5loAtahiTqjKuY3+IAc0WBrONaVTN2eB3czzlRYVle8QDbHS/e0L7c4oe4vKL/OEjTcTs/ZgC810kIwPDkSsJ845RqnMYvLA6mTTYSphkh1rGGXO4zA8VRgYu7cr2oMLqtDqo4IbSvPGBBXUY36/Bcv2w4gMC0YVhFk/Wfe8FbJRehpvAxzlX5rd5mn7KK4z39sql7qiBKbm67w+/8O9VDcaHPOLrac/F2rpwurGuzOIWl2+fOQARCg1e4Y063+o0mABmastbtTkHvuofLrLym+IolSLhe7X7eZJRbBTGfJ1lScy1IGwNIs6aQ/YqP5KZ0nAAo6pMPXbRTfNpZPvfNzRiSU1t1dzEMIIT4bpmAg6YjdgSSZ7GJas8wRPjp5NtvsucND9YDkdUlamHI7pp5tKG/n1Dw5HU1FbNTQyj+t9iciWuF4UMU8OP01wF2iPJ03AEm2cZ+Olkm9HZllw03qGvCfr2FqWnx3Oa1ZFXTPd6kvqT7/lkcgCX3wDRhoYwsx6xantOHDIFOleHlkra57Mhyq/3AmSMBYKJqbwMZDkNa7OOZeZg3s6otaKhagVOWI5wWp/DlT2GpnWzusZ1quf6o8I1UNG5F+Z79CYpyup1XMWf41K8x6lr3aOqf4RDctM2P1Od2f5eX1Id43/8uv+c476OP6dDFWHA4RjH36/iCh1I2AiRPV0KNkITaJrC/6oPEoFm+hKoib5Qw/5dvovT5J9o3/U40BBAAzUJkOkaj7PDmTwRE9vsi8Cm+lIT9dB9VZCz2DI/FzuwNZBMqqRAqZHiFhXHpCwxxrtDbkECkQRqXaTStMy+3RFaZYuhFlkKnZ55mkK6kZ9BfUiJAdfuwgLk3RXKWujKDW3VL0Ok5uopVBbriQybVbSnbkjbQv+UT2igL4H494U6BWq/NXAg7EtA8btC3QDYxjl9j6qnHPp0eAJwOORodG1WeHjGw9hXPJ1C3w1XDrbIkmgaHE6YhLaGIqiZoVT3FXULKfET6krA76cr1LAfMvIK/IciqIGhVAcz+YSrnm2Np9rbZFedC6i/+xLQRF2hWQ8oWuEIFP0RtUTR+5jg2rh/6kjTSYGO8AAHUql6jSHUiYDS5Csqnh+SI6Q9Www2ylCYWZuOISwzOE2jsDlNZtt4Hw7wTZJW8ESmrWIkmlDLTFLFxyVQqGDZURnjsq34Ps7OjzGBtMI4LJVKDprSWBaNEPrWWQozze9PaJc8JjuyBaKifcpsIKNXWQOuY2wXuPqH9u2RODkqycG5UlnDSTpjuWwkMu3Thxjar9GFit4i5WbtfIqLJM6GWKNX+fFzksWSfjGppJBLWU8j75/nmPzyMUugaYcthmRgKdysY24SzdTb/N/+O+IrygUyk8Qal7yebeBeU7O05BYYaWvoFgb9yzdxUdAXgQuCvlR3XpOg4rZIwLU8VQae1QzFmkYGpxWhjaEIaqIu1XK//o6n8yxOL87VU32i1gxN0vMENTkkhbqGRjoSYEuygaHKoHZJcRkZbWIIrexUjy5UNGR2wkeIZY0o+bcUJvx/L/LzSdZIW6hoqaXQtNTGbxYaaX+H+LdFhlsKNmOudE/Bkqk2FSylRgo4b68gBUwGSQFTGkqhaFndmlk3SoYXqkzanUb7FiprLdxIUyZtpCnWNAJmpxSaA6mghkFCgzMlyRZ4KJKdIxltdtnEd9JW5J3GUmhNymTFAozJlMNmZEi06vFJKAAVeRJYTZ5KdwwkJkYQz4NEGvBgSCSzbVy2gpIRGolhtmqShjEHel9CCeNAQmwpjoEcZgLoj7fpoMfiETddCh5z0wTmTTUxxFXNNRSaJhsi7S0WpJlUIxNNgCiv8DKEpVGsRlhC7YaEDREJbEFYAtXKkSPV9eEQj1DsvaEM7LehWDc+Mu9KxbGRKQbHRYZCC8tUuhGgymAopoZL/I+FvBGqDGqEKtato1CG8GZLNbiLJOC6SqDSbRExD0T2r5/Bq1KuHNwqsiTaO6YcvAVof4fvlHKDe4YhgJo4LfVF8IViV2oien/qAWvQF0sVMT02kUY9EhqWUoI3ZzJii1PiB3Q8pfBQApPpTo0HSsPbMIUEIonqdsy45e6YUt6wQKE67TRt9g7VZHv5NSZPAK8tWBqdkYu8LDHzVN6qSAIaWaDSGblZ+0jvvLly0MAsifaEFgyMAhzVgnTwmS1Iai6Iunlto/ojNSYIkniExhSDR2YMhfaLPZ7i5ACNW0MR/IV2pbqRqVkBqQYlngIcj3gig3PPd6iqUKEZnmWEsjNRiFZrgrjE4+hfKDk8QX3KlcPqMyRmDb5OMLhLWG2RRNEsRaVpmYtJIzTLlUNtciS6Wf852ykmfboUnPNpAu1hNx/bAjjg5kngQ22eyqhluVW5cnmbplblXfo0HntqchOfwagmNb/7ZRyn5K5eEjq9L9YdKvESnfhsG7iatdrKPdoECpXnXEuE9A13R9MKPwmRRHXGHV2cTmmC9g95S59YSCFfjggUZjK05HoJOhclg3tuw+vuaKAzBmXvYmnm3Wru5cpEyje/1xViWIg2EUhkzqoslcHU278IBefbvlQ2yfYEBh6K8qaYUpmfomlT8pdiMqwBpArIAdQ2EunEMGhbaJB6BqF2Xo8G13eqjsKNfajAv9qgcoFxfvhYBLmPPVtT4V/fcDHxl3/Bqm9qGvqtgd4uMHUwo0BvKgaLKJ9J2JtDmOPpcayM7luzi5YxqyhXVfaygWiqe62g5ASN7SBX5QsF76Z8iIsDqhxM2VaUG0CqsErBZZoQT2PK75ElCPEJ0i9RGpWhlyZuqjXPSaKGI6wcTTJSSKEG+xSmryd55GKvIrs8j7r1OWoX9YlyPDGvLFcSfvBBFFU/41Bw4TYuADPZc5QgBpSPIuaVFSMJoKxEvaWYjH4sE/V8AfOAhAFMAT0AakygfNdjr3q7B1UpzZP4V5fbT5N6sudf7ipyppMryhJ676UJVe83lv1Rg2LwlBPrVw3gikGpuOQshWEQ1BDyQVBO7KUfl2CGyyStoyP3nBVG4EjDmcAIQyOU7oKGDKzlWgu0IT8B7sUvw0D2jNfeDN1TTeXSWCQKsTzmn5uSmtKnpA7LZOYlY9S/aARWyzClYgnMPp9s1r/wC0y2Hvj6sqnOFXlXvzuM1asPRwAR1YDkX4z6/SNARb8LNP57nD+rbz5r2WNgezVVR/mKWd6kmlwp/p01UUr2hhqsCZpFLAxrHvncb1LNU58vzDzdJYwVdvhKIZEDjT1CWUjD2KCGr+R/SJ3JLMDTe3D9qK4QEidAjAGGiSpogPNkG7HRAaRTLUunUAaIVtBooYhC4Iord7WlL/8jOlyB1BpG1bUqikEWaGXlcRPUvCQxE2DWurgHHgzcmkS/mpNWCbasc+0AL2axMsgGTdEvZYfVgdQSIm2ItYwkqAdtCI8rGV41PR4E0mBomMgETLgRxa4HpPO/84ECmZDKygAlzj3PBVuhm5BCQF7Hs1oQKqSMwPIgZtJ/JCB5sA9lHpNIAtPojaOpGMxM6mAzNDfDCDIOd2WKYDmSSD/gTZoDG8VNjN4uZgYx4MoGHlLwlgQQ8o1WdeO2EFZym9hUC/0CRM9RpYuTnDrcMavgH8uctFKlQYyhcFKSU2uVkmgDqLEMkygCVpkeFhizmOAcwSDYF21Rm3BdQUysn8RNagf7RNdmTjYCmpNNGRZyA0HB2ogpVEHY1mpiB5hOj00Ta4U3kXI5aVxXq7xSa7N14yLNSKK6RNJmjU2q5jOJUUz4MpFxVMzhaDfuCyHDgXLy0TDsPUB0Hx9PKRoiIsoV5ygVSxcuLmOzbJHEXJxQ5T4kY8Q6rosqSyj1HkHuTvhCqElSXR5Fcoz6irlLJPI/W4VXtYubqXSZEonkIru7TPHRPUnN4Ud/noGmT3fUFfQQH+Eup/tIPL8nkWhq4D86+ROcuUykCt6q9Lc0qxgCTSYBbQk3q8C09qbrw9Mq7QRQhTCKEEeXVKV+9aMuiYGr15cjC6YwE9F30BiO1OuockQH1ZXoS9NoRGZC9w4igyF5xdpiRb8927JUdmtDM1rQeXqTfIk0W9UXS9F5FH3i75bE1zV4NgDSyQV3fTPARJUmteCg0a6KqsYmjiLEsBROPSjIdTS418n9+OAKit3baD8+KKQ2w0UZItuTaVq7G9qloR7dr4swRx+2W24DnsSv4kLI8aGep03PIL9iKysS+d/Khle1C/Qe3eL92VNcov1fSfVEtSAqrqviTR2mLh/KnlSVhql3NwTz3Q785WaAK3hSBKwp/eKNcgR4Ms1Hut+N7cPW8jsuzGWePsWAZkCkSAIMiHR6hKEemPnAXkUgmYFyKaSkD7EwUiRvIExMsjH4MYv2u9BX8ouOeUzT5YmQfxMchV+l+Uwa912YCE+vO+g0GNHAV64lS+hJcLCmML8qU3a4boS6kBvaLR9PuKY9H5N8RDPggZRhhjogqUr7JatypYw44DbobCmt//4OHReAz/2iebKkItfuCLw8UZJlvWm/fk0mGw8GUn0ZcuIQH8fsplBsGKW0/veNU5sBzhUUAZmMgJHDtK4CL7LkSw1wdPmU1LxEjxHDzEgu8w2bYyi6yZIqiVPFWlJVwfc6Es6k1E49muxI443RrZXFpvR2kdYNpK6SE7wIN0tv5RDlakjqFAkJnkTLqcgVUzmcgKqZ0tVZpWR8ZDw8m0Q1dYF0IWatadTWqRtcTV49P2oJ6cD0F8gwdbB7ZCj/xHARp0wk4eJ4R6cdi94U+VFlDxV5CIPAGdbahY0yYdpoUzzkFoagiNduhj49XKTYv4lE/jduQoq7pqY0e53LyJ4CUY7hsR2k1Pe1uxOWkA6vHeNlSehc4pXmJFpXcoyL5+vvu6c4O6A7bNohhRqwLdFWUhmFzenWGgTO18buUOg0c822BMwiN9II5A9j7VnqdaktyRunnAy1dUIMfZq8eYSRaRI8f2ZS7Nt1Vfxv3+c1EZggLXqTwAOpglrhu+Dswq9MCHffPIAwye82yiwRm2FNaRSWVq4YlPWN6KPK5iYzjcwgwdDBtGEKErqSV7UWghgmj1nEps4VbaSgVswnQELfZlpRJOplOID52ggLdRo2F2dwG3MoqEOaA0y01nyHyvxpruYYcsBFPWuZMQBa74oAPMR8dxQbRQ47tzQWdKKpqD4wusqzsiripJ5V8O60X5x0oZgf8khMUAXs73zx1q+JHOI2s8sGSeKuZv2gS8blwex04g4DS1LkaqWscoTMahIqBZkpUJisZaLVRnIMjzogadt995hMliJtnGGHZ2pqc/V0auGNn8HNoDaVZ86095nUdMCuZBzH8HgCMvM1GxdFyr1xhh0ixavN1dOphTeORD+D2u0uUkgZaDyrSeorHmj7b2uCmVSqprgj16df9NhNTIGV0dmahqrL9V2P+ZzgpjWtG9eJkWvefaONrI87wxH6P/3yr/qrFw2T2vC4l1HRl7160SRFbX/Af1Z5ER/Q+3yP0pL8+urF3RnXPqLmr9eoTA4Di1eYZ4ZInuiBaUdzkz3WAd9JOk1Ooo6kK+7ztlfxPq7ii6JK6riWuHiHvyWS7pd4mdTnQZ/R/ib7cK5O5wqrjI6fU+bQ+dULdfuvXggyv2oC7ZU+VMBiJlgF9CG7PCfpvpf7TZyW3HZTxuIKW/93hH9v+hJ/mhU6PPec/sgzQ0at+fAmFWV7/Mk9oOMpxczKD9l9/BW5yPaxRO/QId4939ZpvIjTjIyJviNYs796ncSHIj6WLY+hPv4TY3h//P5f/w+t09y6EK8IAA== + + + dbo + + \ No newline at end of file diff --git a/src/Libraries/SmartStore.Data/SmartStore.Data.csproj b/src/Libraries/SmartStore.Data/SmartStore.Data.csproj index aee5f01421..8272d36d87 100644 --- a/src/Libraries/SmartStore.Data/SmartStore.Data.csproj +++ b/src/Libraries/SmartStore.Data/SmartStore.Data.csproj @@ -372,9 +372,9 @@ 201511271019577_ExportFramework3.cs - - - 201512091408315_ImportFramework.cs + + + 201512101150534_ImportFramework.cs @@ -699,8 +699,8 @@ 201511271019577_ExportFramework3.cs - - 201512091408315_ImportFramework.cs + + 201512101150534_ImportFramework.cs diff --git a/src/Libraries/SmartStore.Services/DataExchange/Import/IImportProfileService.cs b/src/Libraries/SmartStore.Services/DataExchange/Import/IImportProfileService.cs index 85d6f64dec..366cb9d5bb 100644 --- a/src/Libraries/SmartStore.Services/DataExchange/Import/IImportProfileService.cs +++ b/src/Libraries/SmartStore.Services/DataExchange/Import/IImportProfileService.cs @@ -1,5 +1,6 @@ using System.Linq; using SmartStore.Core.Domain; +using SmartStore.Core.Domain.DataExchange; namespace SmartStore.Services.DataExchange.Import { @@ -11,7 +12,7 @@ public interface IImportProfileService /// Profile name /// /// Inserted import profile - ImportProfile InsertImportProfile(string name, string entityType); + ImportProfile InsertImportProfile(string name, ImportEntityType entityType); /// /// Updates an import profile diff --git a/src/Libraries/SmartStore.Services/DataExchange/Import/ImportProfileService.cs b/src/Libraries/SmartStore.Services/DataExchange/Import/ImportProfileService.cs index 76f7a0b083..21bbb22823 100644 --- a/src/Libraries/SmartStore.Services/DataExchange/Import/ImportProfileService.cs +++ b/src/Libraries/SmartStore.Services/DataExchange/Import/ImportProfileService.cs @@ -29,10 +29,9 @@ public ImportProfileService( _dataExchangeSettings = dataExchangeSettings; } - public virtual ImportProfile InsertImportProfile(string name, string entityType) + public virtual ImportProfile InsertImportProfile(string name, ImportEntityType entityType) { Guard.ArgumentNotEmpty(() => name); - Guard.ArgumentNotEmpty(() => entityType); var task = new ScheduleTask { diff --git a/src/Presentation/SmartStore.Web/Administration/Controllers/ImportController.cs b/src/Presentation/SmartStore.Web/Administration/Controllers/ImportController.cs index 2c5040e624..4cf43afe3f 100644 --- a/src/Presentation/SmartStore.Web/Administration/Controllers/ImportController.cs +++ b/src/Presentation/SmartStore.Web/Administration/Controllers/ImportController.cs @@ -6,12 +6,16 @@ using SmartStore.Admin.Extensions; using SmartStore.Admin.Models.DataExchange; using SmartStore.Core.Domain; +using SmartStore.Core.Domain.DataExchange; using SmartStore.Core.IO; using SmartStore.Services; using SmartStore.Services.DataExchange.Import; using SmartStore.Services.Helpers; +using SmartStore.Services.Localization; using SmartStore.Services.Security; using SmartStore.Services.Tasks; +using SmartStore.Utilities; +using SmartStore.Web.Framework; using SmartStore.Web.Framework.Controllers; using SmartStore.Web.Framework.Filters; using SmartStore.Web.Framework.Security; @@ -42,20 +46,32 @@ public ImportController( private void PrepareProfileModel(ImportProfileModel model, ImportProfile profile, bool forEdit) { - model.Id = profile.Id; - model.Name = profile.Name; - model.FolderName = profile.FolderName; - model.FileNames = profile.GetImportFiles(); - model.EntityType = profile.EntityType; - model.Enabled = profile.Enabled; - model.Skip = profile.Skip; - model.Take = profile.Take; - model.Cleanup = profile.Cleanup; - model.ScheduleTaskId = profile.SchedulingTaskId; - model.ScheduleTaskName = profile.ScheduleTask.Name.NaIfEmpty(); - model.IsTaskRunning = profile.ScheduleTask.IsRunning; - model.IsTaskEnabled = profile.ScheduleTask.Enabled; - model.LogFileExists = System.IO.File.Exists(profile.GetImportLogPath()); + if (profile != null) + { + model.Id = profile.Id; + model.Name = profile.Name; + model.FolderName = profile.FolderName; + model.EntityType = profile.EntityType; + model.Enabled = profile.Enabled; + model.Skip = profile.Skip; + model.Take = profile.Take; + model.Cleanup = profile.Cleanup; + model.ScheduleTaskId = profile.SchedulingTaskId; + model.ScheduleTaskName = profile.ScheduleTask.Name.NaIfEmpty(); + model.IsTaskRunning = profile.ScheduleTask.IsRunning; + model.IsTaskEnabled = profile.ScheduleTask.Enabled; + model.LogFileExists = System.IO.File.Exists(profile.GetImportLogPath()); + model.EntityTypeName = profile.EntityType.GetLocalizedEnum(_services.Localization, _services.WorkContext); + + model.ExistingFileNames = profile.GetImportFiles() + .Select(x => Path.GetFileName(x)) + .ToList(); + } + + if (forEdit) + { + model.AvailableEntityTypes = ImportEntityType.Product.ToSelectList(false).ToList(); + } } #endregion @@ -87,6 +103,46 @@ public ActionResult List() return View(model); } + public ActionResult Create() + { + if (!_services.Permissions.Authorize(StandardPermissionProvider.ManageImports)) + return AccessDeniedView(); + + var model = new ImportProfileModel(); + PrepareProfileModel(model, null, true); + + return View(model); + } + + [HttpPost, ParameterBasedOnFormName("save-continue", "continueEditing"), FormValueRequired("save", "save-continue")] + public ActionResult Create(ImportProfileModel model, ImportEntityType entityType) + { + if (!_services.Permissions.Authorize(StandardPermissionProvider.ManageImports)) + return AccessDeniedView(); + + if (!System.IO.File.Exists(model.TempImportFile)) + { + ModelState.AddModelError("ImportFiles", T("Admin.DataExchange.Import.MissingImportFile")); + } + else if (ModelState.IsValid) + { + var profile = _importService.InsertImportProfile(model.Name, model.EntityType); + + if (profile != null && profile.Id != 0) + { + var folder = profile.GetImportFolder(true, true); + var destPath = Path.Combine(folder, Path.GetFileName(model.TempImportFile)); + + FileSystemHelper.Copy(model.TempImportFile, destPath, true, true); + + return RedirectToAction("Edit", new { id = profile.Id }); + } + } + + PrepareProfileModel(model, null, true); + return View(model); + } + public ActionResult Edit(int id) { if (!_services.Permissions.Authorize(StandardPermissionProvider.ManageImports)) @@ -158,6 +214,44 @@ public ActionResult DeleteConfirmed(int id) return RedirectToAction("Edit", new { id = profile.Id }); } + [HttpPost] + public JsonResult FileUpload(int id) + { + var success = false; + string error = null; + string tempFile = null; + + if (_services.Permissions.Authorize(StandardPermissionProvider.ManageImports)) + { + var postedFile = Request.ToPostedFileResult(); + if (postedFile != null) + { + if (id == 0) + { + tempFile = Path.Combine(FileSystemHelper.TempDir(), postedFile.FileName); + FileSystemHelper.Delete(tempFile); + } + else + { + } + + success = postedFile.Stream.ToFile(tempFile); + + if (!success) + error = T("Admin.Common.UploadFileFailed"); + } + } + else + { + error = T("Admin.AccessDenied.Description"); + } + + if (error.HasValue()) + NotifyError(error, true); + + return Json(new { success = success, tempFile = tempFile }); + } + [HttpPost] public ActionResult Execute(int id) { diff --git a/src/Presentation/SmartStore.Web/Administration/Models/DataExchange/ImportProfileModel.cs b/src/Presentation/SmartStore.Web/Administration/Models/DataExchange/ImportProfileModel.cs index a1a663f693..77bb5f64ea 100644 --- a/src/Presentation/SmartStore.Web/Administration/Models/DataExchange/ImportProfileModel.cs +++ b/src/Presentation/SmartStore.Web/Administration/Models/DataExchange/ImportProfileModel.cs @@ -1,7 +1,9 @@ using System.Collections.Generic; +using System.Web.Mvc; using FluentValidation.Attributes; using SmartStore.Admin.Models.Tasks; using SmartStore.Admin.Validators.DataExchange; +using SmartStore.Core.Domain.DataExchange; using SmartStore.Web.Framework; using SmartStore.Web.Framework.Modelling; @@ -10,17 +12,18 @@ namespace SmartStore.Admin.Models.DataExchange [Validator(typeof(ImportProfileValidator))] public partial class ImportProfileModel : EntityModelBase { + [SmartResourceDisplayName("Admin.Common.ImportFiles")] + public List ExistingFileNames { get; set; } + [SmartResourceDisplayName("Admin.DataExchange.Import.Name")] public string Name { get; set; } [SmartResourceDisplayName("Admin.DataExchange.Import.FolderName")] public string FolderName { get; set; } - [SmartResourceDisplayName("Common.Files")] - public List FileNames { get; set; } - [SmartResourceDisplayName("Admin.Common.Entity")] - public string EntityType { get; set; } + public ImportEntityType EntityType { get; set; } + public List AvailableEntityTypes { get; set; } [SmartResourceDisplayName("Common.Enabled")] public bool Enabled { get; set; } @@ -42,5 +45,7 @@ public partial class ImportProfileModel : EntityModelBase public ScheduleTaskModel TaskModel { get; set; } public bool LogFileExists { get; set; } + public string TempImportFile { get; set; } + public string EntityTypeName { get; set; } } } \ No newline at end of file diff --git a/src/Presentation/SmartStore.Web/Administration/SmartStore.Admin.csproj b/src/Presentation/SmartStore.Web/Administration/SmartStore.Admin.csproj index 7bc7cfc138..1cb806ab59 100644 --- a/src/Presentation/SmartStore.Web/Administration/SmartStore.Admin.csproj +++ b/src/Presentation/SmartStore.Web/Administration/SmartStore.Admin.csproj @@ -537,6 +537,8 @@ + + diff --git a/src/Presentation/SmartStore.Web/Administration/Validators/DataExchange/ImportProfileValidator.cs b/src/Presentation/SmartStore.Web/Administration/Validators/DataExchange/ImportProfileValidator.cs index 3760f5bae1..044d217456 100644 --- a/src/Presentation/SmartStore.Web/Administration/Validators/DataExchange/ImportProfileValidator.cs +++ b/src/Presentation/SmartStore.Web/Administration/Validators/DataExchange/ImportProfileValidator.cs @@ -1,6 +1,4 @@ -using System.IO; -using System.Linq; -using FluentValidation; +using FluentValidation; using SmartStore.Admin.Models.DataExchange; using SmartStore.Services.Localization; @@ -13,10 +11,6 @@ public ImportProfileValidator(ILocalizationService localization) RuleFor(x => x.Name) .NotEmpty() .WithMessage(localization.GetResource("Admin.Validation.Name")); - - RuleFor(x => x.FolderName) - .Must(x => x.HasValue() && !x.IsCaseInsensitiveEqual("con") && !Path.GetInvalidFileNameChars().Any(y => x.Contains(y))) - .WithMessage(localization.GetResource("Admin.DataExchange.Import.FolderName.Validate")); } } } \ No newline at end of file diff --git a/src/Presentation/SmartStore.Web/Administration/Views/Import/Create.cshtml b/src/Presentation/SmartStore.Web/Administration/Views/Import/Create.cshtml new file mode 100644 index 0000000000..57aaf80b7a --- /dev/null +++ b/src/Presentation/SmartStore.Web/Administration/Views/Import/Create.cshtml @@ -0,0 +1,24 @@ +@using SmartStore.Admin.Models.DataExchange; +@model ImportProfileModel +@{ + var title = string.Concat(T("Admin.Common.AddNew"), " ", T("Common.Profile")); + ViewBag.Title = title; +} + +@using (Html.BeginForm()) +{ +
    +
    +
    + + @title - @Model.Name @Html.ActionLink("(" + T("Admin.Common.BackToList") + ")", "List") +
    +
    + +
    +
    + @Html.Partial("_CreateOrUpdate", Model) +
    +} \ No newline at end of file diff --git a/src/Presentation/SmartStore.Web/Administration/Views/Import/List.cshtml b/src/Presentation/SmartStore.Web/Administration/Views/Import/List.cshtml index 105b8b85b4..11ae7b52b0 100644 --- a/src/Presentation/SmartStore.Web/Administration/Views/Import/List.cshtml +++ b/src/Presentation/SmartStore.Web/Administration/Views/Import/List.cshtml @@ -12,7 +12,7 @@ @T("Common.Import")
    @@ -28,7 +28,7 @@
    @T("Admin.DataExchange.Import.Name") @T("Common.Enabled") @T("Admin.Common.Entity")@T("Common.Files")@T("Admin.Common.ImportFiles") @T("Admin.System.ScheduleTasks.LastStart") @T("Admin.System.ScheduleTasks.NextRun") @T("Admin.Common.Actions") - @profile.EntityType.NaIfEmpty() + @profile.EntityTypeName - @(string.Join("
    ", profile.FileNames)) + @(string.Join("
    ", profile.ExistingFileNames))
    diff --git a/src/Presentation/SmartStore.Web/Administration/Views/Import/_CreateOrUpdate.cshtml b/src/Presentation/SmartStore.Web/Administration/Views/Import/_CreateOrUpdate.cshtml new file mode 100644 index 0000000000..15820d8042 --- /dev/null +++ b/src/Presentation/SmartStore.Web/Administration/Views/Import/_CreateOrUpdate.cshtml @@ -0,0 +1,124 @@ +@using SmartStore.Admin.Models.DataExchange; +@model ImportProfileModel +@{ + Html.AddScriptParts("~/bundles/fileupload"); + Html.AddCssFileParts("~/css/fileupload"); +} + +@Html.ValidationSummary(false) +@Html.HiddenFor(model => model.Id) +@Html.HiddenFor(model => model.TempImportFile) + + + + + + + + + + + + + + + @if (Model.Id != 0) + { + + + + + + + + + + + + + + + + + + + + + } +
    +   + + +
    + + + @T("Admin.DataExchange.Import.FileUpload") + + + + + +
    +
    +
    +
    +
     
    +
    +
    + +
    + @Html.SmartLabelFor(x => x.Name) + + @Html.EditorFor(x => x.Name) + @Html.ValidationMessageFor(x => x.Name) +
    + @Html.SmartLabelFor(x => x.EntityType) + + @Html.DropDownListFor(x => x.EntityType, Model.AvailableEntityTypes) + @Html.ValidationMessageFor(x => x.EntityType) +
    + @Html.SmartLabelFor(x => x.FolderName) + + @Html.EditorFor(x => x.FolderName) + @Html.ValidationMessageFor(x => x.FolderName) +
    + @Html.SmartLabelFor(x => x.Enabled) + + @Html.EditorFor(x => x.Enabled) + @Html.ValidationMessageFor(x => x.Enabled) +
    + @Html.SmartLabelFor(x => x.Skip) + + @Html.EditorFor(x => x.Skip) + @Html.ValidationMessageFor(x => x.Skip) +
    + @Html.SmartLabelFor(x => x.Take) + + @Html.EditorFor(x => x.Take) + @Html.ValidationMessageFor(x => x.Take) +
    + @Html.SmartLabelFor(x => x.Cleanup) + + @Html.EditorFor(x => x.Cleanup) + @Html.ValidationMessageFor(x => x.Cleanup) +
    + + \ No newline at end of file diff --git a/src/Presentation/SmartStore.Web/App_Data/ImportProfiles/produkte-importieren/Content/1-165-0001-produktcsvexport.csv b/src/Presentation/SmartStore.Web/App_Data/ImportProfiles/produkte-importieren/Content/1-165-0001-produktcsvexport.csv new file mode 100644 index 0000000000..4750e5d752 --- /dev/null +++ b/src/Presentation/SmartStore.Web/App_Data/ImportProfiles/produkte-importieren/Content/1-165-0001-produktcsvexport.csv @@ -0,0 +1,219 @@ +ProductTypeId;ParentGroupedProductId;VisibleIndividually;Name;ShortDescription;FullDescription;ProductTemplateId;ShowOnHomePage;HomePageDisplayOrder;MetaKeywords;MetaDescription;MetaTitle;SeName;AllowCustomerReviews;Published;SKU;ManufacturerPartNumber;Gtin;IsGiftCard;GiftCardTypeId;RequireOtherProducts;RequiredProductIds;AutomaticallyAddRequiredProducts;IsDownload;DownloadId;UnlimitedDownloads;MaxNumberOfDownloads;DownloadActivationTypeId;HasSampleDownload;SampleDownloadId;HasUserAgreement;UserAgreementText;IsRecurring;RecurringCycleLength;RecurringCyclePeriodId;RecurringTotalCycles;IsShipEnabled;IsFreeShipping;AdditionalShippingCharge;IsEsd;IsTaxExempt;TaxCategoryId;ManageInventoryMethodId;StockQuantity;DisplayStockAvailability;DisplayStockQuantity;MinStockQuantity;LowStockActivityId;NotifyAdminForQuantityBelow;BackorderModeId;AllowBackInStockSubscriptions;OrderMinimumQuantity;OrderMaximumQuantity;AllowedQuantities;DisableBuyButton;DisableWishlistButton;AvailableForPreOrder;CallForPrice;Price;OldPrice;ProductCost;SpecialPrice;SpecialPriceStartDateTimeUtc;SpecialPriceEndDateTimeUtc;CustomerEntersPrice;MinimumCustomerEnteredPrice;MaximumCustomerEnteredPrice;Weight;Length;Width;Height;CreatedOnUtc;CategoryIds;ManufacturerIds;Picture1;Picture2;Picture3;DeliveryTimeId;QuantityUnitId;BasePriceEnabled;BasePriceMeasureUnit;BasePriceAmount;BasePriceBaseAmount;BundleTitleText;BundlePerItemShipping;BundlePerItemPricing;BundlePerItemShoppingCart;BundleItemSkus;AvailableStartDateTimeUtc;AvailableEndDateTimeUtc;StoreIds;LimitedToStores;Name[DE];ShortDescription[DE];FullDescription[DE];Name[en];ShortDescription[en];FullDescription[en] +5;0;True;_Zero Price;;"

    Optisch zum Verwechseln ähnlich, ebenso kompakt und leicht wie die erfolgreiche SD19, aber mit noch besserer Auflösung, präsentiert sich die brandneue AEE SD21 PRO Action-Cam. Die SD21 PRO ist eine komplette Neuentwicklung, mit Innovationen und einer Ausstattung, die es bisher in diesem Preissegment noch nicht gab.
    Bei der SD21 PRO ist die Monitor-Rückwand wie auch die Fernbedienung ebenso selbstverständlich wie der aufsteckbare Zusatzakku für noch längere Power.
    Für einfaches, unkompliziertes Justieren der Kamera ist ein Laserpointer integriert. Der 10-fach Digitalzoom und die hochwertige Optik garantieren für optimale Aufnahmeergebnisse bei allen Bedingungen.

    Highlights SD21 PRO:

    • 1/3 Zoll CMOS-Sensor 8,0 Megapixel
    • 170° Weitwinkel-Objektiv, Blende F/3.0
    • 10x Digitalzoom
    • Automatische Belichtung und Weissabgleich
    • Externes TFT-Display mit Echtzeit-Anzeige für Video und das Abspielen aufgezeichneter Inhalte
    • Laserpointer als Aufnahmeorientierung
    • Selbst-/Zeit-Auslöser mit Kontroll-LED
    • Eingebautes Mikrofon für hochwertige Stereo-Voice-Aufnahmen
    • Wasserdichtes Gehäuse bis 60 Meter (IP68-Standard)
    • Hochleistungs-Lithium-Batterie
    • Aufsteckbarer Zusatzakku mit eigener Ladestandsanzeige - verdoppelt die Aufnahmedauer
    • Auto Stand-by zur Energieeinsparung
    • Funktionen: HD-Videoaufnahme / Foto
    • Recording MOV Videos können direkt am PC wiedergegeben oder auf Video-Websites hochgeladen werden
    • Photo 180-Grad-Umkehr-Funktion
    • Externe Micro SD/MMC-Speicherkarte, unterstützt bis max. 64GB (nicht enthalten)
    • Speicherkapazität Alarm
    • Schneller Vor- und Rücklauf, Funktion zum Überspringen von Inhalten in das nächste Segment
    • Unterstützung USB2.0
    • HDMI-Ausgang, AV-OUT-Funktion
    • Support-System: Windows 98SE/2000/Me/XP/Vista/Win 7/Mac OS

    Grösse: ca. 61x43x40mm (BxHxT)

    Gewicht: 88g ohne Bildschirm, 112g mit Bildschirm

    Technische Daten SD21 PRO:

    • Auflösung/Sensor: 8.0M CMOS-Sensor (3200 * 2400)
    • Optik / Linse: 170° Weitwinkel-Objektiv, Blende F/3.0
    • Gehäuse: IP68 wasserdichtes Gehäuse bis 60m
    • Memory-Karte: Micro SD unterstützt bis 64GB (nicht enthalten)
    • Photo-Modus: 3M (2048 * 1536) / 5M (2560 * 1920) / 8M (3200 * 2400)
    • Video-Aufnahmemodus: 1080P 720P WVGA QVGA
    • Bildrate: 1080P/30fps 720P/30fps WVGA/60fps QVGA/30fps
    • Video-Aufnahmeformat: MOV (H.264-Video-Kompression)
    • Photo-Format: JPEG
    • Aufnahmekapazität (2GB SDKarte):
    • Photos 3M (1900pcs), 5M (1160pcs), 8M (770pcs) /
    • Videos: 720P/60min, WVGA/135min
    • Laserpointer/Laserleistung: 1MW
    • AV OUT: Unterstützung NTSC / PAL VGA und HDMI
    • USB: USB2.0
    • Mikrofon: 2 Mikrofone, eingebaute
    • Leistungsaufnahme: 500mA@3.7V (MAX)
    • Lithium-Batterie: 1000mAh
    • Batterielaufzeit: 2.5h / Batterie
    • Betriebssystem: Windows XP SP2/Vista oder höher / Mac OS. CPU:
    • Pentium4 1.5GHZ oder höher RAM: min. 1GB
    • RTC-Funktion: Unterstützung
    • Lagertemperatur: -20 bis -60 
    • Betriebstemperatur: -10 bis -50 
    • Luftfeuchtigkeit bei Betrieb: 15 85% RH

     

    ";2;True;0;;;_Wasser;_zero-price-3;True;True;;;;False;0;False;;False;False;0;False;0;1;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;0;False;False;0;0;1;0;False;1;10000;;False;True;False;False;0.0000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;42302,5461930208;"1;2095";;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000696-_zero-price.jpg;;;2;;True;l;35.0000;100;;False;False;False;;;;1;True;;;;;; +5;0;True;Bundle Item 2;;;2;False;0;;;;bundle-item-2;True;True;;;;False;0;False;;False;False;0;True;10;1;False;;False;;False;100;0;10;True;False;0,0000;False;False;1;0;10000;False;False;0;0;0;0;False;1;10000;;False;False;False;False;19.9000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;41965,4767811343;;;;;;;;False;ounce;;;;False;False;False;;;;;False;;;;;; +5;0;True;Bundle Item 1;;;2;False;0;;;;bundle-item-1;True;True;;;;False;0;False;;False;False;0;True;10;1;False;;False;;False;100;0;10;True;False;0,0000;False;False;1;0;0;False;False;0;0;0;0;False;1;10000;;False;False;False;False;84.9000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;41965,4671613079;;;;;;;;False;ounce;;;;False;False;False;;;;;False;;;;;; +5;0;True;_Download;;"

    Downloadable product.

    ";2;False;0;;;;_download;True;True;;;;False;0;False;;False;True;8;True;10;1;False;;False;;False;100;0;10;False;False;0,0000;False;False;1;0;10000;False;False;0;0;1;0;False;1;10000;;False;False;False;False;3.8000;0.0000;0.0000;;0.0;0.0;False;0.0000;1000.0000;0.0000;0.0000;0.0000;0.0000;41863,7438013542;"1;2095";;;;;;;False;ounce;;;;False;False;False;;;;;False;;;;;; +5;0;True;_Attribut Test;;"

    Continually incubate standards compliant content vis-a-vis multifunctional portals. Dynamically exploit collaborative strategic theme areas vis-a-vis extensive partnerships. Monotonectally maximize user friendly relationships for backward-compatible alignments. Objectively deliver covalent opportunities after exceptional scenarios. Objectively drive backend paradigms via excellent meta-services. Uniquely customize sticky core competencies rather than leveraged internal or "organic" sources. Objectively conceptualize client-based users without customer directed applications. Continually generate backend processes and market-driven markets. Proactively evisculate visionary testing procedures with fully tested networks. Collaboratively facilitate B2C schemas vis-a-vis covalent meta-services. Proactively recaptiualize progressive quality vectors vis-a-vis frictionless supply chains. Distinctively synthesize revolutionary leadership vis-a-vis strategic e-markets. Distinctively pontificate principle-centered benefits with pandemic resources. Professionally pontificate multifunctional strategic theme areas via low-risk high-yield data. Uniquely underwhelm technically sound information before functional synergy. Progressively utilize 24/365 ROI whereas client-based interfaces. Seamlessly reintermediate alternative customer service through plug-and-play quality vectors. Professionally repurpose one-to-one scenarios without visionary supply chains. Enthusiastically unleash timely applications after an expanded array of e-commerce. Monotonectally pursue virtual intellectual capital after high standards in scenarios. Professionally benchmark end-to-end internal or "organic" sources with maintainable supply chains. Authoritatively disseminate high-payoff imperatives for stand-alone infomediaries. Completely network stand-alone initiatives for market positioning intellectual capital. Appropriately deliver process-centric collaboration and idea-sharing after multifunctional leadership. Energistically unleash open-source vortals vis-a-vis transparent niches.

    ";2;False;0;;;;ab-22;True;True;SKU-Tester;;;False;0;False;;False;False;7;True;10;1;False;;False;;False;100;0;10;True;False;0,0000;False;False;1;2;10000;True;False;0;1;1;0;False;1;10000;;False;False;False;False;0.0000;0.0000;0.0000;;0.0;0.0;False;0.0000;1000.0000;0.0000;0.0000;0.0000;0.0000;41833,6856570949;"1;2095";;;;;2;;False;ounce;;;;False;False;False;;;;;False;;;;;; +5;0;True;_GiftCard;;

    GiftCart for testing.

    ;2;False;0;;;;_giftcard-2;True;True;;;;True;0;False;;False;False;0;True;10;1;False;;False;;False;100;0;10;False;False;0,0000;False;False;1;0;10000;False;False;0;0;1;0;False;1;10000;;False;False;False;False;10.0000;0.0000;0.0000;;0.0;0.0;False;0.0000;1000.0000;0.0000;0.0000;0.0000;0.0000;41701,4763476505;1;;;;;;;False;ounce;;;;False;False;False;;;;;False;;;;;; +5;0;True;GiftCard;;;2;False;0;;;;_giftcard;True;True;;;;True;0;False;;False;False;0;True;10;1;False;;False;;False;100;0;10;True;False;0,0000;False;False;1;0;10000;False;False;0;0;1;0;False;1;10000;;False;False;False;False;10.0000;0.0000;0.0000;;0.0;0.0;False;0.0000;1000.0000;0.0000;0.0000;0.0000;0.0000;41671,8425473727;2095;;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000666-giftcard.jpg;;;;;False;ounce;;;;False;False;False;;;;;False;;;;;; +15;0;True;_SmartStore Bundle;;"

    SmartStore Test Bundle

    ";2;False;0;;;_SmartStore Bundle;_smartstore-bundle;True;True;PD-01097;;;False;0;False;;False;False;0;False;0;1;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;888.0000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;41656,6659837963;"81;2095";;;;;1;;False;;;;Bestehend aus;False;False;True;;;;;False;;;;;; +15;0;True;_Bundle;;"

    My product bundle.

    ";2;False;0;;;;_bundle;True;True;SKU-1001;;;False;0;False;;False;False;0;True;10;1;False;;False;;False;100;0;10;True;False;0,0000;False;False;1;1;9999;False;False;10;0;1;1;False;1;10000;;False;False;False;False;499.0000;0.0000;260.6000;;0.0;0.0;False;0.0000;1000.0000;0.0000;0.0000;0.0000;0.0000;41656,5811581829;"81;2095";;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000665-_bundle.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000667-_bundle.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000668-_bundle.jpg;2;;False;kg;3.0000;1;Bestehend aus;False;False;True;P-6000,P-2930,P-2940,P-2950;;;;False;;;;;; +10;0;True;_Gruppenprodukt;Grouped product;"

    Tortor dis facilisis augue eros. Porta turpis! Augue! Magna mattis porttitor aliquet eu, montes magna nunc pulvinar hac, augue porttitor, ridiculus! Pulvinar, in tortor risus in scelerisque platea, pulvinar pid! Dapibus proin diam. Pellentesque cum! Tincidunt, tempor a magna turpis, mid amet, aenean, placerat. Phasellus? Tempor, cursus lacus porttitor ac, in tincidunt sociis vel? Eu velit dapibus integer enim risus augue phasellus odio turpis, sociis, eros dapibus et sed auctor, nec nisi montes, egestas integer eu rhoncus tortor integer montes sit scelerisque nec integer! Vel aliquet vut aliquet dis integer sed urna lectus sed habitasse etiam! Nunc purus augue dictumst, lectus platea? Turpis montes cras ultricies, adipiscing? Nunc. Cursus in! In ultricies parturient etiam augue, tempor mauris pellentesque purus rhoncus.

    Vut vut et amet, phasellus? Et in integer enim, aenean elit, montes cum elementum nascetur a penatibus! Ac magna lorem ac placerat, lectus. Scelerisque habitasse elementum sociis scelerisque rhoncus. Natoque mattis parturient tempor dictumst turpis, hac placerat dolor nunc penatibus. Facilisis tristique massa facilisis? Rhoncus habitasse sit! Aenean aliquet ut quis ut in amet ut, phasellus augue sit tempor nunc dictumst eu, porta amet augue, mattis facilisis ac! Turpis egestas ridiculus, lacus in, sed placerat, odio lundium tincidunt nisi amet rhoncus. Augue cras! Velit, mattis! Auctor nisi mus? Amet nunc elementum placerat vut! Porttitor pid porta amet sit magnis, nisi ut cursus. Egestas sed auctor amet nec sit dapibus amet dis? Odio velit ac, hac cum ridiculus, amet ac.

    Integer nisi natoque dictumst, facilisis! Phasellus turpis, pellentesque in! Dictumst pid, nisi a porttitor nec. Nunc natoque magnis etiam odio a diam vut integer aenean magnis cum lundium aenean, risus scelerisque, penatibus! Enim enim, scelerisque non placerat ut auctor, ac parturient auctor tincidunt, porttitor a est sit, nascetur scelerisque lorem in turpis sagittis mus! Enim turpis hac dis? Sit, porta nunc rhoncus ac? Integer tincidunt est porttitor, tincidunt natoque facilisis, facilisis, hac lorem elementum pulvinar tincidunt odio, dignissim cursus, urna auctor magna aliquam! Dolor duis ac tincidunt, magna! A! Urna, enim nascetur cursus, tincidunt aenean ac dis odio vel, ut lacus, duis sed in porttitor massa penatibus enim penatibus integer, augue urna scelerisque nunc elementum tincidunt duis tortor etiam.

    Parturient pulvinar, lacus ut ultrices rhoncus massa! Velit et elementum pulvinar. Urna, magna integer. Nunc hac rhoncus? Amet eu? Sit in ac tortor. Lundium, pulvinar porttitor, tortor! Eros eu. Enim velit tristique elementum? Risus auctor tincidunt vut phasellus pellentesque! Turpis rhoncus vut, purus vel. Nunc ac augue! Ac sagittis pulvinar, in, duis adipiscing, velit sagittis? Penatibus mus scelerisque, nec! Dapibus scelerisque, augue turpis aenean, platea, urna integer risus a aliquet sagittis mid est elementum. Scelerisque? Tincidunt, vel vel natoque. Proin pulvinar sed placerat, cum amet nascetur scelerisque penatibus, ut, amet mus, duis placerat ac mus nec turpis facilisis dolor. Ultrices platea! Et magna enim rhoncus adipiscing odio, platea velit. Purus nunc duis! Enim velit integer facilisis nec? Diam mus.

    Habitasse purus, sed vut cras non porta tincidunt facilisis, tristique, urna integer risus risus magna dictumst dignissim etiam mid! Vut risus lacus placerat, nunc a tincidunt, sociis est elementum, rhoncus pid, ridiculus quis nunc? In est scelerisque dignissim proin tortor sed, quis aenean! Et placerat in vut, risus! Augue. Lundium pid. Sit elit! Sed lorem mus ac pulvinar sit integer odio dignissim montes, adipiscing magna adipiscing porta nunc nascetur sit. Quis tortor ridiculus, in, vut tincidunt urna mus, pulvinar a! Enim arcu nec ultricies lacus sagittis mattis mauris dictumst, magna amet habitasse ut et ac! Ac amet dolor scelerisque. Auctor sit eu vut ac, velit massa tempor! Montes, dis odio quis, magna ac, phasellus purus scelerisque etiam odio penatibus.

    Nec habitasse rhoncus. Pulvinar, et porta, porta tristique odio ut, massa! Purus phasellus eros porttitor, aliquet nascetur, montes turpis? Magna scelerisque rhoncus in dapibus, lundium porttitor, augue, ut placerat. Habitasse dictumst ac cursus pulvinar pid platea. Nascetur cum augue urna nunc? Magnis, arcu, pid pulvinar, natoque sed? In parturient porttitor facilisis mauris sed? Nec cras, urna et augue tristique, tincidunt tortor auctor non? Amet magna et aliquam sit sed, mid, augue pid massa sit tincidunt placerat placerat massa montes magna dapibus, ut pulvinar hac urna parturient nec dolor nunc, tristique nec proin amet ultricies magna, sociis vel etiam dolor? Augue vel augue rhoncus rhoncus enim pid tristique sit porta sit augue, tristique adipiscing! Dignissim, dictumst aliquam lundium rhoncus turpis.

    Mattis platea mauris, etiam duis amet, phasellus massa, mattis, nunc sed massa integer etiam mid dis velit in sagittis vel? Mauris. Enim mid integer, lundium! Mid pid aenean mattis elementum, nunc dis etiam augue augue vel, vel rhoncus tincidunt purus porta pellentesque, pid eu aliquet, ultricies tempor sociis? Dolor! Ac ultrices ultricies! Nec enim! Mauris lorem duis magna tincidunt, vel cursus dis. Pellentesque, urna, mid integer et ac lectus elit velit lectus scelerisque mauris nunc. Aliquet platea adipiscing, sagittis urna dolor vel rhoncus a duis, ac nec diam tincidunt odio! Hac porttitor sed ac parturient purus mauris, urna etiam, nec diam magna pellentesque turpis placerat magnis eros ridiculus, elementum lorem, tempor natoque? Ultrices sed nec dapibus eu rhoncus penatibus? Urna.

    Quis dolor elementum mauris! Ridiculus, auctor in, tortor ut risus velit pulvinar, porta urna rhoncus magna ultrices! Proin integer, cras rhoncus pid integer, nec odio ac, et? Dictumst pulvinar enim adipiscing facilisis ac mid nec? Pulvinar et non tristique! Sit pulvinar, pulvinar penatibus tincidunt, habitasse integer nunc! Tincidunt amet natoque facilisis aliquam tortor. Etiam duis tristique arcu egestas, et, sagittis nec ac aliquam pulvinar aliquet, adipiscing, nisi, sit sit, egestas risus. Ac. Adipiscing elit sit turpis in nec amet, nec in porta sed. Vel in in sit ultricies. Risus. Cum nascetur integer risus phasellus? Lacus mid auctor enim, enim scelerisque elementum vut a, diam eros sit duis, nascetur magna, est in dignissim adipiscing. Quis. Enim sociis egestas? Ut scelerisque.

    Elit placerat turpis, porttitor penatibus phasellus! In magnis eros ut, turpis? Pid? Odio et et, mauris aenean, purus turpis, adipiscing aliquet sed tortor! Turpis dapibus amet augue ut turpis montes mauris aliquam! Penatibus est, sagittis amet nunc ultrices ultrices, amet massa enim aliquam vel odio? Purus turpis? Urna tincidunt! Elementum magna integer enim, porttitor sed aenean mus phasellus vut lorem in ac sociis, in aenean, est! Adipiscing placerat tristique, nec nunc risus turpis. Ut, porta tincidunt dapibus, dignissim? Rhoncus turpis, enim massa massa platea magnis augue amet? Sit, rhoncus, augue magna aenean lorem a et. Cum lorem. Ultrices, duis! Ultrices etiam augue ridiculus! Adipiscing? Egestas elementum magna pulvinar augue, porta elementum aliquet et facilisis phasellus auctor adipiscing lacus tincidunt.

    Nec porta scelerisque ut ac etiam ac lorem cursus urna risus, amet egestas, tristique, etiam vut, adipiscing! Nunc cum habitasse pulvinar eros purus eros turpis in nascetur, habitasse adipiscing. Mattis. Nisi augue turpis, tortor, integer? Velit dis et, tristique augue. Scelerisque elementum adipiscing velit phasellus cras risus tincidunt ut rhoncus montes, scelerisque, ultricies. Et nascetur? Dis adipiscing. Natoque, turpis? Augue facilisis, dapibus augue? Elementum, tortor ac. Integer, nunc dictumst, diam nunc, augue nec non. Risus odio. Odio amet ultrices! Et urna nisi magna nisi nunc pulvinar habitasse facilisis in nunc velit natoque placerat rhoncus auctor? Magna pulvinar pulvinar augue, elementum adipiscing! Nascetur augue! Eros mus, nisi porta integer sed cras porttitor scelerisque. Pulvinar lorem turpis! Etiam, dictumst ac elit.

    Vel augue placerat tempor nunc tortor purus, egestas ut lacus massa quis nec non odio amet, tincidunt parturient nunc urna eros turpis ridiculus cursus penatibus mattis penatibus augue sed! Montes scelerisque. Et dictumst adipiscing lundium, tristique, enim nascetur, cum? Non pellentesque! Mauris magna sit, porttitor, magnis, vel, nisi ultrices velit! Pellentesque, amet augue mid placerat dignissim ac etiam scelerisque, ultrices purus etiam enim, scelerisque sit turpis montes porta nunc cras enim. Non risus in enim mattis nunc. Etiam adipiscing porttitor. Massa, nunc ultricies placerat enim. Est phasellus egestas porttitor. Et et elementum tempor ac? Proin! Augue tempor cras, eros! Rhoncus scelerisque auctor eu eu, diam? Nunc egestas, lectus cum, scelerisque, elementum, scelerisque magna, tempor elit arcu dictumst? Dis elementum.

    Nascetur, cras cras ridiculus lorem ac lectus enim proin odio sit lectus lorem dapibus enim. Ac nisi porttitor aliquet aliquam aenean non lacus, rhoncus pulvinar tempor dapibus dolor aliquam. In, in tincidunt penatibus cras et, lundium, sed turpis sit nunc odio, phasellus rhoncus urna facilisis platea adipiscing, mid etiam nascetur, enim, vut elementum, duis et ridiculus, penatibus urna non? Aliquam turpis augue phasellus risus diam egestas penatibus vel dignissim dignissim, ut! Elementum pulvinar et nascetur dapibus enim lundium hac platea scelerisque pellentesque facilisis! Quis, scelerisque pulvinar aliquet tincidunt elementum aliquam velit? Eros mid in facilisis, porttitor augue mattis ut, elementum placerat! Adipiscing ut augue! Facilisis in facilisis porttitor penatibus! Vel urna ridiculus magna, integer? Amet, penatibus cursus porttitor nisi.

    ";1;False;0;;;;_gruppenprodukt-2;True;True;SKU-1000;;;False;0;False;;False;False;0;True;10;1;False;;False;;False;100;0;10;True;False;0,0000;False;False;1;0;9999;False;False;0;0;1;0;False;1;10000;;False;False;False;False;0.0000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;41645,6860016551;"2095;1;81";;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000672-_gruppenprodukt.jpg;;;;;False;;;;;False;False;False;;;;;False;;;;;; +5;0;True;_Wasser;;"

    Optisch zum Verwechseln ähnlich, ebenso kompakt und leicht wie die erfolgreiche SD19, aber mit noch besserer Auflösung, präsentiert sich die brandneue AEE SD21 PRO Action-Cam. Die SD21 PRO ist eine komplette Neuentwicklung, mit Innovationen und einer Ausstattung, die es bisher in diesem Preissegment noch nicht gab.
    Bei der SD21 PRO ist die Monitor-Rückwand wie auch die Fernbedienung ebenso selbstverständlich wie der aufsteckbare Zusatzakku für noch längere Power.
    Für einfaches, unkompliziertes Justieren der Kamera ist ein Laserpointer integriert. Der 10-fach Digitalzoom und die hochwertige Optik garantieren für optimale Aufnahmeergebnisse bei allen Bedingungen.

    Highlights SD21 PRO:

    • 1/3 Zoll CMOS-Sensor 8,0 Megapixel
    • 170° Weitwinkel-Objektiv, Blende F/3.0
    • 10x Digitalzoom
    • Automatische Belichtung und Weissabgleich
    • Externes TFT-Display mit Echtzeit-Anzeige für Video und das Abspielen aufgezeichneter Inhalte
    • Laserpointer als Aufnahmeorientierung
    • Selbst-/Zeit-Auslöser mit Kontroll-LED
    • Eingebautes Mikrofon für hochwertige Stereo-Voice-Aufnahmen
    • Wasserdichtes Gehäuse bis 60 Meter (IP68-Standard)
    • Hochleistungs-Lithium-Batterie
    • Aufsteckbarer Zusatzakku mit eigener Ladestandsanzeige - verdoppelt die Aufnahmedauer
    • Auto Stand-by zur Energieeinsparung
    • Funktionen: HD-Videoaufnahme / Foto
    • Recording MOV Videos können direkt am PC wiedergegeben oder auf Video-Websites hochgeladen werden
    • Photo 180-Grad-Umkehr-Funktion
    • Externe Micro SD/MMC-Speicherkarte, unterstützt bis max. 64GB (nicht enthalten)
    • Speicherkapazität Alarm
    • Schneller Vor- und Rücklauf, Funktion zum Überspringen von Inhalten in das nächste Segment
    • Unterstützung USB2.0
    • HDMI-Ausgang, AV-OUT-Funktion
    • Support-System: Windows 98SE/2000/Me/XP/Vista/Win 7/Mac OS

    Grösse: ca. 61x43x40mm (BxHxT)

    Gewicht: 88g ohne Bildschirm, 112g mit Bildschirm

    Technische Daten SD21 PRO:

    • Auflösung/Sensor: 8.0M CMOS-Sensor (3200 * 2400)
    • Optik / Linse: 170° Weitwinkel-Objektiv, Blende F/3.0
    • Gehäuse: IP68 wasserdichtes Gehäuse bis 60m
    • Memory-Karte: Micro SD unterstützt bis 64GB (nicht enthalten)
    • Photo-Modus: 3M (2048 * 1536) / 5M (2560 * 1920) / 8M (3200 * 2400)
    • Video-Aufnahmemodus: 1080P 720P WVGA QVGA
    • Bildrate: 1080P/30fps 720P/30fps WVGA/60fps QVGA/30fps
    • Video-Aufnahmeformat: MOV (H.264-Video-Kompression)
    • Photo-Format: JPEG
    • Aufnahmekapazität (2GB SDKarte):
    • Photos 3M (1900pcs), 5M (1160pcs), 8M (770pcs) /
    • Videos: 720P/60min, WVGA/135min
    • Laserpointer/Laserleistung: 1MW
    • AV OUT: Unterstützung NTSC / PAL VGA und HDMI
    • USB: USB2.0
    • Mikrofon: 2 Mikrofone, eingebaute
    • Leistungsaufnahme: 500mA@3.7V (MAX)
    • Lithium-Batterie: 1000mAh
    • Batterielaufzeit: 2.5h / Batterie
    • Betriebssystem: Windows XP SP2/Vista oder höher / Mac OS. CPU:
    • Pentium4 1.5GHZ oder höher RAM: min. 1GB
    • RTC-Funktion: Unterstützung
    • Lagertemperatur: -20 bis -60 
    • Betriebstemperatur: -10 bis -50 
    • Luftfeuchtigkeit bei Betrieb: 15 85% RH

     

    ";2;True;0;;;_Wasser;_wasser;True;True;;;;False;0;False;;False;False;0;False;0;1;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;2;0;False;False;0;0;1;0;False;1;10000;;False;True;False;False;0.9900;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;41540,3761458333;"1;2095";;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000673-_wasser.jpg;;;2;;True;l;35.0000;100;;False;False;False;;;;1;True;;;;;; +5;0;True;Apple MacBook Pro MD313D/A 13,3 Zoll Notebook;3 GB, 18 Zoll, 500 GB, Intel, 4;"
    Apple MacBook Pro MD313D/A 13,3 Zoll Notebook
    Intel Core i5  2x 2,40 GHz
     
    Bis zu 2x schnellere Prozessoren. Bis zu 3x schnellere Grafik.
    Quad-Core und Dual-Core Intel Prozessoren der nächsten Generation.
    Das 13"" MacBook Pro gibt es jetzt mit einem 2,4 GHz Intel Core i5 Prozessor oder dem schnellsten Dual-Core Prozessor, den es gibt: dem 2,8 GHz Intel Core i7. Diese Prozessoren bieten Turbo Boost Geschwindigkeiten und machen das 13"" MacBook Pro bis zu doppelt so schnell wie die Vorgängergeneration.
     
    Aber nur schnell ist uns nicht genug. Deshalb bieten die neuen 15"" und 17"" Modelle Quad-Core Leistung für praktisch alles, was du machen willst. Auch ein 2,4 GHz Quad-Core Intel Core i7 Prozessor mit Turbo Boost Geschwindigkeiten und bis zu 8 MB gemeinsam genutztem L3-Cache ist verfügbar. Auf MacBook Pro Modellen mit diesem Prozessor laufen Programme bis zu doppelt so schnell wie auf der besten Vorgängerkonfiguration.
     
    Die Grafikleistung, die du brauchst, wenn du sie brauchst.
    Alle MacBook Pro Modelle haben jetzt einen integrierten Intel HD Graphics 3000 Prozessor für die täglichen Aufgaben. Er codiert Videos schnell, ermöglicht HD Videotelefonate mit FaceTime und vieles mehr. Und auch Decodieren erledigt er effizienter, was bedeutet, dass du richtig lange DVDs und iTunes Filme schauen kannst.
     
    Bei anspruchsvollen Grafikprogrammen wechseln die 15"" und 17"" MacBook Pro Modelle automatisch den Grafikprozessor und arbeiten mit den neuen leistungsstarken AMD Radeon Grafikprozessoren. Diese bieten verglichen mit den Vorgängermodellen die bis zu 3-fache Leistung.3 So siehst du bei 3D Spielen mehr Bilder pro Sekunde oder kannst schneller als je zuvor an HD Videoprojekten arbeiten.
     
    Das neue Thunderbolt. Die schnellste, vielseitigste I/O Technologie in einem Notebook.
    Stell dir vor, du könntest auf deinem Notebook auf mehrere unkomprimierte HD Videostreams zugreifen - und zwar so schnell, dass du einen HD Spielfilm in Echtzeit schneiden kannst. Thunderbolt macht genau das möglich. Mit Thunderbolt lassen sich superschnelle Peripheriegeräte der nächsten Generation an die Computer der nächsten Generation anschließen - angefangen beim MacBook Pro. Die Thunderbolt Pipeline ist ultraschnell und ultraflexibel. Sie ist über 12 Mal schneller als FireWire 800 und bis zu 20 Mal schneller als USB 2.0. Und sie bietet beispiellose Erweiterungsmöglichkeiten. Kurzum: Sie verändert alles, was du auf deinem Notebook machen kannst.
     
    Der Thunderbolt Anschluss gibt dir Plug&Play Anschluss für eine völlig neue Welt von Thunderbolt Peripheriegeräten sowie für das Apple LED Cinema Display und andere Mini DisplayPort Peripheriegeräte. Du kannst bis zu sechs Thunderbolt Geräte in Reihenschaltung anschließen, darunter auch dein Display. Außerdem unterstützt Thunderbolt Video und Achtkanal-Audio, sodass es auch möglich ist, HDMI-kompatible Geräte wie Fernseher oder Stereoanlagen über einen HDMI-Adapter anzuschließen. Auch aktuelle VGA-, DVI- und DisplayPort Adapter werden unterstützt.
     
    Die neue FaceTime HD Kamera. Der Unterschied ist ganz klar.
    Sieh mehr von deinen Freunden mit dem HD Widescreenformat - und zwar gestochen scharf. Die neue FaceTime HD Kamera bietet die dreifache Auflösung der vorherigen Kamera, was perfekt für das brillante Display mit LED-Hintergrundbeleuchtung ist. Außerdem arbeitet sie jetzt bei schwachem Licht noch besser. Du kannst mit deinen Freunden HD Telefonate in 720p von einem neuen MacBook Pro zu einem anderen führen. Außerdem sind auch Videotelefonate zu anderen Macs mit Intel Prozessor5, zum iPhone 4 oder zum neuen iPod touch möglich.
     
    Multi-Touch Trackpad. Fürs tägliche Handwerk.
    Mit dem Multi-Touch Trackpad interagierst du auf ganz natürliche Art mit den Inhalten auf deinem Display. Und die glatte Glasoberfläche bietet jede Menge Platz für Gesten. Durch Auf- und Zuziehen kannst du ein- und auszoomen, durch Streichen in deinen Fotos blättern, durch Drehen ein Bild anpassen und vieles mehr. Das Trackpad kommt ohne Taste aus, sodass du überall klicken kannst. Wenn du aus der Welt des rechten Mausklicks kommst, kannst du diesen entweder mit zwei Fingern auslösen, oder du konfigurierst einen physischen Rechtsklick-Bereich auf dem Trackpad. Je mehr du mit dem Multi-Touch Trackpad vertraut bist, desto mehr wirst du dich fragen, wie du jemals ohne ausgekommen bist.
     
    Lange Laufzeit. Weniger aufladen. Mehr machen.
    Das neue MacBook Pro bietet eine fantastische Batterielaufzeit und das mit leistungsstärkeren Prozessoren und schnelleren Grafikprozessoren. Die energieeffiziente Prozessorarchitektur mit integriertem Video-Encoder sowie das automatische Umschalten zwischen den Grafikprozessoren bei den 15"" und 17"" Modellen helfen, die Batterielaufzeit weiter zu verbessern. So kannst du pro Ladung bis zu 7 Stunden ohne Kabel im Web surfen6 oder es für Liveauftritte oder auf ein Shooting mitnehmen. Die fortschrittlichen chemischen Eigenschaften und die Adaptive Charging Technologie sorgen dafür, dass die Batterie bis zu 1000 Ladezyklen durchlaufen kann.7 Und da die Batterie des MacBook Pro bis zu fünf Jahre hält, kommt das MacBook Pro in einem Zeitraum, in dem ein herkömmliches Notebook drei Batterien verbraucht, mit nur einer aus. Das ist für die Benutzer genauso gut, wie für die Umwelt.
     
    Apple verwendet eine neue, strengere Testmethode, um zu messen, welche Ergebnisse du unter realen Bedingungen erzielst, z. B. beim Surfen in einem Café oder wenn du die neuesten Webvideos ansiehst. Und wie schneidet dieses MacBook Pro dabei verglichen mit der Vorgängergeneration ab? Es liefert die gleiche fantastische Leistung.
     
    Hat beste Verbindungen.
    Unterwegs hast du mit der 802.11n Technologie im MacBook Pro immer Verbindung.8 Das MacBook Pro findet automatisch verfügbare Netzwerke und du kannst dich mit einem Klick verbinden. Auch die drahtlose Bluetooth Technologie ist integriert, sodass du drahtloses Zubehör sofort nach dem Auspacken verwenden kannst.
     
    Immer Anschluss finden.
    Mit dem neuen Thunderbolt Anschluss kannst du bis zu sechs Geräte in Reihenschaltung anschließen, darunter auch dein Display. So bekommst du eine vollwertige Workstation. Für die Anbindung von iPad, iPod, iPhone, Digitalkameras und externen Festplatten gibt es zwei USB 2.0 Anschlüsse (drei beim 17"" MacBook Pro) und einen FireWire 800 Anschluss.
     
    Der neue SDXC Kartensteckplatz der 13"" und 15"" MacBook Pro Modelle unterstützt bis zu 64 GB Karten und macht es leicht, alle deine Fotos auf und von deinem MacBook Pro zu übertragen, damit du sie sofort bearbeiten und teilen kannst. Und der ExpressCard/34 Steckplatz am 17"" MacBook Pro ist perfekt für einen eSATA Adapter geeignet oder sogar für eine 3G Karte für die drahtlose Kommunikation, wenn kein Wi-Fi Netzwerk vorhanden ist.
     
    DVDs superschnell brennen.
    Homevideos, die du mit iMovie und iDVD gemacht hast, kannst du mit dem 8-fach SuperDrive Laufwerk des MacBook Pro superschnell auf eine DVD brennen. Das SuperDrive kann auch Double-Layer-DVDs (also DVDs mit fast 9 GB Speicherplatz) beschreiben, sodass es auch hervorragend für Datensicherungen geeignet ist.
    ";2;False;0;;;Apple MacBook Pro MD313D/A 13,3 Zoll Notebook;apple-macbook-pro-md313da-133-zoll-notebook-2;True;True;PD-01095;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;1099.9000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;41389,3991782407;5;1;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000456-apple-macbook-pro-md313da-133-zoll-notebook.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000457-apple-macbook-pro-md313da-133-zoll-notebook.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000458-apple-macbook-pro-md313da-133-zoll-notebook.jpg;2;;False;;;;;False;False;False;;;;;False;;;;;; +5;0;True;Apple MacBook Pro MC721D/A 15,4 Zoll Notebook;3 GB, 16 Zoll, 350 GB, AMD, 4;"
    Apple MacBook Pro MC721D/A
    Intel Core i7 2635QM, 2 GHz

    Unibody-Gehäuse. Am Anfang jedes MacBook Pro steht ein Werkstück aus Aluminium.Stark, leicht und schön in einem.
    Das MacBook Pro ist aus einem einzigen Aluminiumblock gefertigt - eine technische Meisterleistung, bei der viele Bauteile durch ein einziges ersetzt werden. Das Ganze nennt sich Unibody. Gleich beim ersten Mal, wenn Sie ein MacBook Pro in der Hand haben, werden Sie den Unterschied spüren. Das Gehäuse ist dünner und leichter als andere Notebooks. Es sieht elegant aus. Und es fühlt sich stabil und robust an: perfekt für die Aktentasche, den Rucksack und natürlich auch für draußen.
     
    Ein Display voll brillanter Ideen.
    Alles, was Apple Designer und Ingenieure tun, ist von A bis Z durchdacht. Sie entschieden sich beim MacBook Pro für die LED-Hintergrundbeleuchtung, weil das Display damit sofort seine volle Helligkeit erreicht und trotzdem unglaublich dünn ist. Sie verwendeten eine durchgehende Oberfläche aus Glas, nicht nur weil es schön aussieht, sondern weil es dem ganzen Display Struktur verleiht. Und über dem Bildschirm haben sie die neue, integrierte FaceTime HD Kamera versteckt. So siehst du Freunde und Familie im Großformat - und dabei so gut wie nichts von der Kamera.
     
    Magnetverschluss
    Da der magnetische Verschluss keine beweglichen Teile hat, die abbrechen können oder an denen man hängen bleibt, ist das Öffnen und Schließen so einfach wie alles beim MacBook Pro.
     
    Einfach auf alle Anschlüsse zugreifen.
    Alle Anschlüsse am MacBook Pro - der MagSafe Netzanschluss, der Gigabit Ethernetanschluss, der Thunderbolt Anschluss, der USB Anschluss, der Karten-Steckplatz und der Audioeingang und -ausgang - sind ganz auf einer Seite des Notebooks integriert. So bleiben die Kabel schön geordnet und Geräte lassen sich schnell und einfach anschließen und auch wieder trennen.
     
    Hinterlässt Eindruck. Aber nicht auf die Umwelt.
    Weil Apple die vollständige Kontrolle über Design, Fertigung und Verpackung des MacBook Pro hat, hat Apple einen Vorsprung beim Umweltschutz. Die Technologie zur Hintergrundbeleuchtung des Displays spart Energie. Glas und Aluminium sind besonders recyclingfähig. Das MacBook Pro kommt fast ohne Giftstoffe aus. Und die Verpackung des 39,11 cm / 15,4"" Modells ist im Vergleich zum Vorgängermodell 34 Prozent kleiner. Das bedeutet nicht nur, dass für die Verpackungen weniger Bäume gefällt werden, es werden für den Transport auch weniger Flugzeugen, Güterzügen und LKWs benötigt.
     
    Thunderbolt AnschlussDie Grafikleistung, die Sie brauchen, wenn Sie sie brauchen.
    Alle MacBook Pro Modelle haben jetzt einen integrierten Intel HD Graphics 3000 Prozessor für die täglichen Aufgaben. Er codiert Videos schnell, ermöglicht HD Videotelefonate mit FaceTime und vieles mehr. Und auch Decodieren erledigt er effizienter, was bedeutet, dass Sie richtig lange DVDs und iTunes Filme schauen können. Bei anspruchsvollen Grafikprogrammen wechseln die 39,11 cm / 15,4"" MacBook Pro Modelle automatisch den Grafikprozessor und arbeiten mit den neuen leistungsstarken AMD Radeon Grafikprozessoren. Diese bieten verglichen mit den Vorgängermodellen die bis zu 3-fache Leistung. So sehen Sie bei 3D Spielen mehr Bilder pro Sekunde oder können schneller als je zuvor an HD Videoprojekten arbeiten.
     
    Das neue Thunderbolt. Die schnellste, vielseitigste I/O Technologie in einem Notebook.
    Stellen Sie sich vor, Sie könnten auf deinem Notebook auf mehrere unkomprimierte HD Videostreams zugreifen - und zwar so schnell, dass Sie einen HD Spielfilm in Echtzeit schneiden können. Thunderbolt macht genau das möglich. Mit Thunderbolt lassen sich superschnelle Peripheriegeräte der nächsten Generation an die Computer der nächsten Generation anschließen - angefangen beim MacBook Pro. Die Thunderbolt Pipeline ist ultraschnell und ultraflexibel. Sie ist über 12 Mal schneller als FireWire 800 und bis zu 20 Mal schneller als USB 2.0. Und sie bietet beispiellose Erweiterungsmöglichkeiten. Kurzum: Sie verändert alles, was Sie auf Ihrem Notebook machen können. Der Thunderbolt Anschluss gibt Ihnen Plug&Play Anschluss für eine völlig neue Welt von Thunderbolt Peripheriegeräten sowie für das Apple LED Cinema Display und andere Mini DisplayPort Peripheriegeräte. Sie können bis zu sechs Thunderbolt Geräte in Reihenschaltung anschließen, darunter auch Ihr Display. Außerdem unterstützt Thunderbolt Video und Achtkanal-Audio, sodass es auch möglich ist, HDMI-kompatible Geräte wie Fernseher oder Stereoanlagen über einen HDMI-Adapter anzuschließen. Auch aktuelle VGA-, DVI- und DisplayPort Adapter werden unterstützt.
     
    Die neue FaceTime HD Kamera. Der Unterschied ist ganz klar.
    Sehen Sie mehr von Ihren Freunden mit dem HD Widescreenformat - und zwar gestochen scharf. Die neue FaceTime HD Kamera bietet die dreifache Auflösung der vorherigen Kamera, was perfekt für das brillante Display mit LED-Hintergrundbeleuchtung ist. Außerdem arbeitet sie jetzt bei schwachem Licht noch besser. Sie können mit Ihren Freunden HD Telefonate in 720p von einem neuen MacBook Pro zu einem anderen führen. Außerdem sind auch Videotelefonate zu anderen Macs mit Intel Prozessor, zum iPhone 4 oder zum neuen iPod touch möglich.
     
    Multi-Touch Trackpad - Jede Menge Platz für GestenMulti-Touch Trackpad. Fürs tägliche Handwerk.
    Mit dem Multi-Touch Trackpad interagieren Sie auf ganz natürliche Art mit den Inhalten auf deinem Display. Und die glatte Glasoberfläche bietet jede Menge Platz für Gesten. Durch Auf- und Zuziehen können Sie ein- und auszoomen, durch Streichen in deinen Fotos blättern, durch Drehen ein Bild anpassen und vieles mehr. Das Trackpad kommt ohne Taste aus, sodass Sie überall klicken können. Wenn Sie aus der Welt des rechten Mausklicks kommen, können Sie diesen entweder mit zwei Fingern auslösen, oder Sie konfigurieren einen physischen Rechtsklick-Bereich auf dem Trackpad. Je mehr Sie mit dem Multi-Touch Trackpad vertraut sind, desto mehr werden Sie sich fragen, wie Sie jemals ohne ausgekommen sind.
     
    Lange Laufzeit. Weniger aufladen. Mehr machen.
    Das neue MacBook Pro bietet eine fantastische Batterielaufzeit und das mit leistungsstärkeren Prozessoren und schnelleren Grafikprozessoren. Die energieeffiziente Prozessorarchitektur mit integriertem Video-Encoder sowie das automatische Umschalten zwischen den Grafikprozessoren bei den 39,11 cm / 15,4"" Modellen helfen, die Batterielaufzeit weiter zu verbessern. So können Sie pro Ladung bis zu 7 Stunden ohne Kabel im Web surfen oder es für Liveauftritte oder auf ein Shooting mitnehmen. Die fortschrittlichen chemischen Eigenschaften und die Adaptive Charging Technologie sorgen dafür, dass die Batterie bis zu 1000 Ladezyklen durchlaufen kann. Und da die Batterie des MacBook Pro bis zu fünf Jahre hält, kommt das MacBook Pro in einem Zeitraum, in dem ein herkömmliches Notebook drei Batterien verbraucht, mit nur einer aus. Das ist für die Benutzer genauso gut, wie für die Umwelt. Apple verwendet eine neue, strengere Testmethode, um zu messen, welche Ergebnisse Sie unter realen Bedingungen erzielen, z. B. beim Surfen in einem Cafe oder wenn Sie die neuesten Webvideos ansehen. Und wie schneidet dieses MacBook Pro dabei verglichen mit der Vorgängergeneration ab? Es liefert die gleiche fantastische Leistung.
     
    Hat beste Verbindungen.
    Unterwegs haben Sie mit der 802.11n Technologie im MacBook Pro immer Verbindung. Das MacBook Pro findet automatisch verfügbare Netzwerke und Sie können sich mit einem Klick verbinden. Auch die drahtlose Bluetooth Technologie ist integriert, sodass Sie drahtloses Zubehör sofort nach dem Auspacken verwenden können.
     
    DVDs superschnell brennen.
    Homevideos, die Sie mit iMovie und iDVD gemacht haben, können Sie mit dem 8-fach SuperDrive Laufwerk des MacBook Pro superschnell auf eine DVD brennen. Das SuperDrive kann auch Double-Layer-DVDs (also DVDs mit fast 9 GB Speicherplatz) beschreiben, sodass es auch hervorragend für Datensicherungen geeignet ist.
     
    Neue Intel Core i7 Prozessoren.
    Neue Quad-Core Intel Core i7 Prozessoren sind Standard beim 39,11 cm / 15,4"" MacBook Pro. Alle Modelle verwenden die kürzlich optimierten Chipsets von Intel. Was heißt das für die neuen MacBook Pro Modelle? Kurz gesagt: Sie sind bis zu zwei Mal schneller als die Vorgängergeneration und erledigen auch anspruchsvolle Aufgaben wie HD Videoschnitt, Audiokompilierung oder Rendering mehrschichtiger Bilddateien unglaublich schnell. Und da Mac OS X Snow Leopard darauf ausgelegt ist, jeden Prozessorkern zu nutzen, holt das Betriebssystem wirklich alles an Leistung aus dem Prozessor heraus.
     
    Schnellere Einzelchip-Mikroarchitektur.
    Ob Sie einen Film ansehen, Ihren Blog auf den neuesten Stand bringen oder Fotos bearbeiten - die Daten müssen von A nach B gelangen, um verarbeitet werden zu können. Die neueste Intel Core Architektur bringt den Prozessor, den Cache, den Speichercontroller und den Grafikprozessor auf einem einzigen Chip unter. Deswegen müssen die Daten keine weiten Wege zurücklegen, was für Sie schnellere Performance und höhere Effizienz bedeutet.
     
    Turbo Boost 2.0.
    Angenommen, Sie arbeiten mit einem prozessorintensiven Programm wie Aperture 3 oder Final Cut Pro, das von einem Leistungsschub profitiert würde. Turbo Boost ist eine dynamische Technologie, die automatisch die Geschwindigkeit der aktiven Prozessorkerne auf 3,4 GHz erhöht. Turbo Boost 2.0 ist noch dynamischer und effizienter. Es wechselt die Kernfrequenz in kleineren Schritten als bisher, sodass der Prozessor die Leistung ohne Effizienzeinbußen verwalten kann. All das passiert im Hintergrund. Sie arbeiten einfach nur schneller.
     
    Hyper-Threading.
    Hyper-Threading ist jetzt Standard auf jedem MacBook Pro. Mit dieser Technologie können auf jedem Kern zwei Threads gleichzeitig laufen, Mac OS X erkennt also bei einem Quad-Core Prozessor acht und bei einem Dual-Core Prozessor vier virtuelle Kerne. Wenn Sie mehrere Programme gleichzeitig verwenden, verteilt der Prozessor die Aufgaben gleichmäßiger über eine größere Anzahl Kerne.
     
    Integrierter Speichercontroller.
    Mit schnellerem Speicherzugriff legt jeder Kern direkt mit der Verarbeitung der Daten los, statt auf ihr Eintreffen zu warten. Genau deshalb nutzt die neue Intel Core Architektur einen integrierten Speichercontroller, der den schnellen 1333 MHz Speicher direkt mit dem Prozessor verbindet und Ihre Programme immer die maximale Prozessorleistung zur Verfügung haben.
     
    Energieeffiziente Grafik.
    Dank der neuen Mikroarchitektur ist der Grafikprozessor auf dem gleichen Chip wie der Zentralprozessor und hat direkten Zugriff auf den L3-Cache. Kurze Wege bedeuten mehr Leistung. Der Grafikprozessor erhöht auch automatisch die Taktrate für noch höhere Auslastung. Ein integrierter Video-Encoder ermöglicht jetzt HD Videotelefonate mit FaceTime, und der effiziente Decoder sorgt für lange Batterielaufzeit, wenn Sie sich DVDs oder iTunes Filme ansiehen.
     
    Mac OS X. Das fortschrittlichste Betriebssystem der Welt.
    Mac OS X ist das Herz jedes MacBook Pro und Mac. Dieses Betriebssystem ist genau auf die integrierten Intel Multicore-Prozessoren und fortschrittlichen Grafikprozessoren zugeschnitten. Die neueste Version, Mac OS X Snow Leopard, basiert komplett auf einer 64-Bit-Architektur, genau wie alle anderen Programme, die mit dem Mac kommen. Das bedeutet: Alles, was Sie auf Ihrem MacBook Pro machen, passiert superschnell und mit einer unglaublichen Gesamtleistung.
     
    Hat eine ganze Menge draufProgramme, ebenso leistungsstark wie benutzerfreundlich.
    Weil Apple sowohl das MacBook Pro, wie auch die integrierte Software entwickelt, arbeitet alles perfekt zusammen. Und mit den Apple Programmen sind Sie ganz schnell vertraut, weil alle ähnlich funktionieren. Das heißt, wenn Sie ein Programm kennen, sind Sie auch schnell mit allen anderen vertraut. Außerdem weiß Apple genau, was mobile Produktivität bedeutet. Darum haben wir Funktionen wie Expose und Spaces hinzugefügt. Damit können Sie ganz einfach auf alles auf Ihrem MacBook Pro zugreifen. Expose zeigt sämtliche geöffneten Fenster nebeneinander, verkleinert sie und ordnet sie so, dass Sie den Inhalt jedes Fensters sehen können - ein Tastendruck oder eine Geste genügt. Und mit Spaces können Sie Fenster zusammen auf ihrem eigenen Schreibtisch oder Bereich gruppieren und ganz einfach zwischen diesen wechseln. Legen Sie einen Bereich zum Arbeiten fest, einen zum Spielen und einen für was auch immer. Mit Expose und Spaces haben Sie beim Multitasking auf einem Notebookdisplay einen riesigen Vorteil.
     
    Darauf verzichten Sie beim Mac: PC-Viren.
    Trojaner, Würmer, E-Mail Viren. Die digitale Welt kann ganz schön beängstigend sein. Zum Glück ist der Mac immun gegen die tausenden von Viren, die Windows Computer plagen. Denn Mac OS X kommt mit integrierten Sicherheitsmechanismen, die Sie schützen - ohne dass Sie etwas machen müssen. Und sollten doch mal potenzielle Sicherheitsrisiken auftreten, reagiert Apple sofort und stellt neue Softwareaktualisierungen und Sicherheitsverbesserungen bereit, die Sie automatisch laden und mit einem Klick installieren können.
     
    Das automatische Backup rettet Ihren Tag. Und die Woche, den Monat ...
    Backups müssen sein. Trotzdem vergissen Sie sie bestimmt hin und wieder. Deshalb kümmert sich jetzt das MacBook Pro um die Datensicherung. Time Machine, ein Programm, das auf jedem Mac dabei ist, sichert automatisch Ihr ganzes System auf einer externen Festplatte oder Time Capsule. Time Machine speichert eine Kopie von jeder Datei. Und es merkt sich, wie Ihr System an einem bestimmten Tag ausgesehen hat. So können Sie, wenn Sie wollen, die Zeit zurückdrehen und Ihren Mac wie in der Vergangenheit sehen.
     
    Mit iMovie können Sie aus Ihren Videos großartige Filme machenAuch die täglichen Sachen machen mehr Spaß.
    Anders als viele PC-Notebooks kommt das MacBook Pro mit allem, was Sie brauchen, um E-Mails zu senden, Kalender zu verwalten, Kontakte zu organisieren und mehr. Und Sie können schon wenige Minuten nach dem Auspacken damit loslegen. Denn jeder Mac kommt mit Mail, um E-Mails zu senden und empfangen, iCal zum Organisieren von Terminen und wichtigen Ereignissen, dem Adressbuch zum Verwalten von Kontakten, iTunes für alles, was mit Unterhaltung zu tun hat, und weiteren tollen und nützlichen Programmen, die Sie jeden Tag verwenden werden.
     
    Der Mac App Store. Tausend weitere Gründe, den Mac zu lieben.
    Über tausend Mac Apps sind nur einen Klick entfernt - im Mac App Store. Suchen Sie einfach Apps, die Ihnen gefallen, und klicken Sie einfach, um sie zu laden und zu installieren. Ohne Verpackung. Ohne CDs oder DVDs. Und ohne Probleme. Sie können die Apps nach Kategorien durchstöbern oder direkt etwas Bestimmtes suchen. Und Sie können einfach dafür sorgen, dass Ihre Apps up-to-date sind, denn Ihr Mac zeigt Ihnen an, wann Updates verfügbar sind.
     
    iPhoto. Fotos ganz einfach verwalten, bearbeiten und teilen.
    iPhoto ist ein benutzerfreundliches Programm für Fotos, mit dem Sie Ihre Bilder schnell organisieren, wiederfinden und verbessern können - sodass sie immer perfekt aussehen. Mit den iPhoto Funktionen ""Gesichter"", ""Orte"" und ""Ereignisse"" behalten Sie den Überblick über Ihre Fotos. Sie sagen Ihnen, wen Sie fotografiert haben, wo und wann. Und all das in den neuen Vollbildmodi.
     
    iMovie. Und aus Homevideos werden Home-Blockbuster.
    Homevideos müssen nicht langweilig sein. Mit iMovie können Sie aus Ihren Videos großartige Filme machen. Zum Beispiel Trailer im Hollywoodstil, mit denen Sie Ihr Publikum begeistern.
     
    GarageBand. Großartige Musik machen, ganz einfachissimo.
    Egal, ob Sie Musiktalent haben oder einfach nur neugierig sind - GarageBand ist genau das richtige Programm für Sie. Schließ einfach eine elektrische Gitarre oder ein USB Keyboard an. Und schon können Sie mit virtuellen Nachbildungen der bekanntesten Amps und Stompboxes der Welt sowie mit 100 Software-Instrumenten spielen.
    ";2;False;0;;;Apple MacBook Pro MC721D/A 15,4 Zoll Notebook;apple-macbook-pro-mc721da-154-zoll-notebook-2;True;True;PD-01093;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;2,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;1483.9000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;41389,3991666667;5;1;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000545-apple-macbook-pro-mc721da-154-zoll-notebook.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000546-apple-macbook-pro-mc721da-154-zoll-notebook.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000547-apple-macbook-pro-mc721da-154-zoll-notebook.jpg;2;;False;;;;;False;False;False;;;;;False;;;;;; +5;0;True;Apple MacBook Pro MC725D/A 17 Zoll Notebook;4 GB, 17 Zoll, 500 GB, Tantel, 3;"
    Apple MacBook Pro MC725D/A
    Intel Core i7 2720QM, 2,2 GHz
     
    Stark, leicht und schön in einem.
    Das MacBook Pro ist aus einem einzigen Aluminiumblock gefertigt - eine technische Meisterleistung, bei der viele Bauteile durch ein einziges ersetzt werden. Das Ganze nennt sich Unibody. Gleich beim ersten Mal, wenn Sie ein MacBook Pro in der Hand haben, werden Sie den Unterschied spüren. Das Gehäuse ist dünner und leichter als andere Notebooks. Es sieht elegant aus. Und es fühlt sich stabil und robust an: perfekt für die Aktentasche, den Rucksack und natürlich auch für draußen.
     
    Ein Display voll brillanter Ideen.
    Alles, was Apple Designer und Ingenieure tun, ist von A bis Z durchdacht. Sie entschieden sich beim MacBook Pro für die LED-Hintergrundbeleuchtung, weil das Display damit sofort seine volle Helligkeit erreicht und trotzdem unglaublich dünn ist. Sie verwendeten eine durchgehende Oberfläche aus Glas, nicht nur weil es schön aussieht, sondern weil es dem ganzen Display Struktur verleiht. Und über dem Bildschirm haben sie die neue, integrierte FaceTime HD Kamera versteckt. So siehst du Freunde und Familie im Großformat - und dabei so gut wie nichts von der Kamera.
     
    Magnetverschluss
    Da der magnetische Verschluss keine beweglichen Teile hat, die abbrechen können oder an denen man hängen bleibt, ist das Öffnen und Schließen so einfach wie alles beim MacBook Pro.
     
    Einfach auf alle Anschlüsse zugreifen.
    Alle Anschlüsse am MacBook Pro - der MagSafe Netzanschluss, der Gigabit Ethernetanschluss, der Thunderbolt Anschluss, der USB Anschluss, der Karten-Steckplatz und der Audioeingang und -ausgang - sind ganz auf einer Seite des Notebooks integriert. So bleiben die Kabel schön geordnet und Geräte lassen sich schnell und einfach anschließen und auch wieder trennen.
     
    Hinterlässt Eindruck. Aber nicht auf die Umwelt.
    Weil Apple die vollständige Kontrolle über Design, Fertigung und Verpackung des MacBook Pro hat, hat Apple einen Vorsprung beim Umweltschutz. Die Technologie zur Hintergrundbeleuchtung des Displays spart Energie. Glas und Aluminium sind besonders recyclingfähig. Das MacBook Pro kommt fast ohne Giftstoffe aus. Und die Verpackung des 43,18 cm / 17"" Modells ist im Vergleich zum Vorgängermodell 34 Prozent kleiner. Das bedeutet nicht nur, dass für die Verpackungen weniger Bäume gefällt werden, es werden für den Transport auch weniger Flugzeugen, Güterzügen und LKWs benötigt.
     
    Thunderbolt AnschlussDie Grafikleistung, die Sie brauchen, wenn Sie sie brauchen.
    Alle MacBook Pro Modelle haben jetzt einen integrierten Intel HD Graphics 3000 Prozessor für die täglichen Aufgaben. Er codiert Videos schnell, ermöglicht HD Videotelefonate mit FaceTime und vieles mehr. Und auch Decodieren erledigt er effizienter, was bedeutet, dass Sie richtig lange DVDs und iTunes Filme schauen können. Bei anspruchsvollen Grafikprogrammen wechseln die 43,18 cm / 17"" MacBook Pro Modelle automatisch den Grafikprozessor und arbeiten mit den neuen leistungsstarken AMD Radeon Grafikprozessoren. Diese bieten verglichen mit den Vorgängermodellen die bis zu 3-fache Leistung. So sehen Sie bei 3D Spielen mehr Bilder pro Sekunde oder können schneller als je zuvor an HD Videoprojekten arbeiten.
     
    Das neue Thunderbolt. Die schnellste, vielseitigste I/O Technologie in einem Notebook.
    Stellen Sie sich vor, Sie könnten auf deinem Notebook auf mehrere unkomprimierte HD Videostreams zugreifen - und zwar so schnell, dass Sie einen HD Spielfilm in Echtzeit schneiden können. Thunderbolt macht genau das möglich. Mit Thunderbolt lassen sich superschnelle Peripheriegeräte der nächsten Generation an die Computer der nächsten Generation anschließen - angefangen beim MacBook Pro. Die Thunderbolt Pipeline ist ultraschnell und ultraflexibel. Sie ist über 12 Mal schneller als FireWire 800 und bis zu 20 Mal schneller als USB 2.0. Und sie bietet beispiellose Erweiterungsmöglichkeiten. Kurzum: Sie verändert alles, was Sie auf Ihrem Notebook machen können. Der Thunderbolt Anschluss gibt Ihnen Plug&Play Anschluss für eine völlig neue Welt von Thunderbolt Peripheriegeräten sowie für das Apple LED Cinema Display und andere Mini DisplayPort Peripheriegeräte. Sie können bis zu sechs Thunderbolt Geräte in Reihenschaltung anschließen, darunter auch Ihr Display. Außerdem unterstützt Thunderbolt Video und Achtkanal-Audio, sodass es auch möglich ist, HDMI-kompatible Geräte wie Fernseher oder Stereoanlagen über einen HDMI-Adapter anzuschließen. Auch aktuelle VGA-, DVI- und DisplayPort Adapter werden unterstützt.
     
    Die neue FaceTime HD Kamera. Der Unterschied ist ganz klar.
    Sehen Sie mehr von Ihren Freunden mit dem HD Widescreenformat - und zwar gestochen scharf. Die neue FaceTime HD Kamera bietet die dreifache Auflösung der vorherigen Kamera, was perfekt für das brillante Display mit LED-Hintergrundbeleuchtung ist. Außerdem arbeitet sie jetzt bei schwachem Licht noch besser. Sie können mit Ihren Freunden HD Telefonate in 720p von einem neuen MacBook Pro zu einem anderen führen. Außerdem sind auch Videotelefonate zu anderen Macs mit Intel Prozessor, zum iPhone 4 oder zum neuen iPod touch möglich.
     
    Multi-Touch Trackpad - Jede Menge Platz für GestenMulti-Touch Trackpad. Fürs tägliche Handwerk.
    Mit dem Multi-Touch Trackpad interagieren Sie auf ganz natürliche Art mit den Inhalten auf deinem Display. Und die glatte Glasoberfläche bietet jede Menge Platz für Gesten. Durch Auf- und Zuziehen können Sie ein- und auszoomen, durch Streichen in deinen Fotos blättern, durch Drehen ein Bild anpassen und vieles mehr. Das Trackpad kommt ohne Taste aus, sodass Sie überall klicken können. Wenn Sie aus der Welt des rechten Mausklicks kommen, können Sie diesen entweder mit zwei Fingern auslösen, oder Sie konfigurieren einen physischen Rechtsklick-Bereich auf dem Trackpad. Je mehr Sie mit dem Multi-Touch Trackpad vertraut sind, desto mehr werden Sie sich fragen, wie Sie jemals ohne ausgekommen sind.
     
    Lange Laufzeit. Weniger aufladen. Mehr machen.
    Das neue MacBook Pro bietet eine fantastische Batterielaufzeit und das mit leistungsstärkeren Prozessoren und schnelleren Grafikprozessoren. Die energieeffiziente Prozessorarchitektur mit integriertem Video-Encoder sowie das automatische Umschalten zwischen den Grafikprozessoren bei den 43,18 cm / 17"" Modellen helfen, die Batterielaufzeit weiter zu verbessern. So können Sie pro Ladung bis zu 7 Stunden ohne Kabel im Web surfen oder es für Liveauftritte oder auf ein Shooting mitnehmen. Die fortschrittlichen chemischen Eigenschaften und die Adaptive Charging Technologie sorgen dafür, dass die Batterie bis zu 1000 Ladezyklen durchlaufen kann. Und da die Batterie des MacBook Pro bis zu fünf Jahre hält, kommt das MacBook Pro in einem Zeitraum, in dem ein herkömmliches Notebook drei Batterien verbraucht, mit nur einer aus. Das ist für die Benutzer genauso gut, wie für die Umwelt. Apple verwendet eine neue, strengere Testmethode, um zu messen, welche Ergebnisse Sie unter realen Bedingungen erzielen, z. B. beim Surfen in einem Cafe oder wenn Sie die neuesten Webvideos ansehen. Und wie schneidet dieses MacBook Pro dabei verglichen mit der Vorgängergeneration ab? Es liefert die gleiche fantastische Leistung.
     
    Hat beste Verbindungen.
    Unterwegs haben Sie mit der 802.11n Technologie im MacBook Pro immer Verbindung. Das MacBook Pro findet automatisch verfügbare Netzwerke und Sie können sich mit einem Klick verbinden. Auch die drahtlose Bluetooth Technologie ist integriert, sodass Sie drahtloses Zubehör sofort nach dem Auspacken verwenden können.
     
    DVDs superschnell brennen.
    Homevideos, die Sie mit iMovie und iDVD gemacht haben, können Sie mit dem 8-fach SuperDrive Laufwerk des MacBook Pro superschnell auf eine DVD brennen. Das SuperDrive kann auch Double-Layer-DVDs (also DVDs mit fast 9 GB Speicherplatz) beschreiben, sodass es auch hervorragend für Datensicherungen geeignet ist.
     
    Neue Intel Core i7 Prozessoren.
    Neue Quad-Core Intel Core i7 Prozessoren sind Standard beim 43,18 cm / 17"" MacBook Pro. Alle Modelle verwenden die kürzlich optimierten Chipsets von Intel. Was heißt das für die neuen MacBook Pro Modelle? Kurz gesagt: Sie sind bis zu zwei Mal schneller als die Vorgängergeneration und erledigen auch anspruchsvolle Aufgaben wie HD Videoschnitt, Audiokompilierung oder Rendering mehrschichtiger Bilddateien unglaublich schnell. Und da Mac OS X Snow Leopard darauf ausgelegt ist, jeden Prozessorkern zu nutzen, holt das Betriebssystem wirklich alles an Leistung aus dem Prozessor heraus.
     
    Schnellere Einzelchip-Mikroarchitektur.
    Ob Sie einen Film ansehen, Ihren Blog auf den neuesten Stand bringen oder Fotos bearbeiten - die Daten müssen von A nach B gelangen, um verarbeitet werden zu können. Die neueste Intel Core Architektur bringt den Prozessor, den Cache, den Speichercontroller und den Grafikprozessor auf einem einzigen Chip unter. Deswegen müssen die Daten keine weiten Wege zurücklegen, was für Sie schnellere Performance und höhere Effizienz bedeutet.
     
    Turbo Boost 2.0.
    Angenommen, Sie arbeiten mit einem prozessorintensiven Programm wie Aperture 3 oder Final Cut Pro, das von einem Leistungsschub profitiert würde. Turbo Boost ist eine dynamische Technologie, die automatisch die Geschwindigkeit der aktiven Prozessorkerne auf 3,4 GHz erhöht. Turbo Boost 2.0 ist noch dynamischer und effizienter. Es wechselt die Kernfrequenz in kleineren Schritten als bisher, sodass der Prozessor die Leistung ohne Effizienzeinbußen verwalten kann. All das passiert im Hintergrund. Sie arbeiten einfach nur schneller.
     
    Hyper-Threading.
    Hyper-Threading ist jetzt Standard auf jedem MacBook Pro. Mit dieser Technologie können auf jedem Kern zwei Threads gleichzeitig laufen, Mac OS X erkennt also bei einem Quad-Core Prozessor acht und bei einem Dual-Core Prozessor vier virtuelle Kerne. Wenn Sie mehrere Programme gleichzeitig verwenden, verteilt der Prozessor die Aufgaben gleichmäßiger über eine größere Anzahl Kerne.
     
    Integrierter Speichercontroller.
    Mit schnellerem Speicherzugriff legt jeder Kern direkt mit der Verarbeitung der Daten los, statt auf ihr Eintreffen zu warten. Genau deshalb nutzt die neue Intel Core Architektur einen integrierten Speichercontroller, der den schnellen 1333 MHz Speicher direkt mit dem Prozessor verbindet und Ihre Programme immer die maximale Prozessorleistung zur Verfügung haben.
     
    Energieeffiziente Grafik.
    Dank der neuen Mikroarchitektur ist der Grafikprozessor auf dem gleichen Chip wie der Zentralprozessor und hat direkten Zugriff auf den L3-Cache. Kurze Wege bedeuten mehr Leistung. Der Grafikprozessor erhöht auch automatisch die Taktrate für noch höhere Auslastung. Ein integrierter Video-Encoder ermöglicht jetzt HD Videotelefonate mit FaceTime, und der effiziente Decoder sorgt für lange Batterielaufzeit, wenn Sie sich DVDs oder iTunes Filme ansiehen.
     
    Mac OS X. Das fortschrittlichste Betriebssystem der Welt.
    Mac OS X ist das Herz jedes MacBook Pro und Mac. Dieses Betriebssystem ist genau auf die integrierten Intel Multicore-Prozessoren und fortschrittlichen Grafikprozessoren zugeschnitten. Die neueste Version, Mac OS X Snow Leopard, basiert komplett auf einer 64-Bit-Architektur, genau wie alle anderen Programme, die mit dem Mac kommen. Das bedeutet: Alles, was Sie auf Ihrem MacBook Pro machen, passiert superschnell und mit einer unglaublichen Gesamtleistung.
     
    Hat eine ganze Menge draufProgramme, ebenso leistungsstark wie benutzerfreundlich.
    Weil Apple sowohl das MacBook Pro, wie auch die integrierte Software entwickelt, arbeitet alles perfekt zusammen. Und mit den Apple Programmen sind Sie ganz schnell vertraut, weil alle ähnlich funktionieren. Das heißt, wenn Sie ein Programm kennen, sind Sie auch schnell mit allen anderen vertraut. Außerdem weiß Apple genau, was mobile Produktivität bedeutet. Darum haben wir Funktionen wie Expose und Spaces hinzugefügt. Damit können Sie ganz einfach auf alles auf Ihrem MacBook Pro zugreifen. Expose zeigt sämtliche geöffneten Fenster nebeneinander, verkleinert sie und ordnet sie so, dass Sie den Inhalt jedes Fensters sehen können - ein Tastendruck oder eine Geste genügt. Und mit Spaces können Sie Fenster zusammen auf ihrem eigenen Schreibtisch oder Bereich gruppieren und ganz einfach zwischen diesen wechseln. Legen Sie einen Bereich zum Arbeiten fest, einen zum Spielen und einen für was auch immer. Mit Expose und Spaces haben Sie beim Multitasking auf einem Notebookdisplay einen riesigen Vorteil.
     
    Darauf verzichten Sie beim Mac: PC-Viren.
    Trojaner, Würmer, E-Mail Viren. Die digitale Welt kann ganz schön beängstigend sein. Zum Glück ist der Mac immun gegen die tausenden von Viren, die Windows Computer plagen. Denn Mac OS X kommt mit integrierten Sicherheitsmechanismen, die Sie schützen - ohne dass Sie etwas machen müssen. Und sollten doch mal potenzielle Sicherheitsrisiken auftreten, reagiert Apple sofort und stellt neue Softwareaktualisierungen und Sicherheitsverbesserungen bereit, die Sie automatisch laden und mit einem Klick installieren können.
     
    Das automatische Backup rettet Ihren Tag. Und die Woche, den Monat ...
    Backups müssen sein. Trotzdem vergissen Sie sie bestimmt hin und wieder. Deshalb kümmert sich jetzt das MacBook Pro um die Datensicherung. Time Machine, ein Programm, das auf jedem Mac dabei ist, sichert automatisch Ihr ganzes System auf einer externen Festplatte oder Time Capsule. Time Machine speichert eine Kopie von jeder Datei. Und es merkt sich, wie Ihr System an einem bestimmten Tag ausgesehen hat. So können Sie, wenn Sie wollen, die Zeit zurückdrehen und Ihren Mac wie in der Vergangenheit sehen.
     
    Mit iMovie können Sie aus Ihren Videos großartige Filme machenAuch die täglichen Sachen machen mehr Spaß.
    Anders als viele PC-Notebooks kommt das MacBook Pro mit allem, was Sie brauchen, um E-Mails zu senden, Kalender zu verwalten, Kontakte zu organisieren und mehr. Und Sie können schon wenige Minuten nach dem Auspacken damit loslegen. Denn jeder Mac kommt mit Mail, um E-Mails zu senden und empfangen, iCal zum Organisieren von Terminen und wichtigen Ereignissen, dem Adressbuch zum Verwalten von Kontakten, iTunes für alles, was mit Unterhaltung zu tun hat, und weiteren tollen und nützlichen Programmen, die Sie jeden Tag verwenden werden.
     
    Der Mac App Store. Tausend weitere Gründe, den Mac zu lieben.
    Über tausend Mac Apps sind nur einen Klick entfernt - im Mac App Store. Suchen Sie einfach Apps, die Ihnen gefallen, und klicken Sie einfach, um sie zu laden und zu installieren. Ohne Verpackung. Ohne CDs oder DVDs. Und ohne Probleme. Sie können die Apps nach Kategorien durchstöbern oder direkt etwas Bestimmtes suchen. Und Sie können einfach dafür sorgen, dass Ihre Apps up-to-date sind, denn Ihr Mac zeigt Ihnen an, wann Updates verfügbar sind.
     
    iPhoto. Fotos ganz einfach verwalten, bearbeiten und teilen.
    iPhoto ist ein benutzerfreundliches Programm für Fotos, mit dem Sie Ihre Bilder schnell organisieren, wiederfinden und verbessern können - sodass sie immer perfekt aussehen. Mit den iPhoto Funktionen ""Gesichter"", ""Orte"" und ""Ereignisse"" behalten Sie den Überblick über Ihre Fotos. Sie sagen Ihnen, wen Sie fotografiert haben, wo und wann. Und all das in den neuen Vollbildmodi.
     
    iMovie. Und aus Homevideos werden Home-Blockbuster.
    Homevideos müssen nicht langweilig sein. Mit iMovie können Sie aus Ihren Videos großartige Filme machen. Zum Beispiel Trailer im Hollywoodstil, mit denen Sie Ihr Publikum begeistern.
     
    GarageBand. Großartige Musik machen, ganz einfachissimo.
    Egal, ob Sie Musiktalent haben oder einfach nur neugierig sind - GarageBand ist genau das richtige Programm für Sie. Schließ einfach eine elektrische Gitarre oder ein USB Keyboard an. Und schon können Sie mit virtuellen Nachbildungen der bekanntesten Amps und Stompboxes der Welt sowie mit 100 Software-Instrumenten spielen.  
    ";2;False;0;;;Apple MacBook Pro MC725D/A 17 Zoll Notebook;apple-macbook-pro-mc725da-17-zoll-notebook-2;True;True;PD-01094;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;2,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;2299.9000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;41389,3991666667;5;1;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000312-apple-macbook-pro-mc725da-17-zoll-notebook.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000313-apple-macbook-pro-mc725da-17-zoll-notebook.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000314-apple-macbook-pro-mc725da-17-zoll-notebook.jpg;2;;False;;;;;False;False;False;;;;;False;;;;;; +5;0;True;Asus Eee PC 1001HA 10,1 Zoll Netbook;3 GB, 17 Zoll, 400 GB, AMDl, 3;"
    Eee PC™ 1001HA: Klasse Leistung zu unschlagbarem Preis
     
    Der Eee PC™ 1001HA unterscheidet sich von seinen großen Brüdern durch Prozessor und Akkukapazität. Ausgestattet mit einem Intel® Atom™ N270 Prozessor, einem 3 Zellen Akku für bis zu 4 Stunden Laufzeit, WLAN 802.11n Standard sowie weiteren Top Merkmalen, überzeugt der Eee PC™ 1001HA zu einem wirklich unschlagbaren Preis.
     
    Eee PC™ 1001HA: Funktionalität meets Design
     
    Mit dem kompakten Eee PC™ 1001HA trägt ASUS seinem Anspruch, in den Produkten höchste Funktionalität mit formvollendetem Design zu verbinden, ein weiteres Mal Rechnung. So besticht der neue Eee PC™ durch sein elegantes und gleichzeitig unempfindliches Gehäuse, das mit klaren Linien und nach unten schmaler zulaufenden Kanten dem schlanken Design einer Muschel nachempfunden ist. Aber auch das Innenleben der Kleinen kommt ganz groß raus. Als gewohnt kontaktfreudig erweisen sich die Neulinge dank VGA Port für den Anschluss eines Monitors sowie drei USB 2.0 Schnittstellen, um Maus, Tastatur oder Digicam anzuschließen. Wer Bilder direkt von der SD oder MMC Speicherkarte auf den Eee PC™ übertragen möchte, nutzt den integrierten Kartenleser. Für das Speichern der Fotos stehen bei beiden Modellen eine 160 GB S-ATA Festplatte zur Verfügung.. Das Modell basiert auf Microsoft® Windows® XP Home und ist – wie alle Eee Familienmitglieder – ausgesprochen einfach zu bedienen. Das 10 Zoll WSVGA Display mit stromsparender LED-Hintergrundbeleuchtung sowie die große Tastatur, die zu 92% einer Standard Notebooktastatur entspricht, gewähren zusätzlichen Komfort. Für Chats oder Videokonferenzen hat ASUS die Minis zudem mit einer 0.3 Megapixel Web-/Videokamera sowie einem Mikrofon ausgestattet.
     
     
    ";2;False;0;;;Asus Eee PC 1001HA 10,1 Zoll;asus-eee-pc-1001ha-101-zoll-netbook-2;True;True;PD-01090;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;243.9000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;41389,3988657407;5;37;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000563-asus-eee-pc-1001ha-101-zoll-netbook.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000564-asus-eee-pc-1001ha-101-zoll-netbook.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000565-asus-eee-pc-1001ha-101-zoll-netbook.jpg;2;;False;;;;;False;False;False;;;;;False;;;;;; +5;0;True;"HP Compaq Mini 110c-1110sg 10.1 Zoll Netbook ";4 GB, 18 Zoll, 800 GB, Intel, 2;"
    HP Compaq Mini 110c-1110sg 10.1 Zoll Netbook
     
    Intel Atom N270 1.6GHz, 1GB RAM, 160GB HDD, Intel GMA 950, Win XP Home
     
    Leicht und kompakt
    Der Compaq Mini 110c wiegt 1,3 kg (mit 6-Zellen-Akku) und ist ca. 5,5 cm hoch – er ist damit sehr kompakt und fällt ins Auge
     
    Elegantes Design
    Der Compaq Mini 110c glänzt mit einem eleganten Gehäuse im neuem Imprint-Finish ""Unity"", einem Karomuster, das ins Auge fällt.
     
    Ständig in Verbindung
    Webcam und Mikrofon sind im Compaq Mini integriert und bieten per WLAN und optionalem WWAN zahlreiche Möglichkeiten zur Pflege sozialer Kontakte; Video-Chats und Video-Konferenzen, die bislang nur zuhause möglich waren, können jetzt im Park, im Cafe oder am Flughafen geführt werden
     
    Information und Kommunikation auch unterwegs
    Mit dem 10,1-Zoll-BrightView-Display, Original Windows® XP Home, der großen Tastatur (92 % der vollen Größe), drei USB-Anschlüssen und einem 5-in-1 Kartenleser sind Informationen, Kommunikation und Unterhaltung im Internet überall bequem zugänglich.
    ";2;False;0;;;"HP Compaq Mini 110c-1110sg 10.1 Zoll Netbook ";hp-compaq-mini-110c-1110sg-101-zoll-netbook-2;True;True;PD-01091;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;259.9000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;41389,3988657407;"5;2095";39;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000598-hp-compaq-mini-110c-1110sg-101-zoll-netbook.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000599-hp-compaq-mini-110c-1110sg-101-zoll-netbook.jpg;;2;;False;;;;;False;False;False;;;;;False;;;;;; +5;0;True;Samsung NC10 anyNet 10,2 Zoll Netbook;2 GB, 15 Zoll, 400 GB, AMDl, 4;"
    Samsung NC10 anyNet10,2"" Netbook

    Intel Atom N270 1.6GHz, 1GB RAM, 160GB HDD, Intel GMA 950 XP Home
     
    NC10-anyNet: Entwickelt für das ""mobile Leben"". Entwickelt für höchste Ansprüche in innovativem Design. Das ultrakompakte und leichte Gehäuse bietet eine Reihe von praktischen Features, die das mobile Leben vereinfachen. Brillante Technologie angepasst an das rasante und digitale Leben für noch mehr Mobilität.
     
    Schlankes Design
    Mit einem optimierten 10,2 Zoll Breitbild Display für ein makelloses visuelles Erlebnis, ist das schlanke NC10 lediglich 1,19 cm hoch und passt nahezu in alle Taschen. Das widerstandsfähige Gehäuse bietet ein Maximum an Tragekomfort und Verlässlichkeit sowie hochwertiger Ergonomie und Stil.
     
    Videokonferenz
    Ob Videokonferenzen oder Live Messaging - die integrierte 1,3 Megapixel Kamera lässt sie noch leichter mit Freunden, Familie und Kollegen in Kontakt bleiben. Die Kamera verbindet die Auflösung und die Bildqualität einer Fotokamera mit der nachhaltig hohen Bildfrequenz einer Videokamera.
     
    Robustes Gehäuse, langlebig und verlässlich
    Fühlen Sie sich sicher mit dem robusten Protect-o-Edge Gehäuse, das für Langlebigkeit und Verlässlichkeit steht. Eine aufwendige Serie von 54 Qualitätstests, die von schnellen Temperaturwechseln bis zu elektrischen Überspannungen reichen, gewährleistet neue Standards in Punkto Belastbarkeit und Ausdauer.
     
    Antibakterielle Tastatur
    Die SilverNano Technologie beschichtet die Tastatur mit nano-kleinen Silberionen, die das Überleben und die Neuentstehung von Bakterien verhindern. Innerhalb von 24 Stunden werden 99,9% aller Bakterien abgetötet und es entsteht eine hygienische Arbeitsatmosphäre.
     
    Leichtgewicht
    Als eines der weltweit leichtesten 10,2 Zoll Mini Notebooks seiner Klasse, mit einem Gewicht von nur 1,45 kg, ist das NC10 voll bepackt mit neuester Technologie und garantiert dabei maximale Mobilität und Leistung.
      
    Vollständige Notebook-Tastatur
    Die vollständige Notebook-Tastatur bietet optimalen Schreibkomfort. Ergonomisches Design und optimierte Tastenabstände machen das Arbeiten und Kommunizieren angenehmer und ermöglichen schnelleres sowie fehlerloses Schreiben.
     
    Voll ausgestattet für einfachen Datenaustausch
    Einfacher Datenaustausch dank einer Vielzahl an Anschlussmöglichkeiten, inklusive einem Kartenleser und drei USB-Anschlüssen, so dass Sie problemlos Bilder, Filme und Daten auf und von nahezu allen modernen Kameras, periphären oder audiovisuellen Geräten transferieren können.
    ";2;False;0;;;;samsung-nc10-anynet-102-zoll-netbook-2;True;True;PD-01092;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;329.9000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;41389,3988657407;5;5;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000511-samsung-nc10-anynet-102-zoll-netbook.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000512-samsung-nc10-anynet-102-zoll-netbook.jpg;;2;;False;;;;;False;False;False;;;;;False;;;;;; +5;0;True;Germot GM 205 Integralhelm Dekor;Der GM 205 ist der Preisgünstige einsteiger Motorradhelm mit kratzfestem Außenvisier.;"
    Germot GM 205 Integralhelm
    Ideal für Rollerfahrer oder kurze touren
     
    klare, getönte und verspiegelte Visiere zu diesem Modell sind in unserem Shop erhältlich!
     
    Eigenschaften: klares, kratzfestes Visier mit Verstellraster, einfacher und schneller Visierwechsel, Visier- und Kopfbelüftung, großes Gesichtsfeld, Nasenspoiler, hautfreundliche Innenausstattung, hochwertige Mehrschichtlackierung mit UV-Schutz, Drucktastensteckschloss, ECE 22 05.

    Material: ABS/Polycarbonat Mix

    Gewicht: 1.400g +/-50g

    Größen: XS (53-54) / S (55-56) / M (57-58) / L (59-60) / XL (61-62) / 2XL (63-64)
    Größenangabe in Klammer= Kopfumfang in cm.
    ";2;False;0;GM205, rollerhelm, integralhelm,germot,motorradhelm;Der GM 205 ist der Preisgünstige einsteiger Motorradhelm und Rollerhelm mit kratzfestem Außenvisier.;Germot GM 205 Integralhelm Dekor;germot-gm-205-integralhelm-dekor;True;True;20596;;5000111105392;False;0;False;;False;False;0;False;0;1;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;2;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;79.9000;79.9000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;41129,4577083333;"1;22";1;;;;5;;False;kg;;;;False;False;False;;;;;False;;;;;; +5;0;True;Apple iPod Nano 16 GB 6. Gen. verschiedene Farben;Apple iPod Nano 16 GB 6. Generation verschiedene Farben;"
    Der Remix für Ihre Finger
    Der iPod nano mit Multi-Touch ist einfach, intuitiv und macht jede Menge Spaß - wie Ihre Musik. Und er ist jetzt noch kleiner, damit Musik bei allem, was Sie machen, eine größere Rolle spielen kann.
     
    Musik. Fühlen Sie den Beat
    Ihre Greatest Hits. Zum Anfassen
    Die besten Dinge im Leben kommen mit Soundtrack. Und genau da glänzt der iPod nano. Mit dem Multi-Touch Display können Sie Ihre Musik ganz neu erleben. Ein Tipp genügt und er spielt, was Sie hören wollen. Stöbern Sie in Ihrer Musik nach Songs, Alben, Interpreten, Wiedergabelisten, Genres oder Komponisten - streichen Sie dazu über den Homescreen. Sie können sogar die Symbole auf dem Homescreen neu ordnen, damit alles so ist, wie Sie es wollen.
     
    Das ist ein echter Musikclip
    Mit dem neuen integrierten Clip können Sie mit Ihren Lieblingssongs am Ärmel (oder in der Tasche, Jacke oder Hose) wandern, laufen, Rad fahren und abrocken. Und das Cover zum Song, der gerade läuft, passt perfekt auf das Display.
     
    Rock around the clock
    Die integrierte aufladbare Lithium-Ionen-Batterie sorgt für 24 Stunden Musik nonstop. Wenn Sie sich den 8 GB oder 16 GB iPod nano anklippen, haben Sie genug Songs für den Weg zur Arbeit, fürs Training und mehr.
     
    Songs aus dem Finger schütteln
    Überlassen Sie alles dem Zufall. Einfach den iPod nano kurz schütteln und er springt zu einem anderen Song aus Ihrer Sammlung. Schütteln ist perfekt, wenn Ihnen gerade nicht nach einer bestimmten Musik ist. Lassen Sie sich einfach überraschen.
     
    Genius. Ihr Mixmaster
     
    Eingebauter Clip

     
    Ihr persönlicher DJ
    Angenommen, Sie hören einen Song, der Ihnen gut gefällt, und möchten ähnliche hören. Ein Tipp auf Genius genügt. Genius findet weitere Songs auf Ihrem iPod nano, die gut dazu passen und erstellt eine Genius Wiedergabeliste für Sie. Wenn Sie einen Mix wollen, auf den Sie selbst nie gekommen wären, erstellen Sie einen Genius Mix in iTunes und synchronisieren ihn mit Ihrem iPod nano. Tippen Sie auf das Symbol für Genius Mixe und entdecken Sie Songs, die Sie lange nicht mehr gehört haben, oder Musik, von der Sie gar nicht mehr wussten, dass Sie sie haben.
     
    FM Radio. Und Sie haben alles auf dem Sender
    Radio nano
    Mit dem iPod nano können Sie auf der Radiowelle surfen. Der FM Tuner zeigt Ihnen den Interpreten, Song oder Sender, der gerade läuft. Ein Tipp genügt und Sie sehen die Radiosteuerungen. Streichen Sie über den Tuner, um den Sender zu wechseln, und stellen Sie dann Ihre Lieblingssender per Fingertipp ein.
     
    Live-Pause
    Wenn Sie Ihre Lieblingssendung im Radio einmal kurz unterbrechen müssen, verpassen Sie dank Live-Pause trotzdem keinen einzigen Beat. Einfach Tippen und Sendung oder Song werden angehalten. Noch mal Tippen und es geht da weiter, wo Sie aufgehört haben. Sie können sogar bis zu 15 Minuten zurückspulen und dann vorspulen, um wieder live dabei zu sein.
     
    Fitness. Treffen Sie Ihren neuen Trainer
     
    Anklippen und los geht´s
    Das neue Design des iPod nano hilft Ihnen fit zu bleiben. Weil er so klein und tragbar ist, ist er auch beim Joggen, Wandern und im Fitnessstudio immer dabei. Klippen Sie ihn an und steuern Sie Ihre Musik mit nur einem Tippen oder Streichen, sodass Sie sich voll auf Ihr Workout konzentrieren können. Ob Laufen, Walken oder der Weg zum Fitnessstudio - für den kleinen iPod nano ist kein Weg zu weit.
     
    Schritte zum Fitbleiben
    Sie können den iPod nano auch als Schrittzähler verwenden. Er zählt Ihre Schritte und hilft Ihnen beim Erreichen Ihrer Fitnessziele. Einfach anklippen und los geht´s. Sie können eine tägliche Schrittvorgabe festlegen und Ihre Fortschritte sehen, wenn Sie Ihre Daten auf die Nike+ Website laden.
     
    Rocken Sie Ihr Training
    Ob beim Joggen oder im Fitnessstudio, mit dem Nike + iPod Sport Kit (separat erhältlich) motiviert Sie der iPod nano vom Warm Up bis zum Cool Down. Ziehen Sie Ihre Nike+ Joggingschuhe an und klippen Sie sich den iPod nano an. Sehen Sie wie Sie Kilometer für Kilometer zurücklegen und hören Sie das Sprachfeedback in Echtzeit, während Ihre Songs laufen. Schließen Sie den iPod nano im Fitnessstudio an ein Gerät an, das mit Nike + iPod kompatibel ist. So zeichnet er Ihre Geschwindigkeit, die Dauer und die Laufstrecke auf, während Sie Ihr Training rocken.
     
    iTunes. Damit der iPod was zu spielen hat
    Alles für gute Unterhaltung
    iTunes ist der beste Weg, Ihren iPod nano mit den neuesten Hits, Podcasts, Hörbüchern und vielem mehr zu füllen. Und auch die beste Art, Ihre immer weiter wachsende Sammlung digitaler Medien zu durchstöbern und auf dem Mac oder PC zu organisieren. Alle im iTunes Store gekauften Inhalte und alle von CDs importierten Songs werden in Ihrer Mediathek in iTunes angezeigt. Sie können Ihre eigenen oder Genius Wiedergabelisten erstellen, Genius Mixe auswählen und alles mit Ihrem iPod nano synchronisieren. Und iTunes ist als kostenloser Download verfügbar.
     
    Der beste Music Store der Welt
    Laden Sie Ihre Lieblingssongs auf Ihren iPod nano. Oder stöbern Sie in über 13 Millionen Songs und finden Sie weitere Hits. Sie können nach dem Namen eines Interpreten, Songs oder Albums suchen und so genau die richtigen Songs finden. Sie suchen neue Musik und brauchen Hilfe? Die Genius Seitenleiste empfiehlt Ihnen neue Musik, die auf Ihren Lieblingssongs basiert. Sie können in jeden Song kostenlos 30 Sekunden reinhören. Und mit einem Klick können Sie einen Song kaufen. Er wird dann sofort geladen. Schneller und einfacher können Sie Ihre digitale Musiksammlung für den iPod nicht zusammenstellen.
     
    Bedienungshilfen
    Integrierte Bedienungshilfen.
    iPod nano kommt mit Bedienungshilfen, die Menschen mit Handicaps helfen Musik, Hörbücher und mehr zu erleben.
     
    VoiceOver
    Der iPod touch bietet VoiceOver, die weltweit erste Bildschirmlesefunktion, die auf Gesten basiert. Tippen Sie auf das Display und Sie hören eine Beschreibung des Objekts, das Sie gerade berühren. Steuern Sie den iPod nano durch Doppeltippen, Bewegen oder Streichen. Mit den optionalen Apple Earphones mit Fernbedienung und Mikrofon können Sie Ihre Musik steuern, ohne auf das Display zu sehen. VoiceOver nennt Ihnen den Song und Interpreten und spricht auch noch 29 Sprachen.
     
    Weiß auf Schwarz
    Wenn Sie stärkeren Kontrast möchten, stellen Sie das Display des iPod nano so ein, dass Weiß auf Schwarz angezeigt wird. Sie können diese Funktion in jeder App und auch auf dem Homescreen verwenden.
     
    Mono Audio
    Wenn Sie nur auf einem Ohr gut hören können, können Sie ""Mono-Audio"" aktivieren, damit die Audioausgabe auf beide Ohrhörer geleitet wird und Sie beide Kanäle mit dem gesunden Ohr hören können.

    Produktbeschreibungen
     
    Highlights
    - Multi-Touch Display
    - Genius - dein Mixmaster
    - FM Radio
    - iTunes
    - Integrierte Bedienungshilfen (VoiceOver und Weiß auf Schwarz)
     
    Akku
    - Akkutyp: Li-Ion
    - Akkulaufzeit bis zu 24 Stunden
     
    Display
    - Farbdisplay
    - Bilddiagonale: 3,91 cm
    - 1,54- Display
    - Auflösung Breite: 240 Pixel
    - Auflösung Höhe: 240 Pixel
     
    Speicher
    - Interner Speicher 8.000 MB
     
    Stromversorgung
    - USB-Lader
     
    Wiedergabeformate Audio
    - AAC
    - MP3
    - WAV
     
    Grundeigenschaften
    - Breite: 40,9 mm
    - Höhe: 37,5 mm
    - Tiefe: 8,78 mm
    - Gewicht: 21,1 g
    - Gewicht: 21,1 g
    - Farbe: Dunkelgrau
     
    Lieferumfang
    - iPod nano
    - Apple Earphones
    -Dock Connector auf USB Kabel
    - Dokumentation und wichtige Produktinformationen
    ";2;False;0;;;Apple iPod Nano 16 GB 6. Gen. verschiedene Farben;apple-ipod-nano-16-gb-6-gen-verschiedene-farben;True;True;PD-01087;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;179.0000;179.0000;179.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;40900,5013078704;49;1;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000266-apple-ipod-nano-16-gb-6-gen-verschiedene-farben.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000267-apple-ipod-nano-16-gb-6-gen-verschiedene-farben.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000268-apple-ipod-nano-16-gb-6-gen-verschiedene-farben.jpg;1;;False;;;;;False;False;False;;;;;False;;;;;; +5;0;True;Microsoft Windows XP Professional SP3 OEM;"Microsoft Windows XP Professional SP3 OEM ";"

    Microsoft Windows XP Professional SP3 OEM

    auf jedem PC installierbar-OEM
     
     
    Windows XP Professional ist das bewährte Windows-Betriebssystem für Unternehmen und Heimanwender.
    Auf der soliden Grundlage von Windows 2000 bietet Windows XP Professional verbesserte Zuverlässigkeit,
    Sicherheit, Leistung und Benutzerfreundlichkeit und setzt zugleich neue Maßstäbe in der Datenverarbeitung.
    Mit den professionellen Features zur Administration und zur Netzwerkanbindung erweitert
    Windows XP Professional den Funktionsumfang von Windows XP Home Edition.
    Windows XP Professional basiert auf einer 32-Bit-PC-Architektur und umfasst ein vollständig geschütztes Speichermodell.
     
    Dies alles macht Windows XP Professional zur zuverlässigen Version. Die Funktion ""Systemwiederherstellung""
    ermöglicht es Benutzern und Systemverwaltern, den Status eines PCs wiederherzustellen, den er vor einem Ausfall hatte,  ohne dass dabei Daten verloren gehen.
    Bei der Systemwiederherstellung werden problemlos erkennbare Wiederherstellungspunkte erstellt,
    anhand derer Sie das System auf eine bestimmte Uhrzeit wiederherstellen können. 
    ";2;False;0;;;Microsoft Windows XP Professional SP3 OEM;microsoft-windows-xp-professional-sp3-oem;True;True;P-2960;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;57.9900;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;40889,6330208333;"30;80";3;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000181-microsoft-windows-xp-professional-sp3-oem.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000182-microsoft-windows-xp-professional-sp3-oem.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000183-microsoft-windows-xp-professional-sp3-oem.jpg;2;;False;;;;;False;False;False;;;;;False;;;;;; +5;0;True;Windows 7 32 Bit;Windows 7 32 Bit;"
    Windows 7  
     
    Die umfassendste Edition von Windows 7
    Windows 7 Ultimate ist die vielseitigste und leistungsfähigste Edition von Windows 7. Sie kombiniert die bemerkenswerte Benutzerfreundlichkeit der Unterhaltungsfunktionen von Home Premium mit den unternehmensorientierten Funktionen von Professional, wozu auch die Fähigkeit zum Ausführen zahlreicher Windows XP-Produktivitätsprogramme im Windows XP-Modus gehört.
     
    Für mehr Sicherheit können Sie Ihre Daten auch mit BitLocker und Bitlocker To Go verschlüsseln. Und zur Erhöhung der Flexibilität können Sie in einer beliebigen von 35 Sprachen arbeiten. Mit Windows 7 Ultimate müssen Sie auf nichts verzichten.
     
    Windows 7 vereinfacht alltägliche Aufgaben
     
    Desktop
    Unter Windows 7 ist es nun einfacher, noch mehr Aufgaben direkt auf dem Desktop zu erledigen: Verbesserte Taskleistenvorschau, größere Symbole, Anheften und kreative Möglichkeiten der Personalisierung.
     
    Neue Möglichkeiten, mit Fenstern zu jonglieren
    Überwältigt von der Zahl der geöffneten Fenster? Windows 7 bietet drei einfache und dennoch leistungsfähige neue Funktionen, die wie folgt bezeichnet werden: Aero Shake, Aero Peek und Snap. Sie unterstützen Sie dabei, sofort den Weg durch den Desktop zu finden.
     
     
    Die verschiedenen Windows 7 Editionen im Vergleich 
     
    Spektakuläre neue Hintergrundbilder
    Seien wir ehrlich: Wir verbringen jede Menge Zeit damit, auf unsere PCs zu starren. Die Ästhetik sollte daher nicht zu kurz kommen. Darum enthält Windows 7 viele neue Desktophintergründe, so genannte Hintergrundbilder, unter denen sich alle möglichen Motive von beeindruckend bis unterhaltsam befinden. Oder probieren Sie doch einmal die neue Desktopdiashow aus, in der eine wiederkehrende Reihe von Bildern (unserer oder Ihrer) angezeigt wird. Desktop und langweilig? Das ist vorbei.
     
    Schauen Sie sich die ""Superleiste"" an
    Schon unter Windows 95 hat die Taskleiste als Ausgangspunkt zum Starten von Programmen und Umschalten zwischen Fenstern gedient. Nicht nur die Zeiten, auch die Arbeitsweisen am PC haben sich geändert. Unter Windows 7 wurde die Taskleiste daher komplett neu gestaltet, damit Sie noch mehr Aufgaben erledigen können. Sie ist ansprechender, kann besser angepasst werden und vereinfacht das Multitasking.
     
    Heimnetzgruppe
    Dank der Heimnetzgruppe brauchen Sie sich keine Gedanken mehr über die Datei- und Druckerfreigabe in einem Heimnetzwerk zu machen. Verbinden Sie mindestens zwei Windows 7-PCs, und schon kann mit der Heimnetzgruppe ganz einfach die automatische Freigabe von Musik, Bildern, Videos und Dokumentbibliotheken für andere Personen im Haus starten. Und das neue Menü ""Freigeben für"" ermöglicht die schnelle Freigabe einzelner Dateien.
     
    Machen Sie sich Sorgen um den Datenschutz? Wir auch. Und deshalb ist die Heimnetzgruppe kennwortgeschützt, sodass Sie die volle Kontrolle über den Zugriff haben. Sie entscheiden, welche Dateien freigegeben werden und welche nicht. Außerdem können Sie Ihre Dateien mit Schreibschutz versehen, d. h., der Inhalt kann von anderen angesehen, aber nicht geändert werden. Einer Heimnetzgruppe beizutreten, ist in jeder Edition von Windows 7 möglich. Das Erstellen einer Heimnetzgruppe ist jedoch nur in den Editionen Home Premium, Professional und Ultimate möglich.
     
     
    Die verbesserte Taskleiste verschafft mit Hilfe der neuen Vollbild-Vorschaufenster schnellen Überblick 
     
    Sprunglisten
    Über die in Windows 7 neu eingeführten Sprunglisten gelangen Sie nun direkt zu den Dokumenten, Bildern, Songs oder Websites, die Sie tagtäglich nutzen. Zum Öffnen einer Sprungliste klicken Sie auf der Taskleiste von Windows 7 einfach mit der rechten Maustaste auf ein Programm (Sie sind auch im Startmenü zu finden.).
     
    Der Inhalt einer Sprungliste hängt vom Programm ab. In der Sprungliste für Internet Explorer 8 werden häufig besuchte Websites angezeigt. Windows Media Player 12 enthält häufig abgespielte Musiktitel. Fehlt in der Sprungliste ein Favorit? Sie können dort beliebige Dateien ""anheften"". In Sprunglisten werden nicht nur Verknüpfungen zu Dateien angezeigt. Manchmal bieten sie auch Schnellzugriff auf Befehle für Aufgaben wie das Verfassen neuer E-Mail-Nachrichten oder das Wiedergeben von Musik.
     
    Snap
    Snap bietet eine schnelle neue Möglichkeit, die Größe geöffneter Fenster einfach durch Ziehen an die Bildschirmränder zu ändern. Je nach Rand, also, oben oder unten, rechts oder links, wird das Fenster verbreitert, oder es füllt den ganzen Bildschirm aus. Und Sie können Fenster auch nebeneinander anordnen. Mit Snap wird das Lesen, das Anordnen und das Vergleichen von Fenstern zum Kinderspiel.
     
     
    Den Desktop jederzeit im Blick dank transparenter Fenster 
     
    Windows Live Essentials
    Was ist Windows Live Essentials? Einfach ausgedrückt, handelt es sich um kostenlose Software, die einen Windows 7-PC mit noch mehr tollen Funktionen ausstattet, z. B. für E-Mail, Instant Messaging, Fotobearbeitung und Blogs. Windows Live Windows Live Essentials ist auf der Windows Live-Website verfügbar. Der kostenlose Download enthält folgende Komponenten: Messenger, Fotogalerie, Mail, Writer, Movie Maker, Symbolleiste und Family Safety.
     
    Windows Search
    Unter Windows 7 finden Sie noch schneller noch mehr Dinge an noch mehr Orten. Sobald Sie im Suchfeld des Startmenüs mit der Eingabe beginnen, wird eine Liste relevanter Dokumente, Bilder, Musiktitel und E-Mails auf dem PC angezeigt. Die Ergebnisse sind nun nach Kategorie gruppiert und enthalten hervorgehobene Stichwörter und Textausschnitte, um die Suche zu vereinfachen.
     
    Dateien werden heutzutage nur noch selten an einem Ort abgelegt. Also ist Windows 7 auch darauf ausgelegt, externe Festplatten, Netzwerk-PCs und Bibliotheken zu durchsuchen. Zu viele Suchergebnisse? Sie können die Suche direkt nach Datum, Dateityp und anderen hilfreichen Kategorien eingrenzen.
     
    Windows 7 funktioniert Ihren Vorstellungen entsprechend
     
    Leistungsverbesserungen
    Niemand wartet gerne. Darum ist Windows 7 nun noch schneller und immer bereit, wenn Sie es sind. Zu den wichtigen Leistungsverbesserungen zählen u. a. schneller Wechsel in und aus dem Energiesparmodus, weniger Speicherbedarf und schnelle Erkennung von USB-Geräten:
     
    Standbymodus
    Windows 7 kann in den Energiesparmodus versetzt und wiederhergestellt werden und die Verbindung mit dem Drahtlosnetzwerk wieder schneller herstellen.
     
     
    Sprunglisten ermöglichen schnellen Zugriff auf häufig anstehende Aufgaben 
     
    Suchen
    Wenn Sie auf der Suche nach Informationen sind, dann möchten Sie nicht lange warten, sondern Antworten bekommen. Unter Windows 7 werden Suchergebnisse schneller angezeigt. Auch das Sortieren und Gruppieren von Suchergebnissen geht viel rascher vonstatten.
     
    USB-Geräte
    Wenn Sie zum ersten Mal ein tragbares Flashlaufwerk oder ein anderes USB-Gerät anschließen, stellt Windows 7 es innerhalb weniger Sekunden für Sie bereit. Und wenn Sie es bereits zuvor verwendet haben, dann geht es sogar noch schneller.
     
    Rationaler und geringere Auslastung
    Anders als seine Vorgänger ist Windows 7 darauf ausgelegt, verlangsamende Hintergrunddienste nur dann auszuführen, wenn Sie sie benötigen. Sie verwenden kein Bluetooth-Gerät? Dann bleibt der Bluetooth-Dienst von Windows 7 ausgeschaltet. Windows 7 benötigt auch weniger Arbeitsspeicher als Windows Vista: eine weitere versteckte Optimierung, mit der die Gesamtleistung gesteigert werden kann.
     
    64-Bit-Unterstützung
    Wenn Sie sich kürzlich nach einem neuen PC umgesehen haben, dann ist Ihnen sicherlich aufgefallen, dass es mehr Computer mit 64-Bit-Prozessoren gibt. Und möglicherweise haben Sie sich gefragt, welche Vorteile sie bieten. Einfach ausgedrückt, kann ein 64-Bit-PC größere Datenmengen verarbeiten als ein 32-Bit-System. Da mehr RAM (4 GB und mehr) verwendet werden kann, kann ein 64-Bit-Computer schneller reagieren, wenn Sie viele Programme gleichzeitig ausführen.
     
    Welchen sollen Sie kaufen? Wenn Sie beabsichtigen, viele Programme gleichzeitig geöffnet zu haben oder häufig zwischen Programmen wechseln müssen und auch wenn Sie lediglich sicherstellen möchten, dass Ihr PC die derzeit größeren Speicher nutzen kann, dann ist ein 64-Bit-Computer die richtige Wahl für Sie. Wenn Sie hingegen höchstens zwei Programme gleichzeitig ausführen oder ältere Hardware und Software verwenden, die von einem 64-Bit-PC nicht unterstützt wird, ist ein 32-Bit-System geeignet. Egal, ob Sie sich für ein 32-Bit- oder ein 64-Bit-System entscheiden, Windows 7 ist bereit.
     
     
    Die verbesserte Windows Suche liefert Ergebnisse mit mehr Relevanz 
     
    Energieverwaltung
    Sie haben es satt, dass sich der Akku Ihres Laptops immer dann verabschiedet, wenn Sie ihn dringend benötigen? Unter Windows 7 können Sie die Akkulaufzeit verlängern. Wie? Zunächst einmal ist die Anzahl von unter Windows 7 ausgeführten Hintergrundaktivitäten viel kleiner, d. h., der PC-Prozessor ist weniger stark ausgelastet und damit die Stromaufnahme geringer.
     
    Zudem ist die DVD-Wiedergabe stromsparender (praktisch auf langen Flügen), der Bildschirm wird automatisch abgedunkelt, nicht verwendete Ports werden abgeschaltet, und die Anzeige für die Akkulaufzeit ist genauer. Es ist also unwahrscheinlicher, dass Sie plötzlich mit einem leeren Akku dastehen.
     
    Windows 7 macht neue Dinge möglich
     
    Netzwerk
    Mit Windows 7 wird es zum Kinderspiel, auf dem Laptop an jedem beliebigen Ort Netzwerke anzuzeigen und eine Verbindung mit diesen herzustellen. Klicken Sie einfach nur auf das Netzwerksymbol auf der Taskleiste. Mit ""Verfügbare Netzwerke anzeigen"" werden alle Optionen für Drahtlos- und verkabelte Netzwerke aufgerufen: WiFi, mobiles Breitband, DFÜ oder Unternehmens-VPN. Nur noch ein Klick, und schon steht die Verbindung.
     
    Windows Media Center
    Live-TV anschauen, anhalten und aufnehmen. Musik hören. Mit der Fotosammlung Eindruck schinden. Onlineunterhaltung genießen. Und das vom Sofa im Wohnzimmer aus. Wundert es da noch, dass Media Center von Kritikern als das verborgene Juwel von Windows bezeichnet wird?
     
    Unter Windows 7 wurde das Programm sogar noch erweitert: mit neuen, tollen Features (viele auf Ihre Anregung hin) und visuellen Verbesserungen. Windows Media Center ist in den Editionen Home Premium, Professional und Ultimate von Windows 7 enthalten. Zu den wichtigsten Neuerungen zählen u. a.:
     
     
    Komponenten wie Dateien oder Drucker gemeinsam im Heimnetzwerk nutzen 
     
    Fernsehen total ...
    Windows Media Center unterstützt mehr globale TV-Standards und TV-Tuner (z. B. Digitalfernsehen und HD). Zudem können Sie mit dem Programm nun mehr häufig verwendete Audio- und Videoformate wiedergeben, z. B. 3GP, AAC, AVCHD, DivX, MOV und Xvid.
     
    ... ohne langes Warten
    Haben Sie es satt, sich durch Fernsehprogramme oder eine umfangreiche Musikbibliothek zu quälen? Wechseln Sie schneller zu Titeln und Sendungen mit dem neuen Feature für schnelles Blättern.
     
    Atemberaubende neue Diashows
    Stellen Sie mit der neuen Diashowerstellung ansprechende Fotocollagen (mit Hintergrundmusik) zusammen. Die sind perfekt geeignet für Partys oder Familienfeiern. Und probieren Sie unbedingt den neuen Diashow-Bildschirmschoner aus: Dafür finden Sie keine Worte!
     
    Einfachere Medienfreigabe
    Schauen Sie sich aufgezeichnete TV-Sendungen, Musiktitel und Videos an, auch wenn diese nicht auf Ihrem PC gespeichert sind. Mit dem neuen Feature Heimnetzgruppe stehen Medien auf jedem PC unter Windows 7 im gesamten Haus zur Verfügung.
     
    Neue Minianwendungen, größere Vorschau
    Es gibt eine neue Media Center-Minianwendung. Videos im Schnelldurchlauf anschauen. Mehr Titel- und Sendungsdetails. Größere, besser erkennbare Vorschauminiaturansichten. Und das sind noch längst nicht alle Verbesserungen.
     
     
    Windows BitLocker verschlüsselt komplette Laufwerke 
     
    Windows Touch
    Es hat sich ""ausgemaust"": Mit Windows 7 und einem Kontaktbildschirm können Sie einfach nur mit Ihren Fingern die Onlineausgabe der Tageszeitung durchsehen, die Seiten in einem Fotoalbum durchblättern und Dateien und Ordner zufällig anordnen.
     
    Eine eingeschränkte Touchtechnologie ist bereits seit Jahren unter Windows verfügbar. Aber unter Windows 7 erobert sie jede Ecke Ihres PC. Das Startmenü und die Taskleiste weisen nun größere, fingerfreundliche Symbole auf. Auch die vertrauten Windows 7-Programme unterstützen die Fingereingabe. In Paint können Sie jetzt sogar mit dem Finger malen!
     
    Windows Touch, nur in den Editionen Home Premium, Professional und Ultimate von Windows 7 enthalten, erkennt auch Mehrfingerbewegungen (geeigneten Monitor vorausgesetzt). Sie möchten ein Bild vergrößern? Bewegen Sie Ihre Finger aufeinander zu. Sie möchten einen Rechtsklick ausführen? Berühren Sie das entsprechende Element mit einem Finger, und tippen Sie mit einem anderen Finger auf den Bildschirm.
     
    Zusätzliche Profi-Funktionen
     
    Windows XP-Modus
    Besser geht's nicht: Mit dem neuen Windows XP-Modus können Sie ältere Windows XP-Geschäftsprogramme direkt auf dem Windows 7-Desktop ausführen. Das Feature, das in erster Linie für kleine und mittelständische Unternehmen entwickelt wurde, steht als separater Download zur Verfügung und kann nur in Verbindung mit Windows 7 Professional und Ultimate eingesetzt werden. Der Windows XP-Modus setzt zudem auch eine Virtualisierungssoftware wie Windows Virtual PC voraus. Beides kann kostenlos von der Microsoft-Website heruntergeladen werden.
     
    Domänenbeitritt
    Nutzen Sie Ihren PC im Büro, oder planen Sie, ihn für die Heimarbeit zu verwenden? Dann müssen Sie ihn ggf. mit einer Domäne verbinden. Eine Domäne ist eine Art Computernetzwerk, das häufig am Arbeitsplatz vorgefunden wird. (Technisch gesehen, handelt es sich um eine Gruppe von Computern, die zentral verwaltet und unter Einhaltung allgemeiner Regeln betrieben wird.)
     
    Windows 7 Professional und Ultimate ermöglichen einen schnellen und sicheren Domänenbeitritt. Führen Sie einfach den benutzerfreundlichen Assistenten aus, und geben Sie Ihre Anmeldeinformationen für das Netzwerk ein. Einen kurzen Moment später sind Sie schon drin.
     
    BitLocker-Laufwerkverschlüsselung
    Wie können Sie zum Schutz Ihrer Daten vor Datenverlust, Diebstahl oder Hackern beitragen? Die Antwort lautet: BitLocker. Das für Windows 7 verbesserte und in der Ultimate Edition verfügbare BitLocker-Feature hilft Ihnen, alles zu schützen, von Dokumenten bis hin zu Kennwörtern, indem das gesamte Laufwerk, auf dem sich Windows und Ihre Daten befinden, verschlüsselt wird. Sobald BitLocker aktiviert ist, wird jede auf dem Laufwerk gespeicherte Datei automatisch verschlüsselt. BitLocker To Go, ein neues Feature von Windows 7, ermöglicht die Sperrung von leicht verlegten tragbaren Speichergeräten wie USB-Flashlaufwerken und externen Festplatten.
     
    Features:
     

    Inklusive 32- und 64-Bit-Version
    Handbuch: mit Installationsanleitung, Schnelleinstieg und Erklärung der wichtigsten Neuerungen von Windows 7.
    Installationssupport: telefonischer Support ist enthalten.
    Schneller und einfacher zu bedienen
    Verbesserte Taskleiste und Vollbild-Vorschaufenster
    Sprunglisten für schnellen Zugriff auf die Programme und Dateien
    Verbesserter Desktop vereinfacht das Arbeiten mit Fenstern
    Verbesserte Windows Suche
    Bessere Geräteverwaltung
    Automatisches Einrichten von Heimnetzgruppen
    Verbesserte Energieverwaltung
    Höchste Kompatibilität
    Windows Media Center mit optimierter Benutzeroberfläche
    Im ganzen Haus auf Musik, Fotos und Videos zugreifen
    Immer auf dem neuesten Stand mit Windows Live
    Windows Touch für berührungsempfindliche Bildschirme
    Location Aware Printing
    Domänenunterstützung und Gruppenrichtlinien
    Remote Desktop Host
    Erweiterte Datensicherung (Netzwerk und Gruppenrichtlinien)
    Windows XP Mode
    Verschlüsselndes Dateisystem (EFS)
    BitLocker & BitLocker To Go
    AppLocker
    DirectAccess
    BranchCache
    Mehrsprachige Bedienerführung (MUI)
     
    ";2;False;0;;;Windows 7 32 Bit;windows-7-32-bit;True;True;P-2980;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;74.9000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;40889,6296990741;"30;80";3;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000393-windows-7-32-bit.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000394-windows-7-32-bit.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000395-windows-7-32-bit.jpg;1;;False;;;;;False;False;False;;;;;False;;;;;; +5;0;True;Windows 7 64 Bit;Windows 7 64 Bit;"
    Windows 7  
     
    Die umfassendste Edition von Windows 7
    Windows 7 Ultimate ist die vielseitigste und leistungsfähigste Edition von Windows 7. Sie kombiniert die bemerkenswerte Benutzerfreundlichkeit der Unterhaltungsfunktionen von Home Premium mit den unternehmensorientierten Funktionen von Professional, wozu auch die Fähigkeit zum Ausführen zahlreicher Windows XP-Produktivitätsprogramme im Windows XP-Modus gehört.
     
    Für mehr Sicherheit können Sie Ihre Daten auch mit BitLocker und Bitlocker To Go verschlüsseln. Und zur Erhöhung der Flexibilität können Sie in einer beliebigen von 35 Sprachen arbeiten. Mit Windows 7 Ultimate müssen Sie auf nichts verzichten.
     
    Windows 7 vereinfacht alltägliche Aufgaben
     
    Desktop
    Unter Windows 7 ist es nun einfacher, noch mehr Aufgaben direkt auf dem Desktop zu erledigen: Verbesserte Taskleistenvorschau, größere Symbole, Anheften und kreative Möglichkeiten der Personalisierung.
     
    Neue Möglichkeiten, mit Fenstern zu jonglieren
    Überwältigt von der Zahl der geöffneten Fenster? Windows 7 bietet drei einfache und dennoch leistungsfähige neue Funktionen, die wie folgt bezeichnet werden: Aero Shake, Aero Peek und Snap. Sie unterstützen Sie dabei, sofort den Weg durch den Desktop zu finden.
     
     
    Die verschiedenen Windows 7 Editionen im Vergleich 
     
    Spektakuläre neue Hintergrundbilder
    Seien wir ehrlich: Wir verbringen jede Menge Zeit damit, auf unsere PCs zu starren. Die Ästhetik sollte daher nicht zu kurz kommen. Darum enthält Windows 7 viele neue Desktophintergründe, so genannte Hintergrundbilder, unter denen sich alle möglichen Motive von beeindruckend bis unterhaltsam befinden. Oder probieren Sie doch einmal die neue Desktopdiashow aus, in der eine wiederkehrende Reihe von Bildern (unserer oder Ihrer) angezeigt wird. Desktop und langweilig? Das ist vorbei.
     
    Schauen Sie sich die "Superleiste" an
    Schon unter Windows 95 hat die Taskleiste als Ausgangspunkt zum Starten von Programmen und Umschalten zwischen Fenstern gedient. Nicht nur die Zeiten, auch die Arbeitsweisen am PC haben sich geändert. Unter Windows 7 wurde die Taskleiste daher komplett neu gestaltet, damit Sie noch mehr Aufgaben erledigen können. Sie ist ansprechender, kann besser angepasst werden und vereinfacht das Multitasking.
     
    Heimnetzgruppe
    Dank der Heimnetzgruppe brauchen Sie sich keine Gedanken mehr über die Datei- und Druckerfreigabe in einem Heimnetzwerk zu machen. Verbinden Sie mindestens zwei Windows 7-PCs, und schon kann mit der Heimnetzgruppe ganz einfach die automatische Freigabe von Musik, Bildern, Videos und Dokumentbibliotheken für andere Personen im Haus starten. Und das neue Menü "Freigeben für" ermöglicht die schnelle Freigabe einzelner Dateien.
     
    Machen Sie sich Sorgen um den Datenschutz? Wir auch. Und deshalb ist die Heimnetzgruppe kennwortgeschützt, sodass Sie die volle Kontrolle über den Zugriff haben. Sie entscheiden, welche Dateien freigegeben werden und welche nicht. Außerdem können Sie Ihre Dateien mit Schreibschutz versehen, d. h., der Inhalt kann von anderen angesehen, aber nicht geändert werden. Einer Heimnetzgruppe beizutreten, ist in jeder Edition von Windows 7 möglich. Das Erstellen einer Heimnetzgruppe ist jedoch nur in den Editionen Home Premium, Professional und Ultimate möglich.
     
     
    Die verbesserte Taskleiste verschafft mit Hilfe der neuen Vollbild-Vorschaufenster schnellen Überblick 
     
    Sprunglisten
    Über die in Windows 7 neu eingeführten Sprunglisten gelangen Sie nun direkt zu den Dokumenten, Bildern, Songs oder Websites, die Sie tagtäglich nutzen. Zum Öffnen einer Sprungliste klicken Sie auf der Taskleiste von Windows 7 einfach mit der rechten Maustaste auf ein Programm (Sie sind auch im Startmenü zu finden.).
     
    Der Inhalt einer Sprungliste hängt vom Programm ab. In der Sprungliste für Internet Explorer 8 werden häufig besuchte Websites angezeigt. Windows Media Player 12 enthält häufig abgespielte Musiktitel. Fehlt in der Sprungliste ein Favorit? Sie können dort beliebige Dateien "anheften". In Sprunglisten werden nicht nur Verknüpfungen zu Dateien angezeigt. Manchmal bieten sie auch Schnellzugriff auf Befehle für Aufgaben wie das Verfassen neuer E-Mail-Nachrichten oder das Wiedergeben von Musik.
     
    Snap
    Snap bietet eine schnelle neue Möglichkeit, die Größe geöffneter Fenster einfach durch Ziehen an die Bildschirmränder zu ändern. Je nach Rand, also, oben oder unten, rechts oder links, wird das Fenster verbreitert, oder es füllt den ganzen Bildschirm aus. Und Sie können Fenster auch nebeneinander anordnen. Mit Snap wird das Lesen, das Anordnen und das Vergleichen von Fenstern zum Kinderspiel.
     
     
    Den Desktop jederzeit im Blick dank transparenter Fenster 
     
    Windows Live Essentials
    Was ist Windows Live Essentials? Einfach ausgedrückt, handelt es sich um kostenlose Software, die einen Windows 7-PC mit noch mehr tollen Funktionen ausstattet, z. B. für E-Mail, Instant Messaging, Fotobearbeitung und Blogs. Windows Live Windows Live Essentials ist auf der Windows Live-Website verfügbar. Der kostenlose Download enthält folgende Komponenten: Messenger, Fotogalerie, Mail, Writer, Movie Maker, Symbolleiste und Family Safety.
     
    Windows Search
    Unter Windows 7 finden Sie noch schneller noch mehr Dinge an noch mehr Orten. Sobald Sie im Suchfeld des Startmenüs mit der Eingabe beginnen, wird eine Liste relevanter Dokumente, Bilder, Musiktitel und E-Mails auf dem PC angezeigt. Die Ergebnisse sind nun nach Kategorie gruppiert und enthalten hervorgehobene Stichwörter und Textausschnitte, um die Suche zu vereinfachen.
     
    Dateien werden heutzutage nur noch selten an einem Ort abgelegt. Also ist Windows 7 auch darauf ausgelegt, externe Festplatten, Netzwerk-PCs und Bibliotheken zu durchsuchen. Zu viele Suchergebnisse? Sie können die Suche direkt nach Datum, Dateityp und anderen hilfreichen Kategorien eingrenzen.
     
    Windows 7 funktioniert Ihren Vorstellungen entsprechend
     
    Leistungsverbesserungen
    Niemand wartet gerne. Darum ist Windows 7 nun noch schneller und immer bereit, wenn Sie es sind. Zu den wichtigen Leistungsverbesserungen zählen u. a. schneller Wechsel in und aus dem Energiesparmodus, weniger Speicherbedarf und schnelle Erkennung von USB-Geräten:
     
    Standbymodus
    Windows 7 kann in den Energiesparmodus versetzt und wiederhergestellt werden und die Verbindung mit dem Drahtlosnetzwerk wieder schneller herstellen.
     
     
    Sprunglisten ermöglichen schnellen Zugriff auf häufig anstehende Aufgaben 
     
    Suchen
    Wenn Sie auf der Suche nach Informationen sind, dann möchten Sie nicht lange warten, sondern Antworten bekommen. Unter Windows 7 werden Suchergebnisse schneller angezeigt. Auch das Sortieren und Gruppieren von Suchergebnissen geht viel rascher vonstatten.
     
    USB-Geräte
    Wenn Sie zum ersten Mal ein tragbares Flashlaufwerk oder ein anderes USB-Gerät anschließen, stellt Windows 7 es innerhalb weniger Sekunden für Sie bereit. Und wenn Sie es bereits zuvor verwendet haben, dann geht es sogar noch schneller.
     
    Rationaler und geringere Auslastung
    Anders als seine Vorgänger ist Windows 7 darauf ausgelegt, verlangsamende Hintergrunddienste nur dann auszuführen, wenn Sie sie benötigen. Sie verwenden kein Bluetooth-Gerät? Dann bleibt der Bluetooth-Dienst von Windows 7 ausgeschaltet. Windows 7 benötigt auch weniger Arbeitsspeicher als Windows Vista: eine weitere versteckte Optimierung, mit der die Gesamtleistung gesteigert werden kann.
     
    64-Bit-Unterstützung
    Wenn Sie sich kürzlich nach einem neuen PC umgesehen haben, dann ist Ihnen sicherlich aufgefallen, dass es mehr Computer mit 64-Bit-Prozessoren gibt. Und möglicherweise haben Sie sich gefragt, welche Vorteile sie bieten. Einfach ausgedrückt, kann ein 64-Bit-PC größere Datenmengen verarbeiten als ein 32-Bit-System. Da mehr RAM (4 GB und mehr) verwendet werden kann, kann ein 64-Bit-Computer schneller reagieren, wenn Sie viele Programme gleichzeitig ausführen.
     
    Welchen sollen Sie kaufen? Wenn Sie beabsichtigen, viele Programme gleichzeitig geöffnet zu haben oder häufig zwischen Programmen wechseln müssen und auch wenn Sie lediglich sicherstellen möchten, dass Ihr PC die derzeit größeren Speicher nutzen kann, dann ist ein 64-Bit-Computer die richtige Wahl für Sie. Wenn Sie hingegen höchstens zwei Programme gleichzeitig ausführen oder ältere Hardware und Software verwenden, die von einem 64-Bit-PC nicht unterstützt wird, ist ein 32-Bit-System geeignet. Egal, ob Sie sich für ein 32-Bit- oder ein 64-Bit-System entscheiden, Windows 7 ist bereit.
     
     
    Die verbesserte Windows Suche liefert Ergebnisse mit mehr Relevanz 
     
    Energieverwaltung
    Sie haben es satt, dass sich der Akku Ihres Laptops immer dann verabschiedet, wenn Sie ihn dringend benötigen? Unter Windows 7 können Sie die Akkulaufzeit verlängern. Wie? Zunächst einmal ist die Anzahl von unter Windows 7 ausgeführten Hintergrundaktivitäten viel kleiner, d. h., der PC-Prozessor ist weniger stark ausgelastet und damit die Stromaufnahme geringer.
     
    Zudem ist die DVD-Wiedergabe stromsparender (praktisch auf langen Flügen), der Bildschirm wird automatisch abgedunkelt, nicht verwendete Ports werden abgeschaltet, und die Anzeige für die Akkulaufzeit ist genauer. Es ist also unwahrscheinlicher, dass Sie plötzlich mit einem leeren Akku dastehen.
     
    Windows 7 macht neue Dinge möglich
     
    Netzwerk
    Mit Windows 7 wird es zum Kinderspiel, auf dem Laptop an jedem beliebigen Ort Netzwerke anzuzeigen und eine Verbindung mit diesen herzustellen. Klicken Sie einfach nur auf das Netzwerksymbol auf der Taskleiste. Mit "Verfügbare Netzwerke anzeigen" werden alle Optionen für Drahtlos- und verkabelte Netzwerke aufgerufen: WiFi, mobiles Breitband, DFÜ oder Unternehmens-VPN. Nur noch ein Klick, und schon steht die Verbindung.
     
    Windows Media Center
    Live-TV anschauen, anhalten und aufnehmen. Musik hören. Mit der Fotosammlung Eindruck schinden. Onlineunterhaltung genießen. Und das vom Sofa im Wohnzimmer aus. Wundert es da noch, dass Media Center von Kritikern als das verborgene Juwel von Windows bezeichnet wird?
     
    Unter Windows 7 wurde das Programm sogar noch erweitert: mit neuen, tollen Features (viele auf Ihre Anregung hin) und visuellen Verbesserungen. Windows Media Center ist in den Editionen Home Premium, Professional und Ultimate von Windows 7 enthalten. Zu den wichtigsten Neuerungen zählen u. a.:
     
     
    Komponenten wie Dateien oder Drucker gemeinsam im Heimnetzwerk nutzen 
     
    Fernsehen total ...
    Windows Media Center unterstützt mehr globale TV-Standards und TV-Tuner (z. B. Digitalfernsehen und HD). Zudem können Sie mit dem Programm nun mehr häufig verwendete Audio- und Videoformate wiedergeben, z. B. 3GP, AAC, AVCHD, DivX, MOV und Xvid.
     
    ... ohne langes Warten
    Haben Sie es satt, sich durch Fernsehprogramme oder eine umfangreiche Musikbibliothek zu quälen? Wechseln Sie schneller zu Titeln und Sendungen mit dem neuen Feature für schnelles Blättern.
     
    Atemberaubende neue Diashows
    Stellen Sie mit der neuen Diashowerstellung ansprechende Fotocollagen (mit Hintergrundmusik) zusammen. Die sind perfekt geeignet für Partys oder Familienfeiern. Und probieren Sie unbedingt den neuen Diashow-Bildschirmschoner aus: Dafür finden Sie keine Worte!
     
    Einfachere Medienfreigabe
    Schauen Sie sich aufgezeichnete TV-Sendungen, Musiktitel und Videos an, auch wenn diese nicht auf Ihrem PC gespeichert sind. Mit dem neuen Feature Heimnetzgruppe stehen Medien auf jedem PC unter Windows 7 im gesamten Haus zur Verfügung.
     
    Neue Minianwendungen, größere Vorschau
    Es gibt eine neue Media Center-Minianwendung. Videos im Schnelldurchlauf anschauen. Mehr Titel- und Sendungsdetails. Größere, besser erkennbare Vorschauminiaturansichten. Und das sind noch längst nicht alle Verbesserungen.
     
     
    Windows BitLocker verschlüsselt komplette Laufwerke 
     
    Windows Touch
    Es hat sich "ausgemaust": Mit Windows 7 und einem Kontaktbildschirm können Sie einfach nur mit Ihren Fingern die Onlineausgabe der Tageszeitung durchsehen, die Seiten in einem Fotoalbum durchblättern und Dateien und Ordner zufällig anordnen.
     
    Eine eingeschränkte Touchtechnologie ist bereits seit Jahren unter Windows verfügbar. Aber unter Windows 7 erobert sie jede Ecke Ihres PC. Das Startmenü und die Taskleiste weisen nun größere, fingerfreundliche Symbole auf. Auch die vertrauten Windows 7-Programme unterstützen die Fingereingabe. In Paint können Sie jetzt sogar mit dem Finger malen!
     
    Windows Touch, nur in den Editionen Home Premium, Professional und Ultimate von Windows 7 enthalten, erkennt auch Mehrfingerbewegungen (geeigneten Monitor vorausgesetzt). Sie möchten ein Bild vergrößern? Bewegen Sie Ihre Finger aufeinander zu. Sie möchten einen Rechtsklick ausführen? Berühren Sie das entsprechende Element mit einem Finger, und tippen Sie mit einem anderen Finger auf den Bildschirm.
     
    Zusätzliche Profi-Funktionen
     
    Windows XP-Modus
    Besser geht's nicht: Mit dem neuen Windows XP-Modus können Sie ältere Windows XP-Geschäftsprogramme direkt auf dem Windows 7-Desktop ausführen. Das Feature, das in erster Linie für kleine und mittelständische Unternehmen entwickelt wurde, steht als separater Download zur Verfügung und kann nur in Verbindung mit Windows 7 Professional und Ultimate eingesetzt werden. Der Windows XP-Modus setzt zudem auch eine Virtualisierungssoftware wie Windows Virtual PC voraus. Beides kann kostenlos von der Microsoft-Website heruntergeladen werden.
     
    Domänenbeitritt
    Nutzen Sie Ihren PC im Büro, oder planen Sie, ihn für die Heimarbeit zu verwenden? Dann müssen Sie ihn ggf. mit einer Domäne verbinden. Eine Domäne ist eine Art Computernetzwerk, das häufig am Arbeitsplatz vorgefunden wird. (Technisch gesehen, handelt es sich um eine Gruppe von Computern, die zentral verwaltet und unter Einhaltung allgemeiner Regeln betrieben wird.)
     
    Windows 7 Professional und Ultimate ermöglichen einen schnellen und sicheren Domänenbeitritt. Führen Sie einfach den benutzerfreundlichen Assistenten aus, und geben Sie Ihre Anmeldeinformationen für das Netzwerk ein. Einen kurzen Moment später sind Sie schon drin.
     
    BitLocker-Laufwerkverschlüsselung
    Wie können Sie zum Schutz Ihrer Daten vor Datenverlust, Diebstahl oder Hackern beitragen? Die Antwort lautet: BitLocker. Das für Windows 7 verbesserte und in der Ultimate Edition verfügbare BitLocker-Feature hilft Ihnen, alles zu schützen, von Dokumenten bis hin zu Kennwörtern, indem das gesamte Laufwerk, auf dem sich Windows und Ihre Daten befinden, verschlüsselt wird. Sobald BitLocker aktiviert ist, wird jede auf dem Laufwerk gespeicherte Datei automatisch verschlüsselt. BitLocker To Go, ein neues Feature von Windows 7, ermöglicht die Sperrung von leicht verlegten tragbaren Speichergeräten wie USB-Flashlaufwerken und externen Festplatten.
     
    Features:
     

    Inklusive 32- und 64-Bit-Version
    Handbuch: mit Installationsanleitung, Schnelleinstieg und Erklärung der wichtigsten Neuerungen von Windows 7.
    Installationssupport: telefonischer Support ist enthalten.
    Schneller und einfacher zu bedienen
    Verbesserte Taskleiste und Vollbild-Vorschaufenster
    Sprunglisten für schnellen Zugriff auf die Programme und Dateien
    Verbesserter Desktop vereinfacht das Arbeiten mit Fenstern
    Verbesserte Windows Suche
    Bessere Geräteverwaltung
    Automatisches Einrichten von Heimnetzgruppen
    Verbesserte Energieverwaltung
    Höchste Kompatibilität
    Windows Media Center mit optimierter Benutzeroberfläche
    Im ganzen Haus auf Musik, Fotos und Videos zugreifen
    Immer auf dem neuesten Stand mit Windows Live
    Windows Touch für berührungsempfindliche Bildschirme
    Location Aware Printing
    Domänenunterstützung und Gruppenrichtlinien
    Remote Desktop Host
    Erweiterte Datensicherung (Netzwerk und Gruppenrichtlinien)
    Windows XP Mode
    Verschlüsselndes Dateisystem (EFS)
    BitLocker & BitLocker To Go
    AppLocker
    DirectAccess
    BranchCache
    Mehrsprachige Bedienerführung (MUI)
    ";2;False;0;;;Windows 7 64 Bit;windows-7-64-bit;True;True;P-2990;;;False;0;False;;False;False;0;False;0;1;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;59.9000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;40889,6295138889;"30;80";3;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000393-windows-7-32-bit.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000397-windows-7-32-bit.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000396-windows-7-32-bit.jpg;2;;False;ounce;;;;False;False;False;;;;;False;;;;;; +5;0;True;Toshiba Satellite L775-11K 43,9 cm (17,3 Zoll) Notebook;4 GB, 18 Zoll, 300 GB, Intel, 2;"
    Der Satellite L775 bietet Ihnen die perfekte Mischung aus schickem Design und starker Leistung. Hier bekommen Sie nicht nur eine umfangreiche Ausstattung, sondern auch echte High-Definition-Performance. Intel®-Prozessoren der zweiten Generation sorgen für zügiges Arbeiten in all Ihren Anwendungen. Das 43,9 cm (17,3"") TruBrite® HD+ Display mit LED-Hintergrundbeleuchtung liefert in Kombination mit der NVIDIA® ein umwerfendes Bild. Dolby® AdvancedAudio-Technologie und integrierte Onkyo®-Lautsprecher mit guter Klangqualität runden die Multimedia-Ausstattung ab. Dazu noch ein Multitouch-Touchpad, 2und ein attraktives Matrix-Design in der Farbvariante Zinkgrau – bei diesem Notebook bleiben wirklich keine Wünsche offen.
     
    Attraktives Design
    Modernes Hochglanzgehäuse mit Matrix-Finish in Zinkgrau.
     
    Beste Bildqualität
    Das riesige 43,9 cm (17,3"") TruBrite® HD+ Display mit LED-Hintergrundbeleuchtung bietet beste High-Definition-Qualität. Eine hoch auflösende Bildwiedergabe wird dadurch selbst bei DVDs möglich.
     
    Optimaler Klang
    Integrierte Onkyo®-Lautsprecher sorgen in Kombination mit der Dolby® Advanced Audio-Technologie für einen vollen Sound.
     
    Ultra schnell
    USB 3.0-Technologie ermöglicht für ihre Multimedia-Dateien einen schnelleren Datentransfers als je zuvor.
     
    ""USB Sleep-and-Charge""-Funktion
    Sie können Ihr Handy oder MP3 Player aufladen – und zwar selbst, wenn das Notebook ausgeschaltet ist.
     
    Bedienerfreundlich
    Touchpad mit Multitouch Gestensteuerung, Touch Pad an/aus Taste, Multi-Kartenleser und Tastatur mit 10er Nummernblock.
     
    Entertainment
    Kinoerlebnis auf einem externen Fernseher genießen über RGB (VGA) Anschluss oder in High Definition Qualität mit HDMI Anschluss.
     
    Umweltfreundlich
    Eco Stromsparfunktion, ENERGY STAR 5.0 qualifiziert und ein energieeffizientes Display mit LED Hintergrundbeleuchtung. 
    ";2;False;0;;;Toshiba Satellite L775-11K 43,9 cm (17,3 Zoll) Notebook;toshiba-satellite-l775-11k-439-cm-173-zoll-notebook;True;True;P-0840;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;539.9000;539.9000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;40889,5852777778;5;40;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000590-toshiba-satellite-l775-11k-439-cm-173-zoll-notebook.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000591-toshiba-satellite-l775-11k-439-cm-173-zoll-notebook.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000592-toshiba-satellite-l775-11k-439-cm-173-zoll-notebook.jpg;2;;False;;;;;False;False;False;;;;;False;;;;;; +5;0;True;"Logitech HD Webcam C615 ";"Logitech HD Webcam C615 ";"
    Logitech HD Webcam C615
    Mit dieser flexibel zusammenklappbaren Webcam führen Sie HD-Videogespräche in 720p und laden Full HD-Videos in 1080p mit nur einem Klick auf Facebook hoch. Inhalte, Ort und Setup wählen Sie.
     
    Full HD-Videoaufnahmen in 1080p und HD-Videogespräche in 720p
    Zeichnen Sie Ihr Videos in Full HD 1080p und im atemberaubenden Breitbildformat auf. Sie können Videogespräche in 720p mit den meisten Instant Messengern und Logitech Vid™ HD führen.* Dank des eingebauten Autofokus bleiben Ihre Bilder selbst bei Nahaufnahmen (ab einer Entfernung von 10 cm vom Objektiv) gestochen scharf. Machen Sie hochauflösende Schnappschüsse mit bis zu 8 Megapixeln (Software-interpoliert).
     

    1-Klick-Upload auf Facebook
    Mit nur einem Klick können Sie Full HD-Videoaufnahmen in 1080p-Auflösung erfassen und auf Facebook, Twitter™ oder YouTube® hochladen.
     

    Flexibles, tragbares Design
    Dank des zusammenklappbaren Designs und des kurzen USB-Kabels ist die Webcam leicht zu transportieren. Das USB-Verlängerungskabel bietet Ihnen bei Bedarf zusätzlichen Spielraum.
     
    Drehbares Design mit Stativhalterung
    Wenn Sie die Webcam an einem Stativ befestigen, haben Sie noch mehr Stellmöglichkeiten. Dank der 360-Grad-Schwenkfunktion sind Gespräche und Aufnahmen aus jedem Winkel möglich. Das Stativ selbst ist nicht im Lieferumfang enthalten.
     
    Kompatibel mit Windows und Mac
    Windows? Mac? iChat®? Skype™? Google Voice™ und Chat? Ganz egal. Ihre Webcam funktioniert mit allen. Für die Bearbeitung Ihrer Fotos ist sie außerdem mit iPhoto®, iMovie® und sogar mit Photo Booth® kompatibel.
     

    Beinhaltet Logitech Vid™ HD
    Jetzt sind HD-Videogespräche kostenlos, schnell und einfach. Die Software wird bei der Einrichtung Ihrer Webcam mitinstalliert. Und Sie können sogar Videonachrichten für Freunde und Familie hinterlassen, wenn diese Ihren Anruf nicht entgegennehmen können.
     
    Kostenlose Videobearbeitungssoftware
    Logitech und MAGIX machen Ihnen ein besonderes Angebot: Sie erhalten jetzt mit Ihrer neuen Logitech-Webcam auch gleich MAGIX™ Photo Manager 9 und MAGIX™ Video Easy. Und zwar kostenlos.****
     
    Anmeldung über Gesichtserkennung
    Melden Sie sich bei Ihrem Computer und auf Ihren Lieblings-Internetseiten mit der eingebauten Gesichtserkennungssoftware an. Damit sparen Sie Zeit und imponieren Ihren Freunden.*****
     

    * Für Mac® sind HD-Videogespräche mit Logitech Vid™ HD verfügbar. Für HD-Videogespräche mit anderer Software überprüfen Sie bitte die Verfügbarkeit.
    ** Nicht für Mac verfügbar.
    *** Nur für Windows-Computer. Intel® Pentium® 4 (2,8 GHz) empfohlen.
    **** E-Mail-Registrierung erforderlich. Es gelten zusätzliche Bestimmungen. Nur für Windows-Computer.
    ***** 60-Tage-Probeangebot. Es gelten zusätzliche Bestimmungen. Nicht für Mac verfügbar.
    ";2;False;0;;;"Logitech HD Webcam C615 ";logitech-hd-webcam-c615;True;True;P-2910;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;89.9000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;40889,4833449074;27;11;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000240-logitech-hd-webcam-c615.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000241-logitech-hd-webcam-c615.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000242-logitech-hd-webcam-c615.jpg;2;;False;;;;;False;False;False;;;;;False;;;;;; +5;0;True;"Microsoft Wired LifeCam VX-3000 ";"Microsoft Wired LifeCam VX-3000 ";"
    LifeCam VX-3000
     
    Die LifeCam VX-3000 begeistert mit leichter Installation und nahtloser Integration in den Windows Live-Messenger. Die kompakte Webcam bietet Top-Bildqualität, kombiniert mit innovativen Features wie der praktischen Windows Live Call-Taste und dem multifunktionalem Standfuß, der sich mit einem Handgriff in eine Halterung für Flachbildschirme verwandeln lässt. Dank integriertem Mikrofon muss kein externes Mikrofon für unterhaltsame Video-Gespräche angeschlossen werden.
     
      Hochauflösende Fotos
    Mit hochauflösenden Fotos (1,3 Megapixel interpoliert) zeigen Sie sich von Ihrer besten Seite.
     
    Integriertes Mikrofon
    Das integrierte Mikrofon erfasst Ihre Stimme automatisch und mit außergewöhnlicher Klarheit.
     
    Windows Live Call-Taste
    Um einen Videoanruf zu starten, drücken Sie einfach diese Taste, und wählen Sie dann einen Onlinekontakt aus.
     
    Software für automatisches Face-Tracking*
    Sie können sich bewegen, ohne vom Bildschirm zu verschwinden. Dank modernster Software bleibt Ihr Gesicht stets im Bildmittelpunkt.
     
     
    Universalhalterung
    Die LifeCam lässt sich problemlos an jedem Monitor befestigen.
     
    Kipp-, Dreh- und Zoomfunktion
    Die Kamera kann sowohl horizontal als auch vertikal geschwenkt werden und bietet somit ein Höchstmaß an Flexibilität.
     
    Flexibles 1,8 m langes Kabel
    Das lange, flexible Kabel gibt Ihnen genügend Bewegungsfreiheit.
     
    Videoeffekte
    Überraschen Sie Ihre Freunde mit coolen Videoeffekten, auf die Sie direkt aus dem Windows Live Messenger-Fenster zugreifen können.
     
    Bis zu 30 Bilder pro Sekunde
    Die Aufnahmen mit LifeCams erfolgen mit 30 Bildern pro Sekunde, wodurch die Videobilder flüssig und ohne Ruckeln angezeigt werden
     
     
     
     
     
    ";2;False;0;;;"Microsoft Wired LifeCam VX-3000 ";microsoft-wired-lifecam-vx-3000;True;True;P-2900;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;29.9000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;40889,480775463;27;3;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000237-microsoft-wired-lifecam-vx-3000.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000238-microsoft-wired-lifecam-vx-3000.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000239-microsoft-wired-lifecam-vx-3000.jpg;2;;False;;;;;False;False;False;;;;;False;;;;;; +5;0;True;SanDisk Secure Dügital Speicherkarte;"SanDisk Secure Digital (SD) Speicherkarte ";"
    SanDisk Secure Digital (SD) Speicherkarte 
    SecureDigital High Capacity Card (SDHC), entspricht neuem SD-2.0-Standard, Klasse 4
    nur geeignet für Endgeräte mit SDHC-Steckplatz (nicht rückwärtskompatibel zu Standard-SD-Cards)
    Schutz gegen unbeabsichtigtes Überschreiben der Daten
    beliebig oft beschreib- und löschbar
    original SanDisk Markenware, Erstausrüsterqualität
    ";2;False;0;;;SanDisk Secure Digital Speicherkarte;sandisk-secure-duegital-speicherkarte;True;True;P-2890;;;False;0;False;;False;False;0;False;0;1;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;1;9589;False;False;0;1;1;0;False;1;10000;;False;False;False;False;9.8000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;40889,4440046296;25;;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000125-sandisk-secure-dugital-speicherkarte.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000126-sandisk-secure-dugital-speicherkarte.jpg;;1;;False;ounce;;;;False;False;False;;;;;False;;;;;; +5;0;True;"Samsung SE-S084D externer DVD Brenner (DVD±RW (±R DL) weiß ";"Samsung SE-S084D externer DVD Brenner (DVD±RW (±R DL) weiß ";"
    Samsung SE-S084D – Exklusiver mobiler Brenner mit AV-Funktion.
    Der mobile Brenner SE-S084D überzeugt durch Innovation, Funktion und Design. Er setzt neue Maßstäbe und hebt sich in seiner Verarbeitung und den Einsatzmöglichkeiten deutlich von aktuellen Modellen ab.Das hochwertige Finish mit Soft-Touch-Taste und trendiger metallischer Linie machen den schlanken Brenner von Samsung optisch zu einem Highlight. Die Qualität des Produktes gewährt hohe Mobilität und vermittelt allein durch die robuste Haptik Zuverlässigkeit.
     
    Angeschlossen wird der Slim-Brenner SE-S084D via HiSpeed-USB. Ein zusätzliches Netzteil ist nicht notwendig, denn der Multiformatbrenner erreicht seine maximale Brenn- und Lesegeschwindigkeit über die Stromversorgung via USB BUS Power. Der 8fach Brenner ist kompatibel sowohl zu Windows als auch zu MAC Betriebssystemen; diese Kompatibilität wurde auch von beiden Partnern offiziell bestätigt. Somit ist seine grundsätzliche Funktion des Brennens und Lesen von Medien aller Art bestens sichergestellt.
     
    Durch die leichte und kompakte Bauweise mit nur 270 Gramm ist er die perfekte Begleitung für Netbook, Notebook oder All-In-One PC.
     
    Als zusätzliches Feature hat Samsung die AV-Funktion entwickelt. Unterstützt Ihr Fernseher die Wiedergabe via USB-Port. so lässt sich der SE-S084D an diese neue TV-Generation mit PVR Funktion anschließen und zum Abspielen JPEG, MP3 und AVI-Dateien nutzen. Der SE-S084D kann also auch als Player eingesetzt.
     
    Dieses neue Produktkonzept wurde auch mit dem IF Design Award 2010 honoriert.
    ";2;False;0;;;"Samsung SE-S084D externer DVD Brenner (DVD±RW (±R DL) weiß ";samsung-se-s084d-externer-dvd-brenner-dvdrw-r-dl-weiss;True;True;P-2870;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;69.9000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;40889,4407638889;24;19;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000287-samsung-se-s084d-externer-dvd-brenner-dvdrw-r-dl-weis.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000288-samsung-se-s084d-externer-dvd-brenner-dvdrw-r-dl-weis.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000289-samsung-se-s084d-externer-dvd-brenner-dvdrw-r-dl-weis.jpg;2;;False;;;;;False;False;False;;;;;False;;;;;; +5;0;True;"Slim USB DVD CD Blu Ray Laufwerk Gehäuse Case extern IDE / PATA Schwarz ";"Slim USB DVD CD Blu Ray Laufwerk Gehäuse Case extern IDE / PATA Schwarz ";"
    Externes USB-Gehäuse für optische Slim Blu-Ray, DVD und CD Laufwerke sowie Brenner
     
    verwandelt Ihr internes Laufwerk in ein externes
     
    - Hochwertiges Firstcom Gehäuse in Matt-Schwarz
    - Unterstützt USB 1.1, USB 2.0 sowie USB 3.0
    - Easy to Install / Sehr leichter Einbau
    - Automatische Erkennung / Plug & Play bei Windows Me / 2000 / XP / Vista / Windows 7
    Mac ab OS 8.6 oder höher (keine Treiber Installation notwendig)
    - Stromversorgung über USB (Bus-powered / kein extra Netzteil nötig)
    - Gummifüße verhindern ein Rutschen auf der Arbeitsfläche
    - Abmessungen: 137 x 135 x 18 (L x B x H mm)
    - für Slimline Laufwerke mit ca. 12,7 mm Höhe und IDE Anschluss geeignet
     
    Lieferumfang:
    1 x externes Slim Gehäuse
    1 x USB <-> IDE Board (Schnittstelle zum Laufwerk)
    1 x USB-Kabel für die Verbindung
    1 x USB-Kabel für die Stromzufuhr
    1 x Kurzanleitung
    und diverses Einbaumaterial
     
    Farbe: Schwarz
     
    Kann auch am PC, MAC, Notebook, Sub Notebook, Netbook etc. verwendet werden.
    Anmerkung: Ein Laufwerk ist nicht eingebaut und gehört nicht zum Lieferumfang.
    ";2;False;0;;;"Slim USB DVD CD Blu Ray Laufwerk Gehäuse Case extern IDE / PATA Schwarz ";slim-usb-dvd-cd-blu-ray-laufwerk-gehaeuse-case-extern-ide-pata-schwarz;True;True;P-2840;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;24.9000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;40889,4399305556;24;;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000223-slim-usb-dvd-cd-blu-ray-laufwerk-gehause-case-extern-ide-pata-schwarz.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000224-slim-usb-dvd-cd-blu-ray-laufwerk-gehause-case-extern-ide-pata-schwarz.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000225-slim-usb-dvd-cd-blu-ray-laufwerk-gehause-case-extern-ide-pata-schwarz.jpg;2;;False;;;;;False;False;False;;;;;False;;;;;; +5;0;True;Samsung SE-406AB/RSBD extern Slim BluRay Combo Laufwerk;"Samsung SE-406AB/RSBD extern Slim BluRay Combo Laufwerk (CyberLink TrueTheater, 3D Support, USB 2.0) ";"
    Erleben Sie HD-Kinospaß mit dem externen Slim Blu-ray Combo-Laufwerk SE-406AB für Ihr Notebook oder PC.
    Mit dem neuen Samsung Blu-ray Combo-Laufwerk verbinden Sie Arbeit und Vergnügen perfekt miteinander. Klassisch können Sie mit dem portablen Laufwerk, CDs und DVDs in hoher Qualität lesen und beschreiben. Aber ebenso können Sie mit dem SE-406AB HD-Inhalte am eigenen PC abspielen oder selbst erstellte Inhalte auf DVD oder BD auch an einem Fernseher mit Smart-TV-Funktion ansehen. Der Anschluss geschieht komfortabel über USB.
     
    Mit dem schlanken Design fällt das Laufwerk kaum ins Gewicht und lässt sich leicht transportieren. Dank Anschluss über USB benötigt es kein zusätzliches Netzteil und verbraucht nur wenig Energie. Das Samsung BD Combo ist extrem leise im Betrieb und zeichnet sich durch eine hohe Kompatibilität und überzeugende Brennergebnisse aus. Die unterstützte Buffer Under Run-Technologie verhindert Pufferunterlauffehler und ermöglicht das Beschreiben von Medien mit hoher Brenngeschwindigkeit.
     
    Mit der beiliegenden Software CyberLink BluRay Disc Suite 7 lässt sich das Combo-Laufwerk bequem bedienen. Sie können mit dem Laufwerk und einem 3D-fähigen Display Ihre 2D-DVD-Filmsammlung jetzt auch in 3D erleben. Denn die Software kann 2D-Filme in plastische 3D-Bilder umwandeln. Möglich wird dies mit der CyberLink TrueTheater 3D-Software. Voraussetzung dafür ist natürlich, dass der Nutzer ein 3D-fähiges Anzeigegerät samt 3D-Brille besitzt.
     
    Durch das Feature der AV-Konnektivität lässt sich das Gerät an Fernseher mit Smart TV-Funktion anschließen. Smart TV führt Online- und Offline-Inhalte auf dem Fernseher zu einem ganzheitlichen Erlebnis zusammen. So lassen sich gestreamte Medieninhalte in den Formaten JPEG, MP3 und AVI auf dem TV Gerät mit SMART Funktion wiedergeben. Das Laufwerk wird dazu einfach an die USB-Schnittstelle des Fernsehers angeschlossen und fungiert dabei wie ein USB-Stick. Dies ermöglicht das Auslesen der Inhalte auf dem Datenträger. Durch die Verbindung per USB-Anschluss ist der schnelle Zugriff auf Videos, Musik und Fotos gewährleistet.
     
    Ein Beispiel für die Multifunktionalität des schicken Laufwerks:
    Für Oma schnell eine Foto-DVD brennen, auf dem Notebook eine neue Software aufspielen und selbstgedrehte BD-Filme bearbeiten und anschließend auf dem Fernseher ansehen? Das Samsung Blu-ray Combo-Laufwerk SE-406AB erfüllt Ihnen all diese Wünsche.
    ";2;False;0;;;LSamsung SE-406AB/RSBD extern Slim BluRay Combo Laufwerk;samsung-se-406abrsbd-extern-slim-bluray-combo-laufwerk;True;True;P-2850;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;79.9000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;40889,4370833333;24;;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000226-samsung-se-406abrsbd-extern-slim-bluray-combo-laufwerk.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000227-samsung-se-406abrsbd-extern-slim-bluray-combo-laufwerk.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000228-samsung-se-406abrsbd-extern-slim-bluray-combo-laufwerk.jpg;2;;False;;;;;False;False;False;;;;;False;;;;;; +5;0;True;Canon Pixma MP 630 Multifunktionsgerät;"Canon Pixma MP 630 Multifunktionsgerät ";"
    Canon PIXMA MP620

    Hochwertiges Multifunktionssystem mit 9.600-dpi*-Drucksystem und nur 1 Picoliter feinen Tintentröpfchen für Fotos und Dokumente in überragender Druckqualität. Erweiterte Funktionen zum Druckmedien-Handling für die Digitalfotografie, kreative Arbeiten und anspruchsvolle Privatanwender. Features
    Drucken, Kopieren und Scannen
    Brillante Fotoprints mit 9.600 x 2.400 dpi und 1 Picoliter feinen Tintentröpfchen*
    Randlose Fotos im Format 10 x 15 cm in ca. 20 Sekunden*
    5-Tintensystem
    6,2 cm großes TFT-Farbdisplay mit Easy-Scroll-Bedienrad
    Scanner mit 4.800 dpi
    Direktscan auf Speicherkarte oder USB-Stick
    CD/DVD–Druck
    Automatische Duplexfunktion
     
    Foto- und Dokumentdruck
    Das hochwertige 9.600-dpi*-Drucksystem des PIXMA MP630 mit FINE-Druckkopf für bis zu 1 Picoliter feine Tintentröpfchen liefert beeindruckende Fotoprints. Der Druck eines randlosen Fotos im Format 10 x 15 cm erfolgt in ca. 20 Sekunden*.Die 1 Picoliter feinen Tintentröpfchen der neuen farbstoffbasierten Tinten – inkl. Fotoschwarz – erzeugen kontrastreiche Prints mit sanften Farbabstufungen und brillanten Details.
     
    ChromaLife100+** ist ein System aus dem FINE-Druckkopf des PIXMA MP630, Canon Originaltinten und ausgewähltem original Canon Fotopapier. Diese drei einzigartigen Komponenten erzeugen brillante Fotoprints mit hoher Farbstabilität. Textdokumente können in Schwarzweiß oder Farbe gedruckt werden, wobei eine schwarze Pigmenttinte für gestochen scharfen Text sorgt.
     
    Single-Ink-Technologie
    5 Tintentanks sorgen für Qualität und Effizienz – ist eine Tinte aufgebraucht, muss nur der betreffende Tank ausgetauscht werden.
     
    Bedienungsfreundlichkeit
    Mit dem hoch auflösenden 6,2 cm großen TFT-Farbdisplay können Sie Ihre Fotos auch ohne Computer bequem ansehen und mit dem Easy-Scroll-Bedienrad durchsuchen, auswählen, bearbeiten und den Druckvorgang starten. Ebenso ist es möglich, Aufnahmen direkt von kompatiblen Speicherkarten, PictBridge-kompatiblen Digitalkameras oder -Camcordern auszudrucken. Mit der Quick-Start-Funktion stehen alle Optionen in wenigen Sekunden zur Verfügung.
     
    Fortschrittliches Medien-Handling
    Gestalten Sie individuelle bedruckbare CDs und DVDs, indem Sie mit der Software CD-LabelPrint Layouts mit Ihren Texten und Bildern erstellen. Die integrierte Duplexeinheit ermöglicht den automatischen beidseitigen Druck auf Normalpapier, was Papier spart. Zwei Papierzuführungen ermöglichen das gleichzeitige Bestücken des Druckers z. B. mit Normalpapier und Fotopapier.
     
    Scannen
    Dank der optischen Auflösung von 4.800 dpi sind hervorragende Farbscans möglich, die Sie direkt an den PC oder als E-Mail senden bzw. als PDF erstellen können. Die intuitive Software MP Navigator EX gewährleistet eine einfache Bedienung. Der Auto-Scan-Modus beschleunigt den Scanvorgang, indem der Vorlagentyp erkannt und die entsprechenden Einstellungen automatisch gewählt werden. Mit der praktischen Option zum Direktscan auf Speicherkarte oder USB-Stick können die gescannten Daten einfach und flexibel gespeichert und transportiert werden.
     
    Betriebssysteme
    Kompatibel mit Windows und Mac OS X
    ";2;False;0;;;Canon Pixma MP 630 Multifunktionsgerät;canon-pixma-mp-630-multifunktionsgeraet;True;True;P-2180;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;2,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;169.0000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;40889,4313888889;"22;2095";25;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000133-canon-pixma-mp-630-multifunktionsgerat.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000134-canon-pixma-mp-630-multifunktionsgerat.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000135-canon-pixma-mp-630-multifunktionsgerat.jpg;2;;False;;;;;False;False;False;;;;;False;;;;;; +5;0;True;"Apple iPhone 4S schwarz ";"Apple iPhone 4S schwarz ";"
    Das neue iPhone 4S - jetzt mit Dual Core A5 Chip, neuer 8 MegaPixel-Kamera, iOS 5 und iCloud sowie dem neuen Siri.
     
    Dual-Core A5 Chip. Der leistungsstärkste iPhone Prozessor aller Zeiten.
    Mit zwei Prozessorkernen liefert der A5 Chip bis zu 2x mehr Leistung und bis zu 7x schnellere Grafik. Das wirst du merken. Und zwar schnell. Das iPhone 4S reagiert extrem schnell, was du sofort merkst, wenn du Apps öffnest, im Web surfst, beim Spielen und auch bei allem anderen. Und ganz egal was du machst, du kannst es richtig lange machen. Denn der A5 Chip ist so effizient, dass das iPhone 4S eine enorm lange Batterielaufzeit hat.
     
    Die Kaum-zu-glauben-dass-es-ein-Handy-ist Kamera.
    Wahrscheinlich die beste Kamera, die es je auf einem Telefon gab. Und dank fortschrittlichster Optik ist sie wahrscheinlich auch die einzige Kamera, die du brauchst. Schließlich hat sie eine Auflösung von 8 Megapixeln und eine spezielle Linse mit einer größeren f/2,4 Blende. Außerdem bietet sie einen optimierten rückwärtig belichteten Sensor, exzellenten Weißabgleich, verbesserte Farbgenauigkeit, Gesichtserkennung und reduzierte Bewegungsunschärfe. Es ist also ganz egal, wie viele Leute, wie viel Licht und wie viel Action du aufnimmst – alles sieht genau so aus, wie es aussehen soll. Und warte erst, bis du die Fotos siehst.
     
    Siri. Dein intelligenter, hilfsbereiter Assistent.Du musst ihn nur fragen.
    Jetzt kannst du dein iPhone einfach mit deiner Stimme benutzen. Sprich mit Siri so, wie du mit einer Person sprichst und sag ""Erinnere mich daran, Mama anzurufen, wenn ich zu Hause bin"" oder ""Brauche ich einen Schirm?"". Siri spricht Deutsch und versteht nicht nur, was du sagst, sondern auch was du meinst. Es erkennt, welche Apps für die richtige Antwort nötig sind. Und antwortet dir dann – wie dein persönlicher Assistent. Siri telefoniert, sendet Nachrichten, plant Meetings, legt Erinnerungen fest und mehr. Was noch? Frag einfach, und Siri sagt es dir selbst.
     
    Videoaufnahmen. In fantastischem 1080p HD.
    Nimm fantastische 1080p HD Videos auf, wo immer du bist. Durch die neue fortschrittliche Optik der Kamera ist das Licht immer genau richtig, die Farben immer leuchtend und alles sieht noch besser aus, als du es in Erinnerung hattest. Die Bildstabilisierung gleicht verwackelte Aufnahmen aus. Und du kannst Videos direkt auf dem iPhone bearbeiten und so schnell mit anderen teilen, wie du sie aufnimmst.
     
    iOS. Das fortschrittlichste mobile Betriebssystem der Welt. Und auch das einfachste.
    Jede neue iOS Version bietet Möglichkeiten, die alles noch einfacher machen. Deshalb ist iOS allen anderen um Jahre voraus. Und iOS 5 geht wieder einen großen Schritt weiter und bringt mehr als 200 neue Features auf das iPhone 4S. Hier sind nur einige unserer Favoriten.
     
    iCloud. Deine Inhalte. Auf all deinen Geräten.
    Mit iCloud kannst du deine Inhalte ganz einfach verwalten, denn iCloud erledigt alles für dich. iCloud speichert deine Musik, Fotos, Apps, Mails, Kontakte, Kalender, Dokumente und mehr und pusht alles drahtlos an all deine Geräte. Automatisch, nahtlos und einfach so.
     
    Retina Display.Das ist ganz klar.
    Auf dem iPhone 4S siehst du einfach alles gestochen scharf und lebendig. Das Retina Display ist das höchstauflösende Telefondisplay aller Zeiten. Die Pixeldichte ist so hoch, dass das menschliche Auge keine einzelnen Pixel erkennen kann. Was du aber ganz bestimmt siehst, sind gestochen scharfe Texte, Grafiken und Bilder. Alles sieht sogar noch besser aus als gedruckt.
     
    FaceTime. Wink doch mal hallo.
    Mit FaceTime hörst du nicht nur eine Stimme, sondern siehst auch das Gesicht dazu – von iPhone zu iPhone, iPad 2, iPod touch oder Mac über Wi-Fi. Es ist also ganz egal, wo die anderen sind und wo du bist – du bist immer da. FaceTime Anrufe sind so einfach wie ganz normale Anrufe. Und mit Siri sind sie sogar noch einfacher. Sag Siri einfach, dass du mit deiner Mutter facetimen willst, und schon seht ihr euch. Einfach so. Du verpasst nie wieder ein wichtiges Ereignis, Meeting oder einen guten Lacher. Und wer würde sich nicht darüber freuen, dich zu sehen?
     
    AirPlay. Live vom iPhone auf deinen Fernseher.
    Mit AirPlay kannst du Inhalte von deinem iPhone via Apple TV drahtlos an deinen HD Fernseher und Lautsprecher streamen.6 Und mit der AirPlay Synchronisierung erscheint alles, was du auf deinem iPhone siehst oder machst, gleichzeitig auf deinem HD Fernseher.
     
    AirPrint.Alles drahtlos drucken.
    Drucke deine Mails, Fotos, Webseiten und Dokumente einfach über Wi-Fi von deinem iPhone aus.7 Ganz ohne Software zu laden, Treiber zu installieren oder Kabel anzuschließen. Nur ein paar Fingertipps und schon hast du das, was eben noch auf dem iPhone war, als Ausdruck in der Hand.
     
    Besser. Schneller. Weltweiter.
    Das iPhone 4S ist das erste Telefon, das zum Übertragen und Empfangen intelligent zwischen zwei Antennen wechselt. So ist die Anrufqualität deutlich besser. Außerdem verdoppeln die Antennen die maximale HSDPA Datengeschwindigkeit auf 14,4 Mbit/s.8 Und das bedeutet schnellere Verbindungen, schnelleres Laden und Neuladen und schnellere Downloads. Das iPhone 4S ist ein Telefon für die ganze Welt. Du kannst es also fast überall verwenden. Ob GSM- oder CDMA-Standard spielt keine Rolle. Nutze es via Roaming in GSM-Netzen in 200 Ländern weltweit.
     
    Integrierte Apps. Machen alles, damit du alles machen kannst.
    Ganz Alltägliches erledigst du mit dem iPhone 4S auf ganz außergewöhnliche Weise. Mach fantastische Fotos und nimm HD Videos auf. Sieh Freunde und Familie mit FaceTime. Tauche auf dem Retina Display richtig ins Web ein. Check deine Mails. Sende Nachrichten. Lege Erinnerungen fest. Schau in deinen Kalender. Oder sag Siri einfach, wie es dir helfen soll. Siri findet dann selbst heraus, welche Apps es verwenden muss.
    Aufgrund der sehr umfangreichen Leistungsmerkmale können wir Ihnen hier nur einen Auszug präsentieren. Die vollständigen Funktionsbeschreibungen inkl. einer Vielzahl von Videos entnehmen Sie bitte der Herstellerwebseite.
    •Apple iPhone 4S
    •115,2 x 58,6 x 9,3 mm klein und 140 g leicht
    •Kapazität: 16 GB Flash-Laufwerk
    •Kamera, Fotos und Video:
    • 8.0 Megapixel Kamera
    • Videoaufnahme, HD (1080p) bis zu 30 fps mit Audio
    • Fotos und Videos in VGA-Qualität mit bis zu 30 fps mit der Kamera an der Vorderseite
    • Fokussieren per Fingertipp für Videos und Fotos LED-Blitz
    • Geotagging für Fotos und Videos
    •Display:
    • Retina Display
    • 3,5""-Multitouch-Display (8,89 cm Diagonale)
    • Auflösung von 960 x 640 Pixeln mit 326ppi
    • Typisches Kontrastverhältnis: 800:1
    • Fettabweisende Beschichtung an der Vorder- und Rückseite
    • Unterstützung für die Anzeige mehrerer Sprachen und Zeichen gleichzeitig
    •Stromversorgung und Batterie:
    • Sprechdauer: bis zu 8 Std. mit 3G, bis zu 14 Std. mit 2G
    • Standbydauer: bis zu 200 Std.
    • Internetnutzung: bis zu 6 Std. mit 3G, bis zu 9 Std. mit Wi-Fi
    • Videowiedergabe: bis zu 10 Std., Audiowiedergabe: bis zu 40 Std.
    •Betriebssystem: iOS 5
    •Mobilfunknetz und Wi-Fi:
    • UMTS/HSDPA/HSUPA (850, 900, 1900, 2100 MHz)
    • GSM/Edge (850, 900, 1800, 1900 MHz)
    • Funktechnologie: 802,11b/g/n Wi-Fi (802.11 nur mit 2,4 GHz), Bluetooth 4.0
    •GPS: Assisted GPS
    •Digitaler Kompass
    •Unterstützte Audioformate: AAC (8 bis 320 KBit/Sek.), Protected AAC (aus dem iTunes Store), HE-AAC, MP3 (8 bis 320 KBit/Sek.), MP3 VBR, Audible (Formate 2, 3, 4, Audible Enhanced Audio, AAX und AAX+), Apple Lossless, AIFF und WAV
    •TV und Video: AirPlay Mirroring to Apple TV support at 720p, Video mirroring and video out support: Up to 1080p with Apple Digital AV Adapter or Apple VGA Adapter (adapters sold separately), Video out support at 576p and 480p with Apple Component AV Cable; 576i and 480i with Apple Composite AV Cable (cables sold separately)
    •Unterstützte Videoformate: H.264 Video: bis zu 720p, 30 Bilder pro Sekunde, Main Level Profile Level 3.1 mit AAC-LC Audio bis zu 160 KBit/Sek., 48 kHz, Stereo-Audio in den Formaten .m4v, .mp4 und .mov; MPEG.4 Video: bis zu 2,5 MBit/Sek., 640 x 480 Pixel, 30 Bilder pro Sekunde, Simple Profile mit AAC-LC Audio bis zu 160 KBit/Sek., 48 kHz, Stereo-Audio in den Formaten .m4v, .mp4 und .mov; Motion JPEG (M-JPEG): bis zu 35 MBit/Sek., 1280 x 720 Pixel, 30 Bilder pro Sekunde, Audio im Format ulaw, PCM Stereo-Audio im Format .avi
    •Sensoren:
    • 3-Achsen-Gyrosensor
    • Beschleunigungssensor
    • Annäherungssensor
    • Umgebungslichtsensor
     
    Lieferumfang:
    iPhone 4S, Apple Earphones mit Fernbedienung und Mikrofon, Dock Connector-auf-USB-Kabel, Dokumentation
    ";2;False;0;;;"Apple iPhone 4S schwarz ";apple-iphone-4s-schwarz;True;True;PD-01081;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;639.0000;639.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;40885,5442708333;71;1;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000651-apple-iphone-4s-schwarz.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000652-apple-iphone-4s-schwarz.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000653-apple-iphone-4s-schwarz.jpg;1;;False;;;;;False;False;False;;;;;False;;;;;; +5;0;True;AVM FRITZ! Box WLAN 3270;AVM FRITZ! Box WLAN 3270 mit 300 Mbit/s und WLAN Eco-Mode;"
    FRITZ!Box WLAN 3270
    Einfach, sicher, kabellos surfen und vernetzen!
     
    FRITZ!Box WLAN 3270 verbindet alle Ihre Computer mit dem Internet - rasend schnell über ADSL oder ADSL2+ und kabellos mit dem neuen WLAN 802.11n.
     
    FRITZ!Box WLAN 3270 vereint ein DSL-Modem mit einem WLAN N-Router in einem Gerät. Mit modernem WLAN N bietet die FRITZ!Box übertragungsgeschwindigkeiten von bis zu 300 MBit/s beim kabellosen Surfen. Computer und netzwerkfähige Geräte lassen sich zudem über die vier Ethernet-Schnittstellen anschließen. Dank des USB-Anschlusses (USB 2.0) stehen Drucker und Speicher im ganzen Netzwerk zur Verfügung.
     
    Ein Hi-Speed-USB 2.0-Anschluss und die erweiterte NAS-Funktionalität mit Mediaserver und Onlinespeicher-Integration erschließen neue Anwendungsmöglichkeiten im Netzwerk.
     
    Damit sind Inhalte wie Filme, Musik und Bilder auch bei ausgeschaltetem Computer im gesamten Netzwerk verfügbar und können auf UPnP-AV-fähigen Geräten (z. B. HD-Fernseher oder Stereoanlage) wiedergegeben werden.
     
     FRITZ!Box WLAN 3270 verfügt über eine umfangreiche Softwareausstattung. Dazu gehören beispielsweise Firewall, Kindersicherung, VPN, WLAN-Nachtschaltung und WLAN-Autokanal.
     
    WLAN N
    FRITZ!Box WLAN 3270 ermöglicht WLAN-Verbindungen mit dem Funkstandard 802.11n im 2,4-GHz- oder im besonders störungsarmen 5-GHz-Band. Durch das Mehrantennenverfahren MIMO (Multiple Input Multiple Output) erhöhen sich Reichweite, Qualität und Datenrate der WLAN-Verbindung. FRITZ!Box WLAN 3270 ist bereits ab Werk sicher dank der voreingestellten, individuellen WPA-/WPA2-Verschlüsselung.
     
    Energie sparen mit FRITZ!
    Mit dem Eco-Mode passt FRITZ!Box WLAN 3270 die Funkleistung automatisch an den Datenverkehr an und sorgt für optimalen Stromverbrauch. Im Ruhezustand wird die Prozessorleistung minimiert und ungenutzte Schnittstellen werden abgeschaltet. Die Funkdauer kann dank der WLAN-Nachtschaltung beliebig eingestellt oder mit einem Schalter verändert werden.
     
    Mehr Möglichkeiten mit USB 2.0
    Ein Hi-Speed-USB 2.0-Anschluss ermöglicht neue Anwendungen im Netzwerk. Bilder, Musik und Videos von an der FRITZ!Box angeschlossenen Speichermedien können an UPnP-AV-kompatiblen Empfängern (HD-Fernseher, Stereoanlage) wiedergegeben werden. Zusätzlich kann ein USB-Drucker dem gesamten Netzwerk zur Verfügung gestellt werden.
     
    Egal ob Online- oder USB-Speicher - die integrierte FRITZ!NAS-Webseite (http://fritz.nas) bietet eine einfache und komfortable Möglichkeit, zentral auf alle Datenbestände an der FRITZ!Box zuzugreifen. Auf Wunsch auch über das Internet.
     
    Anschlüsse
    - DSL-Anschluss an ADSL2+ und ADSL.
     
    - Routerbetrieb auch mit Kabelmodem oder UMTS-Stick (UMTS/HSPA).
     
    - WLAN-Funknetze nach gängigen Standards (802.11n/g/b/a).
     
    - 4 x Ethernet (10/100 Base-T) für Anschluss und Vernetzung von Computern und Spielekonsolen.
     
    - USB 2.0-Anschluss für USB-Geräte wie Drucker und Speichermedien oder UMTS-Stick.
    ";2;False;0;;;AVM FRITZ! Box WLAN 3270 mit 300 Mbit/s und WLAN Eco-Mode;avm-fritz-box-wlan-3270;True;True;P-2690;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;169.0000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;40871,807349537;18;34;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000206-avm-fritz-box-wlan-3270.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000207-avm-fritz-box-wlan-3270.jpg;;2;;False;;;;;False;False;False;;;;;False;;;;;; +5;0;True;AVM FRITZ!Box Fon WLAN 7390;AVM FRITZ!Box Fon WLAN 7390;"
    FRITZ!Box Fon WLAN 7390
    Mehr Leistung für Internet, Telefon und digitale Medien.
     
    FRITZ!Box Fon WLAN 7390 verbindet alle Ihre Computer mit dem Internet - rasend schnell über VDSL (bis 100 MBit/s) oder ADSL2+/ADSL (bis 16 MBit/s). Der neue WLAN-Standard 802.11n (WLAN N) sorgt für ein Maximum an Geschwindigkeit und Reichweite beim kabellosen Surfen. Und dank integrierter DECT-Basisstation und HD-Telefonie wird das Telefonieren über das Internet zu einem komfortablen Erlebnis.
     
    FRITZ!Box Fon WLAN 7390 bietet eine bisher nicht erreichte Vielfalt an Anwendungen für den DSL-Anschluss. Der neue WLAN N-Funkstandard sorgt in Verbindung mit der MIMO- Mehrantennentechnik für eine optimale übertragung mit 2,4 und 5 GHz gleichzeitig (Dualband).
     
    Für die Internet- und Festnetztelefonie steht neben Anschlüssen für analoge und ISDN- Telefone auch eine integrierte DECT-Basis- station für bis zu 6 Schnurlostelefone zur Verfügung.
     
    FRITZ!Box Fon WLAN 7390 bietet dank leistungsstarkem Prozessor die Plattform für vernetzte Anwendungen wie IPTV, Video on Demand oder Mediastreaming.
     
     Zwei Hi-Speed-USB 2.0-Anschlüsse der FRITZ!Box Fon WLAN 7390 und die erweiterte NAS-Funktionalität mit Mediaserver und Onlinespeicher-Integration erschließen neue Anwendungsmöglichkeiten im Netzwerk. Damit sind Inhalte wie Filme, Musik und Bilder auch bei ausgeschaltetem Computer im gesamten Netzwerk verfügbar und können auf UPnP-AV-fähigen Geräten (z. B. HD-Fernseher oder Stereoanlage) wiedergegeben werden.
     
    FRITZ!Box Fon WLAN 7390 verfügt über eine umfangreiche Softwareausstattung. Dazu gehören beispielsweise Telefonbuch, Firewall, Kindersicherung, Faxempfang, VPN, WLAN-Nachtschaltung, WLAN-Autokanal oder ein integrierter Anrufbeantworter.
     
    Dual-WLAN N
    FRITZ!Box Fon WLAN 7390 ermöglicht WLAN-Verbindungen mit dem Funkstandard 802.11n im 2,4-GHz- und im besonders störungsarmen 5-GHz-Band gleichzeitig. Durch das Mehrantennenverfahren MIMO (Multiple Input Multiple Output) erhöhen sich Reichweite, Qualität und Datenrate der WLAN-Verbindung. FRITZ!Box Fon WLAN 7390 ist bereits ab Werk sicher dank der voreingestellten, individuellen WPA-/WPA2-Verschlüsselung.
     
    DECT-Basisstation
    Durch die integrierte DECT-Basisstation können Sie mit bis zu sechs Mobilteilen schnurlos telefonieren. Als ideale Ergänzung zur FRITZ!Box Fon WLAN 7390 bietet AVM die schnurlosen Telefone FRITZ!Fon MT-D und MT-F an, mit denen zahlreiche Komfortfunktionen sowie brillante HD-Telefonie genutzt werden können.
     
    Energie sparen mit FRITZ!
    Mit dem Eco-Mode passt FRITZ!Box Fon WLAN 7390 die Funkleistung automatisch an den Datenverkehr an und sorgt für optimalen Stromverbrauch. Im Ruhezustand wird die Prozessorleistung minimiert und ungenutzte Schnittstellen werden abgeschaltet. Die Funkdauer kann dank der WLAN-Nachtschaltung beliebig eingestellt oder mit einem Schalter verändert werden.
     
    Mehr Möglichkeiten mit USB 2.0
    Zwei Hi-Speed-USB 2.0-Anschlüsse ermöglichen neue Anwendungen im Netzwerk. Bilder, Musik und Videos von an der FRITZ!Box angeschlossenen Speichermedien können an UPnP-AV-kompatiblen Empfängern (HD-Fernseher, Stereoanlage) wiedergegeben werden. Zusätzlich kann ein USB-Drucker dem gesamten Netzwerk zur Verfügung gestellt werden.
     
    Egal ob interner, Online- oder USB-Speicher - die integrierte FRITZ!NAS-Webseite (http://fritz.nas) bietet eine einfache und komfortable Möglichkeit, zentral auf alle Datenbestände an der FRITZ!Box zuzugreifen. Auf Wunsch auch über das Internet.
     
    7390-3.jpg
    ";2;False;0;;;AVM FRITZ!Box Fon WLAN 7390;avm-fritzbox-fon-wlan-7390;True;True;P-2700;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;289.0000;289.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;40871,8066898148;18;34;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000103-avm-fritzbox-fon-wlan-7390.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000104-avm-fritzbox-fon-wlan-7390.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000105-avm-fritzbox-fon-wlan-7390.jpg;1;;False;;;;;False;False;False;;;;;False;;;;;; +5;0;True;"AVM FRITZ!Box Fon WLAN 7270 ";"AVM FRITZ!Box Fon WLAN 7270 ";"
    FRITZ!Box Fon WLAN 7270
    Kabellos mit DSL surfen und über das Internet telefonieren.
     
    FRITZ!Box Fon WLAN 7270 verbindet alle Ihre Computer mit dem Internet - rasend schnell über ADSL oder ADSL2+ und kabellos mit dem neuen WLAN 802.11n.
     
    FRITZ!Box Fon WLAN 7270 vereint DSL-Modem und WLAN-Router mit einer Telefonanlage für Internet- (VoIP-) und Festnetztelefonie und kann wahlweise an analogen oder ISDN-Anschlüssen eingesetzt werden. Sowohl analoge als auch ISDN- und DECT-Telefone werden durch FRITZ!Box Fon WLAN 7270 mit dem Internet und Festnetz verbunden. Das können bis zu zwei analoge Endgeräte wie Telefon und Fax sein, eine ISDN-TK-Anlage, aber auch bis zu sechs Schnurlostelefone, die sich einfach mit der in der FRITZ!Box Fon WLAN 7270 integrierten DECT-Basisstation verbinden lassen.
     
    Unabhängig von der Art des Anschlusses stehen alle wesentlichen Leistungsmerkmale wie Rufnummernanzeige, Dreierkonferenz, Rufumleitung und Makeln an den Telefonen zur Verfügung. Internettelefonie in HD-Qualität (High Definition) wird durch den Einsatz von Breitband-Sprachcodecs unterstützt.
     
     FRITZ!Box Fon WLAN 7270 bietet mit modernem WLAN N übertragungsgeschwindigkeiten von bis zu 300 MBit/s. Computer und netzwerkfähige Geräte lassen sich zudem über die vier LAN-Schnittstellen anschließen. Dank des USB-Anschlusses (USB 2.0) stehen Drucker und Speicher im ganzen Netzwerk zur Verfügung.
     
    FRITZ!Box Fon WLAN 7270 verfügt über eine umfangreiche Softwareausstattung. Dazu gehören beispielsweise Telefonbuch, integrierter Anrufbeantworter, Faxempfang, WLAN-Nachtschaltung, Kindersicherung und VPN.
     
    WLAN N
    FRITZ!Box Fon WLAN 7270 ermöglicht WLAN-Verbindungen mit dem Funkstandard 802.11n im 2,4-GHz- oder im besonders störungsarmen 5-GHz-Band. Durch das Mehrantennenverfahren MIMO (Multiple Input Multiple Output) erhöhen sich Reichweite, Qualität und Datenrate der WLAN-Verbindung. FRITZ!Box Fon WLAN 7270 ist bereits ab Werk sicher dank der voreingestellten, individuellen WPA-/WPA2-Verschlüsselung.
     
    DECT-Basisstation
    Durch die integrierte DECT-Basisstation können Sie mit bis zu sechs Mobilteilen schnurlos telefonieren, wenn diese den Standard CAT-iq oder GAP unterstützen. Als ideale Ergänzungen zur FRITZ!Box bietet AVM die schnurlosen Telefone FRITZ!Fon MT-F und FRITZ!Fon MT-D an, mit denen Sie zahlreiche Komfortfunktionen sowie Internettelefonie in HD-Qualität nutzen können.
     
    Energie sparen mit FRITZ!
    Mit dem Eco-Mode passt FRITZ!Box Fon WLAN 7270 die Funkleistung automatisch an den Datenverkehr an und sorgt für optimalen Stromverbrauch. Im Ruhezustand wird die Prozessorleistung minimiert und ungenutzte Schnittstellen werden abgeschaltet. Die Funkdauer kann dank der WLAN-Nachtschaltung beliebig eingestellt oder mit einem Schalter verändert werden.
     
    Mehr Möglichkeiten mit USB 2.0
    Ein Hi-Speed-USB 2.0-Anschluss ermöglicht neue Anwendungen im Netzwerk. Bilder, Musik und Videos von an der FRITZ!Box angeschlossenen Speichermedien können an UPnP-AV-kompatiblen Empfängern (HD-Fernseher, Stereoanlage) wiedergegeben werden. Zusätzlich kann ein USB-Drucker dem gesamten Netzwerk zur Verfügung gestellt werden.
     
    Egal ob Online- oder USB-Speicher - die integrierte FRITZ!NAS-Webseite (http://fritz.nas) bietet eine einfache und komfortable Möglichkeit, zentral auf alle Datenbestände an der FRITZ!Box zuzugreifen. Auf Wunsch auch über das Internet.
    ";2;False;0;;;AVM FRITZ!Box Fon WLAN 7270 N-Standard mit bis zu 300 MBit/Sek;avm-fritzbox-fon-wlan-7270;True;True;;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;249.0000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;40871,8016898148;18;34;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000200-avm-fritzbox-fon-wlan-7270.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000201-avm-fritzbox-fon-wlan-7270.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000202-avm-fritzbox-fon-wlan-7270.jpg;2;;False;;;;;False;False;False;;;;;False;;;;;; +5;0;True;"Samsung SyncMaster P2270 HD 22 Zoll TFT Monitor ";Samsung SyncMaster P2270 HD 22 Zoll TFT Monitor schwarz;"
    Samsung P2270HD
    Die SyncMaster 70er HD-Serie besticht mit edlem Design und technischen Raffinessen: So können die Modelle dieser Serie als LCD-Monitor, aber auch als vollwertiges LCD-TV-Gerät eingesetzt werden. Der integrierte TV Tuner macht es möglich. Vielseitige AV-Anschlussmöglichkeiten bieten zudem die Möglichkeit, weitere Peripheriegeräte anzuschließen. Das praktische 16:9-Format mit Full HD Auflösung und die Unterstützung von Dolby Digital Plus und SRS TruSurround HD runden die multimedialen Eigenschaften dieser Serie ab.
     
    TV Tuner
    Dieses SyncMaster-Modell ist mit einem TV Tuner ausgestattet und kann somit auch als vollwertiges LCD-TV-Gerät verwendet werden.
     
    16:9-Widescreen-Format
    Das praktische 16:9-Widescreen-Format ermöglicht ein noch angenehmeres Arbeiten bei gleichzeitiger Steigerung Ihrer Produktivität. Das Breitbildformat entspricht dem natürlichen Sichtfeld des Betrachters. Somit haben Sie immer alles im Blick, ohne auf wichtige Informationen verzichten zu müssen.
     
    Full HD
    Dieses SyncMaster Large Format Display verfügt über ein Full HD Panel mit einer nativen Auflösung von 1.920 x 1.080 Pixel. Somit können Bildinhalte im 1.080p-Format, der derzeit besten HD-Auflösung, wiedergegeben werden. 
     
    Dynamischer Kontrast
    Genießen Sie beste Bildqualität mit hoher Bildschärfe und Detailreichtum selbst in dunklen Szenen. Mit einem dynamischen Kontrast von bis zu 50.000:1 werden Sie jedes Detail auf dem Bildschirm erkennen können.
     
    HDMI
    HDMI steht für High Definition Multimedia Interface. Mit dieser Schnittstelle ist es möglich, HD Bild- und Tonmaterial in 100% verlustfreier, digitaler Qualität zu übertragen.
     
    MagicSpeed
    MagicSpeed garantiert Ihnen selbst bei schnell bewegten Bildschirminhalten, wie z. B. Filmen oder Computerspielen, eine schlierenfreie Darstellung für beste Bildqualität. 
      
    HDCP
    HDCP oder auch High Bandwidth Digital Content Protection schützt urheberrechtlich geschützte Formate (z. B. Videodaten) vor illegalen Kopien. HDCP muss dabei sowohl vom Quellgerät (z. B. DVD-Player) als auch vom Ausgabegerät (Monitor) unterstützt werden. Dieses SyncMaster-Modell ist HDCP-kompatibel.
     
    Energiesparfunktion
    Samsung Displays, die dieses Logo tragen, sind besonders energieeffizient und schonen somit die Umwelt.
     
    RoHS-Zertifikat
    Die Displays von Samsung wurden von Nemko mit dem RoHS-Logo zertifiziert, d. h. sie enthalten keine gefährlichen Substanzen gemäß den Richtlinien der Europäischen Union. Damit ist Samsung der erste Hersteller am Markt, der offiziell diese Zertifizierung erhalten hat. 
     
    ";2;False;0;;;Samsung SyncMaster P2270 HD 22 Zoll;samsung-syncmaster-p2270-hd-22-zoll-tft-monitor;True;True;P-2480;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;199.0000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;40871,5791087963;9;5;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000462-samsung-syncmaster-p2270-hd-22-zoll-tft-monitor.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000463-samsung-syncmaster-p2270-hd-22-zoll-tft-monitor.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000464-samsung-syncmaster-p2270-hd-22-zoll-tft-monitor.jpg;2;;False;;;;;False;False;False;;;;;False;;;;;; +5;0;True;Apple iPod Touch 8 GB schwarz;Apple iPod Touch 8 GB schwarz;"
    Apple iPod Touch 8 GB schwarz
     
    mit integrierter WiFi Funktion

     
    Ein großartiger iPod. Ein großartiger Taschencomputer. Großartiger mobiler Spielspaß. Und das Ganze in einem unglaublich schlanken, eleganten neuen Design aus Edelstahl. Filme, Videos und Fernsehsendungen auf einem 3,5"" Display ansehen!Im Web surfen, mailen! Multitouch-Oberfläche: Die revolutionäre Technologie des iPhone und die Software Version 3.1 stecken in diesem genialen iPod. Das brillante Breitformat-Display rückt Ihre Videos und Spiele ins beste Licht Surfen Sie mit Safari im Web und sehen Sie YouTube Videos auf dem iPod mit integrierter Wi-Fi Funktionalität an.
     
    Mit Ihrem iPod touch können Sie im iTunes Wi-Fi Music Store nach Songs suchen, Hörproben abspielen und Titel kaufen.  Lieferumfang: iPod touch, Ohrhörer, USB 2.0 Kabel, Dock-Adapter, Kurzanleitung
     
    Der iPod touch kann alles, was du am iPod toll findest. Und noch vielmehr.
    Du kannst Filme, Videos und Fernsehsendungen auf einem 3,5"" Display ansehen. Mit der revolutionären Multi-Touch-Technologie kannst du dein Musikarchiv mit Cover Flow durchblättern. Und wenn dir nach mehr ist, tipp einfach auf iTunes, um durch das Angebot zu stöbern und sofort einzukaufen. Hör dir Wiedergabelisten an, die automatisch für dich erstellt werden. Schau Filme auf dem brillanten 3,5"" Display. Und kauf mit einem Fingertipp bei iTunes ein - wann immer du willst. All das und noch viel mehr mit dem iPod touch, den es schon ab 189 € gibt. Wi-Fi ist schon integriert. So kannst du im Web surfen, mailen, deinen Facebook Status aktualisieren, mit AIM chatten und noch viel mehr - und das alles auf einem Gerät, das locker in jede Tasche passt. Hier hast du die Finger im Spiel. Und nicht nur die. Denn mit den Spielen auf dem iPod touch tauchst du richtig in die Action ein - einfach neigen, tippen, drehen. Und via Wi-Fi kannst du jederzeit im App Store neue Spiele kaufen. Die iPhone 3.1 Software ist auf dem iPod touch bereits installiert, sodass der Spaß gleich beginnen kann. Damit kannst du nützliche Funktionen wie Peer-to-Peer-Spiele und Cut, Copy & Paste direkt nach dem Auspacken nutzen.
    Next Level Fun: Der neue iPod touch
     
    Musik
    Stöber durch deine Alben. Hör dir einen einzigartigen Mix an, der nur für dich erstellt wurde. Oder schau das Video deines Lieblingssongs an. Mit dem iPod touch kannst du mehr als nur Musik hören.
     
    Cover Flow
    Auf dem iPod touch gibt's Musik nicht nur auf die Ohren. Mit Cover Flow ist Musik auch etwas für Augen und Finger. Dreh den iPod touch einfach auf die Seite und blätter durch deine Albumcover. Tipp auf ein Albumcover, um es umzudrehen und die Songliste zu sehen. Tipp noch einmal und Musik ab.
     
    Genius Mixe
    Die Genius Funktion wurde weiter verbessert. Jetzt gibt es Genius Mixe. Du brauchst den iPod touch nur mit iTunes zu synchronisieren. Genius durchsucht dann automatisch deine Mediathek nach Songs, die gut zusammenpassen und erstellt bis zu zwölf Mixe.
    Diese Mixe sind wie Radiosender, auf denen nur deine Musik läuft.
     
    Genius Wiedergabelisten
    Angenommen du hörst einen Song auf deinem iPod touch, der dir gut gefällt, und du möchtest weitere Titel hören, die dazu passen. Genius findet weitere Songs auf deinem iPod touch und erstellt eine Genius Wiedergabeliste für dich. Hör dir die Wiedergabeliste sofort an, speichere sie für später oder versuch's noch einmal und sieh, was dabei herauskommt. Verlass dich auf Genius, wenn du einen Mix willst, auf den du selbst nie gekommen wärst.
     
    Shake to Shuffle
    Die Dinge mal aufrütteln. Musikalisch natürlich. Wenn du das nächste Mal Musik hörst, aktiviere die Schüttelfunktion und wenn du den iPod touch dann kurz schüttelst, springt er nach dem Zufallsprinzip zu einem anderen Song aus deiner Sammlung.
     
    iTunes
    Pack Musik und Videos aus der iTunes Mediathek deines Computers auf den iPod touch. Oder kauf und lade neue Songs auf den iPod touch, wenn du über Wi-Fi auf iTunes zugreifst. Wenn du den iPod touch das nächste Mal mit dem Computer verbindest, werden alle Songs, die du auf dem iPod touch gekauft hast, auf den Mac oder PC übertragen.
     
    Bluetooth
    Schau mal, keine Kabel. Der iPod touch enthält die iPhone 3.1 Software, sodass du Bluetooth Stereokopfhörer anschließen kannst. Lass den iPod in deiner Tasche stecken oder auf dem Schreibtisch aufladen, während du weiter Musik hörst.
     
    Filme und Fernsehsendungen
    Ein Kinohit. Ein Video-Podcast. Deine Lieblingsserie. Jetzt laufen sie auch in einer U-Bahn oder einem Flugzeug in deiner Nähe.
    Widescreen-Display
    Du kannst Videos für viele Stunden überallhin mitnehmen und auf dem gestochen scharfen 3,5"" Widescreen-Farbdisplay ansehen. Kauf im iTunes Store und wähle unter tausenden vonFilmen, Fernsehsendungen und Video-Podcasts, die du auf den iPod touch laden kannst. Von Hollywood-Hits bis zu Indie-Streifen - es gibt etwas für jeden Geschmack. Mit wenigen Fingertipps kannst du Filme kaufen und laden. Du magst lieber Fernsehsendungen? Lade eine einzelne Folge oder die gesamte Staffel.
     
    On-Screen Steuerung
    Auch während du Video guckst, kannst du die Steuerung einblenden - ein Fingertipp auf das Display genügt. Du kannst die Wiedergabe starten oder unterbrechen, einzelne Kapitel anzeigen und die Lautstärke anpassen. Natürlich kannst du auch die Lautstärkeregler links am iPod touch verwenden. Du willst zwischen Widescreen und bildschirmfüllender Anzeige wechseln? Einfach aufs Display doppeltippen.
     
    iTunes
    Du brauchst Unterhaltung für deinen nächsten Flug oder die Autofahrt? Mit iTunes auf dem iPod touch und einer Wi-Fi-Verbindung kannst du auch unterwegsFilme und Fernsehsendungen kaufen. Du kannst Filme auch leihen, wenn du dir nicht sicher bist, ob du den Film behalten willst. Und natürlich kannst du Filme und Fernsehsendungen auf dem Mac oder PC kaufen und dann mit dem iPod touch synchronisieren.
     
    App Store
    Kaufe im App Store und entdecke über 65.000 Apps, mit denen du noch mehr auf dem iPod touch machen kannst. Stöbere in tausenden von Apps in verschiedenen Kategorien. Von Spielen über Lifestyle und Soziale Netzwerke bis zu Unterhaltung und mehr.
     
    Apps durchstöbern
    Du kannst auf verschiedene Arten im App Store shoppen. Tipp auf ""Neu"" und ""Topaktuell"", um eine Liste der aktuellen und angesagten Apps zu erhalten. Stöbere nach Kategorien. Schau dir die topaktuellen Apps an. Wenn du genau weißt, wonach du suchst, kannst du auch eine Schnellsuche durchführen.
     
    Genius Empfehlungen für Apps
    Es gibt tausende von Apps im App Store, und jeden Tag kommen mehr dazu. Mit dieser neuen Funktion des iPod touch findest du coole neue Apps noch einfacher. Genius für Apps. Funktioniert genau wie Genius für deine Musik. Tipp auf das Genius Symbol und du bekommst Empfehlungen für Apps anhand der Apps, die du und andere schon geladen haben.
     
    Apps laden
    Wenn du eine App findest, die dich interessiert, kannst du sie überall, wo eine Wi-Fi-Verbindung besteht, drahtlos kaufen, auf den iPod laden und dann sofort loslegen.
     
    Updates für Apps
    iPod touch sagt dir, wenn ein App Update verfügbar ist, damit du immer die neuesten Versionen deiner Lieblings-Apps hast.
     
    iTunes
    Entdecke und lade neue Musik, Filme, Fernsehsendungen, Podcasts und Hörbücher in iTunes auf dem iPod touch.
     
    Einkaufen, immer und überall
    Greif über die im iPod touch integrierte Wi-Fi-Funktion auf den iTunes Store zu. Durchsuche Millionen von iTunes Plus Songs in brillanter Audioqualitätund tausende von Filmen, Fernsehsendungen, Hörbüchern und kostenlosen Podcasts und Vorlesungen von iTunes U. Stöbere nach Neuerscheinungen, Top-Titeln und Genres. Oder finde mit der Schnellsuche genau das, wonach du suchst. Hör in einen Song oder sieh dir eine Videovorschau an. Wenn du dann etwas kaufen möchtest, brauchst du nur darauf zu tippen. Nicht sicher, ob es sich lohnt, den Film zu kaufen? Dann leih ihn einfach. Alles was du auf dem iPod touch kaufst, hat denselben Preis wie im iTunes Store auf deinem Computer.
     
    Synchronisieren mit iTunes
    Sobald du den iPod touch mit dem Computer verbindest, werden die Songs, Filme, Fernsehsendungen, Hörbücher und Podcasts, die du unterwegs geladen hast, mit deiner iTunes Mediathek auf deinem Mac oder PC synchronisiert. Wenn du etwas nur teilweise auf den iPod touch geladen hast, beendet der Computer den Download automatisch für dich.
     
    Sprachsteuerung
    Mit der Sprachsteuerung beim neuen 32 GB und 64 GB iPod touch kannst du deine Musik mit Sprachbefehlen steuern. Und der iPod hört aufs Wort. Auf ""Spiel"", ""Shuffle"" oder ""Wie heißt das Lied?"".
     
    Sagen und abspielen.
    Die Sprachsteuerung kennt die Musik auf deinem iPod touch. Wenn du etwas Bestimmtes hören willst, sag es einfach. Zum Beispiel ""Spiel Bob Dylan"" und der iPod touch hört aufs Wort. Frag ihn, welcher Song grad läuft, und der iPod touch sagt es dir. Sag ihm, dass er dein Lieblingsalbum, deinen Lieblingssänger oder deine Lieblingswiedergabeliste spielen soll. Verwende einfache Befehle wie ""shuffle"", ""nächster Song"" und ""anhalten"". Du kannst dem iPod touch sogar sagen, dass er mehr Songs wie den, der gerade läuft, abspielen soll.
     
    Sprich ins Mikro
    Der neue 32 GB und 64 GB iPod touch wird mit den Apple Earphones mit Fernbedienung und Mikro geliefert. So kannst du die Sprachsteuerung auch dann nutzen, wenn der iPod touch in der Tasche steckt. Zum Aktivieren der Sprachsteuerung über die Kopfhörer hältst du einfach die Mitteltaste der Fernbedienung gedrückt.
     
    Die Sprachsteuerung unterstützt die folgenden Sprachen:
    Chinesisch (China), Chinesisch (Kantonesisch), Chinesisch (Taiwan), Deutsch, Englisch (Großbritannien), Englisch (USA), Finnisch, Französisch (Frankreich), Französisch (Kanada), Italienisch, Japanisch, Koreanisch, Niederländisch, Norwegisch, Polnisch, Portugiesisch (Brasilien), Portugiesisch (Portugal), Russisch, Schwedisch, Spanisch (Mexiko), Spanisch (Spanien)
     
    Fotos
    Der iPod touch hat für bis zu 90.000 deiner Lieblingsfotos Platz. Durch Streichen kannst du sie durchschauen und all die Erinnerst-du-dich-noch-Momente mit anderen teilen.
     
    Fotos sichern
    Wenn dir tolle Bilder gemailt werden, kannst du sie einfach im Fotoarchiv auf dem iPod touch sichern und dann wie jedes andere Foto nutzen. Du kannst sie zum Beispiel als Hintergrundbilder verwenden, im Internet teilen oder weitergeben.
     
    Fotos teilen
    Du hast tausende Fotos immer zur Hand. Blätter durch Streichen auf dem Display durch Miniaturen. Mit einem Fingertipp siehst du Fotos bildschirmfüllend. Spiel Diashows mit Musik und Übergängen ab. Maile Fotos an Freunde oder teile sie in einer MobileMe Galerie.
     
    Fotos synchronisieren
    Fotos aus iPhoto auf einem Mac oder Adobe Photoshop Elements und Adobe Photoshop Album auf einem PC werden via iTunes mit dem iPod touch synchronisiert. Einfach nur die Fotos und Alben aussuchen, die mit dem iPod touch synchronisiert werden sollen. Dann kannst du sie überall ansehen und mit anderen teilen.
     
    Homescreen
    Angenommen du möchtest ""Karten"" als erste App in der zweiten Zeile haben. Oder Mail unten im Dock. Mit den anpassbaren Homescreens kannst du den iPod touch zu deinem iPod touch machen.
     
    Individuelles Anpassen
    Ordne die Symbole auf deinem Homescreen an wie du willst - direkt auf dem iPod touch oder auf deinem Computer in iTunes 9. Bewege eine App eine Zeile nach oben, zwei Apps nach rechts oder auf einen anderen Homescreen. Du kannst bis zu 11 Homescreens erstellen und hast so schnellen Zugriff auf Spiele und Apps, die du aus dem App Store lädst, und auf deine Safari Weblinks.
     
    Hometaste
    Was auch immer du gerade mit deinem iPod touch machst – die Hometaste bringt dich immer zurück zum ersten Homescreen. Wenn du auf die Hometaste drückst, kannst du von jedem Homescreen wieder zurück zum ersten springen.
     
    Apps und Weblinks hinzufügen
    Für jede App, die du aus dem App Store lädst, erscheint ein neues Symbol auf dem Homescreen. Von häufig besuchten Websites kannst du praktische Weblinks erstellen. Sie erscheinen auf dem Homescreen und du kannst per Fingertipp darauf zugreifen.
     
    Spotlight Suche
    Du suchst was? Von einem Ort aus kannst du die gesamten Inhalte des iPod touch durchsuchen. Streich auf dem ersten Homescreen einfach nach rechts, um Spotlight zu öffnen. Sobald du anfängst zu tippen, durchsucht Spotlight deine gesamten Songs, Videos, Kontakte, Mails, Kalender, Notizen und sogar deine Hörbücher und Podcasts.
     
    Safari
    Safari, der fortschrittlichste Webbrowser auf einem Mobilgerät, ist auch auf dem iPod touch integriert. Damit erlebst du das Internet in deiner Hand genauso wie auf dem Computer zuhause. Alles was du brauchst ist eine Wi-Fi-Verbindung.
     
    Überall ins Internet
    Der iPod touch ist der einzige iPod mit integriertem drahtlosen Internetzugriff. Bei bestehender Wi-Fi-Verbindung kannst du im Internet surfen und Nachrichten lesen, Sportergebnisse sehen, Rechnungen bezahlen und online einkaufen. Und beim 32 GB oder 64 GB iPod touch wirst du sehen, dass Webseiten jetzt noch schneller als vorher geladen werden.
     
    Im Web stöbern
    Der iPod touch synchronisiert deine Lesezeichen vom PC oder Mac, sodass du ruckzuck auf deine Lieblingsseiten zugreifen kannst. Außerdem ist die Google- und Yahoo!-Suche schon integriert, sodass du im Web schnell findest, was du suchst.
     
    Weblinks
    Wenn du eine Website öfter besuchst - etwa die einer Zeitung, eines Blogs oder eine Sport-Website - kannst du einfach ein Symbol, einen sogenannten Weblink, auf dem Homescreen erstellen. Wenn du mit Safari Weblinks erstellst, sind deine Lieblingsseiten nur einen Fingertipp entfernt.
     
    Zoom
    Wenn du eine Website öfter besuchst, brauchst du nur mit dem Finger auf das Multi-Touch-Display zu tippen oder die Anzeige aufzuziehen. Websites lassen sich im Hoch- oder Querformat anzeigen. Einfach den iPod touch um 90 Grad drehen, und schon wird auch die Darstellung der Webseite gedreht.
     
    Mail
    Mails auf dem iPod touch funktionieren genau wie auf deinem Computer und sehen auch genau so aus. Und sie funktionieren mit deinen vorhandenen Accounts.
     
    Nachrichten und Anhänge ansehen
    Der iPod touch unterstützt Rich-HTML-E-Mail, sodass Bilder und Fotos zusammen mit dem Text einer E-Mail angezeigt werden. Anhänge siehst du in ihrem Originalformat und nicht als abgespeckte Version. Du kannst in mehr als einem Dutzend standardmäßigen Datei- und Bildformaten drehen, zoomen und schwenken, darunter PDF, Microsoft Word, Excel, PowerPoint und iWork.
     
    Zugriff auf alle Accounts
    Mails von gängigen Anbietern wie MobileMe, Google Mail, Microsoft Exchange, Yahoo! und den meisten standardmäßigen IMAP- und POP-Systemen kannst du mit dem iPod touch ganz einfach abrufen.
     
    Schnellere Eingabe
    Der iPod touch erkennt E-Mail-Adressen in verschiedenen Programmen. Wenn du auf einer Webseite oder in einer Karte eine E-Mail-Adresse siehst, reicht ein Fingertipp auf dem iPod touch, um eine neue Mail zu öffnen, in der die Adresse bereits eingetragen ist.
     
    Intelligente Eingabe
    Die innovative iPod touch Tastatur mit integriertem Wörterbuch* schlägt während der Eingabe Wörter vor. So kannst du ganz schnell und einfach Mails schreiben. Dreh den iPod touch einfach. Dann wird die Tastatur vom Hochformat ins Querformat gedreht und du hast größere Tasten und mehr Platz zum Tippen.
     
    Postfach durchsuchen
    Du musst das Postfach jetzt nicht mehr Mail für Mail durchsuchen. Durch schnelles Abwärtsstreichen wird jetzt ein Suchfeld geöffnet, mit dem du deine Mails nach Absender, Empfänger, Betreff oder Titelzeilen durchsuchen kannst.
     
    Karten
    Finde deinen Weg und die nächste Pizzeria. Mit Karten und einer Wi-Fi-Verbindung kannst du Wegbeschreibungen abrufen, Firmen finden und Verkehrsinformationen prüfen.
     
    Finde dich selbst
    Der iPod touch zeigt dir mithilfe von bekannten Wi-Fi-Hot-Spots, wo du bist. Mit der Stichwortsuche kannst du auch interessante Orte finden. Wenn du z. B. ""Kaffee"" eingibst, werden dir alle Cafés in der Nähe angezeigt.
     
    Wo geht's lang?
    Gib einfach eine Adresse ein, um Wegbeschreibungen abzurufen - von jedem Ort aus. Wähle das Transportmittel wie Auto, öffentliches Verkehrsmittel oder zu Fuß. Die Route lässt sich dann Schritt für Schritt anzeigen. Du kannst dem markierten Weg auf der Karte folgen und selbst die Fahrtdauer wird angezeigt. Oder markiere zwei Orte und lass dir die beste Route zwischen diesen anzeigen.
     
    Verschiedene Kartendarstellungen
    Wie bei Google Karten auf deinem Computer kannst du mit dem Programm ""Karten"" auf dem iPod touch zwischen unterschiedlichen Darstellungen von Google-Karten, Satellitenbildern und einer Hybriddarstellung wechseln. Und mit Multi-Touch kannst du unterwegs zoomen, den Ausschnitt bewegen und die Darstellung ändern.
     
    Verkehrsinformationen
    Die Verkehrsinformationen geben dir anhand der grünen, roten und gelben Markierungen einen Überblick über die Verkehrssituation auf deiner Route.
     
    YouTube
    Skateboard Moves, die so nicht geplant waren. Witzige Werbespots aus anderen Ländern. Was auch immer du gern auf YouTube ansiehst - der iPod touch ist für dich da.
     
    Videogrüße von unterwegs.
    Maile Links deiner Lieblingsvideos an Freunde. Tippe auf der Detailseite des YouTube Videos auf ""Senden"", und schon erstellt der iPod touch eine Mail mit dem zugehörigen Videolink.
     
    Auf YouTube suchen.
    Stöber in Videokategorien wie ""Highlights"", ""Topvideos"", ""Neue Videos"" oder ""Bestwertung"". Du kannst auch per Schlagwort nach einem Video suchen. Etwas Passendes gefunden? Mit einem Lesezeichen kannst du das Video auch vormerken und später ansehen.
     
    Nike + iPod Kompatibilität
    Rock dein Training. Der iPod touch hat eine integrierte Unterstützung für Nike + iPod. Das ist Musik und Motivation in einem.
    Finetuning für dein Lauftraining.
     
    Nike + iPod Sensor
    Der iPod touch hat eine integrierte Unterstützung für Nike + iPod. Einfach den Nike + iPod Sensor (separat erhältlich) in die Nike+ Schuhe stecken und los geht's. Der Sensor überträgt deine Laufdaten drahtlos an den iPod touch und zeichnet Laufzeit, Laufstrecke und Kalorienverbrauch auf. Du erhältst sogar Feedback zum Trainingsfortschritt.
     
    Finetuning für dein Cardio Workout
    Diese Funktion kann auch zusammen mit neuen, in vielen Fitnessstudios vorhandenen Geräten für das Ausdauertraining gekoppelt werden. Such dir einfach ein mit Nike + iPod kompatibles Fitnessgerät wie beispielsweise Laufbänder, Ellipsentrainer, Stepper und Hometrainer.
     
    Synchronisieren mit nikeplus.com
    Später kannst du am Computer den iPod touch via iTunes synchronisieren und deine Trainingsdaten an nikeplus.com übertragen. Auf dieser Website kannst du dein Training verfolgen, dir Ziele setzen und deine Freunde herausfordern.
     
    Sprachmemos
    Du hast vielleicht ein ganz gutes Gedächtnis, aber manchmal ist es besser, kleine (und große) Infos einfach irgendwo festzuhalten. Mit ""Sprachmemos"" kein Problem.
     
    Memos (oder alles andere)aufnehmen
    Nimm eine Aufgabenliste, geniale Ideen oder eine Wette zwischen dir und deinem Freund auf. Mit dem Programm ""Sprachmemos"" kannst du über die Apple Earphones mit Fernbedienung und Mikro oder ein externes Mikrofon aufnehmen, was immer du willst. Sprachmemos kannst du selbst dann aufnehmen, wenn du den iPod touch gerade verwendest, um Mails zu checken oder im Web zu surfen.
     
    Memos bearbeiten
    Aufgenommene Memos kannst du direkt auf dem iPod touch trimmen. So behältst du nur das, was du wirklich brauchst.
     
    Memos sortieren
    Ordne deine Memos mithilfe von Etiketten aus einer vordefinierten Liste oder erstelle eigene Etiketten.
     
    Memos teilen
    Maile Memos an Freunde und Kollegen. Mit dem iPod touch aufgenommene Memos werden via iTunes mit deinem Mac oder PC synchronisiert, damit du sie später mit anderen teilen kannst.
     
    Weitere Funktionen
    Auf dem iPod touch ist die neueste Software schon installiert. Und außerdem gibt's praktische Apps wie Kontakte, Kalender, Notizen, Aktien und Wetter.
     
    iPod touch 3.1 Softwarefunktionen.
     
    Genius Mixe
    Diese neue Funktion ist wie ein privater DJ, der deine iTunes Mediathek durchsucht, um Songs zu finden, die gut zusammenpassen und aus diesen dann tolle Mixe erstellt. Alles ganz automatisch.
     
    Genius Empfehlungen für Apps
    Im App Store gibt's zehntausende Apps. Wie soll man da die richtig collen neuen finden? Mit Genius. Denn Genius sieht sich die Apps an, die du schon hast, und empfiehlt dir weitere.
     
    Peer-to-Peer-Spiele
    Die neusten Spiele kannst du ganz leicht mit Freunden spielen - egal, ob sie neben dir oder in einer anderen Ecke des Landes sitzen.
     
    Kauf Filme, Fernsehsendungen und Hörbücher via Wi-Fi
    Lade via Wi-Fi Filme, Fernsehsendungen, Musikvideos und Hörbücher aus dem iTunes Store auf deinen iPod touch.
     
    Tastatur im Querformat
    Du brauchst mehr Platz zum Tippen? Dreh den iPod touch ins Querformat, um in Mail, Notizen und Safari mit einer größeren Tastatur zu arbeiten.
     
    Cut, Copy & Paste
    Einfach Text und Fotos ausschneiden, kopieren und wieder einsetzen - selbst zwischen Programmen. Du kannst auch Inhalte aus dem Web kopieren.
     
    Spotlight Suche
    Gesucht, gefunden - von einem Ort aus. Spotlight durchsucht alle deine Kontakte, E-Mails, Kalender und Notizen und auch alle Songs und Videos.
     
    Stereo Bluetooth
    Hör Musik und andere Audioinhalte drahtlos. Verbinde den iPod touch mit kompatiblen Bluetooth Stereokopfhörern.
     
    Automatischer Wi-Fi-Login
    Wenn du dich einmal bei einem Wi-Fi-Hotspot anmeldest, loggt der iPod touch sich beim nächsten Mal automatisch ein.
     
    Shake to Shuffle
    Schüttel den iPod kurz, und schon springt er nach dem Zufallsprinzip zu einem anderen Song in deiner Sammlung. Lass dich einfach überraschen.
     
    Bedienungshilfen
    Der neue iPod touch hat standardmäßig Bedienungshilfen integriert, mit denen auch Menschen mit Beeinträchtigungen alles, was der iPod touch zu bieten hat, erleben können. Alle Bedienungshilfen des iPod touch ansehen
     
    Kindersicherung
    Du entscheidest, welche Musik, Videos und Apps auf dem iPod touch für deine Kinder geeignet sind.
    Der iPod touch hat auch die folgenden praktischen Apps:
     
    Kalender
    Das Programm ""Kalender"" funktioniert mit Yahoo!, Google, Microsoft Outlook, iCal, MobileMe und Microsoft Exchange ActiveSync für Unternehmen. Füge Termine hinzu, lass dich an Termine erinnern, und abonniere Kalender, damit du über Feiertage und Sportveranstaltungen auf dem Laufenden bleibst.
     
    Kontakte
    Namen, E-Mail-Adressen, Telefonnummern und mehr - immer zur Hand. Synchronisier Kontakte in iTunes auf dem Mac oder PC mit dem iPod touch. Neue Kontakte kannst du auch unterwegs mit einem einfachen Fingertipp hinzufügen.
     
    Notizen
    Schluss mit Papier und Bleistift. Mach dir mit ""Notizen"" auf dem iPod schnell eine Notiz, damit du wichtige Infos immer parat hast. Maile deine Gedanken mit der integrierten Mail-Funktion an dich oder andere.
     
    Aktien
    Die Aktien App auf dem iPod touch zeigt dir Börseninformationen für die Aktien, die dich interessieren. Wenn du nähere Details über eine Aktie brauchst, tipp auf ""Y!"", um im Handumdrehen Yahoo! Finance zu öffnen.
     
    Wetter
    Informier dich über das Wetter in der ganzen Welt oder zuhause. Füge die gewünschten Städte hinzu und zeige eine sechstägige Vorhersage für alle an. Tipp auf ""Y!"", um den Yahoo! Stadtführer zu öffnen, der dir zeigt, wo was los ist.
     
    Rechner
    Im Programm ""Rechner"" des iPod touch stecken gleich zwei Rechner. Im Hochformat kannst du ihn als einfachen Taschenrechner verwenden. Dreh den iPod touch ins Querformat, um aus ihm einen wissenschaftlichen Rechner zu machen.
     
    iPod touch Technologie
    Dank der revolutionären Hardwaretechnologie im iPod touch kannst du alle Funktionen mit Streichen, Tippen und Auf- oder Zuziehen steuern. Deswegen wirkt das Autorennen so echt. Deswegen kannst du das, was du eben im Café mitbekommen hast, sofort twittern. Und genau deswegen ist der iPod touch der beste iPod aller Zeiten.
     
    Multi-Touch
    Das Multi-Touch-Display besitzt einen Schutzfilm über der kapazitiven Sensorik, die Berührungen anhand elektrischer Felder erkennt. Diese Informationen werden an das darunterliegende LCD-Display übertragen. Dank der Software des iPod touch kannst du mit Cover Flow durch Alben stöbern, durch deine Fotos blättern, mit Auf- und Zuziehen Bildausschnitte von Websites zoomen und Spiele superpräzise steuern.
     
    Beschleunigungssensor
    Der iPod touch reagiert über einen integrierten Beschleunigungssensor auf Bewegungen. Dieser Sensor erkennt, wenn du deinen iPod touch ins Querformat drehst und verändert automatisch den Inhalt des Displays. Die Technologie des Beschleunigungssensors kommt besonders bei Spielen gut, denn damit bist du mitten im Spielgeschehen. Das ist perfekt für Autorennen, bei denen der ganze iPod zum Lenkrad wird, und Geschicklichkeitsspiele wie Rolando, bei denen du das Spiel mit deinen Bewegungen steuerst
     
    Drahtlos
    Der iPod touch hat eine integrierte Unterstützung für drahtlosen 802.11b/g Internetzugriff. Überall, wo es ein Wi-Fi-Netzwerk gibt, kommst du mit deinem iPod touch ins Internet. Im Café mailen. Am Flughafen im Web surfen. Spiele vom Sofa aus kaufen. Im iTunes Store stöbern und Musik kaufen und laden. Der iPod touch findet nahegelegene Wi-Fi-Hot-Spots, auch geschützte Netzwerke. Wenn du ein bestimmtes Netzwerk bisher noch nicht verwendet hast, Drahtlos Symbol musst du beim ersten Mal ein Kennwort eingeben, das sich der iPod touch dann merkt. Wenn du dann das nächste Mal in Reichweite dieses Netzwerks bist, loggt er sich automatisch ein.
     
    Bluetooth
    Bluetooth ist eine drahtlose Technologie, mit der du Geräte ohne lästige Kabel verwenden kannst. Was bedeutet das für den iPod touch? Du kannst jetzt mit dem iPod touch und Bluetooth Kopfhörern Musik hören, ganz egal, wo im Raum der iPod ist. Du kannst also auf dem Bett relaxen, während der iPod auf dem Schreibtisch aufgeladen wird. Bluetooth auf dem iPod touch eignet sich auch besonders für Peer-to-Peer-Spiele.
     
    Design
    Der iPod touch ist von außen genau so großartig wie von innen. Du brauchst nur einen in die Hand zu nehmen. Das Gehäuse des iPod touch ist gerade einmal 8,5 mm hoch. Das optische Glas auf der Vorderseite und die Rückseite aus poliertem Edelstahl geben ihm einen eleganten Touch und fühlen sich in der Hand einfach gut an. Schalte ihn ein und du wirst über das brillante 3,5"" Display einfach staunen. Der iPod touch ist die perfekte Kombination aus großartigem Design und revolutionärer Technologie - das perfekte Paket.
    ";2;False;0;;;Apple iPod Touch 8 GB schwarz mit integrierter WiFi Funktion;apple-ipod-touch-8-gb-schwarz-2;True;True;PD-01085;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;169.9000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;40871,5555092593;44;1;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000434-apple-ipod-touch-64-gb-schwarz.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000435-apple-ipod-touch-64-gb-schwarz.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000436-apple-ipod-touch-64-gb-schwarz.jpg;2;;False;;;;;False;False;False;;;;;False;;;;;; +5;0;True;Samsung Galaxy S II (i9100) DualCore Smartphone schwarz;"Samsung Galaxy S II (i9100) DualCore Smartphone (10.9 cm (4.3 Zoll) Super-Amoled Plus Display, Android 2.3, 8 MP Full-HD Kamera, 2 MP Frontkamera) schwarz ";"
    Samsung launcht mit dem Galaxy S II den Nachfolger des Bestsellers Galaxy S. Das Galaxy S II ist nicht nur das schlankste (8,49 mm), sondern dank des 1,2 GHz Dual-Core Prozessors auch das schnellste Smartphone seiner Klasse. Darüber hinaus besticht es durch ein 4,3"" Super Amoled Plus Touch-Display. Das Galaxy S II verwendet als Betriebssystem die aktuellste Android 2.3 Version – auch bekannt unter dem Namen Gingerbread. Die integrierte 8 Megapixel Kamera mit LED Blitz hält die schönsten Momente in erstklassiger Qualität fest – darüber hinaus ermöglicht die 2 Megapixel Frontkamera Video Telefonate in beeindruckender Qualität. Das Schreiben von E-Mails und SMS gelingt unkompliziert dank Swype®-Texteingabe. Zahlreiche aktuelle und nützliche Apps stehen im Android Market™ zum Download bereit. Die integrierte Google Maps Navigation™ führt ans gewünschte Ziel. AllShare, HD Video, Exchange ActiveSync und eine Vielzahl an weiteren Applikationen lassen keine Wünsche offen. Ein erstklassiges Zusammenspiel von Hardware und Funktionen leistet sein Übriges für ein ausgezeichnetes Nutzererlebnis auf höchstem Niveau!
     
    4,27-Zoll SUPER AMOLED Plus
    Bekennen Sie Farbe! Dieses brillante Display bietet den besten Farbumfang, ein hohes Kontrastverhältnis sowie ultimative Schärfe bei Bildern. Die bahnbrechende Verkürzung der Video-Reaktionszeit sorgt für ruckfreie Videowiedergabe. Die neue Technologie benötigt weniger Platz und Energie: Im Vergleich zum Vorgänger benötigt das Display 18% weniger Energie. Es ist damit eines der dünnsten, langlebigsten Smartphones am Markt.
     
    Brillante Performance
    Das Unmögliche ist möglich. Der Samsung Dual Core Application Prozessor ist die reaktionsschnelle Antwort im Bereich mobile Performance. Er bietet Multitasking in Hochgeschwindigkeit, schnelles Laden von Internetseiten, schnelle Reaktionszeiten, eine intuitive Benutzeroberfläche, blitzschnelle Bildbearbeitung und Spiele mit hoher Performance. Und mit der superschnellen Möglichkeit zum Encodieren und Decodieren, die alles im Bereich Videoaufzeichnung und -wiedergabe (1080p / 30fps) unterstützt, stellt er alle anderen Dual Core-Prozessoren in den Schatten. Problemloses Video- oder Musik-Streaming bekommt dank des schnellen Drahtlosstandards HSPA 21 Mbps einen großen Schub. Hervorragende Rechenleistung, herausstechende Performance.
     
    Schlankes Design
    Schlank, schlanker, GALAXY S II. Das Samsung GALAXY S II führt die Riege an – mit nur 8,49 mm und einem luxuriösen Design liegt es zudem gut in der Hand. Das GALAXY S II ist eines der schlanksten Smartphones und bietet außerdem HyperSkin für einen schönen Metall-Look mit einer fingerabdruckfreien und rutschfesten Akkuabdeckung.
     
    Readers Hub
    Lassen Sie Ihre Bücher zu Hause: Das Samsung GALAXY S II übernimmt diese Aufgabe. Stöbern Sie im Readers Hub in Ihrer Bücherei mit Klassikern oder suchen Sie in mehr als 2 Millionen Büchern die neusten Bestseller. Sie können auch 2.500 Magazine in 20 Sprachen und 1.600 Zeitungen in 47 Sprachen zur Lieferung einrichten. Mit klarem, deutlichem Text und der hohen Bedienerfreundlichkeit macht das Lesen Spaß: vergrößern, nur Text und Seitenansichten, Audiozugriff sowie schnelles Verteilen per E-Mail sind nur einige Funktionen. Glauben Sie an Bücher, beschränken Sie sich jedoch nicht nur auf Papier.
     
    8-Megapixel-Kamera mit LED-Blitz
    Immer gute Fotos. Der 8-Megapixel-Kamera mit Autofokus entgehen auch bei Action-Fotos keine Details. Machen Sie auch bei schlechten Lichtverhältnissen mit dem integrierten LED-Blitz wunderschöne und detaillierte Aufnahmen. Und dank der stark verbesserten Benutzeroberfläche von Android Gingerbread ist selbst schneller Szenenwechsel möglich. Wechseln Sie problemlos auf die 2-Megapixel-Kamera vorne, um Selbstporträts zu machen. Einfach immer gute Bilder.
     
    Aufzeichnung & Wiedergabe in Full-HD
    Werden Sie zum Star. Mit den Möglichkeiten zur Videoaufzeichnung des Samsung GALAXY S II können auch Sie zur Berühmtheit werden. Mit der 1080p Full-HD-Aufzeichnung ist jeder Moment ein potenzielles Meisterwerk in der Entstehung. Erfassen Sie die Action in hoher Auflösung und mit Dual Core-Geschwindigkeit und geben Sie Ihre HD-Aufzeichnungen mit bestechender Klarheit auf dem 4,3"" SUPER AMOLED Plus Display wieder.
     
    Spracherkennung & Sprachübersetzung
    Einfach Sprachbefehle nutzen. Tippen Sie nur doppelt auf die Home-Taste und steuern Sie das Samsung GALAXY S II mit ausgewählten Sprachbefehlen. Führen Sie wichtige Funktionen wie anrufen, Musik hören oder SMS schreiben mit einfachen Sprachbefehlen aus. Sie können auch Ihre Gedanken festhalten, sich selbst eine Notiz schreiben oder unterwegs sogar mit Google Voice Translation eine Übersetzung anfertigen. Galaxy S II kann Ihnen eingehende Nachrichten auch vorlesen.
     
    Game Hub
    Noch mehr Spielspaß. Über den Game Hub von Samsung GALAXY S II können Sie hochwertige Spiele herunterladen: 12 soziale Netzwerkspiele und 13 Prämiumspiele einschließlich Gameloft’s Let Golf 2 und Real Football 2011. Sie können nach Spielen und Informationen zu Neuerscheinungen suchen oder einfach nur spielen. Mit einem Beschleunigungsaufnehmer, einem magnetischen Sensor und Gyroskop-Sensor heben sich Spiele mit Hand- und Armbewegungen deutlich aus der Masse ab. Die kleinste Bewegung reicht bereits aus – das ist spannende Unterhaltung.
     
    Social Hub
    Mit dem Social Hub lassen sich Ihre Online-Kontakte besser organisieren und synchronisieren. Sammeln Sie Ihre Informationen aus E-Mails, SMS, IM und SNS in einem einheitlichen Posteingang – Interaktionen mit anderen sind so schneller und auf die von Ihnen gewünschte Art möglich.
     
    Music Hub
    Musik darf nicht fehlen. Der neue native Music-Player von Samsung bietet ein intuitives Wiedergabesystem zum Suchen, Entdecken, Anspielen, Kaufen und Herunterladen von Musikstücken für unterwegs. Die App bietet auch viele Informationen zum Kauf sowie Zugriff auf alle gewünschten Künstler, Liedtexte und Bewertungen. Sie können Empfehlungen für neue Songs abrufen und durch Bassverstärkung und 5.1 Kanal-Sound den Hörspaß noch mehr steigern.
     
    Microsoft Exchange ActiveSync
    Das Samsung GALAXY S II ist für sicheren Zugriff auf Unternehmensressourcen auf einem Microsoft Exchange Server optimiert, damit Sie in Bezug auf geschäftliche E-Mails, Terminplaner, Kontakte und Aufgabensynchronisation auf dem Laufenden sind. Das Handy bietet die umfangreichste mobile Implementierung von Exchange ActiveSync. Es bietet das sicherste Mobile Device Management unter den Smartphones und unterstützt die meisten Richtlinien und Einschränkungen unter den Android ActiveSync Clients und ermöglicht Kommunikation in Echtzeit mit Telefonen der Mitarbeiter, um Einstellungen per Fernzugriff zu konfigurieren, die Einhaltung der Richtlinien zu überwachen, die Sicherheit bei synchronisierten Daten zu gewährleisten und verwaltete Telefone zu sperren oder Daten zu löschen.
    ";2;False;0;;;Samsung Galaxy S II (i9100) DualCore Smartphone schwarz;samsung-galaxy-s-ii-i9100-dualcore-smartphone-schwarz;True;True;PD-01084;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;439.9000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;40871,5057638889;76;5;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000172-samsung-galaxy-s-ii-i9100-dualcore-smartphone-schwarz.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000173-samsung-galaxy-s-ii-i9100-dualcore-smartphone-schwarz.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000174-samsung-galaxy-s-ii-i9100-dualcore-smartphone-schwarz.jpg;2;;False;;;;;False;False;False;;;;;False;;;;;; +5;0;True;Nokia N9 Smartphone schwarz;"Nokia N9 Smartphone (9,9 cm (3,9 Zoll) Display, 16GB, Touchscreen, 8 Megapixel Kamera) schwarz ";"
    Nokia N9 Smartphone
    Formatfüllender Touchscreen
    Ein einzigartiges Smartphone mit formatfüllendem Touchscreen. Die gewölbte Oberfläche aus kratzfestem Glas geht nahtlos in das glatte, aus einem Block gefertigte Gehäuse über. Jedes Detail strahlt Innovation aus. Auf dem brillanten AMOLED-Touchscreen erscheint alles in lebendigen Farben und das gewölbte Glas macht den Wechsel zwischen Apps per Fingerbewegung zum Kinderspiel.
     
    Einfach nur eine Fingerbewegung - Überzeugend benutzerfreundlich
    Alles läuft auf eine einfache Fingerbewegung hinaus. Das macht die Nutzung dieses Smartphones so intuitiv wie nie zuvor. Es gibt keine Zurück- oder Menü-Taste mehr – nur fliessende Fingerbewegungen, während Sie von App zu App wechseln. Mit einer Fingerbewegung über eine beliebige Ecke des Touchscreens gelangen Sie zur Startansicht, mit einer weiteren Bewegung wechseln Sie zwischen den drei Startansichten.
     
    Eine Startansicht - Drei einfache Ansichten
    Drei Ansichten sind alles, was Sie brauchen. In der vertrauten App-Ansicht starten Sie Anwendungen, eine weitere Ansicht zeigt die offenen Apps und macht Multitasking zum Kinderspiel: Sie machen genau dort weiter, wo Sie aufgehört haben.- Die Ansicht ""Ereignisse"" bringt Sie jederzeit auf den neuesten Stand der Dinge. Live-Feeds von Facebook und Twitter, E-Mails in Echtzeit, RSS-Feeds und mehr – alles an einer Stelle.
     
    Karten und Navigation kostenlos
    Live-Feeds von Facebook und Twitter, E-Mails in Echtzeit, RSS-Feeds und mehr – alles an einer Stelle. Sie finden die besten Angebote in Ihrer Stadt wie Cafés, Geschäfte, Konzerte, Hotels und mehr. Für mehr als 80 Städte weltweit steht Ihnen eine Übersicht von Strecken und Haltestellen des öffentlichen Nahverkehrs zur Verfügung. Entsprechendes Kartenmaterial ist bereits vorinstalliert, sodass Sie sofort starten können. Die Anwendung ""Fahren"" ist dank einfacher Bedienung über Touchscreen für die Verwendung im Auto optimiert.
     
    Browser der nächsten Generation
    Zeit für mehr Tempo. Das Nokia N9 bietet einen schnellen mobilen Internet-Browser und Seiten werden in kürzester Zeit aufgebaut. Die Unterstützung für HTML5 bedeutet für Sie das Beste aus dem Web, inklusive interaktiver Apps und schneller Videowiedergabe. Der Browser reagiert schnell auf jede Berührung. Sie können mehrere Seiten gleichzeitig öffnen und schnell zwischen den Seiten wechseln.
     
     
     
    8-Megapixel-Kamera mit Optik von Carl Zeiss
    Die Gelegenheit für ein gutes Foto kommt schnell und ist ebenso schnell vorbei. Mit der integrierten 8-Megapixel-Kamera mit Optik von Carl Zeiss können Sie brillante Fotos oder Videos in herausragender HD-Qualität aufnehmen.
     
    Die besten Apps und Spiele
    Apps sind heutzutage allgegenwärtig. Das Wichtigste ist jedoch die Qualität und nicht, wie viele man besitzt. Auf dem Nokia N9 sind die besten Apps wie Skype, Facebook, Twitter, AccuWeather und AP Mobile bereits vorinstalliert. Auch die Vollversion von Angry Birds ist bereits vorinstalliert – für viele Stunden Spass. Und im Ovi Store gibt es viele weitere Apps und Spiele.
    ";2;False;0;;;Nokia N9 Smartphone schwarz;nokia-n9-smartphone-schwarz;True;True;PD-01083;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;539.0000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;40871,4967013889;74;17;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000164-nokia-n9-smartphone-schwarz.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000165-nokia-n9-smartphone-schwarz.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000166-nokia-n9-smartphone-schwarz.jpg;3;;False;;;;;False;False;False;;;;;False;;;;;; +5;0;True;Nokia N9 Smartphone magenta;Nokia N9 Smartphone (9,9 cm (3,9 Zoll) Display, 16GB, Touchscreen, 8 Megapixel Kamera) magenta;"
    Nokia N9 Smartphone
    Formatfüllender Touchscreen
    Ein einzigartiges Smartphone mit formatfüllendem Touchscreen. Die gewölbte Oberfläche aus kratzfestem Glas geht nahtlos in das glatte, aus einem Block gefertigte Gehäuse über. Jedes Detail strahlt Innovation aus. Auf dem brillanten AMOLED-Touchscreen erscheint alles in lebendigen Farben und das gewölbte Glas macht den Wechsel zwischen Apps per Fingerbewegung zum Kinderspiel.
     
    Einfach nur eine Fingerbewegung - Überzeugend benutzerfreundlich
    Alles läuft auf eine einfache Fingerbewegung hinaus. Das macht die Nutzung dieses Smartphones so intuitiv wie nie zuvor. Es gibt keine Zurück- oder Menü-Taste mehr – nur fliessende Fingerbewegungen, während Sie von App zu App wechseln. Mit einer Fingerbewegung über eine beliebige Ecke des Touchscreens gelangen Sie zur Startansicht, mit einer weiteren Bewegung wechseln Sie zwischen den drei Startansichten.
     
    Eine Startansicht - Drei einfache Ansichten
    Drei Ansichten sind alles, was Sie brauchen. In der vertrauten App-Ansicht starten Sie Anwendungen, eine weitere Ansicht zeigt die offenen Apps und macht Multitasking zum Kinderspiel: Sie machen genau dort weiter, wo Sie aufgehört haben.- Die Ansicht ""Ereignisse"" bringt Sie jederzeit auf den neuesten Stand der Dinge. Live-Feeds von Facebook und Twitter, E-Mails in Echtzeit, RSS-Feeds und mehr – alles an einer Stelle.
     
    Karten und Navigation kostenlos
    Live-Feeds von Facebook und Twitter, E-Mails in Echtzeit, RSS-Feeds und mehr – alles an einer Stelle. Sie finden die besten Angebote in Ihrer Stadt wie Cafés, Geschäfte, Konzerte, Hotels und mehr. Für mehr als 80 Städte weltweit steht Ihnen eine Übersicht von Strecken und Haltestellen des öffentlichen Nahverkehrs zur Verfügung. Entsprechendes Kartenmaterial ist bereits vorinstalliert, sodass Sie sofort starten können. Die Anwendung ""Fahren"" ist dank einfacher Bedienung über Touchscreen für die Verwendung im Auto optimiert.
     
    Browser der nächsten Generation
    Zeit für mehr Tempo. Das Nokia N9 bietet einen schnellen mobilen Internet-Browser und Seiten werden in kürzester Zeit aufgebaut. Die Unterstützung für HTML5 bedeutet für Sie das Beste aus dem Web, inklusive interaktiver Apps und schneller Videowiedergabe. Der Browser reagiert schnell auf jede Berührung. Sie können mehrere Seiten gleichzeitig öffnen und schnell zwischen den Seiten wechseln.
     
     
     
    8-Megapixel-Kamera mit Optik von Carl Zeiss
    Die Gelegenheit für ein gutes Foto kommt schnell und ist ebenso schnell vorbei. Mit der integrierten 8-Megapixel-Kamera mit Optik von Carl Zeiss können Sie brillante Fotos oder Videos in herausragender HD-Qualität aufnehmen.
     
    Die besten Apps und Spiele
    Apps sind heutzutage allgegenwärtig. Das Wichtigste ist jedoch die Qualität und nicht, wie viele man besitzt. Auf dem Nokia N9 sind die besten Apps wie Skype, Facebook, Twitter, AccuWeather und AP Mobile bereits vorinstalliert. Auch die Vollversion von Angry Birds ist bereits vorinstalliert – für viele Stunden Spass. Und im Ovi Store gibt es viele weitere Apps und Spiele.
    ";2;False;0;;;Nokia N9 Smartphone magenta;nokia-n9-smartphone-magenta;True;True;PD-01082;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;549.0000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;40871,4934027778;"74;2095";17;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000655-nokia-n9-smartphone-magenta.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000656-nokia-n9-smartphone-magenta.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000657-nokia-n9-smartphone-magenta.jpg;2;;False;;;;;False;False;False;;;;;False;;;;;; +5;0;True;"Apple iPhone 4S weiß ";Apple iPhone 4S weiß;"
    Das neue iPhone 4S - jetzt mit Dual Core A5 Chip, neuer 8 MegaPixel-Kamera, iOS 5 und iCloud sowie dem neuen Siri.
     
    Dual-Core A5 Chip. Der leistungsstärkste iPhone Prozessor aller Zeiten.
    Mit zwei Prozessorkernen liefert der A5 Chip bis zu 2x mehr Leistung und bis zu 7x schnellere Grafik. Das wirst du merken. Und zwar schnell. Das iPhone 4S reagiert extrem schnell, was du sofort merkst, wenn du Apps öffnest, im Web surfst, beim Spielen und auch bei allem anderen. Und ganz egal was du machst, du kannst es richtig lange machen. Denn der A5 Chip ist so effizient, dass das iPhone 4S eine enorm lange Batterielaufzeit hat.
     
    Die Kaum-zu-glauben-dass-es-ein-Handy-ist Kamera.
    Wahrscheinlich die beste Kamera, die es je auf einem Telefon gab. Und dank fortschrittlichster Optik ist sie wahrscheinlich auch die einzige Kamera, die du brauchst. Schließlich hat sie eine Auflösung von 8 Megapixeln und eine spezielle Linse mit einer größeren f/2,4 Blende. Außerdem bietet sie einen optimierten rückwärtig belichteten Sensor, exzellenten Weißabgleich, verbesserte Farbgenauigkeit, Gesichtserkennung und reduzierte Bewegungsunschärfe. Es ist also ganz egal, wie viele Leute, wie viel Licht und wie viel Action du aufnimmst – alles sieht genau so aus, wie es aussehen soll. Und warte erst, bis du die Fotos siehst.
     
    Siri. Dein intelligenter, hilfsbereiter Assistent.Du musst ihn nur fragen.
    Jetzt kannst du dein iPhone einfach mit deiner Stimme benutzen. Sprich mit Siri so, wie du mit einer Person sprichst und sag ""Erinnere mich daran, Mama anzurufen, wenn ich zu Hause bin"" oder ""Brauche ich einen Schirm?"". Siri spricht Deutsch und versteht nicht nur, was du sagst, sondern auch was du meinst. Es erkennt, welche Apps für die richtige Antwort nötig sind. Und antwortet dir dann – wie dein persönlicher Assistent. Siri telefoniert, sendet Nachrichten, plant Meetings, legt Erinnerungen fest und mehr. Was noch? Frag einfach, und Siri sagt es dir selbst.
     
    Videoaufnahmen. In fantastischem 1080p HD.
    Nimm fantastische 1080p HD Videos auf, wo immer du bist. Durch die neue fortschrittliche Optik der Kamera ist das Licht immer genau richtig, die Farben immer leuchtend und alles sieht noch besser aus, als du es in Erinnerung hattest. Die Bildstabilisierung gleicht verwackelte Aufnahmen aus. Und du kannst Videos direkt auf dem iPhone bearbeiten und so schnell mit anderen teilen, wie du sie aufnimmst.
     
    iOS. Das fortschrittlichste mobile Betriebssystem der Welt. Und auch das einfachste.
    Jede neue iOS Version bietet Möglichkeiten, die alles noch einfacher machen. Deshalb ist iOS allen anderen um Jahre voraus. Und iOS 5 geht wieder einen großen Schritt weiter und bringt mehr als 200 neue Features auf das iPhone 4S. Hier sind nur einige unserer Favoriten.
     
    iCloud. Deine Inhalte. Auf all deinen Geräten.
    Mit iCloud kannst du deine Inhalte ganz einfach verwalten, denn iCloud erledigt alles für dich. iCloud speichert deine Musik, Fotos, Apps, Mails, Kontakte, Kalender, Dokumente und mehr und pusht alles drahtlos an all deine Geräte. Automatisch, nahtlos und einfach so.
     
    Retina Display.Das ist ganz klar.
    Auf dem iPhone 4S siehst du einfach alles gestochen scharf und lebendig. Das Retina Display ist das höchstauflösende Telefondisplay aller Zeiten. Die Pixeldichte ist so hoch, dass das menschliche Auge keine einzelnen Pixel erkennen kann. Was du aber ganz bestimmt siehst, sind gestochen scharfe Texte, Grafiken und Bilder. Alles sieht sogar noch besser aus als gedruckt.
     
    FaceTime. Wink doch mal hallo.
    Mit FaceTime hörst du nicht nur eine Stimme, sondern siehst auch das Gesicht dazu – von iPhone zu iPhone, iPad 2, iPod touch oder Mac über Wi-Fi. Es ist also ganz egal, wo die anderen sind und wo du bist – du bist immer da. FaceTime Anrufe sind so einfach wie ganz normale Anrufe. Und mit Siri sind sie sogar noch einfacher. Sag Siri einfach, dass du mit deiner Mutter facetimen willst, und schon seht ihr euch. Einfach so. Du verpasst nie wieder ein wichtiges Ereignis, Meeting oder einen guten Lacher. Und wer würde sich nicht darüber freuen, dich zu sehen?
     
    AirPlay. Live vom iPhone auf deinen Fernseher.
    Mit AirPlay kannst du Inhalte von deinem iPhone via Apple TV drahtlos an deinen HD Fernseher und Lautsprecher streamen.6 Und mit der AirPlay Synchronisierung erscheint alles, was du auf deinem iPhone siehst oder machst, gleichzeitig auf deinem HD Fernseher.
     
    AirPrint.Alles drahtlos drucken.
    Drucke deine Mails, Fotos, Webseiten und Dokumente einfach über Wi-Fi von deinem iPhone aus.7 Ganz ohne Software zu laden, Treiber zu installieren oder Kabel anzuschließen. Nur ein paar Fingertipps und schon hast du das, was eben noch auf dem iPhone war, als Ausdruck in der Hand.
     
    Besser. Schneller. Weltweiter.
    Das iPhone 4S ist das erste Telefon, das zum Übertragen und Empfangen intelligent zwischen zwei Antennen wechselt. So ist die Anrufqualität deutlich besser. Außerdem verdoppeln die Antennen die maximale HSDPA Datengeschwindigkeit auf 14,4 Mbit/s.8 Und das bedeutet schnellere Verbindungen, schnelleres Laden und Neuladen und schnellere Downloads. Das iPhone 4S ist ein Telefon für die ganze Welt. Du kannst es also fast überall verwenden. Ob GSM- oder CDMA-Standard spielt keine Rolle. Nutze es via Roaming in GSM-Netzen in 200 Ländern weltweit.
     
    Integrierte Apps. Machen alles, damit du alles machen kannst.
    Ganz Alltägliches erledigst du mit dem iPhone 4S auf ganz außergewöhnliche Weise. Mach fantastische Fotos und nimm HD Videos auf. Sieh Freunde und Familie mit FaceTime. Tauche auf dem Retina Display richtig ins Web ein. Check deine Mails. Sende Nachrichten. Lege Erinnerungen fest. Schau in deinen Kalender. Oder sag Siri einfach, wie es dir helfen soll. Siri findet dann selbst heraus, welche Apps es verwenden muss.
     
    Aufgrund der sehr umfangreichen Leistungsmerkmale können wir Ihnen hier nur einen Auszug präsentieren. Die vollständigen Funktionsbeschreibungen inkl. einer Vielzahl von Videos entnehmen Sie bitte der Herstellerwebseite.
    •Apple iPhone 4S
    •115,2 x 58,6 x 9,3 mm klein und 140 g leicht
    •Kapazität: 16 GB Flash-Laufwerk
    •Kamera, Fotos und Video:
    • 8.0 Megapixel Kamera
    • Videoaufnahme, HD (1080p) bis zu 30 fps mit Audio
    • Fotos und Videos in VGA-Qualität mit bis zu 30 fps mit der Kamera an der Vorderseite
    • Fokussieren per Fingertipp für Videos und Fotos LED-Blitz
    • Geotagging für Fotos und Videos
    •Display:
    • Retina Display
    • 3,5""-Multitouch-Display (8,89 cm Diagonale)
    • Auflösung von 960 x 640 Pixeln mit 326ppi
    • Typisches Kontrastverhältnis: 800:1
    • Fettabweisende Beschichtung an der Vorder- und Rückseite
    • Unterstützung für die Anzeige mehrerer Sprachen und Zeichen gleichzeitig
    •Stromversorgung und Batterie:
    • Sprechdauer: bis zu 8 Std. mit 3G, bis zu 14 Std. mit 2G
    • Standbydauer: bis zu 200 Std.
    • Internetnutzung: bis zu 6 Std. mit 3G, bis zu 9 Std. mit Wi-Fi
    • Videowiedergabe: bis zu 10 Std., Audiowiedergabe: bis zu 40 Std.
    •Betriebssystem: iOS 5
    •Mobilfunknetz und Wi-Fi:
    • UMTS/HSDPA/HSUPA (850, 900, 1900, 2100 MHz)
    • GSM/Edge (850, 900, 1800, 1900 MHz)
    • Funktechnologie: 802,11b/g/n Wi-Fi (802.11 nur mit 2,4 GHz), Bluetooth 4.0
    •GPS: Assisted GPS
    •Digitaler Kompass
    •Unterstützte Audioformate: AAC (8 bis 320 KBit/Sek.), Protected AAC (aus dem iTunes Store), HE-AAC, MP3 (8 bis 320 KBit/Sek.), MP3 VBR, Audible (Formate 2, 3, 4, Audible Enhanced Audio, AAX und AAX+), Apple Lossless, AIFF und WAV
    •TV und Video: AirPlay Mirroring to Apple TV support at 720p, Video mirroring and video out support: Up to 1080p with Apple Digital AV Adapter or Apple VGA Adapter (adapters sold separately), Video out support at 576p and 480p with Apple Component AV Cable; 576i and 480i with Apple Composite AV Cable (cables sold separately)
    •Unterstützte Videoformate: H.264 Video: bis zu 720p, 30 Bilder pro Sekunde, Main Level Profile Level 3.1 mit AAC-LC Audio bis zu 160 KBit/Sek., 48 kHz, Stereo-Audio in den Formaten .m4v, .mp4 und .mov; MPEG.4 Video: bis zu 2,5 MBit/Sek., 640 x 480 Pixel, 30 Bilder pro Sekunde, Simple Profile mit AAC-LC Audio bis zu 160 KBit/Sek., 48 kHz, Stereo-Audio in den Formaten .m4v, .mp4 und .mov; Motion JPEG (M-JPEG): bis zu 35 MBit/Sek., 1280 x 720 Pixel, 30 Bilder pro Sekunde, Audio im Format ulaw, PCM Stereo-Audio im Format .avi
    •Sensoren:
    • 3-Achsen-Gyrosensor
    • Beschleunigungssensor
    • Annäherungssensor
    • Umgebungslichtsensor
     
    Lieferumfang:
    iPhone 4S, Apple Earphones mit Fernbedienung und Mikrofon, Dock Connector-auf-USB-Kabel, Dokumentation
    ";2;False;0;;;Apple iPhone 4S weiß;apple-iphone-4s-weiss;True;True;PD-01080;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;2,5000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;779.0000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;40870,6516782407;71;1;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000646-apple-iphone-4s-weis.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000647-apple-iphone-4s-weis.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000648-apple-iphone-4s-weis.jpg;2;;False;;;;;False;False;False;;;;;False;;;;;; +5;0;True;"AVM FRITZ!Fon MT-F VoIP Dect-Telefon ";"AVM FRITZ!Fon MT-F Innovatives DECT-Telefon ";"
    FRITZ!Fon MT-F: HD-Telefonie und komfortable Internetdienste mit DECT.
    Telefonieren Sie mit dem Schnurlostelefon FRITZ!Fon MT-F in bestechender Qualität über das Internet und nutzen Sie komfortable Webdienste. Als intelligentes Telefon der neuesten DECT-Generation vereint das FRITZ!Fon den Komfort der schnurlosen Telefonie mit den Qualitäts- und Leistungsmerkmalen der Internettelefonie (VoIP) in einem Gerät.
     
    Bei der Internettelefonie mit einem FRITZ!Fon wird durch HD-Telefonie (High Definition) ein brillantes, natürliches Klanggefühl erreicht. Sprache lässt sich mit dem FRITZ!Fon in ihrem gesamten Frequenzspektrum wiedergeben, was die Klangqualität von Festnetzverbindungen deutlich übertrifft.
     
    FRITZ!Fon unterstützt die übertragung großer Bandbreiten. Dies ermöglicht neben HD-Telefonie auch die Nutzung komfortabler Internetdienste wie den Empfang von E-Mails, Podcasts, RSS-Feeds und Internetradio.
     
    Die Steuerung von FRITZ!Box-Anwendungen am Handgerät bietet viel zusätzlichen Komfort. Und durch DECT-Eco wird Funkabstrahlung bei Nichtnutzung der Telefone verhindert.
     
    Die FRITZ!Box-Modelle FRITZ!Box Fon WLAN 7390, 7320, 7270, 7240 sowie FRITZ!Box 6360 Cable stellen mit der integrierten DECT-Basisstation, mehreren Anrufbeantwortern und Telefonbüchern für bis zu 300 Einträge den idealen Partner für das FRITZ!Fon dar. Mit der umfangreichen Prozessor- und Speicherausstattung ist auch der Grundstein für neue Anwendungen gelegt. Denn das FRITZ!Fon ist lernfähig:
     
    Als eines der ersten intelligenten Schnurlostelefone wird es auch künftig per Firmware-Updates aktualisiert und um neue Funktionen erweitert werden können.
     
    Umfangreicher Komfort
    Das FRITZ!Fon MT-F ist mit zahlreichen Komfortfunktionen ausgestattet. Dazu zählen Lauthören und Freisprechen in HD-Qualität sowie ISDN-Leistungsmerkmale wie Namensanzeige bei bekannten Rufnummern, Halten, Makeln, Anklopfen, Rufumleitung oder Dreierkonferenz. Die Internettelefonie in HD-Qualität lässt sich so in ihrem vollen Umfang und Komfort nutzen, ohne dass der Computer eingeschaltet sein muss.
     
    FRITZ!Fon informiert zudem aktiv über unbeantwortete Anrufe, Nachrichten auf dem Anrufbeantworter und zeigt eingegangene E-Mails an. An der DECT-Basisstation der FRITZ!Box Fon WLAN 7390, 7320, 7270, 7240 oder FRITZ!Box 6360 Cable lassen sich bis zu 6 FRITZ!Fon-Handgeräte oder andere DECT-Telefone anmelden. Die Erstinstallation und individuelle Einstellungen erfolgen dabei bequem über einfache Assistenten.
     
    FRITZ!Box als idealer Partner
    Das FRITZ!Fon MT-F kann als Mobilteil an jeder DECT-Basisstation eingesetzt werden. Im Zusammenspiel mit der FRITZ!Box Fon WLAN 7390, 7320, 7270, 7240 oder FRITZ!Box 6360 Cable kann jedoch das volle Spektrum der Möglichkeiten beim Telefonieren und Surfen über das Internet ausgenutzt werden.
     
    Die FRITZ!Box Fon WLAN 7390 zum Beispiel vereint eine bisher nicht erreichte Vielfalt in einem Gerät: VDSL- und ADSL-Unterstützung, DECT-Basisstation fürs schnurlose Telefonieren sowie WLAN N für die optimale Datenübertragung. über den Mediaserver sind gespeicherte Filme, Musik und Bilder auch bei ausgeschaltetem Computer im gesamten Netzwerk verfügbar. Darüber hinaus kann der Online-Speicher wie eine lokale Festplatte genutzt werden. So wird die FRITZ!Box Fon WLAN 7390 zur idealen Plattform für vernetzte Anwendungen wie IPTV, Video on Demand oder Mediastreaming.
     
    Bedienung
    - Einfach einschalten und Suchtaste auf FRITZ!Box drücken.
     
    - Einfache Bedienung über intuitives Menü.
     
    - Telefonbuch komfortabel über FRITZ!Box-Oberfläche einrichten und anzeigen.
     
    - In FRITZ!Box integrierte Anrufbeantworter einfach am FRITZ!Fon MT-F einrichten und abhören.
     
    - Blinkende Leuchtdiode signalisiert eingegangene Anrufe, neue Nachrichten auf dem Anrufbeantworter und neue E-Mails.
    ";2;False;0;;;AVM FRITZ!Fon MT-F;avm-fritzfon-mt-f-voip-dect-telefon;True;True;PD-01079;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;79.0000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;40653,4526388889;20;34;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000643-avm-fritzfon-mt-f-voip-dect-telefon.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000644-avm-fritzfon-mt-f-voip-dect-telefon.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000645-avm-fritzfon-mt-f-voip-dect-telefon.jpg;3;;False;;;;;False;False;False;;;;;False;;;;;; +5;0;True;Apple iPhone 4 weiß;Apple iPhone 4 weiß;"
    Produktbeschreibungen
    - Retina Display, 3,5"" Multi-Touch-Widescreen-Display (8,89 cm Diagonale)
    - 960 x 640 Pixel bei 326 ppi
    - Kontrastverhältnis: 800:1
    - Fettabweisende Beschichtung an der Vorder- und Rückseite
    - Unterstützung für die Anzeige mehrerer Sprachen und Zeichen gleichzeitig
    - UMTS/HSDPA/HSUPA
    - GSM/EDGE
    - 802.11b/g/n WLAN
    - Bluetooth 2.1 + EDR
    - Li-Ionen-Akku, Sprechdauer bis zu 14Std. (2G), Internet bis zu 10Std. (WLAN)
     
    ";2;False;0;;;Apple iPhone 4 weiß;apple-iphone-4-weiss;True;True;PD-01078;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;779.0000;779.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.5000;0.0000;0.0000;0.0000;40653,4446064815;71;1;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000641-apple-iphone-4-weis.png;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000642-apple-iphone-4-weis.png;;2;;False;;;;;False;False;False;;;;;False;;;;;; +5;0;True;"Apple iPhone 4 schwarz ";"Apple iPhone 4 schwarz ";"
    Produktbeschreibungen
    - Retina Display, 3,5" Multi-Touch-Widescreen-Display (8,89 cm Diagonale)
    - 960 x 640 Pixel bei 326 ppi
    - Kontrastverhältnis: 800:1
    - Fettabweisende Beschichtung an der Vorder- und Rückseite
    - Unterstützung für die Anzeige mehrerer Sprachen und Zeichen gleichzeitig
    - UMTS/HSDPA/HSUPA
    - GSM/EDGE
    - 802.11b/g/n WLAN
    - Bluetooth 2.1 + EDR
    - Li-Ionen-Akku, Sprechdauer bis zu 14Std. (2G), Internet bis zu 10Std. (WLAN)
    ";2;False;0;;;"Apple iPhone 4 schwarz ";apple-iphone-4-schwarz;True;True;PD-01077;;;False;0;False;;False;False;0;False;0;1;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;2;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;639.0000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;40653,4410763889;71;1;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000639-apple-iphone-4-schwarz.png;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000640-apple-iphone-4-schwarz.png;;1;;False;ounce;;;;False;False;False;;;;;False;;;;;; +5;0;True;Apple iPad 2 schwarz;Apple iPad 2. Generation schwarz;"
    Kapazität
    16-GB-Flash-Laufwerk
    32-GB-Flash-Laufwerk
    64-GB-Flash-Laufwerk

    Abmessungen und Gewicht

    •Höhe: 241,2 mm
    •Breite: 185,7 mm
    •Tiefe: 8,8 mm
    •Gewicht: 601 g

    •Höhe: 241,2 mm
    •Breite: 185,7 mm
    •Tiefe: 8,8 mm
    •Gewicht: 613 g


    Drahtlose Technologie und Funknetz

    •Wi-Fi (802.11a/b/g/n)
    •Bluetooth 2.1 + EDR Technologie
    •Wi-Fi + 3G Modell: UMTS/HSDPA/HSUPA (850, 900, 1900, 2100 MHz); GSM/EDGE (850, 900, 1800, 1900 MHz)
    •Nur Datentransfer
    •Wi-Fi (802.11a/b/g/n)
    •Bluetooth 2.1 + EDR Technologie
    Weitere Infos zu Wi-Fi + 3G

    Display

    •9,7"" Multi-Touch Hochglanz-Widescreendisplay mit LED-Hintergrundbeleuchtung und IPS-Technologie (24,63 cm Diagonale)
    •Auflösung von 1024 x 768 Pixeln bei 132 ppi
    •Fettabweisende Beschichtung
    •Unterstützung für die Anzeige mehrerer Sprachen und Zeichen gleichzeitig
     
    Chip
    Speziell entwickelter, hochleistungsfähiger 1 GHz Dual-Core Apple A5 SOC (System-on-a-Chip) mit niedrigem Stromverbrauch
     
    Kamera, Fotos, Videoaufnahme

    •Rückkamera: Videoaufnahme, HD (720p) bis zu 30 fps mit Audio, Fotokamera mit 5-fach Digitalzoom
    •Frontkamera: Videoaufnahme, VGA mit bis zu 30 fps mit Audio, Fotokamera in VGA-Qualität
    •Fokussieren per Fingertipp für Videos und Fotos
    •Geotagging für Fotos und Videos via Wi-Fi
     
    Stromversorgung und Batterie

    •Integrierte wiederaufladbare Lithium-Polymer-Batterie mit 25 Wattstunden
    •Bis zu 10 Stunden Surfen im Web mit Wi-Fi, Video- oder Musikwiedergabe
    •Aufladen über das Netzteil oder einen USB Anschluss am Computer

    •Integrierte wiederaufladbare Lithium-Polymer-Batterie mit 25 Wattstunden
    •Bis zu 10 Stunden Surfen im Web mit Wi-Fi, Video- oder Musikwiedergabe
    •Bis zu 9 Stunden Batterielaufzeit beim Surfen im Internet über das 3G Datennetzwerk
    •Aufladen über das Netzteil oder einen USB Anschluss am Computer
     
    Ein- und Ausgabe

    •30-poliger Dock-Anschluss
    •3,5 mm Stereo-/Kopfhöreranschluss (Minianschluss)
    •Integrierter Lautsprecher
    •Mikrofon

    •30-poliger Dock-Anschluss
    •3,5 mm Stereo-/Kopfhöreranschluss (Minianschluss)
    •Integrierter Lautsprecher
    •Mikrofon
    •Fach für Micro-SIM-Karte (nur beim Wi-Fi + 3G Modell)
     
    Sensoren

    •3-Achsen-Gyrosensor
    •Beschleunigungssensor
    •Umgebungslichtsensor

    •3-Achsen-Gyrosensor
    •Beschleunigungssensor
    •Umgebungslichtsensor
     
    Ortungsfunktion

    •Wi-Fi
    •Digitaler Kompass

    •Wi-Fi
    •Digitaler Kompass
    •Assisted GPS
    •Mobilfunknetz
     
    Audiowiedergabe

    •Frequenzbereich: 20 Hz bis 20.000 Hz
    •Unterstützte Audioformate: HE-AAC (V1 und V2), AAC (8 bis 320 Kbit/s), Protected AAC (aus dem iTunes Store), MP3 (8 bis 320 Kbit/s), MP3 VBR, Audible (Formate 2, 3, 4, Audible Enhanced Audio, AAX und AAX+), Apple Lossless, AIFF und WAV
    •Maximale Lautstärke vom Benutzer festlegbar
    •Dolby Digital 5.1 Surround Sound Durchschleifen mit Apple Digital AV Adapter (separat erhältlich)
     
    TV und Video

    •Unterstützung für Bildschirmsynchronisation und Videoausgabe: bis zu 1080p mit dem Apple Digital AV Adapter oder dem Apple VGA-Adapter (Kabel separat erhältlich)
    •Unterstützung für die Videoausgabe mit 576p und 480p mit dem Apple AV-Kabel (Komponentenvideo), mit 576i und 480i mit dem Apple AV-Kabel (Composite-Video)
    •Unterstützte Videoformate: H.264 Video: bis zu 720p, 30 Bilder pro Sekunde, Main Profile Level 3.1 mit AAC-LC Audio mit bis zu 160 Kbit/s, 48 kHz, Stereo-Audio in den Formaten .m4v, .mp4 und .mov; MPEG-4 Video: bis zu 2,5 Mbit/s, 640 x 480 Pixel, 30 Bilder pro Sekunde, Simple Profile mit AAC-LC Audio mit bis zu 160 Kbit/s, 48 kHz, Stereo-Audio in den Formaten .m4v, .mp4 und .mov; Motion JPEG (M-JPEG): bis zu 35 Mbit/s, 1280 x 720 Pixel, 30 Bilder pro Sekunde, Audio im Format .ulaw, PCM Stereo-Audio im Format .avi
     
    Unterstützte
    E-Mail Anhänge

    Anzeigbare Dokumenttypen: .jpg, .tiff, .gif (Bilder); .doc und .docx (Microsoft Word); .htm und .html (Webseiten); .key (Keynote); .numbers (Numbers); .pages (Pages); .pdf (Vorschau und Adobe Acrobat); .ppt und .pptx (Microsoft PowerPoint); .txt (Text); .rtf (Rich Text Format); .vcf (Kontaktdaten); .xls und .xlsx (Microsoft Excel)

    Sprachen

    •Sprachunterstützung für Englisch (USA), Englisch (Großbritannien), Französisch (Frankreich), Deutsch, traditionelles Chinesisch, vereinfachtes Chinesisch, Niederländisch, Italienisch, Spanisch, Portugiesisch (Brasilien), Portugiesisch (Portugal), Dänisch, Schwedisch, Finnisch, Norwegisch, Koreanisch, Japanisch, Russisch, Polnisch, Türkisch, Ukrainisch, Ungarisch, Arabisch, Thailändisch, Tschechisch, Griechisch, Hebräisch, Indonesisch, Malaiisch, Rumänisch, Slowakisch, Kroatisch, Katalanisch und Vietnamesisch

    •Tastaturunterstützung für Englisch (USA), Englisch (Großbritannien), Französisch (Frankreich), Französisch (Kanada), Französisch (Schweiz), Deutsch, traditionelles Chinesisch (Handschrift, Pinyin, Zhuyin, Cangjie, Wubihua), vereinfachtes Chinesisch (Handschrift, Pinyin, Wubihua), Niederländisch, Italienisch, Spanisch, Portugiesisch (Brasilien), Portugiesisch (Portugal), Dänisch, Schwedisch, Finnisch, Norwegisch, Koreanisch, Japanisch (Romaji, 10 Tasten), Japanisch (Kana), Russisch, Polnisch, Türkisch, Ukrainisch, Estnisch, Ungarisch, Isländisch, Litauisch, Lettisch, Flämisch, Arabisch, Thailändisch, Tschechisch, Griechisch, Hebräisch, Indonesisch, Malaiisch, Rumänisch, Slowakisch, Kroatisch, Bulgarisch, Serbisch (Kyrillisch/Lateinisch), Katalanisch, Vietnamesisch, Tibetisch, Mazedonisch und Cherokee
     
    •Wörterbuchunterstützung (aktiviert Textvorhersage und automatische Korrektur) für Englisch (USA), Englisch (Großbritannien), Französisch, Deutsch, traditionelles Chinesisch, vereinfachtes Chinesisch, Niederländisch, Italienisch, Spanisch, Portugiesisch (Brasilien), Portugiesisch (Portugal), Dänisch, Schwedisch, Finnisch, Norwegisch, Koreanisch, Japanisch (Romaji), Japanisch (Kana), Russisch, Polnisch, Türkisch, Ukrainisch, Ungarisch, Litauisch, Flämisch, Arabisch, Thailändisch, Tschechisch, Griechisch, Hebräisch, Indonesisch, Malaiisch, Rumänisch, Slowakisch, Kroatisch, Katalanisch, Vietnamesisch und Cherokee

    Bedienungshilfen

    •Unterstützung für die Wiedergabe von Inhalten mit erweiterten Untertiteln
    •VoiceOver Bildschirmlesetechnologie
    •Bildschirmfüllender Zoom
    •Anzeigeoption ""Weiß-auf-Schwarz""
    •Mono-Audioausgabe
     
    Umgebungsbedingungen

    •Betriebstemperatur: 0 °C bis 35 °C
    •Lagertemperatur: -20 °C bis 45 °C
    •Relative Luftfeuchtigkeit: 5 % bis 95 %, nicht kondensierend
    •Maximale Betriebshöhe: ca. 3.000 m über NN, ohne Druckausgleich
     
    Voraussetzungen für Mac

    •Mac mit USB 2.0 Anschluss
    •Mac OS X 10.5.8 (oder neuer)
    •iTunes 10.2 oder neuer empfohlen
    (kostenlos ladbar unter www.itunes.com/de/download)
    •iTunes Store Account
    •Internetzugang
     
    Voraussetzungen für Windows

    •PC mit USB 2.0 Anschluss
    •Windows 7, Windows Vista oder Windows XP Home oder Professional mit Service Pack 3 (oder neuer)
    •iTunes 10.2 oder neuer empfohlen
    (kostenlos ladbar unter www.itunes.com/de/download)
    •iTunes Store Account
    •Internetzugang
     
    Lieferumfang

    •iPad
    •Dock Connector auf USB Kabel
    •10W USB Power Adapter (Netzteil)
    •Dokumentation
     
    Umweltverträglichkeit

     
    Das iPad steht exemplarisch für das Engagement von Apple in Sachen Umweltschutz. Die folgenden Merkmale des iPad tragen zu seiner geringeren Umweltbelastung bei:

    •Arsenfreies Displayglas
    •Frei von bromhaltigen Flammschutzmitteln
    •Quecksilberfreies Display mit LED-Hintergrundbeleuchtung
    •Ohne PVC
    •Recycelbares Gehäuse aus Aluminium und Glas
    ";2;False;0;;;Apple iPad 2 schwarz;apple-ipad-2-schwarz;True;True;PD-01076;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;9300;False;False;0;1;1;0;False;1;10000;;False;False;False;False;479.0000;479.0000;499.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;40653,4073263889;54;1;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000633-apple-ipad-2-schwarz.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000634-apple-ipad-2-schwarz.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000635-apple-ipad-2-schwarz.jpg;1;;False;;;;;False;False;False;;;;;False;;;;;; +5;0;True;Apple iPad 2 weiß;Apple iPad 2. Generation weiß;"
    Kapazität
     
    16-GB-Flash-Laufwerk
    32-GB-Flash-Laufwerk
    64-GB-Flash-Laufwerk

    Abmessungen und Gewicht
     
    •Höhe: 241,2 mm
    •Breite: 185,7 mm
    •Tiefe: 8,8 mm
    •Gewicht: 601 g
     
    •Höhe: 241,2 mm
    •Breite: 185,7 mm
    •Tiefe: 8,8 mm
    •Gewicht: 613 g
     
     
    Drahtlose Technologie und Funknetz

    •Wi-Fi (802.11a/b/g/n)
    •Bluetooth 2.1 + EDR Technologie
    •Wi-Fi + 3G Modell: UMTS/HSDPA/HSUPA (850, 900, 1900, 2100 MHz); GSM/EDGE (850, 900, 1800, 1900 MHz)
    •Nur Datentransfer
    •Wi-Fi (802.11a/b/g/n)
    •Bluetooth 2.1 + EDR Technologie
    Weitere Infos zu Wi-Fi + 3G
     

    Display

     
    •9,7"" Multi-Touch Hochglanz-Widescreendisplay mit LED-Hintergrundbeleuchtung und IPS-Technologie (24,63 cm Diagonale)
    •Auflösung von 1024 x 768 Pixeln bei 132 ppi
    •Fettabweisende Beschichtung
    •Unterstützung für die Anzeige mehrerer Sprachen und Zeichen gleichzeitig
     
     
    Chip
    Speziell entwickelter, hochleistungsfähiger 1 GHz Dual-Core Apple A5 SOC (System-on-a-Chip) mit niedrigem Stromverbrauch
     
     
    Kamera, Fotos, Videoaufnahme
     
    •Rückkamera: Videoaufnahme, HD (720p) bis zu 30 fps mit Audio, Fotokamera mit 5-fach Digitalzoom
    •Frontkamera: Videoaufnahme, VGA mit bis zu 30 fps mit Audio, Fotokamera in VGA-Qualität
    •Fokussieren per Fingertipp für Videos und Fotos
    •Geotagging für Fotos und Videos via Wi-Fi
     
     
    Stromversorgung und Batterie
     
    •Integrierte wiederaufladbare Lithium-Polymer-Batterie mit 25 Wattstunden
    •Bis zu 10 Stunden Surfen im Web mit Wi-Fi, Video- oder Musikwiedergabe
    •Aufladen über das Netzteil oder einen USB Anschluss am Computer
     
    •Integrierte wiederaufladbare Lithium-Polymer-Batterie mit 25 Wattstunden
    •Bis zu 10 Stunden Surfen im Web mit Wi-Fi, Video- oder Musikwiedergabe
    •Bis zu 9 Stunden Batterielaufzeit beim Surfen im Internet über das 3G Datennetzwerk
    •Aufladen über das Netzteil oder einen USB Anschluss am Computer
     
     
    Ein- und Ausgabe
     
    •30-poliger Dock-Anschluss
    •3,5 mm Stereo-/Kopfhöreranschluss (Minianschluss)
    •Integrierter Lautsprecher
    •Mikrofon
     
    •30-poliger Dock-Anschluss
    •3,5 mm Stereo-/Kopfhöreranschluss (Minianschluss)
    •Integrierter Lautsprecher
    •Mikrofon
    •Fach für Micro-SIM-Karte (nur beim Wi-Fi + 3G Modell)
     
     
    Sensoren
     
    •3-Achsen-Gyrosensor
    •Beschleunigungssensor
    •Umgebungslichtsensor
     
    •3-Achsen-Gyrosensor
    •Beschleunigungssensor
    •Umgebungslichtsensor
     
     
    Ortungsfunktion
     
    •Wi-Fi
    •Digitaler Kompass
     
    •Wi-Fi
    •Digitaler Kompass
    •Assisted GPS
    •Mobilfunknetz
     
     
    Audiowiedergabe
     
    •Frequenzbereich: 20 Hz bis 20.000 Hz
    •Unterstützte Audioformate: HE-AAC (V1 und V2), AAC (8 bis 320 Kbit/s), Protected AAC (aus dem iTunes Store), MP3 (8 bis 320 Kbit/s), MP3 VBR, Audible (Formate 2, 3, 4, Audible Enhanced Audio, AAX und AAX+), Apple Lossless, AIFF und WAV
    •Maximale Lautstärke vom Benutzer festlegbar
    •Dolby Digital 5.1 Surround Sound Durchschleifen mit Apple Digital AV Adapter (separat erhältlich)
     
     
    TV und Video
     
    •Unterstützung für Bildschirmsynchronisation und Videoausgabe: bis zu 1080p mit dem Apple Digital AV Adapter oder dem Apple VGA-Adapter (Kabel separat erhältlich)
    •Unterstützung für die Videoausgabe mit 576p und 480p mit dem Apple AV-Kabel (Komponentenvideo), mit 576i und 480i mit dem Apple AV-Kabel (Composite-Video)
    •Unterstützte Videoformate: H.264 Video: bis zu 720p, 30 Bilder pro Sekunde, Main Profile Level 3.1 mit AAC-LC Audio mit bis zu 160 Kbit/s, 48 kHz, Stereo-Audio in den Formaten .m4v, .mp4 und .mov; MPEG-4 Video: bis zu 2,5 Mbit/s, 640 x 480 Pixel, 30 Bilder pro Sekunde, Simple Profile mit AAC-LC Audio mit bis zu 160 Kbit/s, 48 kHz, Stereo-Audio in den Formaten .m4v, .mp4 und .mov; Motion JPEG (M-JPEG): bis zu 35 Mbit/s, 1280 x 720 Pixel, 30 Bilder pro Sekunde, Audio im Format .ulaw, PCM Stereo-Audio im Format .avi
     
     
    Unterstützte
    E-Mail Anhänge
     
    Anzeigbare Dokumenttypen: .jpg, .tiff, .gif (Bilder); .doc und .docx (Microsoft Word); .htm und .html (Webseiten); .key (Keynote); .numbers (Numbers); .pages (Pages); .pdf (Vorschau und Adobe Acrobat); .ppt und .pptx (Microsoft PowerPoint); .txt (Text); .rtf (Rich Text Format); .vcf (Kontaktdaten); .xls und .xlsx (Microsoft Excel)
     
    Sprachen
     
    •Sprachunterstützung für Englisch (USA), Englisch (Großbritannien), Französisch (Frankreich), Deutsch, traditionelles Chinesisch, vereinfachtes Chinesisch, Niederländisch, Italienisch, Spanisch, Portugiesisch (Brasilien), Portugiesisch (Portugal), Dänisch, Schwedisch, Finnisch, Norwegisch, Koreanisch, Japanisch, Russisch, Polnisch, Türkisch, Ukrainisch, Ungarisch, Arabisch, Thailändisch, Tschechisch, Griechisch, Hebräisch, Indonesisch, Malaiisch, Rumänisch, Slowakisch, Kroatisch, Katalanisch und Vietnamesisch
     
    •Tastaturunterstützung für Englisch (USA), Englisch (Großbritannien), Französisch (Frankreich), Französisch (Kanada), Französisch (Schweiz), Deutsch, traditionelles Chinesisch (Handschrift, Pinyin, Zhuyin, Cangjie, Wubihua), vereinfachtes Chinesisch (Handschrift, Pinyin, Wubihua), Niederländisch, Italienisch, Spanisch, Portugiesisch (Brasilien), Portugiesisch (Portugal), Dänisch, Schwedisch, Finnisch, Norwegisch, Koreanisch, Japanisch (Romaji, 10 Tasten), Japanisch (Kana), Russisch, Polnisch, Türkisch, Ukrainisch, Estnisch, Ungarisch, Isländisch, Litauisch, Lettisch, Flämisch, Arabisch, Thailändisch, Tschechisch, Griechisch, Hebräisch, Indonesisch, Malaiisch, Rumänisch, Slowakisch, Kroatisch, Bulgarisch, Serbisch (Kyrillisch/Lateinisch), Katalanisch, Vietnamesisch, Tibetisch, Mazedonisch und Cherokee
     
    •Wörterbuchunterstützung (aktiviert Textvorhersage und automatische Korrektur) für Englisch (USA), Englisch (Großbritannien), Französisch, Deutsch, traditionelles Chinesisch, vereinfachtes Chinesisch, Niederländisch, Italienisch, Spanisch, Portugiesisch (Brasilien), Portugiesisch (Portugal), Dänisch, Schwedisch, Finnisch, Norwegisch, Koreanisch, Japanisch (Romaji), Japanisch (Kana), Russisch, Polnisch, Türkisch, Ukrainisch, Ungarisch, Litauisch, Flämisch, Arabisch, Thailändisch, Tschechisch, Griechisch, Hebräisch, Indonesisch, Malaiisch, Rumänisch, Slowakisch, Kroatisch, Katalanisch, Vietnamesisch und Cherokee
     
    Bedienungshilfen
     
    •Unterstützung für die Wiedergabe von Inhalten mit erweiterten Untertiteln
    •VoiceOver Bildschirmlesetechnologie
    •Bildschirmfüllender Zoom
    •Anzeigeoption ""Weiß-auf-Schwarz""
    •Mono-Audioausgabe
     
     
    Umgebungsbedingungen 

    •Betriebstemperatur: 0 °C bis 35 °C
    •Lagertemperatur: -20 °C bis 45 °C
    •Relative Luftfeuchtigkeit: 5 % bis 95 %, nicht kondensierend
    •Maximale Betriebshöhe: ca. 3.000 m über NN, ohne Druckausgleich
     
     
    Voraussetzungen für Mac
     
    •Mac mit USB 2.0 Anschluss
    •Mac OS X 10.5.8 (oder neuer)
    •iTunes 10.2 oder neuer empfohlen
    (kostenlos ladbar unter www.itunes.com/de/download)
    •iTunes Store Account
    •Internetzugang
     
     
    Voraussetzungen für Windows
     
    •PC mit USB 2.0 Anschluss
    •Windows 7, Windows Vista oder Windows XP Home oder Professional mit Service Pack 3 (oder neuer)
    •iTunes 10.2 oder neuer empfohlen
    (kostenlos ladbar unter www.itunes.com/de/download)
    •iTunes Store Account
    •Internetzugang
     
     
    Lieferumfang
     
    •iPad
    •Dock Connector auf USB Kabel
    •10W USB Power Adapter (Netzteil)
    •Dokumentation
     
     
    Umweltverträglichkeit
     
     
    Das iPad steht exemplarisch für das Engagement von Apple in Sachen Umweltschutz. Die folgenden Merkmale des iPad tragen zu seiner geringeren Umweltbelastung bei:
    •Arsenfreies Displayglas
    •Frei von bromhaltigen Flammschutzmitteln
    •Quecksilberfreies Display mit LED-Hintergrundbeleuchtung
    •Ohne PVC
    •Recycelbares Gehäuse aus Aluminium und Glas
    ";2;False;0;;;Apple iPad 2 weiß;apple-ipad-2-weiss;True;True;PD-01075;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;479.0000;0.0000;499.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;40653,4018865741;54;1;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000627-apple-ipad-2-weis.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000628-apple-ipad-2-weis.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000629-apple-ipad-2-weis.jpg;1;;False;;;;;False;False;False;;;;;False;;;;;; +5;0;True;Apple MacBook Pro MC721D/A 15,4 Zoll Notebook;"Apple MacBook Pro MC721D/A 39.1 cm (15,4 Zoll) Notebook (Intel Core i7 2635QM, 2 GHz, 4GB RAM, 500GB HDD, AMD 6490M, DVD, Mac OS) ";"
    Apple MacBook Pro MC721D/A
    Intel Core i7 2635QM, 2 GHz

    Unibody-Gehäuse. Am Anfang jedes MacBook Pro steht ein Werkstück aus Aluminium.Stark, leicht und schön in einem.
    Das MacBook Pro ist aus einem einzigen Aluminiumblock gefertigt - eine technische Meisterleistung, bei der viele Bauteile durch ein einziges ersetzt werden. Das Ganze nennt sich Unibody. Gleich beim ersten Mal, wenn Sie ein MacBook Pro in der Hand haben, werden Sie den Unterschied spüren. Das Gehäuse ist dünner und leichter als andere Notebooks. Es sieht elegant aus. Und es fühlt sich stabil und robust an: perfekt für die Aktentasche, den Rucksack und natürlich auch für draußen.
     
    Ein Display voll brillanter Ideen.
    Alles, was Apple Designer und Ingenieure tun, ist von A bis Z durchdacht. Sie entschieden sich beim MacBook Pro für die LED-Hintergrundbeleuchtung, weil das Display damit sofort seine volle Helligkeit erreicht und trotzdem unglaublich dünn ist. Sie verwendeten eine durchgehende Oberfläche aus Glas, nicht nur weil es schön aussieht, sondern weil es dem ganzen Display Struktur verleiht. Und über dem Bildschirm haben sie die neue, integrierte FaceTime HD Kamera versteckt. So siehst du Freunde und Familie im Großformat - und dabei so gut wie nichts von der Kamera.
     
    Magnetverschluss
    Da der magnetische Verschluss keine beweglichen Teile hat, die abbrechen können oder an denen man hängen bleibt, ist das Öffnen und Schließen so einfach wie alles beim MacBook Pro.
     
    Einfach auf alle Anschlüsse zugreifen.
    Alle Anschlüsse am MacBook Pro - der MagSafe Netzanschluss, der Gigabit Ethernetanschluss, der Thunderbolt Anschluss, der USB Anschluss, der Karten-Steckplatz und der Audioeingang und -ausgang - sind ganz auf einer Seite des Notebooks integriert. So bleiben die Kabel schön geordnet und Geräte lassen sich schnell und einfach anschließen und auch wieder trennen.
     
    Hinterlässt Eindruck. Aber nicht auf die Umwelt.
    Weil Apple die vollständige Kontrolle über Design, Fertigung und Verpackung des MacBook Pro hat, hat Apple einen Vorsprung beim Umweltschutz. Die Technologie zur Hintergrundbeleuchtung des Displays spart Energie. Glas und Aluminium sind besonders recyclingfähig. Das MacBook Pro kommt fast ohne Giftstoffe aus. Und die Verpackung des 39,11 cm / 15,4"" Modells ist im Vergleich zum Vorgängermodell 34 Prozent kleiner. Das bedeutet nicht nur, dass für die Verpackungen weniger Bäume gefällt werden, es werden für den Transport auch weniger Flugzeugen, Güterzügen und LKWs benötigt.
     
    Thunderbolt AnschlussDie Grafikleistung, die Sie brauchen, wenn Sie sie brauchen.
    Alle MacBook Pro Modelle haben jetzt einen integrierten Intel HD Graphics 3000 Prozessor für die täglichen Aufgaben. Er codiert Videos schnell, ermöglicht HD Videotelefonate mit FaceTime und vieles mehr. Und auch Decodieren erledigt er effizienter, was bedeutet, dass Sie richtig lange DVDs und iTunes Filme schauen können. Bei anspruchsvollen Grafikprogrammen wechseln die 39,11 cm / 15,4"" MacBook Pro Modelle automatisch den Grafikprozessor und arbeiten mit den neuen leistungsstarken AMD Radeon Grafikprozessoren. Diese bieten verglichen mit den Vorgängermodellen die bis zu 3-fache Leistung. So sehen Sie bei 3D Spielen mehr Bilder pro Sekunde oder können schneller als je zuvor an HD Videoprojekten arbeiten.
     
    Das neue Thunderbolt. Die schnellste, vielseitigste I/O Technologie in einem Notebook.
    Stellen Sie sich vor, Sie könnten auf deinem Notebook auf mehrere unkomprimierte HD Videostreams zugreifen - und zwar so schnell, dass Sie einen HD Spielfilm in Echtzeit schneiden können. Thunderbolt macht genau das möglich. Mit Thunderbolt lassen sich superschnelle Peripheriegeräte der nächsten Generation an die Computer der nächsten Generation anschließen - angefangen beim MacBook Pro. Die Thunderbolt Pipeline ist ultraschnell und ultraflexibel. Sie ist über 12 Mal schneller als FireWire 800 und bis zu 20 Mal schneller als USB 2.0. Und sie bietet beispiellose Erweiterungsmöglichkeiten. Kurzum: Sie verändert alles, was Sie auf Ihrem Notebook machen können. Der Thunderbolt Anschluss gibt Ihnen Plug&Play Anschluss für eine völlig neue Welt von Thunderbolt Peripheriegeräten sowie für das Apple LED Cinema Display und andere Mini DisplayPort Peripheriegeräte. Sie können bis zu sechs Thunderbolt Geräte in Reihenschaltung anschließen, darunter auch Ihr Display. Außerdem unterstützt Thunderbolt Video und Achtkanal-Audio, sodass es auch möglich ist, HDMI-kompatible Geräte wie Fernseher oder Stereoanlagen über einen HDMI-Adapter anzuschließen. Auch aktuelle VGA-, DVI- und DisplayPort Adapter werden unterstützt.
     
    Die neue FaceTime HD Kamera. Der Unterschied ist ganz klar.
    Sehen Sie mehr von Ihren Freunden mit dem HD Widescreenformat - und zwar gestochen scharf. Die neue FaceTime HD Kamera bietet die dreifache Auflösung der vorherigen Kamera, was perfekt für das brillante Display mit LED-Hintergrundbeleuchtung ist. Außerdem arbeitet sie jetzt bei schwachem Licht noch besser. Sie können mit Ihren Freunden HD Telefonate in 720p von einem neuen MacBook Pro zu einem anderen führen. Außerdem sind auch Videotelefonate zu anderen Macs mit Intel Prozessor, zum iPhone 4 oder zum neuen iPod touch möglich.
     
    Multi-Touch Trackpad - Jede Menge Platz für GestenMulti-Touch Trackpad. Fürs tägliche Handwerk.
    Mit dem Multi-Touch Trackpad interagieren Sie auf ganz natürliche Art mit den Inhalten auf deinem Display. Und die glatte Glasoberfläche bietet jede Menge Platz für Gesten. Durch Auf- und Zuziehen können Sie ein- und auszoomen, durch Streichen in deinen Fotos blättern, durch Drehen ein Bild anpassen und vieles mehr. Das Trackpad kommt ohne Taste aus, sodass Sie überall klicken können. Wenn Sie aus der Welt des rechten Mausklicks kommen, können Sie diesen entweder mit zwei Fingern auslösen, oder Sie konfigurieren einen physischen Rechtsklick-Bereich auf dem Trackpad. Je mehr Sie mit dem Multi-Touch Trackpad vertraut sind, desto mehr werden Sie sich fragen, wie Sie jemals ohne ausgekommen sind.
     
    Lange Laufzeit. Weniger aufladen. Mehr machen.
    Das neue MacBook Pro bietet eine fantastische Batterielaufzeit und das mit leistungsstärkeren Prozessoren und schnelleren Grafikprozessoren. Die energieeffiziente Prozessorarchitektur mit integriertem Video-Encoder sowie das automatische Umschalten zwischen den Grafikprozessoren bei den 39,11 cm / 15,4"" Modellen helfen, die Batterielaufzeit weiter zu verbessern. So können Sie pro Ladung bis zu 7 Stunden ohne Kabel im Web surfen oder es für Liveauftritte oder auf ein Shooting mitnehmen. Die fortschrittlichen chemischen Eigenschaften und die Adaptive Charging Technologie sorgen dafür, dass die Batterie bis zu 1000 Ladezyklen durchlaufen kann. Und da die Batterie des MacBook Pro bis zu fünf Jahre hält, kommt das MacBook Pro in einem Zeitraum, in dem ein herkömmliches Notebook drei Batterien verbraucht, mit nur einer aus. Das ist für die Benutzer genauso gut, wie für die Umwelt. Apple verwendet eine neue, strengere Testmethode, um zu messen, welche Ergebnisse Sie unter realen Bedingungen erzielen, z. B. beim Surfen in einem Cafe oder wenn Sie die neuesten Webvideos ansehen. Und wie schneidet dieses MacBook Pro dabei verglichen mit der Vorgängergeneration ab? Es liefert die gleiche fantastische Leistung.
     
    Hat beste Verbindungen.
    Unterwegs haben Sie mit der 802.11n Technologie im MacBook Pro immer Verbindung. Das MacBook Pro findet automatisch verfügbare Netzwerke und Sie können sich mit einem Klick verbinden. Auch die drahtlose Bluetooth Technologie ist integriert, sodass Sie drahtloses Zubehör sofort nach dem Auspacken verwenden können.
     
    DVDs superschnell brennen.
    Homevideos, die Sie mit iMovie und iDVD gemacht haben, können Sie mit dem 8-fach SuperDrive Laufwerk des MacBook Pro superschnell auf eine DVD brennen. Das SuperDrive kann auch Double-Layer-DVDs (also DVDs mit fast 9 GB Speicherplatz) beschreiben, sodass es auch hervorragend für Datensicherungen geeignet ist.
     
    Neue Intel Core i7 Prozessoren.
    Neue Quad-Core Intel Core i7 Prozessoren sind Standard beim 39,11 cm / 15,4"" MacBook Pro. Alle Modelle verwenden die kürzlich optimierten Chipsets von Intel. Was heißt das für die neuen MacBook Pro Modelle? Kurz gesagt: Sie sind bis zu zwei Mal schneller als die Vorgängergeneration und erledigen auch anspruchsvolle Aufgaben wie HD Videoschnitt, Audiokompilierung oder Rendering mehrschichtiger Bilddateien unglaublich schnell. Und da Mac OS X Snow Leopard darauf ausgelegt ist, jeden Prozessorkern zu nutzen, holt das Betriebssystem wirklich alles an Leistung aus dem Prozessor heraus.
     
    Schnellere Einzelchip-Mikroarchitektur.
    Ob Sie einen Film ansehen, Ihren Blog auf den neuesten Stand bringen oder Fotos bearbeiten - die Daten müssen von A nach B gelangen, um verarbeitet werden zu können. Die neueste Intel Core Architektur bringt den Prozessor, den Cache, den Speichercontroller und den Grafikprozessor auf einem einzigen Chip unter. Deswegen müssen die Daten keine weiten Wege zurücklegen, was für Sie schnellere Performance und höhere Effizienz bedeutet.
     
    Turbo Boost 2.0.
    Angenommen, Sie arbeiten mit einem prozessorintensiven Programm wie Aperture 3 oder Final Cut Pro, das von einem Leistungsschub profitiert würde. Turbo Boost ist eine dynamische Technologie, die automatisch die Geschwindigkeit der aktiven Prozessorkerne auf 3,4 GHz erhöht. Turbo Boost 2.0 ist noch dynamischer und effizienter. Es wechselt die Kernfrequenz in kleineren Schritten als bisher, sodass der Prozessor die Leistung ohne Effizienzeinbußen verwalten kann. All das passiert im Hintergrund. Sie arbeiten einfach nur schneller.
     
    Hyper-Threading.
    Hyper-Threading ist jetzt Standard auf jedem MacBook Pro. Mit dieser Technologie können auf jedem Kern zwei Threads gleichzeitig laufen, Mac OS X erkennt also bei einem Quad-Core Prozessor acht und bei einem Dual-Core Prozessor vier virtuelle Kerne. Wenn Sie mehrere Programme gleichzeitig verwenden, verteilt der Prozessor die Aufgaben gleichmäßiger über eine größere Anzahl Kerne.
     
    Integrierter Speichercontroller.
    Mit schnellerem Speicherzugriff legt jeder Kern direkt mit der Verarbeitung der Daten los, statt auf ihr Eintreffen zu warten. Genau deshalb nutzt die neue Intel Core Architektur einen integrierten Speichercontroller, der den schnellen 1333 MHz Speicher direkt mit dem Prozessor verbindet und Ihre Programme immer die maximale Prozessorleistung zur Verfügung haben.
     
    Energieeffiziente Grafik.
    Dank der neuen Mikroarchitektur ist der Grafikprozessor auf dem gleichen Chip wie der Zentralprozessor und hat direkten Zugriff auf den L3-Cache. Kurze Wege bedeuten mehr Leistung. Der Grafikprozessor erhöht auch automatisch die Taktrate für noch höhere Auslastung. Ein integrierter Video-Encoder ermöglicht jetzt HD Videotelefonate mit FaceTime, und der effiziente Decoder sorgt für lange Batterielaufzeit, wenn Sie sich DVDs oder iTunes Filme ansiehen.
     
    Mac OS X. Das fortschrittlichste Betriebssystem der Welt.
    Mac OS X ist das Herz jedes MacBook Pro und Mac. Dieses Betriebssystem ist genau auf die integrierten Intel Multicore-Prozessoren und fortschrittlichen Grafikprozessoren zugeschnitten. Die neueste Version, Mac OS X Snow Leopard, basiert komplett auf einer 64-Bit-Architektur, genau wie alle anderen Programme, die mit dem Mac kommen. Das bedeutet: Alles, was Sie auf Ihrem MacBook Pro machen, passiert superschnell und mit einer unglaublichen Gesamtleistung.
     
    Hat eine ganze Menge draufProgramme, ebenso leistungsstark wie benutzerfreundlich.
    Weil Apple sowohl das MacBook Pro, wie auch die integrierte Software entwickelt, arbeitet alles perfekt zusammen. Und mit den Apple Programmen sind Sie ganz schnell vertraut, weil alle ähnlich funktionieren. Das heißt, wenn Sie ein Programm kennen, sind Sie auch schnell mit allen anderen vertraut. Außerdem weiß Apple genau, was mobile Produktivität bedeutet. Darum haben wir Funktionen wie Expose und Spaces hinzugefügt. Damit können Sie ganz einfach auf alles auf Ihrem MacBook Pro zugreifen. Expose zeigt sämtliche geöffneten Fenster nebeneinander, verkleinert sie und ordnet sie so, dass Sie den Inhalt jedes Fensters sehen können - ein Tastendruck oder eine Geste genügt. Und mit Spaces können Sie Fenster zusammen auf ihrem eigenen Schreibtisch oder Bereich gruppieren und ganz einfach zwischen diesen wechseln. Legen Sie einen Bereich zum Arbeiten fest, einen zum Spielen und einen für was auch immer. Mit Expose und Spaces haben Sie beim Multitasking auf einem Notebookdisplay einen riesigen Vorteil.
     
    Darauf verzichten Sie beim Mac: PC-Viren.
    Trojaner, Würmer, E-Mail Viren. Die digitale Welt kann ganz schön beängstigend sein. Zum Glück ist der Mac immun gegen die tausenden von Viren, die Windows Computer plagen. Denn Mac OS X kommt mit integrierten Sicherheitsmechanismen, die Sie schützen - ohne dass Sie etwas machen müssen. Und sollten doch mal potenzielle Sicherheitsrisiken auftreten, reagiert Apple sofort und stellt neue Softwareaktualisierungen und Sicherheitsverbesserungen bereit, die Sie automatisch laden und mit einem Klick installieren können.
     
    Das automatische Backup rettet Ihren Tag. Und die Woche, den Monat ...
    Backups müssen sein. Trotzdem vergissen Sie sie bestimmt hin und wieder. Deshalb kümmert sich jetzt das MacBook Pro um die Datensicherung. Time Machine, ein Programm, das auf jedem Mac dabei ist, sichert automatisch Ihr ganzes System auf einer externen Festplatte oder Time Capsule. Time Machine speichert eine Kopie von jeder Datei. Und es merkt sich, wie Ihr System an einem bestimmten Tag ausgesehen hat. So können Sie, wenn Sie wollen, die Zeit zurückdrehen und Ihren Mac wie in der Vergangenheit sehen.
     
    Mit iMovie können Sie aus Ihren Videos großartige Filme machenAuch die täglichen Sachen machen mehr Spaß.
    Anders als viele PC-Notebooks kommt das MacBook Pro mit allem, was Sie brauchen, um E-Mails zu senden, Kalender zu verwalten, Kontakte zu organisieren und mehr. Und Sie können schon wenige Minuten nach dem Auspacken damit loslegen. Denn jeder Mac kommt mit Mail, um E-Mails zu senden und empfangen, iCal zum Organisieren von Terminen und wichtigen Ereignissen, dem Adressbuch zum Verwalten von Kontakten, iTunes für alles, was mit Unterhaltung zu tun hat, und weiteren tollen und nützlichen Programmen, die Sie jeden Tag verwenden werden.
     
    Der Mac App Store. Tausend weitere Gründe, den Mac zu lieben.
    Über tausend Mac Apps sind nur einen Klick entfernt - im Mac App Store. Suchen Sie einfach Apps, die Ihnen gefallen, und klicken Sie einfach, um sie zu laden und zu installieren. Ohne Verpackung. Ohne CDs oder DVDs. Und ohne Probleme. Sie können die Apps nach Kategorien durchstöbern oder direkt etwas Bestimmtes suchen. Und Sie können einfach dafür sorgen, dass Ihre Apps up-to-date sind, denn Ihr Mac zeigt Ihnen an, wann Updates verfügbar sind.
     
    iPhoto. Fotos ganz einfach verwalten, bearbeiten und teilen.
    iPhoto ist ein benutzerfreundliches Programm für Fotos, mit dem Sie Ihre Bilder schnell organisieren, wiederfinden und verbessern können - sodass sie immer perfekt aussehen. Mit den iPhoto Funktionen ""Gesichter"", ""Orte"" und ""Ereignisse"" behalten Sie den Überblick über Ihre Fotos. Sie sagen Ihnen, wen Sie fotografiert haben, wo und wann. Und all das in den neuen Vollbildmodi.
     
    iMovie. Und aus Homevideos werden Home-Blockbuster.
    Homevideos müssen nicht langweilig sein. Mit iMovie können Sie aus Ihren Videos großartige Filme machen. Zum Beispiel Trailer im Hollywoodstil, mit denen Sie Ihr Publikum begeistern.
     
    GarageBand. Großartige Musik machen, ganz einfachissimo.
    Egal, ob Sie Musiktalent haben oder einfach nur neugierig sind - GarageBand ist genau das richtige Programm für Sie. Schließ einfach eine elektrische Gitarre oder ein USB Keyboard an. Und schon können Sie mit virtuellen Nachbildungen der bekanntesten Amps und Stompboxes der Welt sowie mit 100 Software-Instrumenten spielen.
    ";2;False;0;;;Apple MacBook Pro MC721D/A 15,4 Zoll Notebook;apple-macbook-pro-mc721da-154-zoll-notebook;True;True;P-0760;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;2,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;1483.9000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;40652,8677546296;3;1;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000545-apple-macbook-pro-mc721da-154-zoll-notebook.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000546-apple-macbook-pro-mc721da-154-zoll-notebook.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000547-apple-macbook-pro-mc721da-154-zoll-notebook.jpg;2;;False;;;;;False;False;False;;;;;False;;;;;; +5;0;True;Apple MacBook Pro MD313D/A 13,3 Zoll Notebook;"Apple MacBook Pro MD313D/A 33,78cm (13,3"")";"
    Apple MacBook Pro MD313D/A 13,3 Zoll Notebook
    Intel Core i5  2x 2,40 GHz
     
    Bis zu 2x schnellere Prozessoren. Bis zu 3x schnellere Grafik.
    Quad-Core und Dual-Core Intel Prozessoren der nächsten Generation.
    Das 13"" MacBook Pro gibt es jetzt mit einem 2,4 GHz Intel Core i5 Prozessor oder dem schnellsten Dual-Core Prozessor, den es gibt: dem 2,8 GHz Intel Core i7. Diese Prozessoren bieten Turbo Boost Geschwindigkeiten und machen das 13"" MacBook Pro bis zu doppelt so schnell wie die Vorgängergeneration.
     
    Aber nur schnell ist uns nicht genug. Deshalb bieten die neuen 15"" und 17"" Modelle Quad-Core Leistung für praktisch alles, was du machen willst. Auch ein 2,4 GHz Quad-Core Intel Core i7 Prozessor mit Turbo Boost Geschwindigkeiten und bis zu 8 MB gemeinsam genutztem L3-Cache ist verfügbar. Auf MacBook Pro Modellen mit diesem Prozessor laufen Programme bis zu doppelt so schnell wie auf der besten Vorgängerkonfiguration.
     
    Die Grafikleistung, die du brauchst, wenn du sie brauchst.
    Alle MacBook Pro Modelle haben jetzt einen integrierten Intel HD Graphics 3000 Prozessor für die täglichen Aufgaben. Er codiert Videos schnell, ermöglicht HD Videotelefonate mit FaceTime und vieles mehr. Und auch Decodieren erledigt er effizienter, was bedeutet, dass du richtig lange DVDs und iTunes Filme schauen kannst.
     
    Bei anspruchsvollen Grafikprogrammen wechseln die 15"" und 17"" MacBook Pro Modelle automatisch den Grafikprozessor und arbeiten mit den neuen leistungsstarken AMD Radeon Grafikprozessoren. Diese bieten verglichen mit den Vorgängermodellen die bis zu 3-fache Leistung.3 So siehst du bei 3D Spielen mehr Bilder pro Sekunde oder kannst schneller als je zuvor an HD Videoprojekten arbeiten.
     
    Das neue Thunderbolt. Die schnellste, vielseitigste I/O Technologie in einem Notebook.
    Stell dir vor, du könntest auf deinem Notebook auf mehrere unkomprimierte HD Videostreams zugreifen - und zwar so schnell, dass du einen HD Spielfilm in Echtzeit schneiden kannst. Thunderbolt macht genau das möglich. Mit Thunderbolt lassen sich superschnelle Peripheriegeräte der nächsten Generation an die Computer der nächsten Generation anschließen - angefangen beim MacBook Pro. Die Thunderbolt Pipeline ist ultraschnell und ultraflexibel. Sie ist über 12 Mal schneller als FireWire 800 und bis zu 20 Mal schneller als USB 2.0. Und sie bietet beispiellose Erweiterungsmöglichkeiten. Kurzum: Sie verändert alles, was du auf deinem Notebook machen kannst.
     
    Der Thunderbolt Anschluss gibt dir Plug&Play Anschluss für eine völlig neue Welt von Thunderbolt Peripheriegeräten sowie für das Apple LED Cinema Display und andere Mini DisplayPort Peripheriegeräte. Du kannst bis zu sechs Thunderbolt Geräte in Reihenschaltung anschließen, darunter auch dein Display. Außerdem unterstützt Thunderbolt Video und Achtkanal-Audio, sodass es auch möglich ist, HDMI-kompatible Geräte wie Fernseher oder Stereoanlagen über einen HDMI-Adapter anzuschließen. Auch aktuelle VGA-, DVI- und DisplayPort Adapter werden unterstützt.
     
    Die neue FaceTime HD Kamera. Der Unterschied ist ganz klar.
    Sieh mehr von deinen Freunden mit dem HD Widescreenformat - und zwar gestochen scharf. Die neue FaceTime HD Kamera bietet die dreifache Auflösung der vorherigen Kamera, was perfekt für das brillante Display mit LED-Hintergrundbeleuchtung ist. Außerdem arbeitet sie jetzt bei schwachem Licht noch besser. Du kannst mit deinen Freunden HD Telefonate in 720p von einem neuen MacBook Pro zu einem anderen führen. Außerdem sind auch Videotelefonate zu anderen Macs mit Intel Prozessor5, zum iPhone 4 oder zum neuen iPod touch möglich.
     
    Multi-Touch Trackpad. Fürs tägliche Handwerk.
    Mit dem Multi-Touch Trackpad interagierst du auf ganz natürliche Art mit den Inhalten auf deinem Display. Und die glatte Glasoberfläche bietet jede Menge Platz für Gesten. Durch Auf- und Zuziehen kannst du ein- und auszoomen, durch Streichen in deinen Fotos blättern, durch Drehen ein Bild anpassen und vieles mehr. Das Trackpad kommt ohne Taste aus, sodass du überall klicken kannst. Wenn du aus der Welt des rechten Mausklicks kommst, kannst du diesen entweder mit zwei Fingern auslösen, oder du konfigurierst einen physischen Rechtsklick-Bereich auf dem Trackpad. Je mehr du mit dem Multi-Touch Trackpad vertraut bist, desto mehr wirst du dich fragen, wie du jemals ohne ausgekommen bist.
     
    Lange Laufzeit. Weniger aufladen. Mehr machen.
    Das neue MacBook Pro bietet eine fantastische Batterielaufzeit und das mit leistungsstärkeren Prozessoren und schnelleren Grafikprozessoren. Die energieeffiziente Prozessorarchitektur mit integriertem Video-Encoder sowie das automatische Umschalten zwischen den Grafikprozessoren bei den 15"" und 17"" Modellen helfen, die Batterielaufzeit weiter zu verbessern. So kannst du pro Ladung bis zu 7 Stunden ohne Kabel im Web surfen6 oder es für Liveauftritte oder auf ein Shooting mitnehmen. Die fortschrittlichen chemischen Eigenschaften und die Adaptive Charging Technologie sorgen dafür, dass die Batterie bis zu 1000 Ladezyklen durchlaufen kann.7 Und da die Batterie des MacBook Pro bis zu fünf Jahre hält, kommt das MacBook Pro in einem Zeitraum, in dem ein herkömmliches Notebook drei Batterien verbraucht, mit nur einer aus. Das ist für die Benutzer genauso gut, wie für die Umwelt.
     
    Apple verwendet eine neue, strengere Testmethode, um zu messen, welche Ergebnisse du unter realen Bedingungen erzielst, z. B. beim Surfen in einem Café oder wenn du die neuesten Webvideos ansiehst. Und wie schneidet dieses MacBook Pro dabei verglichen mit der Vorgängergeneration ab? Es liefert die gleiche fantastische Leistung.
     
    Hat beste Verbindungen.
    Unterwegs hast du mit der 802.11n Technologie im MacBook Pro immer Verbindung.8 Das MacBook Pro findet automatisch verfügbare Netzwerke und du kannst dich mit einem Klick verbinden. Auch die drahtlose Bluetooth Technologie ist integriert, sodass du drahtloses Zubehör sofort nach dem Auspacken verwenden kannst.
     
    Immer Anschluss finden.
    Mit dem neuen Thunderbolt Anschluss kannst du bis zu sechs Geräte in Reihenschaltung anschließen, darunter auch dein Display. So bekommst du eine vollwertige Workstation. Für die Anbindung von iPad, iPod, iPhone, Digitalkameras und externen Festplatten gibt es zwei USB 2.0 Anschlüsse (drei beim 17"" MacBook Pro) und einen FireWire 800 Anschluss.
     
    Der neue SDXC Kartensteckplatz der 13"" und 15"" MacBook Pro Modelle unterstützt bis zu 64 GB Karten und macht es leicht, alle deine Fotos auf und von deinem MacBook Pro zu übertragen, damit du sie sofort bearbeiten und teilen kannst. Und der ExpressCard/34 Steckplatz am 17"" MacBook Pro ist perfekt für einen eSATA Adapter geeignet oder sogar für eine 3G Karte für die drahtlose Kommunikation, wenn kein Wi-Fi Netzwerk vorhanden ist.
     
    DVDs superschnell brennen.
    Homevideos, die du mit iMovie und iDVD gemacht hast, kannst du mit dem 8-fach SuperDrive Laufwerk des MacBook Pro superschnell auf eine DVD brennen. Das SuperDrive kann auch Double-Layer-DVDs (also DVDs mit fast 9 GB Speicherplatz) beschreiben, sodass es auch hervorragend für Datensicherungen geeignet ist.
    ";2;False;0;;;Apple MacBook Pro MD313D/A 13,3 Zoll Notebook;apple-macbook-pro-md313da-133-zoll-notebook;True;True;P-0740;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;1099.9000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;40652,639537037;3;1;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000456-apple-macbook-pro-md313da-133-zoll-notebook.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000457-apple-macbook-pro-md313da-133-zoll-notebook.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000458-apple-macbook-pro-md313da-133-zoll-notebook.jpg;2;;False;;;;;False;False;False;;;;;False;;;;;; +5;0;True;Apple MacBook Pro MC725D/A 17 Zoll Notebook;"Apple MacBook Pro MC725D/A 43.2 cm (17 Zoll) Notebook (Intel Core i7 2720QM, 2,2 GHz, 4GB RAM, 750GB HDD, AMD 6750M, DVD, Mac OS) ";"
    Apple MacBook Pro MC725D/A
    Intel Core i7 2720QM, 2,2 GHz
     
    Stark, leicht und schön in einem.
    Das MacBook Pro ist aus einem einzigen Aluminiumblock gefertigt - eine technische Meisterleistung, bei der viele Bauteile durch ein einziges ersetzt werden. Das Ganze nennt sich Unibody. Gleich beim ersten Mal, wenn Sie ein MacBook Pro in der Hand haben, werden Sie den Unterschied spüren. Das Gehäuse ist dünner und leichter als andere Notebooks. Es sieht elegant aus. Und es fühlt sich stabil und robust an: perfekt für die Aktentasche, den Rucksack und natürlich auch für draußen.
     
    Ein Display voll brillanter Ideen.
    Alles, was Apple Designer und Ingenieure tun, ist von A bis Z durchdacht. Sie entschieden sich beim MacBook Pro für die LED-Hintergrundbeleuchtung, weil das Display damit sofort seine volle Helligkeit erreicht und trotzdem unglaublich dünn ist. Sie verwendeten eine durchgehende Oberfläche aus Glas, nicht nur weil es schön aussieht, sondern weil es dem ganzen Display Struktur verleiht. Und über dem Bildschirm haben sie die neue, integrierte FaceTime HD Kamera versteckt. So siehst du Freunde und Familie im Großformat - und dabei so gut wie nichts von der Kamera.
     
    Magnetverschluss
    Da der magnetische Verschluss keine beweglichen Teile hat, die abbrechen können oder an denen man hängen bleibt, ist das Öffnen und Schließen so einfach wie alles beim MacBook Pro.
     
    Einfach auf alle Anschlüsse zugreifen.
    Alle Anschlüsse am MacBook Pro - der MagSafe Netzanschluss, der Gigabit Ethernetanschluss, der Thunderbolt Anschluss, der USB Anschluss, der Karten-Steckplatz und der Audioeingang und -ausgang - sind ganz auf einer Seite des Notebooks integriert. So bleiben die Kabel schön geordnet und Geräte lassen sich schnell und einfach anschließen und auch wieder trennen.
     
    Hinterlässt Eindruck. Aber nicht auf die Umwelt.
    Weil Apple die vollständige Kontrolle über Design, Fertigung und Verpackung des MacBook Pro hat, hat Apple einen Vorsprung beim Umweltschutz. Die Technologie zur Hintergrundbeleuchtung des Displays spart Energie. Glas und Aluminium sind besonders recyclingfähig. Das MacBook Pro kommt fast ohne Giftstoffe aus. Und die Verpackung des 43,18 cm / 17"" Modells ist im Vergleich zum Vorgängermodell 34 Prozent kleiner. Das bedeutet nicht nur, dass für die Verpackungen weniger Bäume gefällt werden, es werden für den Transport auch weniger Flugzeugen, Güterzügen und LKWs benötigt.
     
    Thunderbolt AnschlussDie Grafikleistung, die Sie brauchen, wenn Sie sie brauchen.
    Alle MacBook Pro Modelle haben jetzt einen integrierten Intel HD Graphics 3000 Prozessor für die täglichen Aufgaben. Er codiert Videos schnell, ermöglicht HD Videotelefonate mit FaceTime und vieles mehr. Und auch Decodieren erledigt er effizienter, was bedeutet, dass Sie richtig lange DVDs und iTunes Filme schauen können. Bei anspruchsvollen Grafikprogrammen wechseln die 43,18 cm / 17"" MacBook Pro Modelle automatisch den Grafikprozessor und arbeiten mit den neuen leistungsstarken AMD Radeon Grafikprozessoren. Diese bieten verglichen mit den Vorgängermodellen die bis zu 3-fache Leistung. So sehen Sie bei 3D Spielen mehr Bilder pro Sekunde oder können schneller als je zuvor an HD Videoprojekten arbeiten.
     
    Das neue Thunderbolt. Die schnellste, vielseitigste I/O Technologie in einem Notebook.
    Stellen Sie sich vor, Sie könnten auf deinem Notebook auf mehrere unkomprimierte HD Videostreams zugreifen - und zwar so schnell, dass Sie einen HD Spielfilm in Echtzeit schneiden können. Thunderbolt macht genau das möglich. Mit Thunderbolt lassen sich superschnelle Peripheriegeräte der nächsten Generation an die Computer der nächsten Generation anschließen - angefangen beim MacBook Pro. Die Thunderbolt Pipeline ist ultraschnell und ultraflexibel. Sie ist über 12 Mal schneller als FireWire 800 und bis zu 20 Mal schneller als USB 2.0. Und sie bietet beispiellose Erweiterungsmöglichkeiten. Kurzum: Sie verändert alles, was Sie auf Ihrem Notebook machen können. Der Thunderbolt Anschluss gibt Ihnen Plug&Play Anschluss für eine völlig neue Welt von Thunderbolt Peripheriegeräten sowie für das Apple LED Cinema Display und andere Mini DisplayPort Peripheriegeräte. Sie können bis zu sechs Thunderbolt Geräte in Reihenschaltung anschließen, darunter auch Ihr Display. Außerdem unterstützt Thunderbolt Video und Achtkanal-Audio, sodass es auch möglich ist, HDMI-kompatible Geräte wie Fernseher oder Stereoanlagen über einen HDMI-Adapter anzuschließen. Auch aktuelle VGA-, DVI- und DisplayPort Adapter werden unterstützt.
     
    Die neue FaceTime HD Kamera. Der Unterschied ist ganz klar.
    Sehen Sie mehr von Ihren Freunden mit dem HD Widescreenformat - und zwar gestochen scharf. Die neue FaceTime HD Kamera bietet die dreifache Auflösung der vorherigen Kamera, was perfekt für das brillante Display mit LED-Hintergrundbeleuchtung ist. Außerdem arbeitet sie jetzt bei schwachem Licht noch besser. Sie können mit Ihren Freunden HD Telefonate in 720p von einem neuen MacBook Pro zu einem anderen führen. Außerdem sind auch Videotelefonate zu anderen Macs mit Intel Prozessor, zum iPhone 4 oder zum neuen iPod touch möglich.
     
    Multi-Touch Trackpad - Jede Menge Platz für GestenMulti-Touch Trackpad. Fürs tägliche Handwerk.
    Mit dem Multi-Touch Trackpad interagieren Sie auf ganz natürliche Art mit den Inhalten auf deinem Display. Und die glatte Glasoberfläche bietet jede Menge Platz für Gesten. Durch Auf- und Zuziehen können Sie ein- und auszoomen, durch Streichen in deinen Fotos blättern, durch Drehen ein Bild anpassen und vieles mehr. Das Trackpad kommt ohne Taste aus, sodass Sie überall klicken können. Wenn Sie aus der Welt des rechten Mausklicks kommen, können Sie diesen entweder mit zwei Fingern auslösen, oder Sie konfigurieren einen physischen Rechtsklick-Bereich auf dem Trackpad. Je mehr Sie mit dem Multi-Touch Trackpad vertraut sind, desto mehr werden Sie sich fragen, wie Sie jemals ohne ausgekommen sind.
     
    Lange Laufzeit. Weniger aufladen. Mehr machen.
    Das neue MacBook Pro bietet eine fantastische Batterielaufzeit und das mit leistungsstärkeren Prozessoren und schnelleren Grafikprozessoren. Die energieeffiziente Prozessorarchitektur mit integriertem Video-Encoder sowie das automatische Umschalten zwischen den Grafikprozessoren bei den 43,18 cm / 17"" Modellen helfen, die Batterielaufzeit weiter zu verbessern. So können Sie pro Ladung bis zu 7 Stunden ohne Kabel im Web surfen oder es für Liveauftritte oder auf ein Shooting mitnehmen. Die fortschrittlichen chemischen Eigenschaften und die Adaptive Charging Technologie sorgen dafür, dass die Batterie bis zu 1000 Ladezyklen durchlaufen kann. Und da die Batterie des MacBook Pro bis zu fünf Jahre hält, kommt das MacBook Pro in einem Zeitraum, in dem ein herkömmliches Notebook drei Batterien verbraucht, mit nur einer aus. Das ist für die Benutzer genauso gut, wie für die Umwelt. Apple verwendet eine neue, strengere Testmethode, um zu messen, welche Ergebnisse Sie unter realen Bedingungen erzielen, z. B. beim Surfen in einem Cafe oder wenn Sie die neuesten Webvideos ansehen. Und wie schneidet dieses MacBook Pro dabei verglichen mit der Vorgängergeneration ab? Es liefert die gleiche fantastische Leistung.
     
    Hat beste Verbindungen.
    Unterwegs haben Sie mit der 802.11n Technologie im MacBook Pro immer Verbindung. Das MacBook Pro findet automatisch verfügbare Netzwerke und Sie können sich mit einem Klick verbinden. Auch die drahtlose Bluetooth Technologie ist integriert, sodass Sie drahtloses Zubehör sofort nach dem Auspacken verwenden können.
     
    DVDs superschnell brennen.
    Homevideos, die Sie mit iMovie und iDVD gemacht haben, können Sie mit dem 8-fach SuperDrive Laufwerk des MacBook Pro superschnell auf eine DVD brennen. Das SuperDrive kann auch Double-Layer-DVDs (also DVDs mit fast 9 GB Speicherplatz) beschreiben, sodass es auch hervorragend für Datensicherungen geeignet ist.
     
    Neue Intel Core i7 Prozessoren.
    Neue Quad-Core Intel Core i7 Prozessoren sind Standard beim 43,18 cm / 17"" MacBook Pro. Alle Modelle verwenden die kürzlich optimierten Chipsets von Intel. Was heißt das für die neuen MacBook Pro Modelle? Kurz gesagt: Sie sind bis zu zwei Mal schneller als die Vorgängergeneration und erledigen auch anspruchsvolle Aufgaben wie HD Videoschnitt, Audiokompilierung oder Rendering mehrschichtiger Bilddateien unglaublich schnell. Und da Mac OS X Snow Leopard darauf ausgelegt ist, jeden Prozessorkern zu nutzen, holt das Betriebssystem wirklich alles an Leistung aus dem Prozessor heraus.
     
    Schnellere Einzelchip-Mikroarchitektur.
    Ob Sie einen Film ansehen, Ihren Blog auf den neuesten Stand bringen oder Fotos bearbeiten - die Daten müssen von A nach B gelangen, um verarbeitet werden zu können. Die neueste Intel Core Architektur bringt den Prozessor, den Cache, den Speichercontroller und den Grafikprozessor auf einem einzigen Chip unter. Deswegen müssen die Daten keine weiten Wege zurücklegen, was für Sie schnellere Performance und höhere Effizienz bedeutet.
     
    Turbo Boost 2.0.
    Angenommen, Sie arbeiten mit einem prozessorintensiven Programm wie Aperture 3 oder Final Cut Pro, das von einem Leistungsschub profitiert würde. Turbo Boost ist eine dynamische Technologie, die automatisch die Geschwindigkeit der aktiven Prozessorkerne auf 3,4 GHz erhöht. Turbo Boost 2.0 ist noch dynamischer und effizienter. Es wechselt die Kernfrequenz in kleineren Schritten als bisher, sodass der Prozessor die Leistung ohne Effizienzeinbußen verwalten kann. All das passiert im Hintergrund. Sie arbeiten einfach nur schneller.
     
    Hyper-Threading.
    Hyper-Threading ist jetzt Standard auf jedem MacBook Pro. Mit dieser Technologie können auf jedem Kern zwei Threads gleichzeitig laufen, Mac OS X erkennt also bei einem Quad-Core Prozessor acht und bei einem Dual-Core Prozessor vier virtuelle Kerne. Wenn Sie mehrere Programme gleichzeitig verwenden, verteilt der Prozessor die Aufgaben gleichmäßiger über eine größere Anzahl Kerne.
     
    Integrierter Speichercontroller.
    Mit schnellerem Speicherzugriff legt jeder Kern direkt mit der Verarbeitung der Daten los, statt auf ihr Eintreffen zu warten. Genau deshalb nutzt die neue Intel Core Architektur einen integrierten Speichercontroller, der den schnellen 1333 MHz Speicher direkt mit dem Prozessor verbindet und Ihre Programme immer die maximale Prozessorleistung zur Verfügung haben.
     
    Energieeffiziente Grafik.
    Dank der neuen Mikroarchitektur ist der Grafikprozessor auf dem gleichen Chip wie der Zentralprozessor und hat direkten Zugriff auf den L3-Cache. Kurze Wege bedeuten mehr Leistung. Der Grafikprozessor erhöht auch automatisch die Taktrate für noch höhere Auslastung. Ein integrierter Video-Encoder ermöglicht jetzt HD Videotelefonate mit FaceTime, und der effiziente Decoder sorgt für lange Batterielaufzeit, wenn Sie sich DVDs oder iTunes Filme ansiehen.
     
    Mac OS X. Das fortschrittlichste Betriebssystem der Welt.
    Mac OS X ist das Herz jedes MacBook Pro und Mac. Dieses Betriebssystem ist genau auf die integrierten Intel Multicore-Prozessoren und fortschrittlichen Grafikprozessoren zugeschnitten. Die neueste Version, Mac OS X Snow Leopard, basiert komplett auf einer 64-Bit-Architektur, genau wie alle anderen Programme, die mit dem Mac kommen. Das bedeutet: Alles, was Sie auf Ihrem MacBook Pro machen, passiert superschnell und mit einer unglaublichen Gesamtleistung.
     
    Hat eine ganze Menge draufProgramme, ebenso leistungsstark wie benutzerfreundlich.
    Weil Apple sowohl das MacBook Pro, wie auch die integrierte Software entwickelt, arbeitet alles perfekt zusammen. Und mit den Apple Programmen sind Sie ganz schnell vertraut, weil alle ähnlich funktionieren. Das heißt, wenn Sie ein Programm kennen, sind Sie auch schnell mit allen anderen vertraut. Außerdem weiß Apple genau, was mobile Produktivität bedeutet. Darum haben wir Funktionen wie Expose und Spaces hinzugefügt. Damit können Sie ganz einfach auf alles auf Ihrem MacBook Pro zugreifen. Expose zeigt sämtliche geöffneten Fenster nebeneinander, verkleinert sie und ordnet sie so, dass Sie den Inhalt jedes Fensters sehen können - ein Tastendruck oder eine Geste genügt. Und mit Spaces können Sie Fenster zusammen auf ihrem eigenen Schreibtisch oder Bereich gruppieren und ganz einfach zwischen diesen wechseln. Legen Sie einen Bereich zum Arbeiten fest, einen zum Spielen und einen für was auch immer. Mit Expose und Spaces haben Sie beim Multitasking auf einem Notebookdisplay einen riesigen Vorteil.
     
    Darauf verzichten Sie beim Mac: PC-Viren.
    Trojaner, Würmer, E-Mail Viren. Die digitale Welt kann ganz schön beängstigend sein. Zum Glück ist der Mac immun gegen die tausenden von Viren, die Windows Computer plagen. Denn Mac OS X kommt mit integrierten Sicherheitsmechanismen, die Sie schützen - ohne dass Sie etwas machen müssen. Und sollten doch mal potenzielle Sicherheitsrisiken auftreten, reagiert Apple sofort und stellt neue Softwareaktualisierungen und Sicherheitsverbesserungen bereit, die Sie automatisch laden und mit einem Klick installieren können.
     
    Das automatische Backup rettet Ihren Tag. Und die Woche, den Monat ...
    Backups müssen sein. Trotzdem vergissen Sie sie bestimmt hin und wieder. Deshalb kümmert sich jetzt das MacBook Pro um die Datensicherung. Time Machine, ein Programm, das auf jedem Mac dabei ist, sichert automatisch Ihr ganzes System auf einer externen Festplatte oder Time Capsule. Time Machine speichert eine Kopie von jeder Datei. Und es merkt sich, wie Ihr System an einem bestimmten Tag ausgesehen hat. So können Sie, wenn Sie wollen, die Zeit zurückdrehen und Ihren Mac wie in der Vergangenheit sehen.
     
    Mit iMovie können Sie aus Ihren Videos großartige Filme machenAuch die täglichen Sachen machen mehr Spaß.
    Anders als viele PC-Notebooks kommt das MacBook Pro mit allem, was Sie brauchen, um E-Mails zu senden, Kalender zu verwalten, Kontakte zu organisieren und mehr. Und Sie können schon wenige Minuten nach dem Auspacken damit loslegen. Denn jeder Mac kommt mit Mail, um E-Mails zu senden und empfangen, iCal zum Organisieren von Terminen und wichtigen Ereignissen, dem Adressbuch zum Verwalten von Kontakten, iTunes für alles, was mit Unterhaltung zu tun hat, und weiteren tollen und nützlichen Programmen, die Sie jeden Tag verwenden werden.
     
    Der Mac App Store. Tausend weitere Gründe, den Mac zu lieben.
    Über tausend Mac Apps sind nur einen Klick entfernt - im Mac App Store. Suchen Sie einfach Apps, die Ihnen gefallen, und klicken Sie einfach, um sie zu laden und zu installieren. Ohne Verpackung. Ohne CDs oder DVDs. Und ohne Probleme. Sie können die Apps nach Kategorien durchstöbern oder direkt etwas Bestimmtes suchen. Und Sie können einfach dafür sorgen, dass Ihre Apps up-to-date sind, denn Ihr Mac zeigt Ihnen an, wann Updates verfügbar sind.
     
    iPhoto. Fotos ganz einfach verwalten, bearbeiten und teilen.
    iPhoto ist ein benutzerfreundliches Programm für Fotos, mit dem Sie Ihre Bilder schnell organisieren, wiederfinden und verbessern können - sodass sie immer perfekt aussehen. Mit den iPhoto Funktionen ""Gesichter"", ""Orte"" und ""Ereignisse"" behalten Sie den Überblick über Ihre Fotos. Sie sagen Ihnen, wen Sie fotografiert haben, wo und wann. Und all das in den neuen Vollbildmodi.
     
    iMovie. Und aus Homevideos werden Home-Blockbuster.
    Homevideos müssen nicht langweilig sein. Mit iMovie können Sie aus Ihren Videos großartige Filme machen. Zum Beispiel Trailer im Hollywoodstil, mit denen Sie Ihr Publikum begeistern.
     
    GarageBand. Großartige Musik machen, ganz einfachissimo.
    Egal, ob Sie Musiktalent haben oder einfach nur neugierig sind - GarageBand ist genau das richtige Programm für Sie. Schließ einfach eine elektrische Gitarre oder ein USB Keyboard an. Und schon können Sie mit virtuellen Nachbildungen der bekanntesten Amps und Stompboxes der Welt sowie mit 100 Software-Instrumenten spielen.  
    ";2;False;0;;;Apple MacBook Pro MC725D/A 17 Zoll Notebook;apple-macbook-pro-mc725da-17-zoll-notebook;True;True;P-0700;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;2,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;2299.9000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;40652,5987037037;3;1;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000312-apple-macbook-pro-mc725da-17-zoll-notebook.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000313-apple-macbook-pro-mc725da-17-zoll-notebook.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000314-apple-macbook-pro-mc725da-17-zoll-notebook.jpg;2;;False;;;;;False;False;False;;;;;False;;;;;; +5;0;True;Apple iPod Nano 8 GB 6. Gen. verschiedene Farben;Apple iPod Nano 8 GB 6. Generation verschiedene Farben;"
    Der Remix für Ihre Finger
    Der iPod nano mit Multi-Touch ist einfach, intuitiv und macht jede Menge Spaß - wie Ihre Musik. Und er ist jetzt noch kleiner, damit Musik bei allem, was Sie machen, eine größere Rolle spielen kann.
     
    Musik. Fühlen Sie den Beat
    Ihre Greatest Hits. Zum Anfassen
    Die besten Dinge im Leben kommen mit Soundtrack. Und genau da glänzt der iPod nano. Mit dem Multi-Touch Display können Sie Ihre Musik ganz neu erleben. Ein Tipp genügt und er spielt, was Sie hören wollen. Stöbern Sie in Ihrer Musik nach Songs, Alben, Interpreten, Wiedergabelisten, Genres oder Komponisten - streichen Sie dazu über den Homescreen. Sie können sogar die Symbole auf dem Homescreen neu ordnen, damit alles so ist, wie Sie es wollen.
     
    Das ist ein echter Musikclip
    Mit dem neuen integrierten Clip können Sie mit Ihren Lieblingssongs am Ärmel (oder in der Tasche, Jacke oder Hose) wandern, laufen, Rad fahren und abrocken. Und das Cover zum Song, der gerade läuft, passt perfekt auf das Display.
     
    Rock around the clock
    Die integrierte aufladbare Lithium-Ionen-Batterie sorgt für 24 Stunden Musik nonstop. Wenn Sie sich den 8 GB oder 16 GB iPod nano anklippen, haben Sie genug Songs für den Weg zur Arbeit, fürs Training und mehr.
     
    Songs aus dem Finger schütteln
    Überlassen Sie alles dem Zufall. Einfach den iPod nano kurz schütteln und er springt zu einem anderen Song aus Ihrer Sammlung. Schütteln ist perfekt, wenn Ihnen gerade nicht nach einer bestimmten Musik ist. Lassen Sie sich einfach überraschen.
     
    Genius. Ihr Mixmaster
     
    Eingebauter Clip

     
    Ihr persönlicher DJ
    Angenommen, Sie hören einen Song, der Ihnen gut gefällt, und möchten ähnliche hören. Ein Tipp auf Genius genügt. Genius findet weitere Songs auf Ihrem iPod nano, die gut dazu passen und erstellt eine Genius Wiedergabeliste für Sie. Wenn Sie einen Mix wollen, auf den Sie selbst nie gekommen wären, erstellen Sie einen Genius Mix in iTunes und synchronisieren ihn mit Ihrem iPod nano. Tippen Sie auf das Symbol für Genius Mixe und entdecken Sie Songs, die Sie lange nicht mehr gehört haben, oder Musik, von der Sie gar nicht mehr wussten, dass Sie sie haben.
     
    FM Radio. Und Sie haben alles auf dem Sender
    Radio nano
    Mit dem iPod nano können Sie auf der Radiowelle surfen. Der FM Tuner zeigt Ihnen den Interpreten, Song oder Sender, der gerade läuft. Ein Tipp genügt und Sie sehen die Radiosteuerungen. Streichen Sie über den Tuner, um den Sender zu wechseln, und stellen Sie dann Ihre Lieblingssender per Fingertipp ein.
     
    Live-Pause
    Wenn Sie Ihre Lieblingssendung im Radio einmal kurz unterbrechen müssen, verpassen Sie dank Live-Pause trotzdem keinen einzigen Beat. Einfach Tippen und Sendung oder Song werden angehalten. Noch mal Tippen und es geht da weiter, wo Sie aufgehört haben. Sie können sogar bis zu 15 Minuten zurückspulen und dann vorspulen, um wieder live dabei zu sein.
     
    Fitness. Treffen Sie Ihren neuen Trainer
     
    Anklippen und los geht´s
    Das neue Design des iPod nano hilft Ihnen fit zu bleiben. Weil er so klein und tragbar ist, ist er auch beim Joggen, Wandern und im Fitnessstudio immer dabei. Klippen Sie ihn an und steuern Sie Ihre Musik mit nur einem Tippen oder Streichen, sodass Sie sich voll auf Ihr Workout konzentrieren können. Ob Laufen, Walken oder der Weg zum Fitnessstudio - für den kleinen iPod nano ist kein Weg zu weit.
     
    Schritte zum Fitbleiben
    Sie können den iPod nano auch als Schrittzähler verwenden. Er zählt Ihre Schritte und hilft Ihnen beim Erreichen Ihrer Fitnessziele. Einfach anklippen und los geht´s. Sie können eine tägliche Schrittvorgabe festlegen und Ihre Fortschritte sehen, wenn Sie Ihre Daten auf die Nike+ Website laden.
     
    Rocken Sie Ihr Training
    Ob beim Joggen oder im Fitnessstudio, mit dem Nike + iPod Sport Kit (separat erhältlich) motiviert Sie der iPod nano vom Warm Up bis zum Cool Down. Ziehen Sie Ihre Nike+ Joggingschuhe an und klippen Sie sich den iPod nano an. Sehen Sie wie Sie Kilometer für Kilometer zurücklegen und hören Sie das Sprachfeedback in Echtzeit, während Ihre Songs laufen. Schließen Sie den iPod nano im Fitnessstudio an ein Gerät an, das mit Nike + iPod kompatibel ist. So zeichnet er Ihre Geschwindigkeit, die Dauer und die Laufstrecke auf, während Sie Ihr Training rocken.
     
    iTunes. Damit der iPod was zu spielen hat
    Alles für gute Unterhaltung
    iTunes ist der beste Weg, Ihren iPod nano mit den neuesten Hits, Podcasts, Hörbüchern und vielem mehr zu füllen. Und auch die beste Art, Ihre immer weiter wachsende Sammlung digitaler Medien zu durchstöbern und auf dem Mac oder PC zu organisieren. Alle im iTunes Store gekauften Inhalte und alle von CDs importierten Songs werden in Ihrer Mediathek in iTunes angezeigt. Sie können Ihre eigenen oder Genius Wiedergabelisten erstellen, Genius Mixe auswählen und alles mit Ihrem iPod nano synchronisieren. Und iTunes ist als kostenloser Download verfügbar.
     
    Der beste Music Store der Welt
    Laden Sie Ihre Lieblingssongs auf Ihren iPod nano. Oder stöbern Sie in über 13 Millionen Songs und finden Sie weitere Hits. Sie können nach dem Namen eines Interpreten, Songs oder Albums suchen und so genau die richtigen Songs finden. Sie suchen neue Musik und brauchen Hilfe? Die Genius Seitenleiste empfiehlt Ihnen neue Musik, die auf Ihren Lieblingssongs basiert. Sie können in jeden Song kostenlos 30 Sekunden reinhören. Und mit einem Klick können Sie einen Song kaufen. Er wird dann sofort geladen. Schneller und einfacher können Sie Ihre digitale Musiksammlung für den iPod nicht zusammenstellen.
     
    Bedienungshilfen
    Integrierte Bedienungshilfen.
    iPod nano kommt mit Bedienungshilfen, die Menschen mit Handicaps helfen Musik, Hörbücher und mehr zu erleben.
     
    VoiceOver
    Der iPod touch bietet VoiceOver, die weltweit erste Bildschirmlesefunktion, die auf Gesten basiert. Tippen Sie auf das Display und Sie hören eine Beschreibung des Objekts, das Sie gerade berühren. Steuern Sie den iPod nano durch Doppeltippen, Bewegen oder Streichen. Mit den optionalen Apple Earphones mit Fernbedienung und Mikrofon können Sie Ihre Musik steuern, ohne auf das Display zu sehen. VoiceOver nennt Ihnen den Song und Interpreten und spricht auch noch 29 Sprachen.
     
    Weiß auf Schwarz
    Wenn Sie stärkeren Kontrast möchten, stellen Sie das Display des iPod nano so ein, dass Weiß auf Schwarz angezeigt wird. Sie können diese Funktion in jeder App und auch auf dem Homescreen verwenden.
     
    Mono Audio
    Wenn Sie nur auf einem Ohr gut hören können, können Sie ""Mono-Audio"" aktivieren, damit die Audioausgabe auf beide Ohrhörer geleitet wird und Sie beide Kanäle mit dem gesunden Ohr hören können.

    Produktbeschreibungen
     
    Highlights
    - Multi-Touch Display
    - Genius - dein Mixmaster
    - FM Radio
    - iTunes
    - Integrierte Bedienungshilfen (VoiceOver und Weiß auf Schwarz)
     
    Akku
    - Akkutyp: Li-Ion
    - Akkulaufzeit bis zu 24 Stunden
     
    Display
    - Farbdisplay
    - Bilddiagonale: 3,91 cm
    - 1,54- Display
    - Auflösung Breite: 240 Pixel
    - Auflösung Höhe: 240 Pixel
     
    Speicher
    - Interner Speicher 8.000 MB
     
    Stromversorgung
    - USB-Lader
     
    Wiedergabeformate Audio
    - AAC
    - MP3
    - WAV
     
    Grundeigenschaften
    - Breite: 40,9 mm
    - Höhe: 37,5 mm
    - Tiefe: 8,78 mm
    - Gewicht: 21,1 g
    - Gewicht: 21,1 g
    - Farbe: Dunkelgrau
     
    Lieferumfang
    - iPod nano
    - Apple Earphones
    -Dock Connector auf USB Kabel
    - Dokumentation und wichtige Produktinformationen
    ";2;False;0;;;Apple iPod Nano 8 GB 6. Gen. verschiedene Farben;apple-ipod-nano-8-gb-6-gen-verschiedene-farben;True;True;PD-01073;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;149.9000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;40652,5607638889;49;1;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000266-apple-ipod-nano-16-gb-6-gen-verschiedene-farben.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000267-apple-ipod-nano-16-gb-6-gen-verschiedene-farben.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000268-apple-ipod-nano-16-gb-6-gen-verschiedene-farben.jpg;3;;False;;;;;False;False;False;;;;;False;;;;;; +5;0;True;Apple MacBook Air MC966D/A-i7 13,3 Zoll Notebook;"Apple MacBook Air 33,78cm (13,3"") 1,8GHz i7 4GB 256GB SSD";"
    Eindrücke:
    Bei der Entwicklung des neuen MacBook Air gab’s nur ein Ziel: ein unglaublich dünnes und leichtes Notebook, genauso leistungsstark und vielseitig wie doppelt so große Geräte. Und mit Flash-Speicher,
     
    stabilem Unibody-Gehäuse, Multi-Touch und einer ausdauernden
     
    Batterie erreicht das MacBook Air nicht nur das Ziel, es ist der neue Standard, wie ein Notebook sein sollte. Perfekt bis ins letzte Detail.
     
    Design:
    Gerade mal 1,7 cm flach. Aber damit legt das neue MacBook Air die Messlatte sehr hoch - und es macht den Flash-Speicher zum Maßstab. Da Flash-Chips so klein sind, ist das MacBook Air so unglaublich dünn und leicht. Diese Flash-Chips sind Solid-State-Komponenten, sie arbeiten ohne bewegliche Teile. Das macht sie zuverlässig, robust und sehr leise beim Arbeiten. Und da wir sie direkt auf der Hauptplatine platzieren, brauchen sie viel weniger Platz – etwa 90 % weniger, um genau zu sein. Es bleibt mehr Platz für andere wichtige Dinge. Zum Beispiel eine größere Batterie. Damit ist ein Notebook entstanden, das fast nichts wiegt und mit einer Batterieladung stundenlang durchhält. So entsteht echte Mobilität.
     
    Umweltverträglichkeit:
    Die folgenden Merkmale des MacBook Air tragen zu seiner geringeren Umweltbelastung bei:
     
    Frei von bromhaltigen Flammschutzmitteln
    Ohne PVC
    PVC-freie Netzkabel sind in Australien, Japan, Neuseeland, Nord- und Südamerika, der Schweiz, Taiwan, Thailand und Großbritannien verfügbar.
    Hochgradig recyclebares Aluminiumgehäuse
    ENERGY STAR 5.2 konform
    EPEAT-Bewertung ""Gold""
    Das MacBook Air hat in den USA und Kanada von der EPEAT die Bewertung ""Gold"" erhalten.
     
    Mitgelieferte Software:
     
    OS X Lion
    Enthält Mail, Adressbuch, iCal, Mac App Store, iTunes, Safari, Time Machine, FaceTime, Photo Booth, Mission Control, Launchpad, AirDrop, Resume-Funktion, automatisches Sichern, Versionen, Übersicht, Spotlight, QuickTime und mehr.
     
    iLife '11
    Enthält iPhoto, iMovie und GarageBand.
     
    Display:
     
    Hochauflösendes 13,3"" Hochglanz-Widescreendisplay mit LED-Hintergrundbeleuchtung (33,78 cm Diagonale), Unterstützung für Millionen Farben
     
    Unterstützte Auflösungen:
     
    1440 x 900 (nativ), 1280 x 800, 1152 x 720 und 1024 x 640 Pixel bei einem Seitenverhältnis von 16:10, 1024 x 768 und 800 x 600 Pixel bei einem Seitenverhältnis von 4:3
    ";2;False;0;;;Apple MacBook Air MC966D/A-i7 13,3 Zoll Notebook;apple-macbook-air-mc966da-i7-133-zoll-notebook;True;True;P-0720;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;2,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;1599.9000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;40652,0359953704;4;1;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000465-apple-macbook-air-mc966da-i7-133-zoll-notebook.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000466-apple-macbook-air-mc966da-i7-133-zoll-notebook.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000467-apple-macbook-air-mc966da-i7-133-zoll-notebook.jpg;2;;False;;;;;False;False;False;;;;;False;;;;;; +5;0;True;Samsung Galaxy S II (i9100) DualCore Smartphone weiß;Samsung Galaxy S II (i9100) DualCore Smartphone (10.9 cm (4.3 Zoll) Super-Amoled Plus Display, Android 2.3, 8 MP Full-HD Kamera, 2 MP Frontkamera) weiß;"
    Samsung launcht mit dem Galaxy S II den Nachfolger des Bestsellers Galaxy S. Das Galaxy S II ist nicht nur das schlankste (8,49 mm), sondern dank des 1,2 GHz Dual-Core Prozessors auch das schnellste Smartphone seiner Klasse. Darüber hinaus besticht es durch ein 4,3"" Super Amoled Plus Touch-Display. Das Galaxy S II verwendet als Betriebssystem die aktuellste Android 2.3 Version – auch bekannt unter dem Namen Gingerbread. Die integrierte 8 Megapixel Kamera mit LED Blitz hält die schönsten Momente in erstklassiger Qualität fest – darüber hinaus ermöglicht die 2 Megapixel Frontkamera Video Telefonate in beeindruckender Qualität. Das Schreiben von E-Mails und SMS gelingt unkompliziert dank Swype®-Texteingabe. Zahlreiche aktuelle und nützliche Apps stehen im Android Market™ zum Download bereit. Die integrierte Google Maps Navigation™ führt ans gewünschte Ziel. AllShare, HD Video, Exchange ActiveSync und eine Vielzahl an weiteren Applikationen lassen keine Wünsche offen. Ein erstklassiges Zusammenspiel von Hardware und Funktionen leistet sein Übriges für ein ausgezeichnetes Nutzererlebnis auf höchstem Niveau!
     
    4,27-Zoll SUPER AMOLED Plus
    Bekennen Sie Farbe! Dieses brillante Display bietet den besten Farbumfang, ein hohes Kontrastverhältnis sowie ultimative Schärfe bei Bildern. Die bahnbrechende Verkürzung der Video-Reaktionszeit sorgt für ruckfreie Videowiedergabe. Die neue Technologie benötigt weniger Platz und Energie: Im Vergleich zum Vorgänger benötigt das Display 18% weniger Energie. Es ist damit eines der dünnsten, langlebigsten Smartphones am Markt.
     
    Brillante Performance
    Das Unmögliche ist möglich. Der Samsung Dual Core Application Prozessor ist die reaktionsschnelle Antwort im Bereich mobile Performance. Er bietet Multitasking in Hochgeschwindigkeit, schnelles Laden von Internetseiten, schnelle Reaktionszeiten, eine intuitive Benutzeroberfläche, blitzschnelle Bildbearbeitung und Spiele mit hoher Performance. Und mit der superschnellen Möglichkeit zum Encodieren und Decodieren, die alles im Bereich Videoaufzeichnung und -wiedergabe (1080p / 30fps) unterstützt, stellt er alle anderen Dual Core-Prozessoren in den Schatten. Problemloses Video- oder Musik-Streaming bekommt dank des schnellen Drahtlosstandards HSPA 21 Mbps einen großen Schub. Hervorragende Rechenleistung, herausstechende Performance.
     
    Schlankes Design
    Schlank, schlanker, GALAXY S II. Das Samsung GALAXY S II führt die Riege an – mit nur 8,49 mm und einem luxuriösen Design liegt es zudem gut in der Hand. Das GALAXY S II ist eines der schlanksten Smartphones und bietet außerdem HyperSkin für einen schönen Metall-Look mit einer fingerabdruckfreien und rutschfesten Akkuabdeckung.
     
    Readers Hub
    Lassen Sie Ihre Bücher zu Hause: Das Samsung GALAXY S II übernimmt diese Aufgabe. Stöbern Sie im Readers Hub in Ihrer Bücherei mit Klassikern oder suchen Sie in mehr als 2 Millionen Büchern die neusten Bestseller. Sie können auch 2.500 Magazine in 20 Sprachen und 1.600 Zeitungen in 47 Sprachen zur Lieferung einrichten. Mit klarem, deutlichem Text und der hohen Bedienerfreundlichkeit macht das Lesen Spaß: vergrößern, nur Text und Seitenansichten, Audiozugriff sowie schnelles Verteilen per E-Mail sind nur einige Funktionen. Glauben Sie an Bücher, beschränken Sie sich jedoch nicht nur auf Papier.
     
    8-Megapixel-Kamera mit LED-Blitz
    Immer gute Fotos. Der 8-Megapixel-Kamera mit Autofokus entgehen auch bei Action-Fotos keine Details. Machen Sie auch bei schlechten Lichtverhältnissen mit dem integrierten LED-Blitz wunderschöne und detaillierte Aufnahmen. Und dank der stark verbesserten Benutzeroberfläche von Android Gingerbread ist selbst schneller Szenenwechsel möglich. Wechseln Sie problemlos auf die 2-Megapixel-Kamera vorne, um Selbstporträts zu machen. Einfach immer gute Bilder.
     
    Aufzeichnung & Wiedergabe in Full-HD
    Werden Sie zum Star. Mit den Möglichkeiten zur Videoaufzeichnung des Samsung GALAXY S II können auch Sie zur Berühmtheit werden. Mit der 1080p Full-HD-Aufzeichnung ist jeder Moment ein potenzielles Meisterwerk in der Entstehung. Erfassen Sie die Action in hoher Auflösung und mit Dual Core-Geschwindigkeit und geben Sie Ihre HD-Aufzeichnungen mit bestechender Klarheit auf dem 4,3"" SUPER AMOLED Plus Display wieder.
     
    Spracherkennung & Sprachübersetzung
    Einfach Sprachbefehle nutzen. Tippen Sie nur doppelt auf die Home-Taste und steuern Sie das Samsung GALAXY S II mit ausgewählten Sprachbefehlen. Führen Sie wichtige Funktionen wie anrufen, Musik hören oder SMS schreiben mit einfachen Sprachbefehlen aus. Sie können auch Ihre Gedanken festhalten, sich selbst eine Notiz schreiben oder unterwegs sogar mit Google Voice Translation eine Übersetzung anfertigen. Galaxy S II kann Ihnen eingehende Nachrichten auch vorlesen.
     
    Game Hub
    Noch mehr Spielspaß. Über den Game Hub von Samsung GALAXY S II können Sie hochwertige Spiele herunterladen: 12 soziale Netzwerkspiele und 13 Prämiumspiele einschließlich Gameloft’s Let Golf 2 und Real Football 2011. Sie können nach Spielen und Informationen zu Neuerscheinungen suchen oder einfach nur spielen. Mit einem Beschleunigungsaufnehmer, einem magnetischen Sensor und Gyroskop-Sensor heben sich Spiele mit Hand- und Armbewegungen deutlich aus der Masse ab. Die kleinste Bewegung reicht bereits aus – das ist spannende Unterhaltung.
     
    Social Hub
    Mit dem Social Hub lassen sich Ihre Online-Kontakte besser organisieren und synchronisieren. Sammeln Sie Ihre Informationen aus E-Mails, SMS, IM und SNS in einem einheitlichen Posteingang – Interaktionen mit anderen sind so schneller und auf die von Ihnen gewünschte Art möglich.
     
    Music Hub
    Musik darf nicht fehlen. Der neue native Music-Player von Samsung bietet ein intuitives Wiedergabesystem zum Suchen, Entdecken, Anspielen, Kaufen und Herunterladen von Musikstücken für unterwegs. Die App bietet auch viele Informationen zum Kauf sowie Zugriff auf alle gewünschten Künstler, Liedtexte und Bewertungen. Sie können Empfehlungen für neue Songs abrufen und durch Bassverstärkung und 5.1 Kanal-Sound den Hörspaß noch mehr steigern.
     
    Microsoft Exchange ActiveSync
    Das Samsung GALAXY S II ist für sicheren Zugriff auf Unternehmensressourcen auf einem Microsoft Exchange Server optimiert, damit Sie in Bezug auf geschäftliche E-Mails, Terminplaner, Kontakte und Aufgabensynchronisation auf dem Laufenden sind. Das Handy bietet die umfangreichste mobile Implementierung von Exchange ActiveSync. Es bietet das sicherste Mobile Device Management unter den Smartphones und unterstützt die meisten Richtlinien und Einschränkungen unter den Android ActiveSync Clients und ermöglicht Kommunikation in Echtzeit mit Telefonen der Mitarbeiter, um Einstellungen per Fernzugriff zu konfigurieren, die Einhaltung der Richtlinien zu überwachen, die Sicherheit bei synchronisierten Daten zu gewährleisten und verwaltete Telefone zu sperren oder Daten zu löschen.
    ";2;False;0;;;Samsung Galaxy S II (i9100) DualCore Smartphone weiß;samsung-galaxy-s-ii-i9100-dualcore-smartphone-weiss;True;False;P-0020;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;439.9000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;40651,9089699074;76;5;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000473-samsung-galaxy-s-ii-i9100-dualcore-smartphone-weis.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000474-samsung-galaxy-s-ii-i9100-dualcore-smartphone-weis.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000475-samsung-galaxy-s-ii-i9100-dualcore-smartphone-weis.jpg;2;;False;;;;;False;False;False;;;;;False;;;;;; +5;0;True;HTC Hero;"HTC Hero ";"
    HTC Hero Smartphone ohne Vertrag, ohne Branding, kein Simlock
    Probiere etwas Neues. Sei Du selbst.
     
    Der HTC Hero bietet Dir das ultimative HTC-Erlebnis. Du kannst dieses Smartphone wie kein anderes an Deine individuellen Bedürfnisse anpassen und machst es dadurch zu einem Mobiltelefon, das wie für Dich geschaffen ist. Es verbindet Dich leichter denn je mit den Menschen, die für Dich wichtig sind. - Denn alle Kommunikationen werden nach Personen anstatt nach Anwendungen organisiert. Der HTC Hero wird Dir - egal wo Du gerade bist und was Du gerade machst - das Leben durch seine einfache und intuitive Bedienung erleichtern. So, wie Du es Dir von Deinem Handy immer gewünscht hast!
     
    Make it your Hero
    Der HTC Hero ermöglicht Dir einen Level der Personalisierung, den kein anderes Smartphone bislang geboten hat. Anstatt wichtige Anwendungen hinter zahlreichen Menüstrukturen zu verstecken, kannst Du sie nun dort positionieren, wo Du direkten Zugriff hast: nämlich direkt auf einem der 7-teiligen Homescreens! Und weil HTC an die absolute Personalisierung glaubt, kannst Du auch viele Widgets mit vielfältigen Designs und in verschiedener Größe anpassen, ganz nach Deinem Geschmack. Das interaktive Erlebnis geht weiter, wenn Du z.B. einen Aktien-Ticker auf den Homescreen legst oder Dir die aktuelle Wettervorhersage für heute oder auch gleich für die nächsten fünf Tage auf einen Blick anzeigen lässt.
     
    Stay close with friends
    Die vernetzte Welt bietet uns zwar die Möglichkeit, mit mehr Menschen als jemals zuvor in Kontakt zu bleiben, aber den Überblick über alle Kontakte zu behalten, wird immer schwieriger. Statt umständlich eine Anwendung nach der anderen zu öffnen, um Deine Freunde zu kontaktieren, funktioniert das mit dem HTC Hero einfacher: Wenn Du Deine Kontakte aufrufst, siehst Du auf einen Blick die verschiedenen Möglichkeiten der Kontaktaufnahme und alle bisherigen Interaktionen - einschließlich der E-Mails, die Du an Deine privaten und beruflichen E-Mail-Adressen erhalten hast. Außerdem kannst Du direkt Status-Updates in Deinen Social Communities verfolgen und Dir die neuesten Fotos ansehen, die Deine Freunde gerade hochgeladen haben.
     
    Discover the Unexpected
    Selbst grundlegende Dinge wie die Anruf-Funktion werden Dich beim HTC Hero angenehm überraschen. Denn Du findest eine Person, indem Du ihre Telefonnummer wählst oder einfach nur die ersten Buchstaben ihres Namens eingibst. Und während Du in der Kontakt-Ansicht bist, kannst Du auch gleich einmal nachsehen, ob Dein Kontakt bald Geburtstag hat oder neue Infos oder Bilder auf Facebook oder Flickr eingestellt hat.
     
    Mit dem HTC Hero kannst Du Deine Inhalte immer aus der Perspektive betrachten, die Dir gerade am besten passt. Deine Inbox ist zum Beispiel nicht nur eine Liste mit E-Mails, sondern vielmehr ein Konversations-Chat. Mails mit Anhängen kannst Du in einer separaten Dokumenten-Bibliothek ansehen. Die Fotos in Deinem Fotoalbum sind nicht nur auf Deinem Handy abgespeichert, sondern Du kannst sie via Upload auf Facebook oder Flickr auch mit Deinen Freunden teilen.
     
    Suche und finde einfach alles, überall – mit Deinem HTC Hero. Anhand des Such-Buttons durchsuchst Du Tweets in Twitter, findest Personen in Deiner Kontaktliste, suchst nach E-Mails in Deinem Posteingang oder Terminen in Deinem Kalender… und selbst die sprichwörtliche Suche nach der Nadel im Heuhaufen ist so von Erfolg gekrönt.
     
     
    ";2;False;0;;;HTC Hero weiß;htc-hero;True;True;P-0015;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;449.0000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;40651,7809027778;"73;2095";36;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000344-htc-hero.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000345-htc-hero.jpg;;2;;False;;;;;False;False;False;;;;;False;;;;;; +5;0;True;LG KM 900 Arena;LG KM 900 Arena;"LG KM 900 Arena
     
    FM Transmitter, GPS, 5MP,WLAN 
     

    brilliantes, hochauflösendes 3Zoll Touchscreen
    benutzerfreundliches S-Class User Interface durch taktiles Feedback bei Tastendruck & Widgets
    Dolby Mobile Surround Sound und FM Transmitter für ein einzigartiges Musikerlebnis
    FM-Radio mit Senderspeicher und FMTransmitter
    Lieferumfang: Gerät, Akku, Ladegerät, stereo Kabel, Headset, Bedienungsanleitung, USB Datenkabel, PC-Software ";2;False;0;;;LG KM900 Arena;lg-km-900-arena;True;True;P-0026;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;219.0000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;40651,7531597222;"72;2095";19;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000233-lg-km-900-arena.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000234-lg-km-900-arena.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000235-lg-km-900-arena.jpg;2;;False;;;;;False;False;False;;;;;False;;;;;; +5;0;True;HTC Touch Diamond 2;HTC Touch Diamond 2;"
    HTC Touch Diamond II
     
    Brillantes Design und intuitive Bedienung sorgen schon beim ersten Ausprobieren für ein faszinierendes Erlebnis.
    Der HTC Touch Diamond2 liefert ein komplett neues Erlebnis mobiler Kommunikation, das die Interaktionsfähigkeit mit anderen Menschen spürbar vereinfacht.
     
    In Kombination mit der neuen TouchFLO™ 3D-Oberfläche ist der HTC Touch Diamond2 das aktuell attraktivste Smartphone für Konsumenten, die auf Design und Funktion setzen.
     
    Erstmals präsentiert HTC einen personenzentrischen Kommunikationsansatz: Zu jeder Kontaktperson steht die gesamte Konversationshistorie auf einen Fingerstreich zur Verfügung, unabhängig von der Art der Kommunikation wie Sprache, Text oder E-Mail.
     
    Features
     
    5-Megapixel-Kamera mit Autofokus
    Erweitertes TouchFLO 3D für eine bessere intuitive Nutzung
    3,2” WVGA LCD Touchscreen mit 480x800 Pixeln
    Zoom-Leiste für präzises Hinein- und Heraus- Zoomen in Bildern, Webseiten oder Google Maps™
    microSD™ (SD 2.0-kompatibel) Erweiterungs-Slot 
     
    Mehr als ein Telefongespräch
    In der heutigen Zeit gibt es viele verschiedene Arten der Kommunikation, doch sie haben alle etwas gemeinsam: Am anderen Ende befindet sich immer eine Person. Aus diesem Grund ermöglicht Ihnen der HTC Touch Diamond2, Ihre Kommunikation nach Personen zu organisieren – nicht nur nach der Art wie Sie kommunizieren.
     
    In Ihren Kontakten befindet sich Ihre gesamte Kommunikations-Historie – egal ob E-Mail, SMS oder Telefongespräch. Es spielt keine Rolle, ob Sie während eines Gesprächs nach einer E-Mail gefragt werden oder Sie in einem Café sitzend einen Text abrufen möchten – alle Interaktionen sind nach Personen geordnet in einem Kommunikationsbaum abgelegt.
     
    Erweitern Sie Ihr Blickfeld
    Eine unbestrittene Tatsache bei Smartphones – ein großer Bildschirm bei einem kleinen Gerät, das ist gut. Genau darum haben wir das Display des Touch Diamond2 so groß wie möglich designt, bei gleichbleibend kompaktem Gehäuse. Genießen Sie Videos, Webseiten, Fotos und andere Abbildungen auf dem ultra-scharfen Widescreen-Display – es lässt auch das kleinste Detail erkennen. 
    Schön und leistungsfähig zugleich
    Das Mobiltelefon ist eines der wenigen Gegenstände, die wir heutzutage immer an unserer Seite haben. Es hilft uns nicht nur mit unseren Freunden, Geschäftspartnern und dem weltweiten Geschehen verbunden zu sein – es ergänzt uns. Der Touch Diamond2 ist Ihr perfekter Begleiter: Er hält Sie auf dem Laufenden und ist stilvolles Accessoire zugleich.
    Mit seinem klaren und doch elegantem Design ist das HTC Touch Diamond 2 ein Smartphone mit Stil und Eleganz. Seine einfache Handhabung über den TouchFlo-3D- Bildschirm überzeugt. Feinste Sensoren garantieren eine empfindliche, daher schnelle Bedienbarkeit. Ein neues Erlebnis von mobiler Kommunikation ob im privaten oder im business-Bereich.
     
    Die zahlreichen Funktionen sind komfortabel zu bedienen, die ausgeprägte Technik im HTC Touch Diamond 2 vereint zahlreiche Funktionen mit wenig Aufwand. Als Navigationsgerät ein zuverlässiger Wegweiser ist das HTC Touch Diamond 2 ein edler Begleiter, nicht zuletzt durch die zahlreichen Onlinefunktionen für Unterwegs der ideale Communicator.
     
    ";2;False;0;;;HTC Touch Diamond 2 Smartphone;htc-touch-diamond-2;True;True;P-0012;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;399.0000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;40651,7106365741;73;36;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000198-htc-touch-diamond-2.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000199-htc-touch-diamond-2.jpg;;2;;False;;;;;False;False;False;;;;;False;;;;;; +5;0;True;HTC Touch HD;HTC Touch HD;"
    HTC Touch HD (Blackstone) (UMTS, HSDPA, 5MP, Touch Screen, 3.8 Zoll Display) Smartphone ohne Branding
     
    HTC – Smarte Geräte für smarte Leute / Perfekt für Sie geeignet
    Bei der Entwicklung von HTC-Produkten berücksichtigen wir immer die Bedürfnisse individueller Anwender. Wenn Sie gerne Text eintippen, gibt es für Sie Geräte mit praktischen aufschiebbaren QWERTZ-Tastaturen. Mit einem unserer vielen Touch-Geräte können Sie entweder mit Ihren Fingern oder einem Stift Anwendungen bedienen und im Internet browsen. Wenn Sie sich eine hohe Leistungsfähigkeit wünschen, geben Ihnen unsere 3,5G-Geräte die Geschwindigkeit, die Sie für das Herunterladen und Streaming von Medieninhalt aus dem Internet benötigen. Wenn Sie nach einem Telefon suchen, das einfach alles kann, finden Sie in unserem Produktsortiment leistungsfähige PDA-Telefone, die Ihnen alle möglichen Funktionen für unterwegs bieten. Die Liste kann unaufhörlich fortgesetzt werden.
     
    HTC glaubt nicht, dass es lediglich eine große Lösung für alle Probleme gibt. Warum sollten Sie Ihre Lebensweise auf die Funktionen eines einzelnen Produktes abstimmen? Egal welche Bedürfnisse Sie haben, mit unserer jahrelangen Erfahrung in Innovation, unserem Fachwissen und unserem Vorstellungsvermögen kann HTC Ihnen mit Sicherheit Produkte bieten, die perfekt auf Sie und Ihren Lebensstil zugeschnitten sind.
     
    Führende Technologie
    HTC ist ein Vorreiter in der Technologie für mobile Geräte. Wir entwickeln nicht nur Produkte mit Funktionen, die Sie haben sollten, wir entwickeln Produkte mit Funktionen, die Sie wirklich benötigen, und die Sie sich wirklich wünschen. Wir wissen, dass Sie sich ein schickes und smartes Gerät wünschen, mit dem Sie Ihre Arbeiten erledigen können, mit denen Sie jederzeit erreichbar sind und mit denen Sie auch mal etwas Spaß haben können. Dies ist der Grund dafür, warum HTC immer wieder neue Maßstäbe bei der Herstellung von Produkten setzt, die Kunden das bestmögliche mobile Erlebnis bieten können.
     
    HTC hört Ihnen zu
    HTC produziert Produkte, die Ihnen, unserem geschätzten Kunden, gefallen. Um dies auch wirklich zu erreichen, legen wir sehr viel Wert darauf, Ihnen zuzuhören und herauszufinden, wie Sie Ihr Leben gestalten und welche Wünsche Sie haben. Wir verfolgen nicht nur die Trends auf dem Markt sondern auch die Entwicklungen im kulturellen Umfeld. Wir nehmen uns die Bedürfnisse unserer Kunden zu Herzen und entwickeln auf effiziente Weise neue Produkte, um Ihre Wünsche in kürzester Zeit zu erfüllen.
     
    Das HTC Touch HD im Detail
    Genießen Sie Musikvideos, Filme und Streams, wie Sie es sich nie auf einem Mobilgerät erträumt hätten. Das Surfen im Internet wird zu einer berauschenden Erfahrung ... so als hätten Sie Ihren Laptop dabei. Und das alles auf einem hochauflösenden 3,8""-WVGA-Display, das sich nahtlos mit der berührungsempfindlichen TouchFLOTM 3D-Oberfläche vereint.
     
    Dank der blitzschnellen 3.5G-Technologie erreicht Ihre Internetverbindung echte Breitbandgeschwindigkeit. In HSDPA-Netzen liefert das Touch HDTM eine Downloadgeschwindigkeit von bis zu 7,2 Mbit/s – so können Sie ohne Einschränkungen arbeiten und spielen.
     
    Das neue Register „Stock“ (Aktien) informiert über aktuelle Aktienkurse, während in der Startanzeige E-Mails, Nachrichten und der Kalender nur einen Fingerzeig entfernt sind.
     
    Die Routenführung bringt Sie sicher ans Ziel, Satellitenkarten weisen Ihnen den Weg und mit GoogleTM Maps wissen Sie jederzeit, wo Sie gerade sind. Auf dem breiten Display sind die Karten jetzt noch größer und schärfer. Die Anzeigesteuerung bietet eine Zoomfunktion und eine Detailansicht. So wird Navigation völlig neu definiert.
     
    Zu den Highlights des Gerätes gehören:
    - Kinoerlebnis für unterwegs mit 3,8 Zoll breitem WVGA-Display (480 X 800 Pixel)
    - Fortschrittliche TouchFLOTM 3D -Oberfläche, die beim Navigieren durch Kontakte und Webseiten sowie Anzeigen von 
      Medieninhalten perfekt auf Fingerbewegungen reagiert
    - HSDPA-Internetverbindung ermöglicht Surfen und Datentransfer mit Breitbandgeschwindigkeit.
    - Google MapsTM im Breitbildformat
    - 5-Megapixel-Kamera für höchste Foto- und Videoqualität
    - Durch den 3,5-mm-Audioanschluss ist das Touch HDTM mit umfangreichen Audiozubehör kompatibel.
     
    ";2;False;0;;;HTC Touch HD Smartphone;htc-touch-hd;True;True;P-0009;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;449.0000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;40651,6773263889;73;36;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000188-htc-touch-hd.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000189-htc-touch-hd.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000190-htc-touch-hd.jpg;1;;False;;;;;False;False;False;;;;;False;;;;;; +5;0;True;Sony Ericsson Xperia PLAY Smartphone;Sony Ericsson Xperia PLAY Smartphone (10,1 cm (4 Zoll) Touchscreen, 5 MP Kamera, Android OS 2.3, inkl. 7 vorinstallierten Spielen);"
    Sony Ericsson Xperia PLAY
    Effizientes Arbeiten und hochklassiges Spielevergnügen
    Sie brauchen ein hocheffizientes, voll ausgestattetes Smartphone? Und was wäre, wenn es noch richtige Spielsteuerungselemente bieten würde? Hier ist es: Das Xperia™ PLAY. Ein PlayStation™ certified Android™ Smartphone, das Sie in die Spiele Ihrer Wahl eintauchen lassen.
     
    Vorinstallierte Spiele
    Auf dem Xperia™ PLAY haben Sie viele Spiele vorinstalliert, mit denen Sie Ihr Können unter Beweis stellen können. Und das ist nur der Anfang. Wählen Sie aus einem riesigen Angebot, das ständig wächst und bereits Tausende von Spielen der weltbesten Anbieter umfasst, unter anderem auch PlayStation®-Spiele. Besuchen Sie den Android Market™ und schauen SIe nach, welche Anbieter bereits Spiele bereitgestellt haben. (Vorinstalliert sind folgende Spiele: Star Battalion, Bruce Lee: Dragon Warrior, Crash Bandicoot, FIFA10, SIMS 3, Tetris)
     
    Das Xperia PLAY™ ist in aller Munde. Das erste PlayStation®-zertifizierte Smartphone löst wahre Begeisterungsstürme bei den Spieleanbietern aus.
     
    So, das ist nun das PSP Handy?
    Einst ein Traum. Heute Realität. Das erste PlayStation certified Android™-Smartphone bietet eine unglaubliche Grafik, eine großartige Tonqualität und richtige Spielsteuerungselemente. Das Handy wird dennoch nicht ""das PSP Handy"" genannt. Wir nennen es Xperia™ PLAY.
     
    Das Smartphone als Controller
    Spielbegeisterte erkennen sofort die Konsolentasten. Sie wurden von demselben Team entwickelt und getestet, das auch den PS3-Controller entwickelt hat.
     
    Das erste PlayStation®-zertifizierte Smartphone mit speziellen Spieletasten, L/R-Schultertasten und vier Symboltasten
    4-Zoll-Multitouch-Bildschirm mit 16 Millionen Farben
    Spielvergnügen wie bei einer Spielekonsole mit überragendem Stereo-Sound
    Mit Snapdragon 1-GHz-CPU und dem leistungsstarken Grafikprozessor Adreno 205, der optimales Spielvergnügen garantiert
    Micro SD mit 8 GB (im Lieferumfang enthalten), erweiterbar auf 32 GB
     
    Multimedia-Smartphone mit Android™
    Nie wieder verlaufen. Entdecken Sie Städte und Sehenswürdigkeiten mit 3D-Karten. Verwenden Sie Google Voice Search™, um Anrufe zu tätigen, Nachrichten zu schreiben usw. Mit Ihrem Xperia™ PLAY Android™ Handy brauchen Sie nicht mehr zu tippen. Geben Sie die Anweisungen einfach per Sprache ein. Darf's etwas mehr sein? Holen Sie sich alle Apps, die Sie brauchen, aus dem Android Market™.
     
    Greife direkt auf die mobilen Dienste von Google™
    Surfe per Sprachbefehl mit Google Voice Search™ im Internet
    Mach aus deinem Smartphone im Handumdrehen eine Spielekonsole
    ";2;False;0;;;Sony Ericsson Xperia PLAY Smartphone;sony-ericsson-xperia-play-smartphone;True;True;P-0028;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;269.9000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;40651,6637268519;77;35;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000573-sony-ericsson-xperia-play-smartphone.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000574-sony-ericsson-xperia-play-smartphone.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000575-sony-ericsson-xperia-play-smartphone.jpg;2;;False;;;;;False;False;False;;;;;False;;;;;; +5;0;True;LG P970 Optimus Black Smartphone;"LG P970 Optimus Black Smartphone (10.2cm (4 Zoll) NOVA-Touchscreen, 5 MP Kamera, 9.2mm dünn, Android 2.2, 3.5mm Buchse, Wifi, GPS) schwarz ";"
    Die Superlative - LG P970 Optimus Black mit NOVA Display Technologie
    Neue Technologie für helles und gleichzeitig energiesparendes Display
    10.2 cm (4 Zoll) Touchscreen Smartphone mit Android 2.2 Betriebssystem, 2 Megapixel Frontkamera, WiFi (b/g/n standards).
     
    Superflach, superhell und super energiesparend: Das neue Android-Modell LG P970 OPTIMUS BLACK steht für eine neue Form der Superlative bei Smartphones. Das NOVA-Display mit einer Bildschirmdiagonale von 10,2 Zentimetern garantiert die hellste, klarste und deutlichste Anzeige auf einem Mobiltelefon-Display — selbst bei direkter Sonneneinstrahlung. Einen Superlativ bringt LG auch mit dem Design des neuen Android-Modells: Mit nur 9,2 Millimetern ist das LG P970 OPTIMUS BLACK eines der dünnsten Smartphones auf dem Markt.
     
    LG’s NOVA-Technologie — ein Display-Novum in Sachen Helligkeit…
    „Unser LG P970 OPTIMUS BLACK ist der Inbegriff des innovativen Smartphones. Die Kombination aus anspruchsvoller Technologie sowohl beim Display als auch beim Design machen unser neues Android-Modell zu einem absoluten Must-Have“, so Gunter Thiel, Head of Mobile Marketing bei der LG Electronics Deutschland GmbH.
    Mit einer Leuchtdichte von 700cd/m² (Candela pro Quadratmeter) setzt das NOVA-Display neue Standards: Sehr gute Smartphones-Displays kommen aktuell auf bis zu 480 cd/m². Dank seiner größeren Helligkeit und reinen Weißtönen, die eine kontrastreiche Schwarz-Weiß-Darstellung ermöglichen, bietet das neue Smartphone den Anwendern mehr Komfort beim Surfen im Internet, Lesen von E-Mails und Verfassen von Dokumenten.
     
    … und im Stromverbrauch
    Das NOVA-Display zeigt auch seine „grüne“ Seite: Es verfügt nicht nur über eine höhere Leuchtkraft, sondern sorgt darüber hinaus für eine deutliche Reduzierung des Energieverbrauchs. Im Vergleich zu einer herkömmlichen LCD-Anzeige benötigt das Display 50 Prozent weniger Strom. Auch AMOLEDs verbrauchen doppelt so viel Energie wie ein NOVA-Display für die Darstellung eines hauptsächlich weißen Bildschirms, also des Farbschemas, das am häufigsten beim Browsen im Web genutzt wird. In Verbindung mit dem 1500-mAh-Akku des LG P970 OPTIMUS BLACK steht den Nutzern genügend Energie für ihre täglichen Anforderungen selbst bei maximaler Helligkeitseinstellung zur Verfügung.
     
    Superlative auch in Sachen Style …
    Dank seinem ultraflachen 9,2 Millimetern Design setzt das LG P970 OPTIMUS BLACK mehr als nur stylishe Akzente: Mit einem Gewicht von gerade mal 109 Gramm, einer eleganten Linienführung und abgerundeten Kanten wird das neue Smartphone zu einem wahren Handschmeichler. Mit der raffinierten Rückseite des Geräts, die nach Außen flach zuläuft, wirkt das Profil von 6,0 Millimetern noch einmal schlanker. Ein unverwechselbares Kennzeichen des LG P970 OPTIMUS BLACK ist das minimalistische Design — selbst der Lautsprecher ist nahezu unsichtbar im Rahmen des Telefons integriert.
     
    … und Funktionen: Wi-Fi Direct, Apps und vieles mehr
    Als weltweit erste Gerät unterstützt das LG P970 OPTIMUS BLACK Wi-Fi Direct1 für die schnelle Übertragung von Daten zu anderen Geräten. Zudem bietet das neue Android-Smartphone eine Reihe von intelligenten Funktionen für den einfachen und schnelleren Zugriff auf relevante Apps und Inhalte. Das OPTIMUS User Interface (UI) 2.0 ermöglicht den Anwendern den direkten Zugriff auf Nachrichten, E-Mails und verpasste Anrufe mit nur einer Fingerberührung auf dem gesperrten Display. Die Gestensteuerung unterstützt auch intuitive Kommandos wie Hochheben, Schütteln und Antippen, um Anrufe entgegenzunehmen, in den Kameramodus zu schalten oder Musik zu genießen. Ebenfalls ein Novum ist die Ausstattung mit einer Frontkamera mit 2 Megapixeln Auflösung.
    (1Für die Aktivierung von Wi-Fi Direct™ auf dem Smartphone ist eine Anwendung erforderlich, die in der erste Hälfte des Jahres 2011 im Android Market zum Download zur Verfügung gestellt wird.)
     
    Alle Features des LG P970 OPTIMUS BLACK sind auf der Android 2.2 Froyo Plattform mit der Möglichkeit zum zukünftigen Upgrade auf Android 2.3 Gingerbread verfügbar. Nach einem Upgrade auf Android Gingerbread können die Nutzer Videogespräche mit höherer Qualität über die 2- Megapixel-Frontkamera des LG P970 OPTIMUS BLACK führen.
     
    Beschreibung der Features
     
    2 MP Front-Kamera
    Warum auf Bildqualität für sich selbst verzichten? Mit der 2 MP Front-Kamera haben Sie jetzt eine noch höhere Auflösung für die Front-Kamera zur Verfügung. Für Selbstporträts und Videotelefonie in noch höherer Qualität.
     
    Volle Flash-Unterstützung und Android Market
    Dank des Android Betriebssystems haben Sie uneingeschränkten mobilen Zugriff auf das Internet. Ihr Smartphone unterstützt sämtliche Flash-Formate und setzt dem Online-Spaß keine Grenzen. Ausserdem haben Sie die Möglichkeit, auf Apps zuzugreifen und können Sich beispielsweise den Google Navigator kostenlos herunterladen. So haben Sie ein Navigationsgerät in Ihrem Handy.
     
    Im gigantischen Online Store Android Market stöbern Sie vom Handy aus durch über 200.000 Apps für Social Networks, Games, Lifestyle, Shopping und mehr. Oder Sie finden genau die App, die Sie schon lange gesucht haben. So individualisieren Sie Ihr Smartphone genau nach Ihren Wünschen und machen Ihren neuen Begleiter zu einem Spezialisten auf jedem Gebiet.
     
    G-Key
    Mit dem G-Key bedienen Sie Ihr Smartphone noch intuitiver. Bei aktiviertem G-Key nehmen Sie eingehende Anrufe mit einer einfachen Bewegung ihres LG an, scrollen zwischen Fotos oder wechseln Anwendungen wörtlich im Handumdrehen.
     
    NOVA Display
    Mit einem NOVA-Display müssen Sie nie wieder nach einem schattigen Platz suchen, um etwas erkennen zu können. Ob in völliger Dunkelheit oder direkter Sonneneinstrahlung, das NOVA Display bietet Ihnen jederzeit perfekte Klarheit und eine ungekannte Farbechtheit. Es ist dabei bis zu 50% energieeffizienter als vergleichbare LCD-Displays.
     
    Wi-Fi Direct
    Mit der Wi-Fi Direct Technik übertragen Sie Daten zwischen Wi-Fi-Geräten ganz simpel und schnell, ohne einen externen Acces Point zu benötigen. Wi-Fi Direct zeichnet sich dabei nicht nur durch die einfache Bedienung sondern darüber hinaus auch durch die extrem hohe Übertragungsrate aus: 20 mal schneller als über eine herkömmliche Bluetooth-Verbindung.
    ";2;False;0;;;LG P970 Optimus Black Smartphone;lg-p970-optimus-black-smartphone;True;True;P-0023;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;189.0000;189.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;40651,6470023148;"72;2095";19;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000259-lg-p970-optimus-black-smartphone.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000260-lg-p970-optimus-black-smartphone.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000261-lg-p970-optimus-black-smartphone.jpg;2;;False;;;;;False;False;False;;;;;False;;;;;; +5;0;True;Motorola Milestone 2 Smartphone;Motorola Milestone 2 Smartphone (9,4 cm (3,7 Zoll) Touch-Display, 5 Megapixel Kamera, 1Ghz, 16GB, Android 2.2);"
    Motorola Milestone 2 - Slider Smartphone mit QWERTZ Tastatur (9,4 cm (3,7 Zoll) Touch-Display, 5 Megapixel Kamera, 1Ghz, 16GB, Android 2.2)
     
    Motorola Milestone 2 - Ansichten
    MILESTONE™ 2 mit MOTOBLUR™
    Das ultraflache Slider - Smartphone mit Android™ 2.2 und ausklappbarer QWERTZ-Tastatur bietet im Vergleich zu seinem Vorgänger noch mehr Geschwindigkeit, noch mehr Verbindungsmöglichkeiten, noch mehr Messaging, noch mehr Speicher, noch mehr Web-Erlebnisse, noch mehr Multimedia, den Adobe® Flash®-Player 10.1 und ein Plus an Personalisierung.
     
    Das Hochleistungs-Smartphone besitzt einen 1 GHz-Prozessor, der alle Eingaben blitzschnell umsetzt, selbst wenn viele Anwendungen parallel laufen oder eine Vielzahl von Webseiten geöffnet sind. E-Mails oder Nachrichten lassen sich dank verbesserter QWERTZ-Tastatur mit noch größeren Tasten und sehr gutem Tastendruck schneller eingeben. MILESTONE 2 ist bestens auf die Anbindung an das firmeneigene IT-Netz eingestellt. Zusätzliche Kontrollmöglichkeiten erhöhen die Sicherheit in Firmennetzwerken. Das Smartphone lässt sich außerdem als persönlicher WLAN-Hotspot einsetzen, über den sich bis zu fünf Nutzer mit ihren Geräten im Internet einloggen können.
     
    MOTOBLUR synchronisiert DatenMOTOBLUR™ erleben
     
    Das MILESTONE 2 ist mit der neuesten MOTOBLUR-Version, Motorolas mobilem Dienst für soziale Netzwerke, ausgestattet.
    MOTOBLUR fasst alle verfolgten Threads, Freunde und freigegebene Posts, Links oder Fotos in einem einzigen Datenstrom zusammen.
    MOTOBLUR synchronisiert Daten von Gmail, Arbeits-E-Mails, Facebook, Myspace und Twitter. Dabei werden Ihre Daten sogar gesichert, d. h. Sie können auch bei einem Verlust des Telefons die Informationen auf einem neuen Telefon von Motorola mit MOTOBLUR wiederherstellen, wenn Sie Ihren Benutzernamen und ein Kennwort eingeben.
     
     
    Fotos und VideosBilder und Videosequenzen in großartiger Qualität

    Die 5-MP-Kamera mit Zoom, Autofokus, Blitzlicht und Bildstabilisation ist ideal für die Aufnahme von Bildern und Videosequenzen in großartiger Qualität. Content posten, runterladen oder synchronsieren mit Motorola Media Link. Das Motorola MILESTONE 2 nimmt HD-Videos mit 720p-Signal auf und gibt diese auch in HD wieder. Und das Beste: Da das MILESTONE 2 nach dem DLNA-Standard (Digital Living Network Alliance) arbeitet, können die Videos oder andere Multimedia-Inhalte anschließend mit DLNA-kompatiblen Geräten ausgetauscht werden.
     
    Multimedia-Inhalte
    Internet - Nachrichten - Multimedia und Online-Communitys
    Dank Adobe Flash Player 10.1 kann man außerdem Angebote Tausender Webseiten so sehen, wie sie sein sollen. Ein weiteres Highlight ist der vernetzte Mediaplayer, der neben der Musik die Songtexte sowie zusätzliche Informationen zum Künstler zugänglich macht und Applikationen bietet, um Empfehlungen zu geben und auszutauschen.
     
    Mit einem internen Speicher von 8 GB bietet MILESTONE 2 jede Menge Speicherplatz für Multimedia-Inhalte. Dieser lässt sich über die mitgelieferte 8 GB microSD-Karte erweitern. Wem das nicht genügt, kann microSD-Karten von bis zu 32 GB verwenden.
     
    Eine Reihe von Google™-Applikationen wie Google Search™, Google Maps™, Google Mail™ und YouTube™ runden die Geräteausstattung ab. Außerdem bietet der Android Market™ Zugang zu Tausenden Apps.
     
    Smartes Zubehör
    Das MILESTONE 2 wird mit einer 8 GB-microSD-Karte und einem Headset ausgeliefert. Nutzer können die Motorola Media Link Software kostenlos herunterladen, um Musik oder andere Multimedia-Inhalte ganz einfach zwischen dem Smartphone und dem PC auszutauschen
     
     
    Zubehör: Multimedia-StationMit weiterem optionalem Zubehör läuft das MILESTONE 2 zuhause, im Auto oder im Büro zur Höchstform auf:
    Die optionale Autohalterung ist startklar für die Straße. Sobald das Handy in der Autohalterung steckt, stellt es auf den Automodus um. Mit einer Berührung sind alle Funktionen zugänglich, egal, ob Kontaktauswahl über die Freisprecheinrichtung, Musik, Internetradio, Podcasts, Google Maps™ mit Navigation™ oder vieles mehr. Das Handy lässt sich einfach über das Ladekabel aufladen, das an die Autohalterung angeschlossen werden kann. Mit integriertem GPS und der MOTONAV Schritt-für-Schritt-Navigation gelangt man immer ans Ziel
     

    MILESTONE 2 verwandelt sich in der komfortablen Multimedia-Station in eine Schaltzentrale für Filme, Musik, Bilder oder in einen Digitalwecker. Im Desktop-Modus kann das Gerät mit den Wunsch-Apps individualisiert werden. Und das alles, während das Milestone 2 automatisch auflädt. Die Multimedia-Station ist auch mit dem ersten MILESTONE kompatibel.
    ";2;False;0;;;Motorola Milestone 2 Smartphone;motorola-milestone-2-smartphone;True;True;P-0036;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;499.0000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;40651,6393981481;"75;2095";16;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000424-motorola-milestone-2-smartphone.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000425-motorola-milestone-2-smartphone.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000426-motorola-milestone-2-smartphone.jpg;2;;False;;;;;False;False;False;;;;;False;;;;;; +5;0;True;BlackBerry Curve 8520;BlackBerry Curve 8520 schwarz;"
    BlackBerry Curve 8520
      
     
    QWERTZ-Tastatur


    Das BlackBerry Curve 8520 Smartphone passt genau in Ihre Hand, in Ihre Tasche - und in Ihr Leben.
    Mit dem schlanken und leichten Design liegt es gut in der Hand und bietet hohen Bedienkomfort.
    Nachrichten können mit dem BlackBerry Curve 8520 Smartphone mit der vollständigen QWERTZ-Tastatur
    einfach und schnell versendet werden. Jeder Buchstabe ist einer eigenen Taste zugewiesen.
    Dies erleichtert die Eingabe und fühlt sich ganz natürlich an.
    Das helle Display sorgt mit mehr als 65.000 Farben für eine brillante Anzeige, ganz egal, ob Sie sich E-Mails,
    Textnachrichten, Videos oder Bilder ansehen.
     
    Das BlackBerry Curve 8520 Smartphone ist unmittelbar mit Apple-Computern kompatibel.
    Synchronisieren Sie Ihre Kontaktlisten, Kalender, Termine und Notizen mit den Anwendungen,
    die Sie am häufigsten nutzen. Wenn Sie die BlackBerry Desktop Software auf Ihrem BlackBerry
    Curve 8520 Smartphone verwenden, ist das BlackBerry Smartphone ganz ähnlich zu bedienen
    wie Ihr Apple-Computer.
    Schlankes vereinfachtes Design
    Spezielle Medientasten
    Verbindung mit BlackBerry App World
    Videokamerafunktionen (2.0 Megapixel-Digitalkamera)
    Unterstützung von Apple-Computern
    ";2;False;0;;;BlackBerry Curve 8520 Smartphone ohne Vertrag;blackberry-curve-8520;True;True;P-0033;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;269.0000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;40651,6285069444;"70;2095";43;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000488-blackberry-curve-8520.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000489-blackberry-curve-8520.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000490-blackberry-curve-8520.jpg;2;;False;;;;;False;False;False;;;;;False;;;;;; +5;0;True;LG KP500 Cookie;"LG KP500 Cookie schwarz ";"
    LG KP500 Cookie
     
    LG KP500 Cookie Smartphone
    Touchscreenhandy mit iPhone-Feeling für Einsteiger!
    Das Full-Touchscreen-Telefon LG KP500 überzeugt durch innovative Technologien und Features, wie sie bislang nur High-End-Telefonen mit kompletter Touchscreen-Bedienung vorbehalten waren.
     
    Touchscreen für alle
    Die Optimierung der Benutzeroberfläche stand bei der Entwicklung des LG KP500 im Mittelpunkt. Die Onscreen-QWERTZ-Tastatur wird eingeblendet, sobald der Benutzer das LG KP500 quer hält, und das Auto- Rotating-Display zeigt Bilder oder Dokumente immer in der passenden Ausrichtung an, egal wie man das Handy hält.
     
    Spielspaß
    Darüber hinaus bietet das LG KP500 auch noch Bewegungssensor-Spiele, die für ein aktiveres und spannenderes Spielerlebnis sorgen, indem der Benutzer das Mobiltelefon in die gewünschte Richtung dreht oder neigt.
     
    Intuitive Bedienung
    Dank seiner intuitiven Benutzeroberfläche kann das LG KP500 mit den klaren Symbolen auf dem 3-Zoll-Display sofort von jedermann verwendet werden. So ist es auch ganz einfach, den Kontakt zu Freunden zu halten.
     
    Kurzwahlfunktionen über Icons
    Über die innovative Bedienoberfläche kann der Benutzer das Foto von Freunden der entsprechenden Kurzwahl zuordnen und muss dann lediglich zu dem Bild des gewünschten Gesprächspartners blättern und es berühren, um ihn anzurufen.
     
    3,0-Megapixel-Digitalkamera
    Das großzügige 3""-Display bietet darüber hinaus nicht nur genügend Platz für eine komfortable Bedienung, sondern auch die Möglichkeit Videoclips, eigene Filmchen (max.320 x 240 Pixel, bis zu 24fps) oder Fotos zu betrachten. Diese können mit der 3,0-Megapixel-Digitalkamera (2-faches Digital-Zoom) geschossen und auch per Internet versendet werden.
     
    Unterhaltung an Bord
    Radio und MP3-Player befinden sich ebenfalls an Bord. Für einfachen Datentransfer besitzt das LG KP500 sowohl einen USB-Anschluss, als auch eine Bluetooth-Anbindung.
     
    Reichhaltiger Lieferumfang
    Geliefert wird das LG KP500 in schwarzer Farbausführung inklusive Akku, Ladegerät, Stereo-Kabel-Headset, Bedienungsanleitung, USB-Datenkabel, PC-Software und Styluspen.
    ";2;False;0;;;LG KP500 Cookie;lg-kp500-cookie;True;True;P-0022;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;139.0000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;40651,569375;"72;2095";19;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000247-lg-kp500-cookie.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000248-lg-kp500-cookie.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000249-lg-kp500-cookie.jpg;1;;False;;;;;False;False;False;;;;;False;;;;;; +5;0;True;Sony Ericsson Satio;Sony Ericsson Satio;"
    Sony Ericsson Satio
     
    Satio - Erlebe Entertainment in nicht für möglich gehaltenen Farbdimensionen.
    Das Satio bringt Technik und Ästhetik auf völlig neue Weise zusammen und ist mit einer 12,1 Megapixel Kamera ausgestattet.
    Lass Bilder sprechen Mit den einzigartigen Touch Panels tippst du dich direkt in deine beste Musik und deine Lieblingsvideos.
    Die leistungsfähige Touchscreen-Kamera liefert dir gestochen scharfe Bilder. Jede Aufnahme ein Meisterstück.
    Zum Scharfstellen tippen

    Die 12,1 Megapixel Kamera mit Xenon-Blitzlicht und intuitivem manuellen Fokus liefert hochaufgelöste Aufnahmen, die auch auf einem großen Bildschirm beeindrucken.
    The Magic Touch
    Auf dem Sony Ericsson Satio holst du deine Lieblingsinhalte mit nur einer Berührung auf den Bildschirm.
    Ob TV-Serien, Handyvideos, Podcasts oder Musik: Mit dem genialen Fulltouch-Medienmenü dieses beeindruckenden Entertainment-Handys tauchst du direkt ein.
    Widescreenwunder
    Die 16 Millionen Farben auf dem Sony Ericsson Satio machen Videos und Fotos zum Augenschmaus.
    Auf dem gestochen klaren 3,5-Zoll-Bildschirm im 16:9-Format siehst du sie genau so, wie sie gedacht sind.
    Symbian OS
    Ein offenes Betriebssystem für Mobilgeräte, das Ihnen den Download neuer Anwendungen auf Ihr Handy ermöglicht
    TFT-Touchscreen mit 360x640 Pixel und 16,777,216 Farben
    unterstützte Netze: GSM/GPRS/EDGE 850/900/1800/1900 UMTS/HSPA 900/2100
    12.1 Megapixel mit Autofokus und Bildstabilisator
    Betriebssystem: Symbian OS
    Lieferumfang:
    Sony Ericsson Satio, Verpackung, Akku, Ladegerät, Bedienungsanleitung, Headset, Datenkabel, Handytasche, TV Kabel, Bedienstift
    ";2;False;0;;;Sony Ericsson Satio;sony-ericsson-satio;True;True;P-0029;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;299.0000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;40651,4580324074;77;35;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000415-sony-ericsson-satio.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000416-sony-ericsson-satio.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000417-sony-ericsson-satio.jpg;2;;False;;;;;False;False;False;;;;;False;;;;;; +5;0;True;Blackberry Bold 9700 QWERTZ;"Blackberry Bold 9700 QWERTZ ";"
    Blackberry Bold 9700 QWERTZ
     
    Schlank, smart und beeindruckend: Das Flagschiff Blackberry Bold 9700!
     
     
    Das Blackberry Bold 9700 ist ein Blackberry Smartphone mit vollständiger QWERTZ-Tastatur in edlem Schwarz!
    Es kombiniert praktische Funktionen wie eine 3,2-Megapixel-Autofokuskamera samt Bildstabilisator und Blitz mit
    dem Bedienkomfort eines sensitiven Trackpads, das eine mühelose Steuerung aller wichtigen Funktionen per
    Fingertip ermöglicht. Im Gegensatz zu seinen Vorgängern wurden behutsame Modifikationen bei der Gestaltung
    des User-Interface, der Anordnung von Bedienelementen und technischer Auslegung von Media-Player und
    Stereo-Lautsprechern vorgenommen. Ansonsten wartet dieses Smartphone mit bewährten Attributen auf,
    darunter geschwungenes und harmonisches Design, sowie ein großes helles Display, das mit seinen brillanten
    Farben Webseiten, Fotos, Spiele und Videoclips optimal darstellt.
    Smartphone mit hochauflösendem 2,44¿-Farbdisplay mit 480 x 360 Pixeln und mehr als 65.000 Farben
    Bedienfreundliches Touchpad und vollständige, beleuchtete QWERTZ-Tastatur
    3,2 Megapixel-Digitalkamera mit Autofokus, Bildstabilisierung und 2-fach Digitalzoom
    Integrierter A-GPS-Empfänger
    Lieferumfang:
    Akku, Ladegerät, Stereo-Kabel-Headset, Bedienungsanleitung, USB Datenkabel und PC-Software
    ";2;False;0;;;"Blackberry Bold 9700 QWERTZ ";blackberry-bold-9700-qwertz;True;True;P-0032;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;499.0000;499.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;40651,4502777778;"70;2095";43;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000403-blackberry-bold-9700-qwertz.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000404-blackberry-bold-9700-qwertz.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000405-blackberry-bold-9700-qwertz.jpg;2;;False;;;;;False;False;False;;;;;False;;;;;; +5;0;True;Samsung Galaxy S Super Clear LCD (i9003) Smartphone;"Samsung Galaxy S Super Clear LCD (i9003) Smartphone (10,1 cm (4 Zoll) Display, Touchscreen, 5 Megapixel Kamera) schwarz ";"
    Überirdisch leistungsstark.
    Eine Leistungsklasse für sich, das ist das Samsung Galaxy S Super Clear LCD (i9003). Highlight des eleganten Android™-Smartphones ist der extragroße Super Clear LCD-Touchscreen. Hier wird das Betrachten von Videos zum mobilen Kinoerlebnis. Auch das Surfen im Internet geht dank großem Display und Multitouch-Zoom leicht von der Hand. Das Schreiben von E-Mails und SMS gelingt unkompliziert dank Swype®-Texteingabe. Zahlreiche aktuelle und nützliche Apps stehen im Android Market™ zum Download bereit. Die integrierte Google Maps Navigation™ führt ans gewünschte Ziel. Ein erstklassiges Zusammenspiel von Hardware und Funktionen leistet sein Übriges für ein ausgezeichnetes Nutzererlebnis auf höchstem Niveau! Das Samsung Galaxy S Super Clear LCD - überirdisch leistungsstark und galaktisch gut.
     
    Unvergessliche Bildqualität
    Das Super Clear LC-Display beeindruckt durch seine ausgeprägte Farbtreue und ist deutlich heller und weniger anfällig für reflektierendes Licht als konventionelle LC-Displays. Eine Luftpolsterschicht zwischen Bildschirm und berührungsempfindlicher Schicht des Touchscreens besteht nicht, da die Berührungssensoren direkt auf dem Display angebracht sind. Dies sorgt nicht nur für die sichtbar bessere Farbdarstellung, sondern auch für höhere Schärfe und erlaubt dünnere Displaybauweisen.
     
    In bester Kommunikation
    Wollen Sie selbstgedrehte Videos oder Bilder mit anderen teilen, gelangen diese auf direktem Wege über das Mobilfunknetz in Social Communities wie zum Beispiel Facebook®, Twitter ™oder MySpace™ – ein Antippen des Touchscreens genügt. Das interaktive Telefonbuch hält Sie übersichtlich darüber auf dem Laufenden, was Ihre Freunde in den Sozialen Netzwerken posten. Ohne, dass Sie deren Profile einzeln aufrufen müssten. Ein Blick genügt.
     
    Schnelle Texteingabe
    Von den Erfindern der automatischen Textvervollständigung T9 kommt mit Swype® die Revolution der Texteingabe über Touchscreens. Texte werden nicht Buchstabe für Buchstabe eingegeben, sondern einzelne Worte werden ohne abzusetzen mit dem Finger über die virtuelle Tastatur nachgefahren. Texte lassen sich so bis zu 1,5-mal schneller verfassen. Bei mehrdeutigen Eingaben bietet Swype® eine Übersicht in Frage kommender Begriffe. Typische Rechtschreibfehler werden dabei automatisch korrigiert.
     
    Kabelloser Datenaustausch
    Multimediainhalte bringen Sie spielend leicht auf DLNA™-kompatible Geräte wie Fernseher, PCs und Notebooks. Dank DLNA™-Standard AllShare™ komplett kabellos und ohne lange Einrichtung. Sollte Ihr Fernseher nicht DLNA™-tauglich sein, erweitert das optional erhältliche Multimedia Gateway WMG160 diesen mit der entsprechenden Funktionalität.
     
    Mobil arbeiten
    ThinkFree® bietet auch unterwegs Zugriff auf lokal oder online gespeicherte Office-Dokumente. Diese stehen zur Ansicht und zur Bearbeitung zur Verfügung.
    ";2;False;0;;;Samsung Galaxy S Super Clear LCD (i9003) Smartphone;samsung-galaxy-s-super-clear-lcd-i9003-smartphone;True;True;PD-01071;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;469.0000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;40651,4194212963;76;5;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000623-samsung-galaxy-s-super-clear-lcd-i9003-smartphone.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000624-samsung-galaxy-s-super-clear-lcd-i9003-smartphone.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000625-samsung-galaxy-s-super-clear-lcd-i9003-smartphone.jpg;2;;False;;;;;False;False;False;;;;;False;;;;;; +5;0;True;HTC Desire HD;"HTC Desire HD Smartphone (10,9 cm (4.3 Zoll) Touchscreen, 8MP Kamera, Android OS 2.2, HSPA) Maduro Brown ";"
    Innovation, die macht was Sie wollen
    Das HTC Desire HD ermöglichtmit der neuesten Technologie, einem 10,9 cm Touchscreen und dem bislang schnellsten Prozessor ein besonderes Interneterlebnis. Es ist mit Android™ 2.2 und der neuesten Version von HTC Sense™ ausgestattet.
     
    Ein 10,9 cm WVGA Touchscreen
    Der große Touchscreen eigent sich perfektzum Anschauen von Videos, Filmen und Fotos sowie zum Surfen im Internet. Videos können mit einer Auflösung von 720p aufgenommen und in HD-Qualität auf Ihrem TV wiedergegeben werden. Musik wird ganz einfach auf den internen Speicher oder eine SD-Karte übertragen.
     
    Das ultimative Interneterlebnis
    Die Kombination aus dem 10,9 cm Touchscreenund dem 1 GHz-Prozessor sorgt für das ultimative Interneterlebnis. Sie können mehrere Websites gleichzeitig öffnen und diese parallel nutzen, genau so, wie Sie es von Ihrem PC gewöhnt sind. Die Textanpassung sorgt dafür, dass sich der Text beim Hineinzoomen in eine Website automatisch an das Display anpasst, so dass Sie nicht mehr scrollen müssen. Dank Flash 10.1-Unterstützung werden alle Websites so angezeigt, wie sie aussehen sollen.
     
    Mit nur einem Fingertipp...
    ...Ihre Freunde erreichen
    Mit dem Favoriten-Widget können Sie direkt auf Ihrem Homescreen verschiedene Kontaktgruppen mit Freunden oder Kollegen anlegen. Ein Anruf, eine SMS oder eine E-Mail sind dann nur noch einen Fingertipp entfernt.
     
    ...alle Anwendungen oder Apps bedienen
    Sie können jede beliebige Anwendung oder App auf dem 7-teiligen Homescreen platzieren und nach Belieben anordnen, indem Sie sie einfach per Drag & Drop dort hinziehen. So ist alles, was Ihnen wichtig ist, immer nur einen Fingertipp entfernt.
     
    Auf Facebook, Twitter und Flickr gleichzeitig zugreifen
    Mit Friend Stream sehen Sie alle neuen Facebook-Updates, Tweets und Flickr-Fotos Ihrer Freunde in einer Ansicht, die sich automatisch aktualisiert. Und wenn Sie Ihre eigenen Profile in diesen Sozialen Netzwerken aktualisieren wollen, können Sie das in nur einem Schritt erledigen. 
     
    Schöne Momente Festhalten
    Mit der 8 Megapixel Kamera erzielen Sie erstaunliche Aufnahmen. Eine hohe Auflösung, großartige Farben und eine Vielzahl an Einstellungsmöglichkeiten bringen ein hohes Maß an Professionalität in Ihre Aufnahmen. Im dunkler Umgebung helfen Ihnen 2 LED-Blitze, immer alles im Bild zu haben. Und auch Videos erscheinen nun in HD-Auflösung. Erfassen Sie Ihre nächste Geburtstagsparty, die Firmenfeier oder Ihre Freunde in 720p Qualität.
    Sehen Sie alles auf einem großen Display
    Vorbei sind die Zeiten, in denen Sie Texte auf winzigen Displays entziffern mussten und die entscheidenden Informationen übersehen haben. Auf dem 10,9 cm großen Display des HTC Desire HD genießen Sie ein wahrhaft großartiges Interneterlebnis. Mit Features wie der gestochen scharfen Textdarstellung und der brillanten Wiedergabe von Fotos und Videos ist das HTC Desire HD wie dafür geschaffen, Ihre Lieblingswebsites, YouTube-Clips und Facebook-Fotos optimal wiederzugeben.
     
    Ein Handy, das Sie nicht verlieren können
    Mit HTC Sense™ können Sie Ihr Handy aus derFerne über ein sicheres Web-Portal steuern. Sie können es anweisen zu klingeln, selbst wenn es stumm geschaltet ist, um es wiederzufinden, oder Sie sperren es und löschen alle Inhalte, falls es gestohlen wurde. Sie können eine Nachricht an Ihr Handy senden, in der Sie den Finder um die Rückgabe bitten. Kontakte, SMS und MMS können gesichert werden, sodass sie einfach wieder hergestellt werden können.
    ";2;False;0;;;HTC Desire HD Smartphone;htc-desire-hd;True;True;;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;3,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;299.0000;299.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;40651,414375;"73;2095";36;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000621-htc-desire-hd.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000622-htc-desire-hd.jpg;;1;;False;;;;;False;False;False;;;;;False;;;;;; +5;0;True;HTC HD7;"HTC HD7 Smartphone (10,9 cm (4,3 Zoll) Touchscreen, Windows Phone 7, 5MP Kamera, GPS, Dolby Mobile, 8 GB interner Speicher, ohne Branding) schwarz ";"
    Mobiles Entertainment in High Definition
    Das HTC HD7 ist das ultimative Handy für die Wiedergabe von Filmen. Denn durch das Widescreen-Display, den hochwertigen Klang und den großen Speicher erleben Sie auch unterwegs perfektes Kino.
     
    Großes Display und toller Klang
    Genießen Sie Ihre Filme auf dem riesigen 10,9 cm Widescreen-Display. Dabei müssen Sie Ihr Handy nicht die ganze Zeit in der Hand halten – klappen Sie einfach den Ständer aus und lehnen Sie sich bequem zurück. Durch die Dolby Mobile-Technologie erleben Sie auch unterwegs einen bislang unerreichten Klang in Kinoqualität. Mit Zune® haben Sie ein perfektes Mediencenter, denn damit können Sie auch unterwegs Inhalte herunterladen und diese mit Ihrem PC synchronisieren. 8-16 GB integrierter Speicher sorgen für genug Platz, um all Ihre Filme, Musik und Spiele überallhin mitzunehmen.
     
    Neue Features mit Windows Phone 7
    Freuen Sie sich darauf, mit weniger Bedienschritten mehr zu erledigen. Nutzen Sie den Windows® Phone Marketplace für den schnellen, bequemen Einkauf und besuchen Sie den HTC Hub für weitere Windows® Apps, die für HTC-Nutzer kostenlos sind. Langeweile ist dank Xbox Live® Gaming auf Ihrem Handy kein Thema mehr.
     
    Der Mensch an erster Stelle
    Auf dem HTC HD7 finden Sie die gesamte Kommunikation mit Ihren Kontakten an einem Ort. So haben Sie direkt Zugriff auf Facebook®- und Windows® Live-Updates und Fotos, SMS und MMS, E-Mails und Anrufe. Die Personen, die Sie zuletzt kontaktiert haben, werden Ihnen auch zuerst angezeigt oder Sie gehen alternativ Ihre ganze Kontaktliste durch.
     
    Momente festhalten und teilen
    Mit der integrierten 5 Megapixel Kamera halten Sie jeden Augenblick fest. Ob Firmenveranstaltungen, Geburtstagsfeiern, Trips durch die Natur - Ihr HTC HD7 lässt Sie nie im Stich. Der eingebaute Blitz hilft Ihnen, selbst an dunklen Orten ein scharfes Bild zu erhalten. Direkt nach der Aufnahme, können Sie dieses auf einer der unzähligen Social Network Seiten veröffentlichen und so mit Ihren Freunden und Bekannten teilen.Mit der Videofunktion zeichnen Sie verblüffende HD-Videos mit 720p auf
    ";2;False;0;;;HTC HD7 Smartphone;htc-hd7;True;True;PD-01069;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;3,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;299.0000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;40651,4104166667;73;36;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000619-htc-hd7.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000620-htc-hd7.jpg;;1;;False;;;;;False;False;False;;;;;False;;;;;; +5;0;True;Blackberry Bold 9000;Blackberry Bold 9000 black;"
    Blackberry Bold 9000  
     
     
    WLAN, GPS, QWERTZ-Tastatur, Kamera mit 2 MP, MP3-Player

     
    Das BlackBerry Bold Smartphone ist Innovation pur
    Mobile Komplettlösung mit hinterleuchteter QWERTZ (Tastatur), beweglichem Trackwheel und 480 x 320 Pixel Display
     
    Verfügbare Funktionen:
    Mobile E-Mail, Organizer, Mobiles Internet, Telefon, Kamera, Videoaufnahme, Media Player, Zugriff auf Unternehmensdaten, SMS, MMS, GPS & Blackberry Maps
    Erweiterbarer Speicherplatz - unterstützt microSD-Karten, 1 GB integrierter + 128 MB Flash-Speicher
    Unterstützt Tri-Band-HSDPA, Quad-Band-GSM/EDGE 3G und WLAN 4 und kann als Hochgeschwindigkeits-Modem mit 3,6 MB/s eingesetzt werden
    ";2;False;0;;;Blackberry Bold 9000;blackberry-bold-9000;True;True;P-0031;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;459.0000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;40651,1651736111;"70;2095";43;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000370-blackberry-bold-9000.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000371-blackberry-bold-9000.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000372-blackberry-bold-9000.jpg;2;;False;;;;;False;False;False;;;;;False;;;;;; +5;0;True;Blackberry Curve 8900;Blackberry Curve 8900;"
    Blackberry Curve 8900 
     
     
    WLAN, GPS, QWERTZ-Tastatur, BlackBerry Maps, Organizer, Kamera mit 3,2 MP, MP3-Player
     
     
    Deutsche Tastatur im QWERTZ-Layout mit beweglichem Trackball, ESC- und Menütaste zur intuitiven Menüsteuerung, hochauflösendes 2,44 Zoll-Farbdisplay mit 480x360 Pixel
     
    Verfügbare Funktionen:
    WLAN-kompatibel IEEE 802.11b/g, Integrierter GPS-Empfänger, Media Player für Audio und Video, Videoaufzeichnung, BlackBerry Maps, Mobile E-Mail, Organizer, Browser, Mobiltelefon, Zugriff auf
    Unternehmens-EDV, SMS/MMS
     
    3,2 Megapixel-Kamera mit Autofokus, automatischem Blitz und Bildstabilisierung, Videofunktion
    Netzkompatibilität: GSM 900/1800/GPRS (Europa, Asien, Australien, Südamerika (teilw.)), CDMA 850/1900/GPRS (Nordamerika), EDGE
    ";2;False;0;;;Blackberry Curve 8900;blackberry-curve-8900;True;True;P-0035;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;359.0000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;40651,1558101852;70;43;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000365-blackberry-curve-8900.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000366-blackberry-curve-8900.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000367-blackberry-curve-8900.jpg;1;;False;;;;;False;False;False;;;;;False;;;;;; +5;0;True;HTC Touch 2;HTC Touch 2;"
    HTC Touch 2 
     
    Das HTC Touch2 macht es Ihnen leicht
     
      
    Bleiben Sie in Kontakt mit Ihren Freunden, finden Sie heraus, was es bei Facebook Neues gibt, rufen Sie Ihre Mails ab oder surfen Sie im Web.
    All diese Möglichkeiten stehen Ihnen auf Fingerdruck zur Verfügung – mit einem kompakten Telefon, das perfekt in der Hand liegt.
    Sie möchten noch mehr mit dem Touch2 erleben? Dann laden Sie doch einfach Spiele und Anwendungen aus dem Windows Marketplace auf Ihr Handy, um es noch besser an Ihre Wünsche anzupassen.
    Und damit Ihre Daten jederzeit sicher sind, können Sie direkt auf dem Microsoft MyPhone-Server ein Backup anlegen – ohne einen PC dafür zu benötigen.
    Der HTC Touch2 bietet zahlreiche Verbesserungen bezüglich des TouchFLO, des User Interface (Wetterbericht, Shortcuts zu den beliebtesten Anwendungen...) und die Einführung von Google Maps für Mobiltelefone, YouTube und vieles mehr.
    Touch2 - Technische Details :
    Displaytaktiles 2.8"" TFT-LCD Display mit QVGA Auflösung Windows Mobile® 6.5
    Professionaltaktile Front Panel Buttons für einfache Bedienbarkeit NetworkSchnelles Surfen und hohe Download-Geschwindigkeiten dank HSDPA
    GPSintegrierte GPS Antenne
    Fotoapparat3.2 Megapixel mit der Möglichkeit, Videos aufzunehmen
    AnschlüsseWi-Fi (IEEE 802.11 b/g), Bluetooth 2.0, 3.5 mm Audioanschluss
    Betriebssystem: HTC TouchFLO mit Windows Mobile 6.5 Professional
    Verbindungsoptionen: GSM/Edge (850/900/1800/1900 MHz), WCDMA/HSDPA (900/2100 MHz), HSDPA (7,2 Mbps)
    Gesprächszeiten: WCDMA bis zu 370 Minuten, GSM bis zu 440 Minuten
    Standby-Zeiten: WCDMA bis zu 500 Stunden, GSM bis zu 370 Stunden
    ";2;False;0;;;HTC Touch 2;htc-touch-2;True;True;P-0016;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;299.0000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;40650,9831712963;73;36;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000577-htc-touch-2.jpg;;;2;;False;;;;;False;False;False;;;;;False;;;;;; +5;0;True;"HTC HD2 ";"HTC HD2 in edlem schwarzen Design ";"
    HTC HD2 in edlem schwarzen Design
      
    Windows Mobile 6.5; 4,3 Zoll WVGA Touchscreen Display, 5 Megapixel-Kamera mit Auto-Fokus und LED Blitzlicht
     
    Mit dem HTC HD2 präsentiert die HTC Corporation, weltweiter Marktführer bei Telefonen auf Basis von Windows Mobile und Android, das neue Flaggschiff seiner Windows Phone-Familie.
     
    Der HTC HD2 ist das weltweit erste Windows Phone mit HTC Sense, einem mobilen Erlebnis, das den Anwender und seine natürlichen Handlungsstränge in den Mittelpunkt stellt.
    Mächtige Leistungsreserven verspricht der mit 1 GHz getaktete Snapdragon-Prozessor von Qualcomm, der den HTC HD2 zur ultimativen Surf-, Multimedia- und Gaming-Maschine macht.
    Erstes Windows Phone mit HTC Sense
    HTC Sense basiert auf drei fundamentalen Prinzipien, die durch Zuhören und Beobachten, wie Menschen leben und kommunizieren, ermittelt wurden: Make it Mine, Stay Close und Discover the Unexpected.
    Make it Mine
    Der HD2 lässt sich maßgeschneidert an individuelle Anforderungen anpassen. Und dabei spielt das brillante Display seine gesamte Größe aus.
     
    Animierte Hintergründe oder Wetterapplikationen (bei Regen fallen Regentropfen, bei bewölktem Himmel ziehen Wolkenschwaden über den Bildschirm etc.) vermitteln ein einzigartiges Erlebnis,
    ohne dabei andere wichtige Anwendungen oder Inhalte zu stören.
    Eine Vielzahl an Unterhaltungs- und Zusatzapplikationen aus dem Windows Marketplace for Mobile lädt zudem ein, den HD2 komplett an die eigenen Vorlieben anzupassen.
    Stay Close
    Egal über welche Art von Kommunikationskanal (Sprache, SMS, Email, Facebook etc.) die Verbindung mit Freunden, Verwandten oder Geschäftspartnern aufrecht gehalten werden soll,
    der Personen-bezogene Kommunikationsansatz von HTC stellt zu jeder Kontaktperson die gesamte Konversationshistorie auf einen Fingerstreich zur Verfügung.

    Discover the Unexpected
    Auf Basis des mobilen Erlebnisses HTC Sense hält der HTC HD2 eine Vielzahl an Erweiterungen bereit, die den Umgang mit dem Smartphone-Giganten spürbar vereinfachen.
     
    Der HD2 verfügt über diverse Sensoren, unter anderem einen Näherungssensor, der Fehleingaben während eines Telefonats verhindert.

    Lieferumfang:
    HTC Touch HD2, Akku, Ladekabel, USB-Kabel, kabelgebundenes Headset
    ";2;False;0;;;HTC HD2 Smartphone;htc-hd2;True;True;P-0011;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;3,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;599.0000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;40650,9376967593;"73;2095";36;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000386-htc-hd2.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000387-htc-hd2.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000388-htc-hd2.jpg;1;;False;;;;;False;False;False;;;;;False;;;;;; +5;0;True;Sony Ericsson XPERIA X10 Mini Pro Smartphone;Sony Ericsson XPERIA X10 Mini Pro Smartphone (6,6 cm (2,6 Zoll) Display, QWERTZ-Tastatur, Android, WLAN, GPS, 5 Megapixel Kamera;"
    Leistungsmerkmale des Sony Ericsson X10 Mini Pro Smartphone
    Cleveres Zubehör
    Rufen Sie Ihre Freunde an und lassen Sie Sich anrufen. Hören Sie Musik, halten Sie die Musik an und überspringen Sie einen Titel. Ganz ohne Ihr Handy. Sind Sie auf der Suche nach portablen Stereo-Lautsprechern? Die Sony Ericsson MS450 Lautsprecher (Optional) oder einem Hi-Fi-Headset mit Fernbedienung (z.B. Sony Ericsson MH810 - Optional)? Lassen Sie Ihr Handy in der Tasche und verwenden Sie Ihr Zubehör als Fernbedienung.
     
    Timescape™ - Freunde treffen
    Sony Ericsson Timescape™ ermöglicht die Anzeige der gesamten Kommunikation an einem Ort. Facebook™, Twitter™, SMS, Anrufe in Abwesenheit - alles in einer Anwendung zusammgefasst. Jede Menge geöffnete Anwendungen, um zu sehen, was gerade los ist? Die Zeiten sind endlich vorbei.
     
    Mit der Kraft von QWERTZ
    Sie tippen lieber auf einer Tastatur? Mit der kompletten QWERTZ-Tastatur können Sie Nachrichten noch einfacher schreiben.
     
    Alles von überall
    Die gesamte Kommunikation mit Ihren Freunden über das Telefonbuch. Alle Informationen zu Interpreten über den Music-Player. Einfach die Infinity-Taste berühren und schon werden alle Informationen angezeigt. Sofort.
     
    Individuelle Freiheit
    Ihre unverzichtbare Navigationsanwendung? Ihre Musik? Eine News-Site? Sie entscheiden, was wichtig für Sie ist. Wählen Sie die Symbole für die vier Ecken auf dem Startbildschirm selbst aus. Sie können die Anordnung jederzeit wieder ändern. In der Mitte des Bildschirms können Sie ein Widget einfügen. Gestalten Sie Ihren Bildschirm frei nach Ihren individuellen Bedürfnissen.
     
    Android - Google - Apps
    Das Xperia™ X10 Mini basiert auf der Android™-Plattform. Sie haben die Möglichkeit alle Google™-Anwendungen im vollen Umfang genießen zu können – Google Search™, Google Voice Search™, Google Talk™, Gmail™, YouTube™, Google™ Maps und dem Android Market™.
     
    Selbst aussuchen - Android Market™
    In Ausgehstimmung? In Aufbruchlaune? Oder im Ausruhmodus? Downloaden Sie jede beliebige Anwendung vom Android Market™ und passen Sie Ihr Xperia™ X10 Mini nach Ihren individuellen Vorlieben an.
     
    HSPA – rasante Geschwindigkeit
    Turbo-UMTS ermöglicht Ihnen breitbandähnliche Geschwindigkeiten auf dem Handy. Laden Sie große Dateien und E-Mail-Anhänge in wenigen Augenblicken herunter. Holen Sie sich Websites und Newsfeeds in Sekunden auf den Bildschirm.
     
    Finden Sie Ihr Ziel - mit aGPS
    Nie wieder verlaufen. Ihr Telefon verfügt über integriertes aGPS. Ortsgebundene Dienste helfen Ihnen, den Weg an Ihr Ziel zu finden. Oder fügen Sie Ihren Bildern mit der Geo-Tagging-Funktion Ortsangaben hinzu.
     
    UKW-Radio
    Musik liegt in der Luft - einfach einstellen und genießen. Ihr Handy verfügt über ein integriertes UKW-Radio.
     
    Wi-Fi-Verbindung
    Schnell und einfach in Verbindung bleiben. Unterwegs. In Cafés. Am Flughafen. Ihr Xperia™ X10 Mini unterstützt Wi-Fi.
    ";2;False;0;;;Sony Ericsson XPERIA X10 Mini Pro Smartphone;sony-ericsson-xperia-x10-mini-pro-smartphone;True;True;P-0027;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;159.9000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;40650,9259606482;77;35;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000476-sony-ericsson-xperia-x10-mini-pro-smartphone.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000477-sony-ericsson-xperia-x10-mini-pro-smartphone.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000478-sony-ericsson-xperia-x10-mini-pro-smartphone.jpg;2;;False;;;;;False;False;False;;;;;False;;;;;; +5;0;True;"Apple iPod touch 4G 64 GB ";"Der neue iPod touch. Jetzt mit FaceTime, Retina Display, HD-Video und Game Center. ";"
    Der neue iPod touch. Jetzt mit FaceTime, Retina Display, HD-Video und Game Center.
     
    Spaß, hoch entwickelt. Der neue iPod touch.
    Tonnen von innovativen Funktionen gibt es jetzt auch auf dem iPod touch. Einfach damit er noch mehr Spaß macht. Teilen Sie schöne Momente mit Freunden via FaceTime. Nehmen Sie Videos in HD auf. Oder erleben Sie Spiele auf dem höchstauflösenden iPod Display, das es je gab. Der iPod touch hat so viel Technologie, dass Sie glatt vergessen, dass es ein iPod ist.
     
    Sieht unglaublich aus. Ist aber wahr.

    Mit seinem neuen Design ist der iPod touch der dünnste, leichteste und fantastischste iPod touch, den es je gab. Um das zu spüren, müssen Sie ihn nur in die Hand nehmen. Er ist gerade mal 7,2 mm dünn. Mit seiner Vorderseite aus Hightech-Glas und der Rückseite aus Edelstahl fühlt er sich einfach fantastisch an. Wenn Sie ihn einschalten, sind Sie sofort vom brillanten Retina Display fasziniert. Der iPod touch kombiniert großartiges Design und revolutionäre Technologie - von außen wie von innen.
     
    Retina Display. Die Zukunft sieht gut aus.
    Es gibt viele Gründe, den iPod touch immer wieder anzusehen. Beispielsweise das LCD-Display mit 960 x 640 Pixeln und Hintergrundbeleuchtung. Es hat eine Pixeldichte von 326 ppi und ist damit das höchstauflösende iPod Display, das es je gab. Die Apple Ingenieure haben dafür superkleine, kaum 78 Mikrometer breite Pixel entwickelt, die das menschliche Auge nicht mehr als einzelne Pixel wahrnehmen kann. Und obwohl Sie sie nicht sehen können, werden Sie den Unterschied bemerken. Der Text ist gestochen scharf und alles sieht leuchtend und lebendig aus.
     
    Apple A4 Prozessor. Mehr Power für Sie.
    Hinter - oder besser gesagt unter - dem ganzen Spaß, den Sie mit dem iPod touch haben, steckt der Apple A4 Chip. Die Apple Ingenieure haben den A4 Chip als leistungsstarken und energieeffizienten Mobilprozessor entworfen. Damit bewältigt der iPod touch komplexe Aufgaben wie Multitasking, Videoschnitt und FaceTime Anrufe. All das bei noch mehr Batterielaufzeit. Und mehr Spaß.
     
    Gyrosensor + Beschleunigungssensor. Wirklich bewegend.
    Der iPod touch hat jetzt ein paar neue Tricks drauf. Er hat einen integrierten 3-Achsen-Gyrosensor, der zusammen mit dem Beschleunigungssensor dafür sorgt, dass der iPod touch Aktionen wie Beschleunigung, 3D Bewegung und Drehrate erkennt. Im Klartext: Mehr Bewegungen, mehr Gesten und größere Präzision für noch mehr Spielspaß.
     
    Zwei Kameras. Doppelt so viel Spaß.
    Für Videoaufnahmen hat der iPod touch zwei integrierte Kameras. Mit der Rückkamera nimmt er fantastische HD 720p Videos auf. Und der hoch entwickelte rückwärtig belichtete Sensor sorgt selbst bei schwacher Beleuchtung für tolle Aufnahmen. Das integrierte Mikrofon nimmt dabei gleichzeitig Gespräche, Musik oder alles andere auf. Die Frontkamera des iPod touch ist perfekt für FaceTime Anrufe1 und um sich selbst aufzunehmen. Schon erstaunlich, wie viel Spaß in etwas so Kleines passt.
    Multi-Touch. Alles unter Kontrolle Ihrer.
    Wie macht der iPod touch eigentlich genau das, was Sie wollen, wenn Sie mit Ihren Fingern über das Display streichen? Genau genommen ist es eine Kettenreaktion. Das Multi-Touch Display hat einen Schutzfilm über der kapazitiven Sensorik, die Berührungen anhand elektrischer Felder erkennt. Diese Informationen werden an das Retina Display darunter übermittelt. So könen Sie alles mit den Fingern steuern, mit Cover Flow in Ihren Alben blättern, Fotos sehen und vergrößern, in eine Website zoomen und Spiele steuern.
     
    FaceTime auf dem iPod touch. Sagen Sie nicht einfach Hallo. Sagen Sie es mit einem Lächeln.
    Ein Lächeln sagt mehr als tausend SMS.
    Bringen Sie LOL auf die nächste Stufe und sehen Sie Ihre Freunde wirklich lachen. Oder lassen Sie XOXO lebendig werden und schicken Sie einen Kuss um die halbe Welt. FaceTime auf dem iPod touch macht's möglich. FaceTime funktioniert sofort nach dem Auspacken - Sie geben einfach Ihre Apple ID und E-Mail Adresse ein. Oder erstellen einen neuen E-Mail Account extra für FaceTime. FaceTime ist supereinfach. Stellen Sie sich vor, Sie wollen über Wi-Fi mit Ihrer besten Freundin videotelefonieren. Dann tippen Sie auf die FaceTime App, finden sie dort und starten den Anruf. Auf ihrem iPod touch oder iPhone 4 erscheint dann eine Einladung, die sie annehmen kann. Sobald sie annimmt, wird FaceTime gestartet. Das alles funktioniert ganz nahtlos und sowohl im Hoch- als auch im Querformat. Sie werden im wahrsten Sinne des Wortes sehen, wie viel Spaß Sie haben können.
     
    Videotelefonieren Sie mit Freunden per FaceTime oder spielen Sie gegen Freunde oder Fremde mit Game Center.
     
    Zwei Kameras für Spaß von jeder Seite.
    Der iPod touch hat zwei Kameras - eine vorne über dem Display und eine auf der Rückseite. Die Frontkamera ist für FaceTime optimiert. Sie hat genau das richtige Sichtfeld und die richtige Brennweite, um auf die Entfernung einer Armlänge das Gesicht zu fokussieren. So zeigt sie Sie immer im besten Licht. Was besonders praktisch ist, wenn Sie mit jemandem sprechen, der mehr als nur ein Freund ist.
    Die Rückkamera. Teilen Sie Ihre Ansicht.
    Wenn Ihre Mitbewohnerin es doch nicht mehr zum Konzert schafft, lassen Sie sie mit FaceTime doch wenigstens die Zugabe sehen. Wenn die Band auf die Bühne kommt und ihren Lieblingshit spielt, tippen Sie einfach auf die Taste. Und noch bevor der Sänger die erste Zeile singt, wechselt der iPod touch zur Rückkamera und überträgt einen mit Sicherheit legendären Auftritt. Tippen Sie noch einmal und der iPod touch wechselt zurück auf die Frontkamera und zu Ihnen. Einfach und schnell - macht einfach Spaß!
     
    HD Videoaufnahme auf dem iPod touch. Nehmen Sie jeden Spaß mit. Und auf.
     
    Integrierter Schnittplatz.
    Sie müssen mit dem Bearbeiten Ihrer Videos nicht warten, bis Sie wieder am Computer sitzen. Einfache Schnittfunktionen sind direkt im iPod touch integriert, sodass Sie gleich damit loslegen können. Ziehen Sie einfach, um Start- und Endpunkt des Films festzulegen. Behalten Sie nur die Teile des Videos, die Ihnen besonders gefallen, und machen Sie daraus einen Film, den Sie und Ihre Freunde immer und immer wieder anschauen wollen.
     
    Mit iMovie auf dem iPod touch erstellen Sie Minikinofilmhits mit ein paar Fingertipps.
    Stellen Sie sich vor, Sie sind unterwegs und wollen eine Videopostkarte erstellen, mit allem, was Sie erlebt und gesehen haben. Machen Sie das einfach mit der iMovie App - Sie bekommen sie im App Store. Mit iMovie für den iPod touch können Sie Videoclips zusammenfügen und bearbeiten, ihnen mit dynamischen Themen und Übergängen noch eine Extraportion Wow geben, Musik und Fotos hinzufügen und den fertigen Film mit allen teilen.
     
    Drehen Sie einen Film. Mit Ihnen in der Hauptrolle.
    Wenn Sie das nächste Mal eine aufregende Wanderung gemacht haben, erzählen Sie Ihren Freunden nicht nur davon - zeigen Sie es ihnen. Neben der HD Kamera auf der Rückseite besitzt der iPod touch eine Frontkamera mit VGA-Qualität über dem Display. So sehen Sie sich selbst, während Sie Videos aufnehmen. Das ist perfekt, um sich selbst zu filmen, denn Sie brauchen nicht mehr zu hoffen, dass Sie im Bild sind, sondern sehen es gleich. Also machen Sie sich bereit für die Aufnahme.
     
    Teilen Sie mit Freunden den Rest Ihres Lebens.
    Haben Sie auch schon mal eine Mail geschrieben und dabei etwas Unbeschreibliches gesehen? Dann nehmen Sie die Kamera und nehmen Sie es auf. Anschließend können Sie Ihren HD Film direkt auf YouTube laden. Oder wählen Sie ein Video aus den Aufnahmen und verschicken es mit einer Mail. Sie können es auch mit einem Fingertipp auf Ihre Facebook Seite oder in Ihren Blog posten. Und alle mit dem iPod touch aufgenommenen Videos ganz leicht mit Ihrem Mac oder PC synchronisieren.
    So haben alle ein gutes Bild von Ihnen.

    Eine unglaubliche Aussicht. Ein toller Kuchen. Ihr Hund, wie er soooooo süß schaut. Wenn Sie einen Schnappschuss für Facebook machen wollen, können Sie eine der beiden Kameras des iPod touch verwenden. Tippen Sie einfach auf das Display, um die Belichtung anzupassen. Dann posten Sie das Bild auf Facebook und warten auf die Kommentare.
     
    Game Center. Spielen Sie gegen Ihre besten Feinde
    Game Center. Mögen die Spiele beginnen.
    Mit der neuen Game Center App auf dem iPod touch können Sie Ihr Spiele-Netzwerk erweitern. Exponentiell. Zum Spielen brauchen Sie nur einen iPod touch oder ein iPhone mit iOS 4.1. Bei iOS 4.1 wird eine Game Center App auf dem Homescreen angezeigt. Tippen Sie einfach darauf, meldes sich mit Ihrer Apple ID an und schon kann´s losgehen. Sie können einen Spielernamen erstellen, der für Ihre Freunde und die Spieler-Community sichtbar ist. Fügen Sie mehrere E-Mail Adressen zur Game Center App hinzu, damit Freunde Sie einfacher finden können. Sie können die Spiele über die Links im Game Center laden und auch direkt aus der Game Center App starten. Und das Beste: Sobald Sie sich bei Game Center anmelden, bleiben Sie verbunden. Bis Sie dich wieder abmelden.
     
    Beste Freunde. Bald beste Gegner.
    Treten Sie gegen Ihre Freunde in einem Rennen an. Oder einem Match. Oder in einem Kampf. Wenn Sie bei der Game Center App angemeldet sind, können Sie jemanden mit einer Freundschaftsanfrage einladen und dafür den Spielernamen oder die E-Mail Adresse der Person verwenden. Ihre Freunde erscheinen in einer separaten Freundeliste in der Game Center App. Tippen Sie auf die Namen von Freunden und Sie sehen, welche Spiele sie gespielt haben. Sie können auch neue Freundschaftsanfragen ansehen und eigene hinzufügen.
    Leaderbords und Erfolge. Damit jeder sieht, wo Sie stehen.
    Sehen Sie sich auf den Ranglisten für jedes Spiel Ihre Platzierung unter Ihren Freunden und anderen Spielern an. Sie können auch Ihre Erfolge mit denen Ihrer Freunde vergleichen. Sehen Sie sich die Leaderboards und Erfolge in der Game Center App und jedem einzelnen Spiel an. Und dann lassen Sie es krachen.
     
    Trefen Sie Ihre Gegner. Und treffen Sie sie hart.
    Sie möchten eine Runde mit mehreren Freunden spielen? Mit Auto-Match werden Ihnen zuerst Ihre Freunde als Gegner vorgeschlagen, wenn diese auch nach einem Auto-Match suchen. Wenn nicht, wird Ihnen ein Freund in spe irgendwo auf dem Globus als Gegner vorgeschlagen. Oder laden Sie Ihre Freunde ein und lassen Sie Auto-Match alle für ein Spiel benötigten Spieler finden.
    Musik. Lassen Sie Ihre Finger tanzen.
    Cover Flow. Musik sieht so gut aus.
    Auf dem iPod touch gibt's Musik nicht nur auf die Ohren. Mit Cover Flow ist sie auch was für Augen und Finger. Drehen Sie den iPod touch auf die Seite und blättern Sie durch Ihre Albumcover. Tippen Sie auf ein Cover, um es umzudrehen und die Songliste zu sehen. Noch ein Tipp und die Musik läuft.
     
    Genius Wiedergabelisten. In jedem guten Song steckt eine noch bessere Wiedergabeliste.
    Angenommen Sie hören einen Song auf einem iPod touch, der Ihnen gut gefällt, und möchten weitere Titel hören, die gut dazu passen. Genius findet weitere Songs auf Ihrem iPod touch und erstellt eine Genius Wiedergabeliste. Hören Sie sich die Liste sofort an, speichern Sie sie für später oder versuchen's noch einmal und sehen, was dabei herauskommt. Verlassen Sie sich auf Genius, wenn Sie einen Mix wollen, auf den Sie selbst nie gekommen wären. 
     
    Genius Mixe. Nehmen Sie den DJ mit nach Hause.
    Genius ist Ihr persönlicher DJ. Synchronisieren Sie Ihren iPod touch mit iTunes und Genius durchsucht Ihre Mediathek automatisch nach Songs, die gut zusammenpassen. Dann erstellt Genius mehrere Mixe. Diese Mixe sind wie Radiosender, auf denen nur Ihre Lieblingshits laufen. So finden Sie Songs wieder, die Sie lange nicht mehr gehört haben oder von denen Sie gar nicht mehr wussten, dass Sie sie haben.
     
    Lassen Sie Ihre Finger tanzen. 
     
    Shake to shuffle. So ein Zufall.
    Die Dinge mal aufrütteln. Musikalisch natürlich. Wenn Sie das nächste Mal Musik hören, aktivieren Sie einfach die Schüttelfunktion. Wenn Sie den iPod touch dann kurz schütteln, springt er nach dem Zufallsprinzip zu einem anderen Song in Ihrer Sammlung. So entdecken Sie Ihre Musik immer wieder neu.
     
    iTunes. Das ist Entertainment.
    Packen Sie Songs und Musikvideos aus Ihrer iTunes Mediathek auf dem Computer auf den iPod touch. Oder kaufen und laden Sie neue Songs auf den iPod touch, wenn Sie sich über Wi-Fi mit iTunes verbinden. Wenn Sie dann den iPod touch das nächste Mal mit dem Computer verbinden, werden alle Songs, die Sie auf dem iPod touch gekauft haben, auf den Mac oder PC übertragen. Und mit iTunes Ping können Sie jetzt sehen, welche Musik Ihre Freunde hören, kaufen und empfehlen. Oder informieren Sie sich dort über Ihre Lieblingskünstler und was sie so hören.
     
    Bluetooth. Entfesseln Sie Ihre Musik.
    Die Unterstützung für das drahtlose Bluetooth ist im iPod touch schon drin. Das heißt, Sie können drahtlose Stereokopfhörer verwenden. Lassen Sie den iPod in Ihrer Tasche stecken oder auf dem Schreibtisch aufladen, während Sie weiter Musik hören.
     
    Filme und Fernsehsendungen. So haben Sie überall eine Sehenswürdigkeit.
    Ganz großes Kino. Auf einem kleinen Display.
    Mit dem iPod touch ist jeden Tag und überall Kinotag. Nehmen Sie Videos für viele Stunden Unterhaltung mit und sehen Sie sie auf dem fantastischen 3,5 Zoll Retina Display an. Kaufen Sie im iTunes Store und wählen Sie aus tausenden Filmen, Fernsehsendungen und Video-Podcasts für Ihren iPod touch. Da ist für jeden etwas dabei - von Hollywood Blockbustern bis zu Independent Filmen. Ein paar Fingertipps und Sie haben Filme geladen und können sie ansehen. Sie mögen lieber Fernsehsendungen? Die gibt's auch. Sie können einzelne Folgen oder gleich eine ganze Staffel kaufen. Mit dem iPod touch haben Sie Ihre Videos immer dabei.
    Sie haben alles unter Kontrolle.
    Wenn Sie ein Video schauen, tippen Sie einfach auf das Display und schon haben Sie die Steuerung. Damit können Sie die Wiedergabe starten oder unterbrechen, zu einzelnen Kapiteln springen und die Lautstärke anpassen. Oder verwenden Sie die Lautstärketasten links am iPod touch. Wenn Sie zwischen Widescreen- und Vollbildanzeige wechseln wollen, reicht ein Doppeltipp auf das Display. Das ist wie die Fernbedienung des Fernsehers. Nur, dass Sie nicht darum kämpfen müssen.
     
    iTunes. Für beste Unterhaltung.
    Sie brauchen für den nächsten Flug oder die nächste Fahrt etwas Unterhaltung? Mit iTunes auf dem iPod touch und einer Wi-Fi Verbindung können Sie sofort Filme und Fernsehsendungen kaufen. Oder Sie kaufen sie auf Ihrem Mac oder PC und synchronisieren sie mit dem iPod touch. Nur das Popcorn ist nicht dabei.
     
     
    Besuchen Sie Ihre Lieblingswebsites. Alles, was Sie dazu brauchen, ist ein iPod touch und Wi-Fi. 
     
    Laden Sie die iBooks App kostenlos und Sie haben nicht nur einen großartigen E-Book-Reader, sondern auch einen tollen Ort, um Bücher zu kaufen. 
     
    Und vieles mehr...
     
    App Store
    Laden Sie Apps direkt auf den iPod touch
     
    iTunes
    Erstellen Sie einen iTunes Store Account und kaufen Sie jederzeit via Wi-Fi ein.
     
    iBooks
    Laden Sie die iBooks App kostenlos und Sie haben nicht nur einen großartigen E-Book-Reader, sondern auch einen tollen Ort, um Bücher zu kaufen.
     
    iMovie
    Bearbeiten Sie Videos, fügen Sie Themen und Musik hinzu und teilen Sie Ihre Filme mit Anderen
     
    Mail
    Senden Sie Mails und sehen Sie sich Anhänge von Ihrem Google Mail, MobileMe oder einem anderen E-Mail Account an.
     
    Safari Webbrowser
    Besuchen Sie Ihre Lieblingswebsites. Alles, was Sie dazu brauchen, ist ein iPod touch und Wi-Fi.
     
    Fotos
    Nehmen Sie Ihre Fotos mit. Teilen Sie sie per E-Mail. Wählen Sie Ihr Lieblingsfoto als Hintergrundbild.
     
    Homescreen
    Ordnen Sie in iTunes Ihre Apps auf mehreren Homescreens an.
     
     
    Sprachsteuerung
    Steuern Sie die Musik auf dem iPod touch mit Sprachbefehlen
     
    Karten
    Finden Sie Restaurants, Konzerte und mehr und lassen Sie sich mit Karten zeigen, wie Sie hinkommen.
     
    YouTube
    Sehen Sie sich die neuesten Videohits und Ihre Lieblingsvideos an.
     
    Nike + iPod
    Erreichen Sie Ihre Trainingsziele mit integrierter Unterstützung für Nike + iPod
     
    Sprachmemos
    Nehmen Sie Notizen, Gedanken oder alles andere auf.
     
    Bedienungshilfen
    Der iPod touch kommt mit Bildschirmlesefunktion und weiteren Bedienungshilfen
     
    Lieferumfang
    iPod touch, Ohrhörer, USB 2.0 Kabel, Dock Adapter, Kurzanleitung
    ";2;False;0;;;"Apple iPod touch 4G 64 GB ";apple-ipod-touch-4g-64-gb;True;True;PD-01068;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;359.9900;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;40637,4565162037;45;1;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000615-apple-ipod-touch-4g-32-gb.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000616-apple-ipod-touch-4g-32-gb.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000617-apple-ipod-touch-4g-32-gb.jpg;1;;False;;;;;False;False;False;;;;;False;;;;;; +5;0;True;"Apple iPod touch 4G 8 GB ";"Der neue iPod touch. Jetzt mit FaceTime, Retina Display, HD-Video und Game Center. ";"
    Der neue iPod touch. Jetzt mit FaceTime, Retina Display, HD-Video und Game Center.
     
    Spaß, hoch entwickelt. Der neue iPod touch.
    Tonnen von innovativen Funktionen gibt es jetzt auch auf dem iPod touch. Einfach damit er noch mehr Spaß macht. Teilen Sie schöne Momente mit Freunden via FaceTime. Nehmen Sie Videos in HD auf. Oder erleben Sie Spiele auf dem höchstauflösenden iPod Display, das es je gab. Der iPod touch hat so viel Technologie, dass Sie glatt vergessen, dass es ein iPod ist.
     
    Sieht unglaublich aus. Ist aber wahr.

    Mit seinem neuen Design ist der iPod touch der dünnste, leichteste und fantastischste iPod touch, den es je gab. Um das zu spüren, müssen Sie ihn nur in die Hand nehmen. Er ist gerade mal 7,2 mm dünn. Mit seiner Vorderseite aus Hightech-Glas und der Rückseite aus Edelstahl fühlt er sich einfach fantastisch an. Wenn Sie ihn einschalten, sind Sie sofort vom brillanten Retina Display fasziniert. Der iPod touch kombiniert großartiges Design und revolutionäre Technologie - von außen wie von innen.
     
    Retina Display. Die Zukunft sieht gut aus.
    Es gibt viele Gründe, den iPod touch immer wieder anzusehen. Beispielsweise das LCD-Display mit 960 x 640 Pixeln und Hintergrundbeleuchtung. Es hat eine Pixeldichte von 326 ppi und ist damit das höchstauflösende iPod Display, das es je gab. Die Apple Ingenieure haben dafür superkleine, kaum 78 Mikrometer breite Pixel entwickelt, die das menschliche Auge nicht mehr als einzelne Pixel wahrnehmen kann. Und obwohl Sie sie nicht sehen können, werden Sie den Unterschied bemerken. Der Text ist gestochen scharf und alles sieht leuchtend und lebendig aus.
     
    Apple A4 Prozessor. Mehr Power für Sie.
    Hinter - oder besser gesagt unter - dem ganzen Spaß, den Sie mit dem iPod touch haben, steckt der Apple A4 Chip. Die Apple Ingenieure haben den A4 Chip als leistungsstarken und energieeffizienten Mobilprozessor entworfen. Damit bewältigt der iPod touch komplexe Aufgaben wie Multitasking, Videoschnitt und FaceTime Anrufe. All das bei noch mehr Batterielaufzeit. Und mehr Spaß.
     
    Gyrosensor + Beschleunigungssensor. Wirklich bewegend.
    Der iPod touch hat jetzt ein paar neue Tricks drauf. Er hat einen integrierten 3-Achsen-Gyrosensor, der zusammen mit dem Beschleunigungssensor dafür sorgt, dass der iPod touch Aktionen wie Beschleunigung, 3D Bewegung und Drehrate erkennt. Im Klartext: Mehr Bewegungen, mehr Gesten und größere Präzision für noch mehr Spielspaß.
     
    Zwei Kameras. Doppelt so viel Spaß.
    Für Videoaufnahmen hat der iPod touch zwei integrierte Kameras. Mit der Rückkamera nimmt er fantastische HD 720p Videos auf. Und der hoch entwickelte rückwärtig belichtete Sensor sorgt selbst bei schwacher Beleuchtung für tolle Aufnahmen. Das integrierte Mikrofon nimmt dabei gleichzeitig Gespräche, Musik oder alles andere auf. Die Frontkamera des iPod touch ist perfekt für FaceTime Anrufe1 und um sich selbst aufzunehmen. Schon erstaunlich, wie viel Spaß in etwas so Kleines passt.
    Multi-Touch. Alles unter Kontrolle Ihrer.
    Wie macht der iPod touch eigentlich genau das, was Sie wollen, wenn Sie mit Ihren Fingern über das Display streichen? Genau genommen ist es eine Kettenreaktion. Das Multi-Touch Display hat einen Schutzfilm über der kapazitiven Sensorik, die Berührungen anhand elektrischer Felder erkennt. Diese Informationen werden an das Retina Display darunter übermittelt. So könen Sie alles mit den Fingern steuern, mit Cover Flow in Ihren Alben blättern, Fotos sehen und vergrößern, in eine Website zoomen und Spiele steuern.
     
    FaceTime auf dem iPod touch. Sagen Sie nicht einfach Hallo. Sagen Sie es mit einem Lächeln.
    Ein Lächeln sagt mehr als tausend SMS.
    Bringen Sie LOL auf die nächste Stufe und sehen Sie Ihre Freunde wirklich lachen. Oder lassen Sie XOXO lebendig werden und schicken Sie einen Kuss um die halbe Welt. FaceTime auf dem iPod touch macht's möglich. FaceTime funktioniert sofort nach dem Auspacken - Sie geben einfach Ihre Apple ID und E-Mail Adresse ein. Oder erstellen einen neuen E-Mail Account extra für FaceTime. FaceTime ist supereinfach. Stellen Sie sich vor, Sie wollen über Wi-Fi mit Ihrer besten Freundin videotelefonieren. Dann tippen Sie auf die FaceTime App, finden sie dort und starten den Anruf. Auf ihrem iPod touch oder iPhone 4 erscheint dann eine Einladung, die sie annehmen kann. Sobald sie annimmt, wird FaceTime gestartet. Das alles funktioniert ganz nahtlos und sowohl im Hoch- als auch im Querformat. Sie werden im wahrsten Sinne des Wortes sehen, wie viel Spaß Sie haben können.
     
    Videotelefonieren Sie mit Freunden per FaceTime oder spielen Sie gegen Freunde oder Fremde mit Game Center.
     
    Zwei Kameras für Spaß von jeder Seite.
    Der iPod touch hat zwei Kameras - eine vorne über dem Display und eine auf der Rückseite. Die Frontkamera ist für FaceTime optimiert. Sie hat genau das richtige Sichtfeld und die richtige Brennweite, um auf die Entfernung einer Armlänge das Gesicht zu fokussieren. So zeigt sie Sie immer im besten Licht. Was besonders praktisch ist, wenn Sie mit jemandem sprechen, der mehr als nur ein Freund ist.
    Die Rückkamera. Teilen Sie Ihre Ansicht.
    Wenn Ihre Mitbewohnerin es doch nicht mehr zum Konzert schafft, lassen Sie sie mit FaceTime doch wenigstens die Zugabe sehen. Wenn die Band auf die Bühne kommt und ihren Lieblingshit spielt, tippen Sie einfach auf die Taste. Und noch bevor der Sänger die erste Zeile singt, wechselt der iPod touch zur Rückkamera und überträgt einen mit Sicherheit legendären Auftritt. Tippen Sie noch einmal und der iPod touch wechselt zurück auf die Frontkamera und zu Ihnen. Einfach und schnell - macht einfach Spaß!
     
    HD Videoaufnahme auf dem iPod touch. Nehmen Sie jeden Spaß mit. Und auf.
     
    Integrierter Schnittplatz.
    Sie müssen mit dem Bearbeiten Ihrer Videos nicht warten, bis Sie wieder am Computer sitzen. Einfache Schnittfunktionen sind direkt im iPod touch integriert, sodass Sie gleich damit loslegen können. Ziehen Sie einfach, um Start- und Endpunkt des Films festzulegen. Behalten Sie nur die Teile des Videos, die Ihnen besonders gefallen, und machen Sie daraus einen Film, den Sie und Ihre Freunde immer und immer wieder anschauen wollen.
     
    Mit iMovie auf dem iPod touch erstellen Sie Minikinofilmhits mit ein paar Fingertipps.
    Stellen Sie sich vor, Sie sind unterwegs und wollen eine Videopostkarte erstellen, mit allem, was Sie erlebt und gesehen haben. Machen Sie das einfach mit der iMovie App - Sie bekommen sie im App Store. Mit iMovie für den iPod touch können Sie Videoclips zusammenfügen und bearbeiten, ihnen mit dynamischen Themen und Übergängen noch eine Extraportion Wow geben, Musik und Fotos hinzufügen und den fertigen Film mit allen teilen.
     
    Drehen Sie einen Film. Mit Ihnen in der Hauptrolle.
    Wenn Sie das nächste Mal eine aufregende Wanderung gemacht haben, erzählen Sie Ihren Freunden nicht nur davon - zeigen Sie es ihnen. Neben der HD Kamera auf der Rückseite besitzt der iPod touch eine Frontkamera mit VGA-Qualität über dem Display. So sehen Sie sich selbst, während Sie Videos aufnehmen. Das ist perfekt, um sich selbst zu filmen, denn Sie brauchen nicht mehr zu hoffen, dass Sie im Bild sind, sondern sehen es gleich. Also machen Sie sich bereit für die Aufnahme.
     
    Teilen Sie mit Freunden den Rest Ihres Lebens.
    Haben Sie auch schon mal eine Mail geschrieben und dabei etwas Unbeschreibliches gesehen? Dann nehmen Sie die Kamera und nehmen Sie es auf. Anschließend können Sie Ihren HD Film direkt auf YouTube laden. Oder wählen Sie ein Video aus den Aufnahmen und verschicken es mit einer Mail. Sie können es auch mit einem Fingertipp auf Ihre Facebook Seite oder in Ihren Blog posten. Und alle mit dem iPod touch aufgenommenen Videos ganz leicht mit Ihrem Mac oder PC synchronisieren.
    So haben alle ein gutes Bild von Ihnen.

    Eine unglaubliche Aussicht. Ein toller Kuchen. Ihr Hund, wie er soooooo süß schaut. Wenn Sie einen Schnappschuss für Facebook machen wollen, können Sie eine der beiden Kameras des iPod touch verwenden. Tippen Sie einfach auf das Display, um die Belichtung anzupassen. Dann posten Sie das Bild auf Facebook und warten auf die Kommentare.
     
    Game Center. Spielen Sie gegen Ihre besten Feinde
    Game Center. Mögen die Spiele beginnen.
    Mit der neuen Game Center App auf dem iPod touch können Sie Ihr Spiele-Netzwerk erweitern. Exponentiell. Zum Spielen brauchen Sie nur einen iPod touch oder ein iPhone mit iOS 4.1. Bei iOS 4.1 wird eine Game Center App auf dem Homescreen angezeigt. Tippen Sie einfach darauf, meldes sich mit Ihrer Apple ID an und schon kann´s losgehen. Sie können einen Spielernamen erstellen, der für Ihre Freunde und die Spieler-Community sichtbar ist. Fügen Sie mehrere E-Mail Adressen zur Game Center App hinzu, damit Freunde Sie einfacher finden können. Sie können die Spiele über die Links im Game Center laden und auch direkt aus der Game Center App starten. Und das Beste: Sobald Sie sich bei Game Center anmelden, bleiben Sie verbunden. Bis Sie dich wieder abmelden.
     
    Beste Freunde. Bald beste Gegner.
    Treten Sie gegen Ihre Freunde in einem Rennen an. Oder einem Match. Oder in einem Kampf. Wenn Sie bei der Game Center App angemeldet sind, können Sie jemanden mit einer Freundschaftsanfrage einladen und dafür den Spielernamen oder die E-Mail Adresse der Person verwenden. Ihre Freunde erscheinen in einer separaten Freundeliste in der Game Center App. Tippen Sie auf die Namen von Freunden und Sie sehen, welche Spiele sie gespielt haben. Sie können auch neue Freundschaftsanfragen ansehen und eigene hinzufügen.
    Leaderbords und Erfolge. Damit jeder sieht, wo Sie stehen.
    Sehen Sie sich auf den Ranglisten für jedes Spiel Ihre Platzierung unter Ihren Freunden und anderen Spielern an. Sie können auch Ihre Erfolge mit denen Ihrer Freunde vergleichen. Sehen Sie sich die Leaderboards und Erfolge in der Game Center App und jedem einzelnen Spiel an. Und dann lassen Sie es krachen.
     
    Trefen Sie Ihre Gegner. Und treffen Sie sie hart.
    Sie möchten eine Runde mit mehreren Freunden spielen? Mit Auto-Match werden Ihnen zuerst Ihre Freunde als Gegner vorgeschlagen, wenn diese auch nach einem Auto-Match suchen. Wenn nicht, wird Ihnen ein Freund in spe irgendwo auf dem Globus als Gegner vorgeschlagen. Oder laden Sie Ihre Freunde ein und lassen Sie Auto-Match alle für ein Spiel benötigten Spieler finden.
    Musik. Lassen Sie Ihre Finger tanzen.
    Cover Flow. Musik sieht so gut aus.
    Auf dem iPod touch gibt's Musik nicht nur auf die Ohren. Mit Cover Flow ist sie auch was für Augen und Finger. Drehen Sie den iPod touch auf die Seite und blättern Sie durch Ihre Albumcover. Tippen Sie auf ein Cover, um es umzudrehen und die Songliste zu sehen. Noch ein Tipp und die Musik läuft.
     
    Genius Wiedergabelisten. In jedem guten Song steckt eine noch bessere Wiedergabeliste.
    Angenommen Sie hören einen Song auf einem iPod touch, der Ihnen gut gefällt, und möchten weitere Titel hören, die gut dazu passen. Genius findet weitere Songs auf Ihrem iPod touch und erstellt eine Genius Wiedergabeliste. Hören Sie sich die Liste sofort an, speichern Sie sie für später oder versuchen's noch einmal und sehen, was dabei herauskommt. Verlassen Sie sich auf Genius, wenn Sie einen Mix wollen, auf den Sie selbst nie gekommen wären. 
     
    Genius Mixe. Nehmen Sie den DJ mit nach Hause.
    Genius ist Ihr persönlicher DJ. Synchronisieren Sie Ihren iPod touch mit iTunes und Genius durchsucht Ihre Mediathek automatisch nach Songs, die gut zusammenpassen. Dann erstellt Genius mehrere Mixe. Diese Mixe sind wie Radiosender, auf denen nur Ihre Lieblingshits laufen. So finden Sie Songs wieder, die Sie lange nicht mehr gehört haben oder von denen Sie gar nicht mehr wussten, dass Sie sie haben.
     
    Lassen Sie Ihre Finger tanzen. 
     
    Shake to shuffle. So ein Zufall.
    Die Dinge mal aufrütteln. Musikalisch natürlich. Wenn Sie das nächste Mal Musik hören, aktivieren Sie einfach die Schüttelfunktion. Wenn Sie den iPod touch dann kurz schütteln, springt er nach dem Zufallsprinzip zu einem anderen Song in Ihrer Sammlung. So entdecken Sie Ihre Musik immer wieder neu.
     
    iTunes. Das ist Entertainment.
    Packen Sie Songs und Musikvideos aus Ihrer iTunes Mediathek auf dem Computer auf den iPod touch. Oder kaufen und laden Sie neue Songs auf den iPod touch, wenn Sie sich über Wi-Fi mit iTunes verbinden. Wenn Sie dann den iPod touch das nächste Mal mit dem Computer verbinden, werden alle Songs, die Sie auf dem iPod touch gekauft haben, auf den Mac oder PC übertragen. Und mit iTunes Ping können Sie jetzt sehen, welche Musik Ihre Freunde hören, kaufen und empfehlen. Oder informieren Sie sich dort über Ihre Lieblingskünstler und was sie so hören.
     
    Bluetooth. Entfesseln Sie Ihre Musik.
    Die Unterstützung für das drahtlose Bluetooth ist im iPod touch schon drin. Das heißt, Sie können drahtlose Stereokopfhörer verwenden. Lassen Sie den iPod in Ihrer Tasche stecken oder auf dem Schreibtisch aufladen, während Sie weiter Musik hören.
     
    Filme und Fernsehsendungen. So haben Sie überall eine Sehenswürdigkeit.
    Ganz großes Kino. Auf einem kleinen Display.
    Mit dem iPod touch ist jeden Tag und überall Kinotag. Nehmen Sie Videos für viele Stunden Unterhaltung mit und sehen Sie sie auf dem fantastischen 3,5 Zoll Retina Display an. Kaufen Sie im iTunes Store und wählen Sie aus tausenden Filmen, Fernsehsendungen und Video-Podcasts für Ihren iPod touch. Da ist für jeden etwas dabei - von Hollywood Blockbustern bis zu Independent Filmen. Ein paar Fingertipps und Sie haben Filme geladen und können sie ansehen. Sie mögen lieber Fernsehsendungen? Die gibt's auch. Sie können einzelne Folgen oder gleich eine ganze Staffel kaufen. Mit dem iPod touch haben Sie Ihre Videos immer dabei.
    Sie haben alles unter Kontrolle.
    Wenn Sie ein Video schauen, tippen Sie einfach auf das Display und schon haben Sie die Steuerung. Damit können Sie die Wiedergabe starten oder unterbrechen, zu einzelnen Kapiteln springen und die Lautstärke anpassen. Oder verwenden Sie die Lautstärketasten links am iPod touch. Wenn Sie zwischen Widescreen- und Vollbildanzeige wechseln wollen, reicht ein Doppeltipp auf das Display. Das ist wie die Fernbedienung des Fernsehers. Nur, dass Sie nicht darum kämpfen müssen.
     
    iTunes. Für beste Unterhaltung.
    Sie brauchen für den nächsten Flug oder die nächste Fahrt etwas Unterhaltung? Mit iTunes auf dem iPod touch und einer Wi-Fi Verbindung können Sie sofort Filme und Fernsehsendungen kaufen. Oder Sie kaufen sie auf Ihrem Mac oder PC und synchronisieren sie mit dem iPod touch. Nur das Popcorn ist nicht dabei.
     
     
    Besuchen Sie Ihre Lieblingswebsites. Alles, was Sie dazu brauchen, ist ein iPod touch und Wi-Fi. 
     
    Laden Sie die iBooks App kostenlos und Sie haben nicht nur einen großartigen E-Book-Reader, sondern auch einen tollen Ort, um Bücher zu kaufen. 
     
    Und vieles mehr...
     
    App Store
    Laden Sie Apps direkt auf den iPod touch
     
    iTunes
    Erstellen Sie einen iTunes Store Account und kaufen Sie jederzeit via Wi-Fi ein.
     
    iBooks
    Laden Sie die iBooks App kostenlos und Sie haben nicht nur einen großartigen E-Book-Reader, sondern auch einen tollen Ort, um Bücher zu kaufen.
     
    iMovie
    Bearbeiten Sie Videos, fügen Sie Themen und Musik hinzu und teilen Sie Ihre Filme mit Anderen
     
    Mail
    Senden Sie Mails und sehen Sie sich Anhänge von Ihrem Google Mail, MobileMe oder einem anderen E-Mail Account an.
     
    Safari Webbrowser
    Besuchen Sie Ihre Lieblingswebsites. Alles, was Sie dazu brauchen, ist ein iPod touch und Wi-Fi.
     
    Fotos
    Nehmen Sie Ihre Fotos mit. Teilen Sie sie per E-Mail. Wählen Sie Ihr Lieblingsfoto als Hintergrundbild.
     
    Homescreen
    Ordnen Sie in iTunes Ihre Apps auf mehreren Homescreens an.
     
     
    Sprachsteuerung
    Steuern Sie die Musik auf dem iPod touch mit Sprachbefehlen
     
    Karten
    Finden Sie Restaurants, Konzerte und mehr und lassen Sie sich mit Karten zeigen, wie Sie hinkommen.
     
    YouTube
    Sehen Sie sich die neuesten Videohits und Ihre Lieblingsvideos an.
     
    Nike + iPod
    Erreichen Sie Ihre Trainingsziele mit integrierter Unterstützung für Nike + iPod
     
    Sprachmemos
    Nehmen Sie Notizen, Gedanken oder alles andere auf.
     
    Bedienungshilfen
    Der iPod touch kommt mit Bildschirmlesefunktion und weiteren Bedienungshilfen
     
    Lieferumfang
    iPod touch, Ohrhörer, USB 2.0 Kabel, Dock Adapter, Kurzanleitung
    ";2;False;0;;;"Apple iPod touch 4G 8 GB ";apple-ipod-touch-4g-8-gb;True;True;PD-01067;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;209.9900;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;40637,4560300926;45;1;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000615-apple-ipod-touch-4g-32-gb.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000616-apple-ipod-touch-4g-32-gb.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000617-apple-ipod-touch-4g-32-gb.jpg;1;;False;;;;;False;False;False;;;;;False;;;;;; +5;0;True;"Apple iPod touch 4G 32 GB ";"Der neue iPod touch. Jetzt mit FaceTime, Retina Display, HD-Video und Game Center. ";"
    Der neue iPod touch. Jetzt mit FaceTime, Retina Display, HD-Video und Game Center.
     
    Spaß, hoch entwickelt. Der neue iPod touch.
    Tonnen von innovativen Funktionen gibt es jetzt auch auf dem iPod touch. Einfach damit er noch mehr Spaß macht. Teilen Sie schöne Momente mit Freunden via FaceTime. Nehmen Sie Videos in HD auf. Oder erleben Sie Spiele auf dem höchstauflösenden iPod Display, das es je gab. Der iPod touch hat so viel Technologie, dass Sie glatt vergessen, dass es ein iPod ist.
     
    Sieht unglaublich aus. Ist aber wahr.

    Mit seinem neuen Design ist der iPod touch der dünnste, leichteste und fantastischste iPod touch, den es je gab. Um das zu spüren, müssen Sie ihn nur in die Hand nehmen. Er ist gerade mal 7,2 mm dünn. Mit seiner Vorderseite aus Hightech-Glas und der Rückseite aus Edelstahl fühlt er sich einfach fantastisch an. Wenn Sie ihn einschalten, sind Sie sofort vom brillanten Retina Display fasziniert. Der iPod touch kombiniert großartiges Design und revolutionäre Technologie - von außen wie von innen.
     
    Retina Display. Die Zukunft sieht gut aus.
    Es gibt viele Gründe, den iPod touch immer wieder anzusehen. Beispielsweise das LCD-Display mit 960 x 640 Pixeln und Hintergrundbeleuchtung. Es hat eine Pixeldichte von 326 ppi und ist damit das höchstauflösende iPod Display, das es je gab. Die Apple Ingenieure haben dafür superkleine, kaum 78 Mikrometer breite Pixel entwickelt, die das menschliche Auge nicht mehr als einzelne Pixel wahrnehmen kann. Und obwohl Sie sie nicht sehen können, werden Sie den Unterschied bemerken. Der Text ist gestochen scharf und alles sieht leuchtend und lebendig aus.
     
    Apple A4 Prozessor. Mehr Power für Sie.
    Hinter - oder besser gesagt unter - dem ganzen Spaß, den Sie mit dem iPod touch haben, steckt der Apple A4 Chip. Die Apple Ingenieure haben den A4 Chip als leistungsstarken und energieeffizienten Mobilprozessor entworfen. Damit bewältigt der iPod touch komplexe Aufgaben wie Multitasking, Videoschnitt und FaceTime Anrufe. All das bei noch mehr Batterielaufzeit. Und mehr Spaß.
     
    Gyrosensor + Beschleunigungssensor. Wirklich bewegend.
    Der iPod touch hat jetzt ein paar neue Tricks drauf. Er hat einen integrierten 3-Achsen-Gyrosensor, der zusammen mit dem Beschleunigungssensor dafür sorgt, dass der iPod touch Aktionen wie Beschleunigung, 3D Bewegung und Drehrate erkennt. Im Klartext: Mehr Bewegungen, mehr Gesten und größere Präzision für noch mehr Spielspaß.
     
    Zwei Kameras. Doppelt so viel Spaß.
    Für Videoaufnahmen hat der iPod touch zwei integrierte Kameras. Mit der Rückkamera nimmt er fantastische HD 720p Videos auf. Und der hoch entwickelte rückwärtig belichtete Sensor sorgt selbst bei schwacher Beleuchtung für tolle Aufnahmen. Das integrierte Mikrofon nimmt dabei gleichzeitig Gespräche, Musik oder alles andere auf. Die Frontkamera des iPod touch ist perfekt für FaceTime Anrufe1 und um sich selbst aufzunehmen. Schon erstaunlich, wie viel Spaß in etwas so Kleines passt.
    Multi-Touch. Alles unter Kontrolle Ihrer.
    Wie macht der iPod touch eigentlich genau das, was Sie wollen, wenn Sie mit Ihren Fingern über das Display streichen? Genau genommen ist es eine Kettenreaktion. Das Multi-Touch Display hat einen Schutzfilm über der kapazitiven Sensorik, die Berührungen anhand elektrischer Felder erkennt. Diese Informationen werden an das Retina Display darunter übermittelt. So könen Sie alles mit den Fingern steuern, mit Cover Flow in Ihren Alben blättern, Fotos sehen und vergrößern, in eine Website zoomen und Spiele steuern.
     
    FaceTime auf dem iPod touch. Sagen Sie nicht einfach Hallo. Sagen Sie es mit einem Lächeln.
    Ein Lächeln sagt mehr als tausend SMS.
    Bringen Sie LOL auf die nächste Stufe und sehen Sie Ihre Freunde wirklich lachen. Oder lassen Sie XOXO lebendig werden und schicken Sie einen Kuss um die halbe Welt. FaceTime auf dem iPod touch macht's möglich. FaceTime funktioniert sofort nach dem Auspacken - Sie geben einfach Ihre Apple ID und E-Mail Adresse ein. Oder erstellen einen neuen E-Mail Account extra für FaceTime. FaceTime ist supereinfach. Stellen Sie sich vor, Sie wollen über Wi-Fi mit Ihrer besten Freundin videotelefonieren. Dann tippen Sie auf die FaceTime App, finden sie dort und starten den Anruf. Auf ihrem iPod touch oder iPhone 4 erscheint dann eine Einladung, die sie annehmen kann. Sobald sie annimmt, wird FaceTime gestartet. Das alles funktioniert ganz nahtlos und sowohl im Hoch- als auch im Querformat. Sie werden im wahrsten Sinne des Wortes sehen, wie viel Spaß Sie haben können.
     
    Videotelefonieren Sie mit Freunden per FaceTime oder spielen Sie gegen Freunde oder Fremde mit Game Center.
     
    Zwei Kameras für Spaß von jeder Seite.
    Der iPod touch hat zwei Kameras - eine vorne über dem Display und eine auf der Rückseite. Die Frontkamera ist für FaceTime optimiert. Sie hat genau das richtige Sichtfeld und die richtige Brennweite, um auf die Entfernung einer Armlänge das Gesicht zu fokussieren. So zeigt sie Sie immer im besten Licht. Was besonders praktisch ist, wenn Sie mit jemandem sprechen, der mehr als nur ein Freund ist.
    Die Rückkamera. Teilen Sie Ihre Ansicht.
    Wenn Ihre Mitbewohnerin es doch nicht mehr zum Konzert schafft, lassen Sie sie mit FaceTime doch wenigstens die Zugabe sehen. Wenn die Band auf die Bühne kommt und ihren Lieblingshit spielt, tippen Sie einfach auf die Taste. Und noch bevor der Sänger die erste Zeile singt, wechselt der iPod touch zur Rückkamera und überträgt einen mit Sicherheit legendären Auftritt. Tippen Sie noch einmal und der iPod touch wechselt zurück auf die Frontkamera und zu Ihnen. Einfach und schnell - macht einfach Spaß!
     
    HD Videoaufnahme auf dem iPod touch. Nehmen Sie jeden Spaß mit. Und auf.
     
    Integrierter Schnittplatz.
    Sie müssen mit dem Bearbeiten Ihrer Videos nicht warten, bis Sie wieder am Computer sitzen. Einfache Schnittfunktionen sind direkt im iPod touch integriert, sodass Sie gleich damit loslegen können. Ziehen Sie einfach, um Start- und Endpunkt des Films festzulegen. Behalten Sie nur die Teile des Videos, die Ihnen besonders gefallen, und machen Sie daraus einen Film, den Sie und Ihre Freunde immer und immer wieder anschauen wollen.
     
    Mit iMovie auf dem iPod touch erstellen Sie Minikinofilmhits mit ein paar Fingertipps.
    Stellen Sie sich vor, Sie sind unterwegs und wollen eine Videopostkarte erstellen, mit allem, was Sie erlebt und gesehen haben. Machen Sie das einfach mit der iMovie App - Sie bekommen sie im App Store. Mit iMovie für den iPod touch können Sie Videoclips zusammenfügen und bearbeiten, ihnen mit dynamischen Themen und Übergängen noch eine Extraportion Wow geben, Musik und Fotos hinzufügen und den fertigen Film mit allen teilen.
     
    Drehen Sie einen Film. Mit Ihnen in der Hauptrolle.
    Wenn Sie das nächste Mal eine aufregende Wanderung gemacht haben, erzählen Sie Ihren Freunden nicht nur davon - zeigen Sie es ihnen. Neben der HD Kamera auf der Rückseite besitzt der iPod touch eine Frontkamera mit VGA-Qualität über dem Display. So sehen Sie sich selbst, während Sie Videos aufnehmen. Das ist perfekt, um sich selbst zu filmen, denn Sie brauchen nicht mehr zu hoffen, dass Sie im Bild sind, sondern sehen es gleich. Also machen Sie sich bereit für die Aufnahme.
     
    Teilen Sie mit Freunden den Rest Ihres Lebens.
    Haben Sie auch schon mal eine Mail geschrieben und dabei etwas Unbeschreibliches gesehen? Dann nehmen Sie die Kamera und nehmen Sie es auf. Anschließend können Sie Ihren HD Film direkt auf YouTube laden. Oder wählen Sie ein Video aus den Aufnahmen und verschicken es mit einer Mail. Sie können es auch mit einem Fingertipp auf Ihre Facebook Seite oder in Ihren Blog posten. Und alle mit dem iPod touch aufgenommenen Videos ganz leicht mit Ihrem Mac oder PC synchronisieren.
    So haben alle ein gutes Bild von Ihnen.

    Eine unglaubliche Aussicht. Ein toller Kuchen. Ihr Hund, wie er soooooo süß schaut. Wenn Sie einen Schnappschuss für Facebook machen wollen, können Sie eine der beiden Kameras des iPod touch verwenden. Tippen Sie einfach auf das Display, um die Belichtung anzupassen. Dann posten Sie das Bild auf Facebook und warten auf die Kommentare.
     
    Game Center. Spielen Sie gegen Ihre besten Feinde
    Game Center. Mögen die Spiele beginnen.
    Mit der neuen Game Center App auf dem iPod touch können Sie Ihr Spiele-Netzwerk erweitern. Exponentiell. Zum Spielen brauchen Sie nur einen iPod touch oder ein iPhone mit iOS 4.1. Bei iOS 4.1 wird eine Game Center App auf dem Homescreen angezeigt. Tippen Sie einfach darauf, meldes sich mit Ihrer Apple ID an und schon kann´s losgehen. Sie können einen Spielernamen erstellen, der für Ihre Freunde und die Spieler-Community sichtbar ist. Fügen Sie mehrere E-Mail Adressen zur Game Center App hinzu, damit Freunde Sie einfacher finden können. Sie können die Spiele über die Links im Game Center laden und auch direkt aus der Game Center App starten. Und das Beste: Sobald Sie sich bei Game Center anmelden, bleiben Sie verbunden. Bis Sie dich wieder abmelden.
     
    Beste Freunde. Bald beste Gegner.
    Treten Sie gegen Ihre Freunde in einem Rennen an. Oder einem Match. Oder in einem Kampf. Wenn Sie bei der Game Center App angemeldet sind, können Sie jemanden mit einer Freundschaftsanfrage einladen und dafür den Spielernamen oder die E-Mail Adresse der Person verwenden. Ihre Freunde erscheinen in einer separaten Freundeliste in der Game Center App. Tippen Sie auf die Namen von Freunden und Sie sehen, welche Spiele sie gespielt haben. Sie können auch neue Freundschaftsanfragen ansehen und eigene hinzufügen.
    Leaderbords und Erfolge. Damit jeder sieht, wo Sie stehen.
    Sehen Sie sich auf den Ranglisten für jedes Spiel Ihre Platzierung unter Ihren Freunden und anderen Spielern an. Sie können auch Ihre Erfolge mit denen Ihrer Freunde vergleichen. Sehen Sie sich die Leaderboards und Erfolge in der Game Center App und jedem einzelnen Spiel an. Und dann lassen Sie es krachen.
     
    Trefen Sie Ihre Gegner. Und treffen Sie sie hart.
    Sie möchten eine Runde mit mehreren Freunden spielen? Mit Auto-Match werden Ihnen zuerst Ihre Freunde als Gegner vorgeschlagen, wenn diese auch nach einem Auto-Match suchen. Wenn nicht, wird Ihnen ein Freund in spe irgendwo auf dem Globus als Gegner vorgeschlagen. Oder laden Sie Ihre Freunde ein und lassen Sie Auto-Match alle für ein Spiel benötigten Spieler finden.
    Musik. Lassen Sie Ihre Finger tanzen.
    Cover Flow. Musik sieht so gut aus.
    Auf dem iPod touch gibt's Musik nicht nur auf die Ohren. Mit Cover Flow ist sie auch was für Augen und Finger. Drehen Sie den iPod touch auf die Seite und blättern Sie durch Ihre Albumcover. Tippen Sie auf ein Cover, um es umzudrehen und die Songliste zu sehen. Noch ein Tipp und die Musik läuft.
     
    Genius Wiedergabelisten. In jedem guten Song steckt eine noch bessere Wiedergabeliste.
    Angenommen Sie hören einen Song auf einem iPod touch, der Ihnen gut gefällt, und möchten weitere Titel hören, die gut dazu passen. Genius findet weitere Songs auf Ihrem iPod touch und erstellt eine Genius Wiedergabeliste. Hören Sie sich die Liste sofort an, speichern Sie sie für später oder versuchen's noch einmal und sehen, was dabei herauskommt. Verlassen Sie sich auf Genius, wenn Sie einen Mix wollen, auf den Sie selbst nie gekommen wären. 
     
    Genius Mixe. Nehmen Sie den DJ mit nach Hause.
    Genius ist Ihr persönlicher DJ. Synchronisieren Sie Ihren iPod touch mit iTunes und Genius durchsucht Ihre Mediathek automatisch nach Songs, die gut zusammenpassen. Dann erstellt Genius mehrere Mixe. Diese Mixe sind wie Radiosender, auf denen nur Ihre Lieblingshits laufen. So finden Sie Songs wieder, die Sie lange nicht mehr gehört haben oder von denen Sie gar nicht mehr wussten, dass Sie sie haben.
     
    Lassen Sie Ihre Finger tanzen. 
     
    Shake to shuffle. So ein Zufall.
    Die Dinge mal aufrütteln. Musikalisch natürlich. Wenn Sie das nächste Mal Musik hören, aktivieren Sie einfach die Schüttelfunktion. Wenn Sie den iPod touch dann kurz schütteln, springt er nach dem Zufallsprinzip zu einem anderen Song in Ihrer Sammlung. So entdecken Sie Ihre Musik immer wieder neu.
     
    iTunes. Das ist Entertainment.
    Packen Sie Songs und Musikvideos aus Ihrer iTunes Mediathek auf dem Computer auf den iPod touch. Oder kaufen und laden Sie neue Songs auf den iPod touch, wenn Sie sich über Wi-Fi mit iTunes verbinden. Wenn Sie dann den iPod touch das nächste Mal mit dem Computer verbinden, werden alle Songs, die Sie auf dem iPod touch gekauft haben, auf den Mac oder PC übertragen. Und mit iTunes Ping können Sie jetzt sehen, welche Musik Ihre Freunde hören, kaufen und empfehlen. Oder informieren Sie sich dort über Ihre Lieblingskünstler und was sie so hören.
     
    Bluetooth. Entfesseln Sie Ihre Musik.
    Die Unterstützung für das drahtlose Bluetooth ist im iPod touch schon drin. Das heißt, Sie können drahtlose Stereokopfhörer verwenden. Lassen Sie den iPod in Ihrer Tasche stecken oder auf dem Schreibtisch aufladen, während Sie weiter Musik hören.
     
    Filme und Fernsehsendungen. So haben Sie überall eine Sehenswürdigkeit.
    Ganz großes Kino. Auf einem kleinen Display.
    Mit dem iPod touch ist jeden Tag und überall Kinotag. Nehmen Sie Videos für viele Stunden Unterhaltung mit und sehen Sie sie auf dem fantastischen 3,5 Zoll Retina Display an. Kaufen Sie im iTunes Store und wählen Sie aus tausenden Filmen, Fernsehsendungen und Video-Podcasts für Ihren iPod touch. Da ist für jeden etwas dabei - von Hollywood Blockbustern bis zu Independent Filmen. Ein paar Fingertipps und Sie haben Filme geladen und können sie ansehen. Sie mögen lieber Fernsehsendungen? Die gibt's auch. Sie können einzelne Folgen oder gleich eine ganze Staffel kaufen. Mit dem iPod touch haben Sie Ihre Videos immer dabei.
    Sie haben alles unter Kontrolle.
    Wenn Sie ein Video schauen, tippen Sie einfach auf das Display und schon haben Sie die Steuerung. Damit können Sie die Wiedergabe starten oder unterbrechen, zu einzelnen Kapiteln springen und die Lautstärke anpassen. Oder verwenden Sie die Lautstärketasten links am iPod touch. Wenn Sie zwischen Widescreen- und Vollbildanzeige wechseln wollen, reicht ein Doppeltipp auf das Display. Das ist wie die Fernbedienung des Fernsehers. Nur, dass Sie nicht darum kämpfen müssen.
     
    iTunes. Für beste Unterhaltung.
    Sie brauchen für den nächsten Flug oder die nächste Fahrt etwas Unterhaltung? Mit iTunes auf dem iPod touch und einer Wi-Fi Verbindung können Sie sofort Filme und Fernsehsendungen kaufen. Oder Sie kaufen sie auf Ihrem Mac oder PC und synchronisieren sie mit dem iPod touch. Nur das Popcorn ist nicht dabei.
     
     
    Besuchen Sie Ihre Lieblingswebsites. Alles, was Sie dazu brauchen, ist ein iPod touch und Wi-Fi. 
     
    Laden Sie die iBooks App kostenlos und Sie haben nicht nur einen großartigen E-Book-Reader, sondern auch einen tollen Ort, um Bücher zu kaufen. 
     
    Und vieles mehr...
     
    App Store
    Laden Sie Apps direkt auf den iPod touch
     
    iTunes
    Erstellen Sie einen iTunes Store Account und kaufen Sie jederzeit via Wi-Fi ein.
     
    iBooks
    Laden Sie die iBooks App kostenlos und Sie haben nicht nur einen großartigen E-Book-Reader, sondern auch einen tollen Ort, um Bücher zu kaufen.
     
    iMovie
    Bearbeiten Sie Videos, fügen Sie Themen und Musik hinzu und teilen Sie Ihre Filme mit Anderen
     
    Mail
    Senden Sie Mails und sehen Sie sich Anhänge von Ihrem Google Mail, MobileMe oder einem anderen E-Mail Account an.
     
    Safari Webbrowser
    Besuchen Sie Ihre Lieblingswebsites. Alles, was Sie dazu brauchen, ist ein iPod touch und Wi-Fi.
     
    Fotos
    Nehmen Sie Ihre Fotos mit. Teilen Sie sie per E-Mail. Wählen Sie Ihr Lieblingsfoto als Hintergrundbild.
     
    Homescreen
    Ordnen Sie in iTunes Ihre Apps auf mehreren Homescreens an.
     
     
    Sprachsteuerung
    Steuern Sie die Musik auf dem iPod touch mit Sprachbefehlen
     
    Karten
    Finden Sie Restaurants, Konzerte und mehr und lassen Sie sich mit Karten zeigen, wie Sie hinkommen.
     
    YouTube
    Sehen Sie sich die neuesten Videohits und Ihre Lieblingsvideos an.
     
    Nike + iPod
    Erreichen Sie Ihre Trainingsziele mit integrierter Unterstützung für Nike + iPod
     
    Sprachmemos
    Nehmen Sie Notizen, Gedanken oder alles andere auf.
     
    Bedienungshilfen
    Der iPod touch kommt mit Bildschirmlesefunktion und weiteren Bedienungshilfen
     
    Lieferumfang
    iPod touch, Ohrhörer, USB 2.0 Kabel, Dock Adapter, Kurzanleitung
    ";2;False;0;;;"Apple iPod touch 4G 32 GB ";apple-ipod-touch-4g-32-gb;True;True;PD-01066;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;279.9900;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;40637,445775463;45;1;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000615-apple-ipod-touch-4g-32-gb.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000616-apple-ipod-touch-4g-32-gb.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000617-apple-ipod-touch-4g-32-gb.jpg;1;;False;;;;;False;False;False;;;;;False;;;;;; +5;0;True;Apple iPod shuffle 2 GB 4G;"Der neue, bunte, tragbare iPod shuffle. Mit Tasten, VoiceOver und Wiedergabelisten - der beste iPod shuffle, den es je gab. ";"Der neue, bunte, tragbare iPod shuffle.
    Mit Tasten, VoiceOver und Wiedergabelisten - der beste iPod shuffle, den es je gab.
     
    Eingebauter Clip.

    Sie ist wieder da - die große Klickbedienung vorn auf dem iPod shuffle.
     
    Erhältlich in Silber, Blau, Grün, Orange und Pink.
     
    Design. Ganz schön ansteckend.
    Elegantes, poliertes Aluminium. Fünf leuchtende Farben.
    Das Gehäuse des iPod shuffle ist aus einem Stück Aluminium. Und weil es außerdem poliert ist, können Sie mit dem neuen, eleganten und robusten iPod shuffle richtig glänzen. Seine brillanten Farben machen ihn dabei zum perfekten Accessoire. Wählen Sie zwischen Silber, Blau, Grün, Orange und Pink.
     
    Hunderte Songs für unterwegs.
    Nehmen Sie Ihre Lieblingssongs überallhin mit. Neben 15 Stunden Batterielaufzeit1 kommt der iPod shuffle mit 2 GB Speicher - das heißt Platz für hunderte von Songs. Genug für alle Songs für Ihr Fitness-Training oder den Weg zur Arbeit. Und auch für mehrere Wiedergabelisten, Genius Mixe, Podcasts und Hörbücher.
     
    Geht immer. Und überall.
    Der iPod shuffle ist nicht nur tragbar. Er ist auch ansteckbar. Klippen Sie ihn an Hemd, Jacke, Jogginghose, Rucksack oder Tasche und er ist überall mit dabei - egal, ob Sie zum Supermarkt laufen oder zu Ihrer persönlichen Bestzeit.
     
    Bedienung. Musik auf Knopfdruck.

    Steuern Sie Ihre Musik mit nur einem Klick.
    Sie ist wieder da - die große Klickbedienung vorn auf dem iPod shuffle. Sie ist 18 Prozent größer als bei den Vorgängermodellen. So können Sie sie sie noch leichter sehen und bedienen. Drücken Sie auf die Mitteltaste, um die Wiedergabe zu starten oder zu stoppen. Drücken Sie auf die äußeren Tasten, um vor- und zurückzuspringen oder die Lautstärke anzupassen. Klick, klick, klick. Das ist Musik für Ihre Finger.
     
    Spielt nach Ihren Regeln.
    Sie sind eher ein spontaner Typ? Oder haben Sie vielleicht lieber Ihre Ordnung? Stellen Sie den Schalter für die Zufallswiedergabe so ein, wie Sie wollen. Links wird Ihre Musik zufällig durcheinander gewürfelt. In der Mitte werden Ihre Songs in der normalen Reihenfolge gespielt. Und rechts schalten Sie den iPod shuffle aus.
     
    Geben Sie Ihren Songs eine Stimme.
    Angenommen Sie hören einen Song und wollen den Titel oder den Interpreten wissen. Drücken Sie einfach oben auf deinem iPod shuffle auf die neue VoiceOver Taste und VoiceOver nennt Ihnen beides. VoiceOver nennt Ihnen auch die Namen Ihrer Wiedergabelisten und wechselt zwischen diesen. Und wenn die Batterie aufgeladen werden muss, sagt VoiceOver das auch.
     
    Spricht Ihre Sprache.
    Französische Chansons. Spanische Flamencos. Italienische Arien. Ihr Musikarchiv enthält Songs aus allen Ländern der Erde. Deshalb spricht VoiceOver 25 verschiedene Sprachen. Und kann Ihnen Songtitel und Interpreten in deren jeweiliger Landessprache oder einer anderen Sprache nennen.
     
    Wiedergabelisten. Der perfekte Mix für jede Stimmung.
    Ganz einfach synchronisieren.
    Mit iTunes auf dem Mac oder PC können Sie Ihre Sachen ganz einfach auf den iPod shuffle laden. Wählen Sie einfach die Hörbücher, Wiedergabelisten, Podcasts und andere Audiodateien, die Sie wollen, und synchronisieren Sie sie.
     
    Wenn eine Wiedergabeliste nicht reicht.

    Wahrscheinlich haben Sie in iTunes auf Ihrem Computer mehrere Wiedergabelisten. Eine für unterwegs. Eine fürs Fitnessstudio. Eine zum Chillen. Jetzt können Sie diese Wiedergabelisten mit dem iPod shuffle synchronisieren und haben immer genau den richtigen Mix - egal, in welcher Stimmung Sie gerade sind. VoiceOver nennt Ihnen den Namen jeder Wiedergabeliste. So können Sie ganz leicht zwischen ihnen wechseln und genau die auswählen, nach der Ihnen gerade ist.
     
    Genius auf dem iPod shuffle.

    Und es gibt noch einen anderen Weg einen guten Mix auf den iPod shuffle zu bekommen: Verlassen Sie sich auf Genius. Aktivieren Sie Genius in iTunes auf dem Computer und er findet automatisch Songs, die gut zusammenpassen. Dann werden Genius Mixe erstellt, die Sie ganz einfach mit Ihrem iPod shuffle synchronisieren können. Das ist perfekt, um Songs zu entdecken, die Sie schon seit Jahrhunderten nicht mehr gehört haben.
     
    Lieferumfang
    iPod shuffle, Ohrhörer, iPod shuffle USB Kabel (4,5 cm), Dokumentation";2;False;0;;;Apple iPod shuffle 2 GB 4G;apple-ipod-shuffle-2-gb-4g;True;True;PD-01065;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;54.9000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;40637,4367824074;41;1;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000600-apple-ipod-shuffle-2-gb-4g.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000601-apple-ipod-shuffle-2-gb-4g.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000602-apple-ipod-shuffle-2-gb-4g.jpg;1;;False;;;;;False;False;False;;;;;False;;;;;; +5;0;True;Nokia Lumia 800 Smartphone;Nokia Lumia 800 Smartphone (9,4 cm (3.7 Zoll) AMOLED Clear Black-Touchscreen, Micro-SIM only, Windows Phone Mango OS, 8 MP Kamera) schwarz;"
    Einfacher ist besser.
    Das Nokia Lumia 800 mit Windows Phone. Alle Aktivitäten Ihrer Kontakte auf einen Blick.
     
    Startseite
    Legen Sie Gruppen oder Kontakte auf der Startseite ab, um noch schneller auf sie zuzugreifen. Sie können beliebige Elemente auf der Startseite ablegen. Halten Sie einfach den Finger auf die gewünschten Apps oder Tools, bis das Menü „Auf Startseite“ angezeigt wird.
     
    Gruppen
    Die Gruppe „Familie“ ist im Kontakte-Hub vorkonfiguriert, damit Sie sofort loslegen können. Sie schlägt Ihnen Kontakte mit übereinstimmenden Namen als Gruppenmitglieder vor. Doch Sie können auch beliebige andere Gruppen als Kachel auf der Startseite ablegen. In diesen Kacheln werden Profilfotos, entgangene Anrufe und Status-Updates aller Kontakte dieser Gruppe anzeigt. Sofort nach einer Status-Änderung beginnt diese Kachel, sich in sich selbst zu drehen, damit Sie keine Nachricht mehr verpassen. Wenn Sie Ihre Kontakte leichter voneinander unterscheiden möchten, können Sie ihnen individuell oder als Gruppe eigene Klingeltöne zuweisen. Tippen Sie einfach auf das gewünschte Profil und dann auf das Stift-Symbol, um einen Klingelton zu bearbeiten und hinzuzufügen.
     
    Immer tolle Fotos
    Fotografieren war noch nie so einfach – betätigen Sie einfach den Auslöser. Sie müssen das Smartphone noch nicht einmal entsperren, um richtig tolle Fotos zu machen. Danach können Sie die Fotos ebenso schnell auf Facebook oder anderen sozialen Netzwerken veröffentlichen. Und die 5-Megapixel-Kamera mit Autofokus sorgt für brillante, detailreiche Fotos, die garantiert Eindruck machen.
     
    Sprachgesteuerte Aktivierung
    Halten Sie einfach die Windows-Taste gedrückt, um die Spracherkennung zu aktivieren. Sie können mithilfe von Sprachbefehlen Anrufe tätigen, Ihren Kalender aufrufen, Texte diktieren und sogar Internetrecherchen durchführen.
     
    Multitasking
    Halten Sie den Zurück-Pfeil gedrückt, um zu sehen, welche Anwendungen gleichzeitig ausgeführt werden. Profil
    Nokia Lumia Smartphones sind automatisch mit Facebook verknüpft und verwenden Ihr Standard-Profilbild. Doch auch das können Sie im Handumdrehen ändern – tippen Sie einfach auf „Profil“, um ein neues Foto auszuwählen.
     
    Nokia Lumia Smartphones und Bing
    Starten Sie die Anwendung im Handumdrehen über das Symbol „Suchen“, um Internetrecherchen durchführen zu können, ohne den Browser zu öffnen. Geben Sie einfach Ihren Suchbegriff ein und wählen Sie das beste Ergebnis. Einfach. Intuitiv. Schnell.
     
    Apps
    Mit Wi-Fi laden Sie Apps mit größerem Dateiumfang, mobile Spiele und Medien noch schneller herunter. So können Sie das von Ihrem Provider ggf. im Rahmen eines Vertrags zur Verfügung gestellte Dateivolumen genau dann nutzen, wenn Sie es wirklich benötigen.
     
    Xbox Live Avatar
    In Xbox Live erstellen Sie ganz leicht einen Avatar für die Xbox Community. Öffnen Sie einfach Xbox Live und klicken Sie auf „Avatar“. Dort können Sie Ihrer Figur je nach Wunsch Frisur, Gesichtszüge und Kleider geben - auch als Abbild Ihrer selbst. Eben einfach die vielen kleinen Dinge, die Sie unverwechselbar machen. Lassen Sie Ihrer Kreativität freien Lauf und freuen Sie sich auf rasantes Gaming.
     
    Musik kaufen
    Mit Millionen von Songs zur Auswahl bietet Ihnen Nokia Musik jederzeit Zugriff auf die neuesten Hits und Ihre Lieblings-Klassiker. Nutzen Sie einfach die Suchfunktion oder stöbern Sie in den neuesten Veröffentlichungen. Wenn Sie sich entschieden haben, genügt eine Berührung, um den Song zu kaufen und in Ihre Bibliothek herunterzuladen.
     
    Schnelle Steuerung
    Wahrscheinlich möchten Sie noch mehr tun, als nur Musik zu hören. Deshalb ist es gut, dass Sie nicht jedes Mal Nokia Musik öffnen müssen, um zu einem anderen Song zu wechseln. Tippen Sie einfach auf die Lautstärkeregelung und unterbrechen oder überspringen Sie Songs über den Schnellzugriff. Das funktioniert auch, wenn das Smartphone gesperrt ist.
     
    Aktuelle Wiedergabe
    Über die Wiedergabeliste können Sie Musik aus Ihrer Bibliothek jederzeit individuell steuern - beispielsweise als zufällige Wiedergabe oder als Dauerschleife.
     
    Sprachgestützte Navigation
    Die Nokia Navigation mit gesprochenen Richtungsanweisungen ist auf Ihrem Nokia Lumia Smartphone vorinstalliert. Ihnen gefällt die Stimme nicht? Dann ändern Sie einfach die Ansagestimme der Navigation oder laden Sie eine neue herunter. Öffnen Sie dazu die Einstellungen und wählen Sie die Stimme, die Ihnen am angenehmsten ist.
     
    Tag und Nacht
    Sie werden bei Nachtfahrten nie wieder durch Ihr Navigationssystem geblendet. Mit der Nokia Navigation können Sie die Helligkeit des Displays anpassen, ohne dadurch die Deutlichkeit der Anzeige zu beeinträchtigen.
     
    2D und 3D
    Die Nokia Navigation bietet sowohl 2D- als auch 3D-Kartenansichten. Wenn Sie also eine genauere Ansicht Ihrer Route benötigen oder nach einprägsamen Orientierungspunkten Ausschau halten möchten, können Sie die Ansicht einfach über die Einstellungen ändern.
     
    Nokia Karten herunterladen
    Nokia Karten ist nach wenigen Handgriffen auf Ihrem Smartphone einsatzbereit. Diese App beinhaltet kostenlose Reiseführer, Veranstaltungstipps, interessante Ziele in Ihrer Nähe, Wetterinfos und vieles mehr. Öffnen Sie die Karten-Kachel, rufen Sie Marketplace auf und starten Sie den Download – die Anwendung ist kostenlos. Nach der Installation können Sie Nokia Karten über 3G- oder WLAN-Verbindungen nutzen.
    ";2;False;0;;;Nokia Lumia 800 Smartphone;nokia-lumia-800-smartphone;True;True;P-0006;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;499.0000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;40603,5677546296;"74;2095";17;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000534-nokia-lumia-800-smartphone.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000535-nokia-lumia-800-smartphone.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000536-nokia-lumia-800-smartphone.jpg;1;;False;;;;;False;False;False;;;;;False;;;;;; +5;0;True;Nokia N9 Smartphone blau;Nokia N9 Smartphone (9,9 cm (3,9 Zoll) Display, 16GB, Touchscreen, 8 Megapixel Kamera) blau;"
    Nokia N9 Smartphone
    Formatfüllender Touchscreen
    Ein einzigartiges Smartphone mit formatfüllendem Touchscreen. Die gewölbte Oberfläche aus kratzfestem Glas geht nahtlos in das glatte, aus einem Block gefertigte Gehäuse über. Jedes Detail strahlt Innovation aus. Auf dem brillanten AMOLED-Touchscreen erscheint alles in lebendigen Farben und das gewölbte Glas macht den Wechsel zwischen Apps per Fingerbewegung zum Kinderspiel.
     
    Einfach nur eine Fingerbewegung - Überzeugend benutzerfreundlich
    Alles läuft auf eine einfache Fingerbewegung hinaus. Das macht die Nutzung dieses Smartphones so intuitiv wie nie zuvor. Es gibt keine Zurück- oder Menü-Taste mehr – nur fliessende Fingerbewegungen, während Sie von App zu App wechseln. Mit einer Fingerbewegung über eine beliebige Ecke des Touchscreens gelangen Sie zur Startansicht, mit einer weiteren Bewegung wechseln Sie zwischen den drei Startansichten.
     
    Eine Startansicht - Drei einfache Ansichten
    Drei Ansichten sind alles, was Sie brauchen. In der vertrauten App-Ansicht starten Sie Anwendungen, eine weitere Ansicht zeigt die offenen Apps und macht Multitasking zum Kinderspiel: Sie machen genau dort weiter, wo Sie aufgehört haben.- Die Ansicht ""Ereignisse"" bringt Sie jederzeit auf den neuesten Stand der Dinge. Live-Feeds von Facebook und Twitter, E-Mails in Echtzeit, RSS-Feeds und mehr – alles an einer Stelle.
     
    Karten und Navigation kostenlos
    Live-Feeds von Facebook und Twitter, E-Mails in Echtzeit, RSS-Feeds und mehr – alles an einer Stelle. Sie finden die besten Angebote in Ihrer Stadt wie Cafés, Geschäfte, Konzerte, Hotels und mehr. Für mehr als 80 Städte weltweit steht Ihnen eine Übersicht von Strecken und Haltestellen des öffentlichen Nahverkehrs zur Verfügung. Entsprechendes Kartenmaterial ist bereits vorinstalliert, sodass Sie sofort starten können. Die Anwendung ""Fahren"" ist dank einfacher Bedienung über Touchscreen für die Verwendung im Auto optimiert.
     
    Browser der nächsten Generation
    Zeit für mehr Tempo. Das Nokia N9 bietet einen schnellen mobilen Internet-Browser und Seiten werden in kürzester Zeit aufgebaut. Die Unterstützung für HTML5 bedeutet für Sie das Beste aus dem Web, inklusive interaktiver Apps und schneller Videowiedergabe. Der Browser reagiert schnell auf jede Berührung. Sie können mehrere Seiten gleichzeitig öffnen und schnell zwischen den Seiten wechseln.
     
     
     
    8-Megapixel-Kamera mit Optik von Carl Zeiss
    Die Gelegenheit für ein gutes Foto kommt schnell und ist ebenso schnell vorbei. Mit der integrierten 8-Megapixel-Kamera mit Optik von Carl Zeiss können Sie brillante Fotos oder Videos in herausragender HD-Qualität aufnehmen.
     
    Die besten Apps und Spiele
    Apps sind heutzutage allgegenwärtig. Das Wichtigste ist jedoch die Qualität und nicht, wie viele man besitzt. Auf dem Nokia N9 sind die besten Apps wie Skype, Facebook, Twitter, AccuWeather und AP Mobile bereits vorinstalliert. Auch die Vollversion von Angry Birds ist bereits vorinstalliert – für viele Stunden Spass. Und im Ovi Store gibt es viele weitere Apps und Spiele.
    ";2;False;0;;;Nokia N9 Smartphone blau;nokia-n9-smartphone-blau;True;True;P-0008;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;569.0000;569.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;40602,8930439815;74;17;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000280-nokia-n9-smartphone-blau.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000281-nokia-n9-smartphone-blau.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000282-nokia-n9-smartphone-blau.jpg;1;;False;;;;;False;False;False;;;;;False;;;;;; +5;0;True;Apple iPod Nano 8 GB verschiedene Farben;Apple iPod Nano 8 GB;"
    Apple iPod Nano 8 GB
     
     
    Neues gebogenes Design, der dünnste iPod, den es je gab mit neuen Farben zu Auswahl
    Die Bedieung optimiert: ein einziges Handschütteln und ein anderes Lied wird gespielt
    Die neue Funktion ""Genius"" findet die Songs in Ihrer Mediathek, die besonders gut zusammenpassen, und erstellt daraus eine Genius Wiedergabeliste.
    Viele Abspielformate: z.B. MP3, AAC, Apple Lossless, AIFF, WAV, H.264, MPEG-4
    Lieferumfang: iPod Nano, Ohrhörer, USB 2.0 Kabel, Dock-Adapter, Dokumentation
     
    Neues gebogenes Design, der dünnste iPod, den es je gab mit neuen Farben zu Auswahl
    Die Bedieung optimiert: ein einziges Handschütteln und ein anderes Lied wird gespielt
    Die neue Funktion ""Genius"" findet die Songs in Ihrer Mediathek, die besonders gut zusammenpassen, und erstellt daraus eine Genius Wiedergabeliste.
    Viele Abspielformate: z.B. MP3, AAC, Apple Lossless, AIFF, WAV, H.264, MPEG-4
    Lieferumfang: iPod Nano, Ohrhörer, USB 2.0 Kabel, Dock-Adapter, Dokumentation
     
    Ein musikalisches Genie
    Stell Dir vor, Du hörst einen Song. Toll wären jetzt andere Titel, die gut dazu passen. Was machst du? Ganz einfach: Du verwendest die neue Funktion ""Genius"". Diese findet die Songs in Deiner Mediathek, die gut zusammenpassen. Du erhältst eine Genius Wiedergabeliste, zusammengestellt von Deinem persönlichen, superintelligenten DJ.  
    Musik schneller finden
    Auch einen Song, den Du hören willst, findest Du jetzt viel einfacher. Du kannst Deine Alben mit Cover Flow anzeigen oder hältst einfach die mittlere Taste gedrückt und blätterst in Deinen Alben oder Interpreten. Den gewünschten Song gefunden? Einmal auf die mittlere Taste gedrückt, und schon hast Du ihn zur aktuellen Wiedergabeliste hinzugefügt. 
     
    Aufdrehen und rumdrehen
    Neige Deinen iPod nano in die Waagerechte, und schon kannst Du hören, sehen oder spielen wie nie zuvor. Deine Alben kannst Du mit Cover Flow durchblättern und siehst so viel mehr Alben oder Interpreten gleichzeitig auf dem Display.
     
    Shake it, Baby!
    Manchmal hat man einfach Lust auf eine kleine Überraschung. Darum kannst Du jetzt komplett dem Zufall überlassen, welches Lied Du als Nächstes hörst. Einfach den iPod nano kurz schütteln – und er springt zu irgendeinem anderen Song aus Deiner Musik-Bibliothek. Lass dich überraschen, was er Dir als Nächstes präsentiert.   
    Spiel ab!
    Jetzt kannst Du Dir mit Spielen die Zeit vertreiben, die ganz speziell auf den iPod nano und den Beschleunigungssensor zugeschnitten sind. Sie reagieren auf Deine Bewegungen und wirken dadurch so überzeugend, dass sie fast schon süchtig machen können. In jedem Fall wirst Du begeistert sein. Bereits vorinstalliert ist Maze, wo Du Dich durch Neigen, Kippen und allerlei andere Bewegungen durch riesige Labyrinthe manövrieren musst. Im iTunes Store stehen natürlich noch viele weitere Spiele zur Auswahl.
     
    Sogar Deine Fotos rocken
    Jetzt kannst Du gleich hunderte von Fotos aus der Tasche zaubern und überall vorführen. Senkrecht gehalten zeigt der iPod nano Deine Fotos im Hochformat an, wenn Du ihn um 90 Grad drehst, wechseln auch die Fotos ins Querformat. Die Fotos wirken in ihrem richtigen Größen- und Seitenverhältnis auf dem brillanten Display mit 320 x 240 Pixeln einfach hervorragend. 
    Der größte kleine Bildschirm der Welt
    Filme, Fernsehsendungen und Videos auf dem iPod nano anzusehen, ist das pure Vergnügen. Die hochauflösende Anzeige wirkt auf dem kristallklaren 2"" Breitbild-Display besonders brillant und lebendig. So hast Du mit dem iPod nano Dein eigenes Kino im Taschenformat immer dabei.  
     
    Produktbeschreibungen
    Flach, flacher, am flachsten mit nur 6,2mm bringt der iPod nano, in leuchtenden Farben, neuen Schwung ins Leben.
    Mit brilianterem Display, höherer Speicherkapazität und noch längerer Batterielaufzeit schütteln Sie sich einfach durch Ihre Mediathek.
    Leistungsmerkmale
    - Verschieden Menüs: Musik, Fernsehsendungen, Videos, Hörbücher, Podcasts, Diashows, Spiele
    - Geschwungenen Aluminium-Design mit gewölbtem Glas
    - HxBxT: 90,7 x 38,7 x 6,2 mm
    - Gewicht: 36,8 g
    Lieferumfang
    - iPod nano
    - Ohrhörer
    - USB 2.0-Kabel
    - Dock-Adapter
    - Dokumentation
    Display
    - 2- Farb-LCD mit LED-Hintergrundbeleuchtung
    - 320 x 240 Pixel
    Kapazität
    - 8 GB Flash-Laufwerk1 für bis zu 2.000 Songs, 7.000 Fotos, 8 Std. Videomaterial
    Batterie
    - Integrierte, wiederaufladbare Lithium-Ionen-Batterie
    - Musikwiedergabe: bis zu 24 Stunden bei voller Ladung
    - Videowiedergabe: bis zu 4 Stunden bei voller Ladung
    Audio
    - Unterbrechungsfreie Wiedergabe
    - Frequenzbereich: 20 Hz bis 20.000 Hz
    - Unterstützte Audioformate: AAC, Protected AAC, MP3, MP3 VBR, Audible, Apple Lossless, AIFF und WAV
    Systemvoraussetzungen
    - USB 2.0-Anschluss
    - mind. Mac OS X 10.4.11 bzw. mind. Windows Vista oder Windows XP Home oder Professional
    - mind. iTunes 8  

     
     
     
    ";2;False;0;;;Apple iPod Nano 8 GB;apple-ipod-nano-8-gb-verschiedene-farben;True;True;P-1371;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;139.0000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;40218,6740856481;47;1;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000075-apple-ipod-nano-8-gb-verschiedene-farben.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000076-apple-ipod-nano-8-gb-verschiedene-farben.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000077-apple-ipod-nano-8-gb-verschiedene-farben.jpg;1;;False;;;;;False;False;False;;;;;False;;;;;; +5;210;True;_SmartStore.biz 6;Das Shopping System;"
    SHOP
    Mit neuesten Technologien topmoderne Ergebnisse erzielen
    Durch konsequente Verwendung von HTML5, CSS3, jQuery und jQuery UI erzeugt SmartStore.biz 6 schnelle und übersichtliche Seiten. Erst kürzlich hat auch YouTube sein Portal mit diesen Technologien neu aufgestellt. Das jQuery Framework bietet komfortable Funktionen zur Manipulation von Webseiten. jQuery UI ist eine Erweiterung von jQuery und bietet Lösungen zur Gestaltung und Funktionalität der Benutzeroberfläche an.
    Zusammen mit HTML5 und CSS können mit diesen Technologien komplexe Seiten hochperformant erstellt werden. Komponenten aus der jQuery UI-Bibliothek passen sich automatisch SmartStore-Theme Designs an. So können Sie selbst Komponenten und Effekte aus jQuery UI einbinden.
    Facebook, Google & Co
    Soziale Interaktion und Zusammenarbeit belebt den Shop und bindet Besucher. SmartStore.biz 6 bietet Möglichkeiten für die Verwendung von allen wichtigen Plattformen.
    Kunden können mit Google+ und Facebook Like Ihren Shop weiterempfehlen oder über Facebook Kommentare ein Kommentar zu einem Ihrer Angebote verfassen, welcher dann auch auf der Facebook-Seite des Kunden erscheint.
    Megamenü Navigation
    Mehrspaltige Menüs werden immer beliebter. Die Megamenü Navigation bietet gegenüber der einfachen Dropdown Navigation größere Navigationsflächen und die Darstellung von mehreren Navigationsebenen auf einer Ebene.
    Shrinkmenü
    Klein aber fein. Navigationsleisten mit sehr vielen Einträgen werden oft unzureichend gut dargestellt. Meist werden Einträge abgeschnitten oder alle Einträge werden angezeigt und das Layout passt nicht mehr.
    Die Funktion „Shrinkmenu“ passt die Navigation so an, dass der Platz für die Navigation optimal genutzt wird.
    Produktliste
    Eine Produkliste führt sämtliche Produkte eines Shops auf. Die neue Produktliste in SmartStore.biz 6 stellt Produkte wahlweise in einer mehrspaltigen Galerieansicht und in einer Listenansicht dar.
    Produktdetail
    Das neue Produktdetail-Modul zeigt jetzt alle zum Produkt zugehörigen Bilder in einer Galerie dar. Eine Zoom-Ansicht, in der die Bilder-Galerie in Vollbild angezeigt wird und eine Vollbild-Ansicht, in der jeweils ein Bild in einer LightBox angezeigt, erlauben Ihnen eine detaillierte und schöne Produktpräsentation. In der Vollbild-Ansicht kann zudem, ohne diese Ansicht zu verlassen zu anderen Bildern navigiert werden.
    Durch die Verwendung des Tab-Moduls können Daten wie Produktbeschreibung aber auch andere Module übersichtlich dargestellt werden.
    Docked Minibasket
    Der neue interaktive Mini-Warenkorb dockt sich stets griffbereit in die Fußzeile des Shops an. Der Shop-Kunde kann nicht nur per Knopfdruck, sondern auch per Drag & Drop seine Waren in den Warenkorb legen.
    Die detaillierte Ansicht des Warenkorbs verschafft dem Käufer stets einen klaren Überblick über seine Einkaufsliste. Derartige Design Highlights  erzeugen beim Käufer Sympathiepunkte, die sich in den meisten Fällen verkaufsfördernd auswirken.
    Tabs
    Das neue Tab-Modul stellt beliebige Module in Tabs dar und ermöglicht somit eine übersichtliche Darstellung von vielen Inhalten. Inhalte können so platzsparend und übersichtlich bei minimalem Platzverbrauch angezeigt werden. Überlange Seiten und langes scrollen gehören damit zur Vergangenheit.
      
    Splitter
    Der neue Splitter ermöglicht es, beliebig viele Module horizontal anzuordnen. Inhalten werden so platzsparend und ansprechend dargestellt.
    Content-Slider
    Der Content-Slider macht aus beliebigem Inhalt auf der Seite eine Dia-Show.
    Stellen Sie Top-Produkte, Sonderangebote und News eindrucksvoll mit einem Conten-Slider dar. Viele hübsche und effektvolle Übergangseffekte, Auto-Slide-Modus und die Paginierung machen den Content-Slider zu einem Hingucker in Ihrem Shop. 
    THEMING & DESIGN
    Neue Themes
    Smartstore.biz 6 enthält zwei von Grund auf neu entwickelte Themes. Ein modernes und ansprechendes Shop-Design ist somit "out-of-the-box" garantiert!
    60 neue Banner-Grafiken
    60 neue Banner-Grafiken aus unterschiedlichen Themenbereichen bilden die Grundlage für schicke und harmonische Banner. Mit den neuen Editierfunktionen lassen sich so hervorragende Banner mühelos mit ein paar Klicks erstellen.
    Seiten-Layout
    Das neue Seitenlayout basiert auf dem 960 Grid System.
    Per Knopfdruck kann das Layout eines Themes verändert werden. Layout-Typen wie Feste Breite, Hybrid und Dynamisch können sofort auf jedes Theme angewendet werden.
    Darüber hinaus können Außen- und Innenabstände, die Ausrichtung und die Breite der Seite einfach eingestellt werden.
    HTML Container
    HTML Container sind „Behälter“ für andere HTML-Elemente und dienen zur optischen Ausgestaltung. Container schaffen Übersicht und setzen Akzente.
    SmartStore.biz 6 enthält eine Container-Bibliothek mit mehr als 60 modern gestalteten Containern, die sich beliebig mit jedem Theme kombinieren lassen.
    Banner-Editor
    Der neue Banner-Editor bietet jetzt Ausblendeffekte für Ihren Banner nach allen Seiten und intelligente Spiegelungsfunktionen. Banner können nach allen Seiten mit eleganten Ausblendeffekten versehen werden und erzielen. Mit den neuen Editierfunktionen lassen sich so hervorragende Banner mühelos mit ein paar Klicks erstellen.
    WEITERE HIGHLIGHTS
    User Interface
    Innerhalb von SmartStore.biz 6 wurden die Funktionen in vielen Bereichen verbessert.
    Die Benutzeroberfläche wurde auf den neusten Stand gebracht.
    Alle wichtigen Menü-Einträge und Funktionen sind nun über ein anpassbares, Office 2010 ähnliches Ribbon erreichbar.
    Page-Designer
    Der Page-Designer wurde grundlegend Überarbeitet. Zur Übersichtlichkeit lassen sich nun Module auf- und zuklappen. Die Bedienung per Drag & Drop wurde intuitiver gestaltet.
    Multipanel Module
    Multipanel Module erzeugen aus anderen Modulen neue Darstellungen. So können z.B. aus vielen Bildern Galerien erzeugt werden oder eine Sammlung von Bildern, Buttons und Eingabefeldern kann in einem Tab dargestellt werden.
    SmartStore.biz 6 beinhaltet die Multipanel Module Tab, Splitter und Content-Slider.
    Ereigniskonsole
    Die Ereigniskonsole zeigt Fehlermeldungen und Ereignisse beim Testen und Erstellen an.
    Mit ihr lassen sich leicht Fehler in Skripten, Modulen und Plug-Ins finden. Fehler werden mit einer Beschreibung, dem Zeitpunkt des Auftritts, dem Fehler-Typ und dem Ursprung der Meldung angezeigt.
    Designer und Entwickler bekommen so direkt ein Feedback über Fehler. Über Aufrufe in eigenen Anwendungen können Entwickler Zeitmessungen vornehmen oder beliebige Nachrichten in der Ereigniskonsole anzeigen
    Payment-Schnittstellen
    masterpayment Zahlungsschnittstelle
    MASTERPAYMENT bietet das Rundum-Sorglos-Paket wie Rechnungskauf, Kreditkarte, Ratenzahlung, Sofortüberweisung jetzt für SmartStore-Händler an.
    Wer in seinem SmartStore-Shop MASTERPAYMENT bis zum 31.12.2011 aktiviert, spart sich sämtliche Grundgebühren und Set-Up-Gebühren für alle Zahlarten!
    Klarna Zahlungsschnittstelle
    Mit Klarna Rechnung und Ratenkauf anbieten!
    Klarna ist Europas führender Anbieter von rechnungsbasierten Zahlungs- und Finanzierungslösungen im Internethandel. Rechnung und Ratenkauf mit Klarna bieten Onlineshoppern entscheidende Vorteile.
    BillSafe Zahlunsschnittstelle
    Mit BillSAFE bieten Sie Ihren Kunden die beliebteste Zahlart in Deutschland – den Kauf auf Rechnung! Dadurch steigern Sie Ihren Umsatz, gewinnen
    neue Käufergruppen und erhöhen den Anteil an Bestandskunden. Das alles geht mit
    BillSAFE völlig ohne Ausfallrisiko..
    ";2;True;0;;;SmartStore.Biz 6;_smartstorebiz-6;True;True;P-6000;;MYEAN-65487;False;0;False;;False;False;0;True;0;1;False;;False;;False;100;0;10;True;False;0,0000;False;False;1;2;10000;True;True;0;0;0;0;False;1;10000;;False;False;False;False;190.0000;0.0000;0.0000;166.0000;42248,5157986111;42250,9999884259;False;100.0000;200.0000;0.0000;0.0000;0.0000;0.0000;40218,6501736111;"29;78;81;2095";42;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000070-_smartstorebiz-6.png;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000071-_smartstorebiz-6.png;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000072-_smartstorebiz-6.png;3;1;True;kg;2.0000;1;;False;False;False;;;;;False;;Toll Software DE;"

    Langbeschreibung

    ";SmartStore Biz EN;Nice software;"

    Long descriiption

    " +5;0;True;Sandisk Sansa Clip 2 GB rot;Sandisk Sansa Clip 2 GB mit integriertem FM-Tuner rot;"

    Sandisk Sansa Clip 2 GB mit integriertem FM-Tuner rot

    digitaler SanDisk Player für MP3, WMA, Secure WMA und FM Radio
    kleines, kompaktes Design, kaum größer als eine Streichholzschachtel
    FM-Radio mit 40 Stationsspeicherplätzen
    Diktiergerät-Funktion über integriertes Mikrofon
    4-zeiliges OLED-Display
     
    Sortierung der Titel nach versch. Kriterien möglich, wie z.B. Künstler, Album, Genre, u.a.
    bis zu 15-h-Wiedergabe mittels internem, wiederaufladbaren Akku
    inkl. abnehmbarem Trageclip, Ohrhörer, USB 2.0 Kabel, Installations-CD mit Bedienungsanleitung
    unterstützt Win 2000 / XP / Vista
     
    Lieferumfang:
    Player inkl. abnehmbarem Trageclip, Ohrhörer, USB 2.0 Kabel, Installations-CD mit Bedienungsanleitung
    ";2;False;0;;;"Sandisk Sansa Clip 2 GB mit integriertem FM-Tuner ";sandisk-sansa-clip-2-gb-rot;True;True;P-1620;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;42.9000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;40206,8077430556;52;8;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000571-sandisk-sansa-clip-2-gb-rot.jpg;;;2;;False;;;;;False;False;False;;;;;False;;;;;; +5;0;True;Sandisk Sansa Fuze 8 GB silber;"Sandisk Sansa Fuze MP3-/Video-Player 8 GB mit Radio silber ";"

    Sandisk Sansa Fuze MP3-/Video-Player 8 GB mit Radio silber

     
     
    Mit der verfügbaren Akkuleistung können Sie 24 Stunden lang Musik hören, Bilder anschauen oder spielen.
    Der neue Sansa Fuze von SanDisk ist der ideale tragbare Musikplayer für Sie.
    Er steht mit einer Speicherkapazität 4 GB in schwarz,rot,pink zur Verfügung.
    Sehen Sie sich Ihre Lieblingsvideoclips auf dem 1,9""-Farbdisplay des Sansa Fuze an.
    Lauschen Sie dem FM-Radio mit 40 voreingestellten Sendern oder probieren Sie den integrierten Sprachrekorder aus. Mit einer unglaublich starken Akkuleistung in einem 0,3"" schmalen Gerät setzt der Sansa Fuze Zeichen.
    ";2;False;0;;;Sandisk Sansa Fuze MP3-/Video-Player 4 GB mit Radio;sandisk-sansa-fuze-8-gb-silber;True;True;P-1610;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;89.9000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;40206,8019444444;52;8;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000570-sandisk-sansa-fuze-8-gb-silber.jpg;;;2;;False;;;;;False;False;False;;;;;False;;;;;; +5;0;True;Asus Eee PC 1001HA 10,1 Zoll Netbook;Asus Eee PC 1001HA 10,1 Zoll Netbook;"
    Eee PC™ 1001HA: Klasse Leistung zu unschlagbarem Preis
     
    Der Eee PC™ 1001HA unterscheidet sich von seinen großen Brüdern durch Prozessor und Akkukapazität. Ausgestattet mit einem Intel® Atom™ N270 Prozessor, einem 3 Zellen Akku für bis zu 4 Stunden Laufzeit, WLAN 802.11n Standard sowie weiteren Top Merkmalen, überzeugt der Eee PC™ 1001HA zu einem wirklich unschlagbaren Preis.
     
    Eee PC™ 1001HA: Funktionalität meets Design
     
    Mit dem kompakten Eee PC™ 1001HA trägt ASUS seinem Anspruch, in den Produkten höchste Funktionalität mit formvollendetem Design zu verbinden, ein weiteres Mal Rechnung. So besticht der neue Eee PC™ durch sein elegantes und gleichzeitig unempfindliches Gehäuse, das mit klaren Linien und nach unten schmaler zulaufenden Kanten dem schlanken Design einer Muschel nachempfunden ist. Aber auch das Innenleben der Kleinen kommt ganz groß raus. Als gewohnt kontaktfreudig erweisen sich die Neulinge dank VGA Port für den Anschluss eines Monitors sowie drei USB 2.0 Schnittstellen, um Maus, Tastatur oder Digicam anzuschließen. Wer Bilder direkt von der SD oder MMC Speicherkarte auf den Eee PC™ übertragen möchte, nutzt den integrierten Kartenleser. Für das Speichern der Fotos stehen bei beiden Modellen eine 160 GB S-ATA Festplatte zur Verfügung.. Das Modell basiert auf Microsoft® Windows® XP Home und ist – wie alle Eee Familienmitglieder – ausgesprochen einfach zu bedienen. Das 10 Zoll WSVGA Display mit stromsparender LED-Hintergrundbeleuchtung sowie die große Tastatur, die zu 92% einer Standard Notebooktastatur entspricht, gewähren zusätzlichen Komfort. Für Chats oder Videokonferenzen hat ASUS die Minis zudem mit einer 0.3 Megapixel Web-/Videokamera sowie einem Mikrofon ausgestattet.
     
     
    ";2;False;0;;;Asus Eee PC 1001HA 10,1 Zoll;asus-eee-pc-1001ha-101-zoll-netbook;True;True;P-0890;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;243.9000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;40205,9519907407;6;37;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000563-asus-eee-pc-1001ha-101-zoll-netbook.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000564-asus-eee-pc-1001ha-101-zoll-netbook.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000565-asus-eee-pc-1001ha-101-zoll-netbook.jpg;2;;False;;;;;False;False;False;;;;;False;;;;;; +5;0;True;Canon PGI 520BK Tintenpatrone schwarz;Canon PGI 520BK Tintenpatrone schwarz;"
    Canon PGI 520BK ,Tintenpatrone, schwarz, 19ml
     
     
     
    kompatibel  PIXMA iP3600/iP4600/IP4700 und MP540/620/630/640

     
     
    ";2;False;0;;;"Canon CLI-521, Tintenpatrone, cyan, 9ml, für PIXMA iP3600/iP4600/IP4700 und MP540/620/630/980 - ""R"" ";canon-pgi-520bk-tintenpatrone-schwarz;True;True;P-2280;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;-1,2000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;11.9900;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;40205,7303009259;23;25;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000562-canon-pgi-520bk-tintenpatrone-schwarz.jpg;;;2;;False;;;;;False;False;False;;;;;False;;;;;; +5;0;True;Canon CLI-521 Tintenpatrone schwarz;Canon CLI-521 Tintenpatrone;"
    Canon CLI-521BK,Tintenpatrone, schwarz, 9ml
     
     
     
    kompatibel  PIXMA iP3600/iP4600/IP4700 und MP540/620/630/640

     
     
    ";2;False;0;;;"Canon CLI-521, Tintenpatrone, cyan, 9ml, für PIXMA iP3600/iP4600/IP4700 und MP540/620/630/980 - ""R"" ";canon-cli-521-tintenpatrone-schwarz;True;True;P-2270;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;-1,2000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;11.9900;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;40205,7265509259;23;25;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000555-canon-cli-521-tintenpatrone-schwarz.jpg;;;2;;False;;;;;False;False;False;;;;;False;;;;;; +5;0;True;Canon CLI-521 Tintenpatrone magenta;Canon CLI-521 Tintenpatrone;"
    Canon CLI-521M,Tintenpatrone, magenta, 9ml
     
     
     
    kompatibel  PIXMA iP3600/iP4600/IP4700 und MP540/620/630/640

     
     
    ";2;False;0;;;"Canon CLI-521, Tintenpatrone, cyan, 9ml, für PIXMA iP3600/iP4600/IP4700 und MP540/620/630/980 - ""R"" ";canon-cli-521-tintenpatrone-magenta;True;True;P-2260;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;-1,2000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;11.9900;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;40205,7246643519;"23;2095";25;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000554-canon-cli-521-tintenpatrone-magenta.jpg;;;2;;False;;;;;False;False;False;;;;;False;;;;;; +5;0;True;Canon CLI-521 Tintenpatrone cyan;Canon CLI-521 Tintenpatrone;"
    Canon CLI 521C,Tintenpatrone, cyan, 9ml
     
     
     
    kompatibel  PIXMA iP3600/iP4600/IP4700 und MP540/620/630/640

     
     

     
     
    ";2;False;0;;;"Canon CLI-521, Tintenpatrone, cyan, 9ml, für PIXMA iP3600/iP4600/IP4700 und MP540/620/630/980 - ""R"" ";canon-cli-521-tintenpatrone-cyan;True;True;P-2250;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;-1,2000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;11.9900;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;40205,7210416667;23;25;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000553-canon-cli-521-tintenpatrone-cyan.jpg;;;2;;False;;;;;False;False;False;;;;;False;;;;;; +5;0;True;Canon CLI-521 Tintenpatrone gelb;Canon CLI-521 Tintenpatrone;"
    Canon CLI-521Y,Tintenpatrone, gelb, 9ml
     
     
     
    kompatibel  PIXMA iP3600/iP4600/IP4700 und MP540/620/630/640

     
     
    ";2;False;0;;;"Canon CLI-521, Tintenpatrone, cyan, 9ml, für PIXMA iP3600/iP4600/IP4700 und MP540/620/630/980 - ""R"" ";canon-cli-521-tintenpatrone-gelb;True;True;P-2240;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;-1,2000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;11.9900;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;40205,6889814815;23;25;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000552-canon-cli-521-tintenpatrone-gelb.jpg;;;2;;False;;;;;False;False;False;;;;;False;;;;;; +5;0;True;"Philips DC 200 iPod Soundsytem ";"Philips DC 200 iPod Soundsytem ";"
    Philips DC 200 iPod Soundsytem  - Radio, USB, Apple iPod kompatibel

    Genießen Sie Ihre MP3-Lieblingsmusik auch beim Aufladen Ihres iPods! Dank der Docking-Station können Sie Ihren iPod direkt an das Docking-Entertainment-System anschließen und Ihre Lieblingsmusik in ausgezeichneter Soundqualität wiedergeben.
     
    Ihr iPod wird während der Wiedergabe aufgeladen, sodass Sie Ihre Musik genießen können, ohne sich Gedanken über den Ladestand des Akkus machen zu müssen. Verwenden Sie zum Durchsuchen, Auswählen und Wiedergeben der auf dem iPod gespeicherten Musiktitel die Fernbedienung.
     
    Das Docking-Entertainment-System lädt Ihren iPod automatisch auf, solange er sich in der Station befindet.
    Durch den direkten USB-Anschluss können Sie einfach Musik auf einem USB-Gerät auswählen und wiedergeben.
    Um Musik wiederzugeben oder Inhalte zu exportieren, stecken Sie das USB-Gerät einfach ein.
    Das digitale UKW-Radio bietet Ihnen zusätzliche Musikoptionen für die Musiksammlung auf Ihrem Philips Player.
    Stellen Sie einfach den gewünschten Radiosender ein, und halten Sie die Speichertaste gedrückt, um die Frequenz zu speichern.
     
    Dank der voreingestellten und gespeicherten Radiosender können Sie ganz einfach Ihren Lieblingssender hören,
    ohne die Frequenz jedes Mal manuell einstellen zu müssen.
     
    Das Bassreflex-Lautsprechersystem sorgt bei kompakten Lautsprecher-Systemen für tiefe Bässe.
    Der Unterschied zu konventionellen Lautsprecher-Systemen liegt in der Tiefbassröhre, die akustisch auf den Woofer abgestimmt ist,
     
    um den Low Frequency Roll Off des Systems zu optimieren. Ergebnis sind tiefer gesteuerte Bässe und weniger Verzerrung.
     
    Das Prinzip besteht darin, dass die Luftmasse in der Tiefbassröhre mitschwingt und wie ein herkömmlicher Woofer vibriert.
     
    In Kombination mit der Reaktion des Woofers erweitert das System alle niederfrequenten Töne und erzeugt tiefe Bässe in einer völlig neuen Dimension.
     
    Lieferumfang: 3,5 mm Stereo-Line-Eingangskabel;AC/DC-Adapter;Schnellstartanleitung;Benutzerhandbuch
    ";2;False;0;;;;philips-dc-200-ipod-soundsytem;True;True;P-1540;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;82.9000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;40203,8622569444;"51;2095";6;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000544-philips-dc-200-ipod-soundsytem.jpg;;;1;;False;;;;;False;False;False;;;;;False;;;;;; +5;0;True;"Logitech G500 Gaming Maus ";"Logitech G500 Gaming Maus ";"
     Logitech G500 Gaming Maus
     
     
     
    Der spieletaugliche Laser geben Ihnen bei jeder Bewegungsgeschwindigkeit eine atemberaubende Präzision
    Durch Feintuning mit bis zu 27 Gramm an zusätzlichen Gewichten bestimmen Sie exakt, wie die Maus in der Hand liegt
     
    Der integrierte Speicher ermöglicht es Ihnen, die Einstellungen für Dein Lieblingsspiel zu speichern und mitzunehmen – es ist keine Software erforderlich

    Das Tastenrad bietet Ihnen zwei Einstellungen – den präzisen Click-to-Click-Modus oder hyperschnelle Bildläufe
     
    Lieferumfang:
    Logitech G500 Gaming Maus, Anpassbares Gewichtsmagazin, Tuninggewichte und Etui, Bedienungsanleitung
    ";2;False;0;;;"Logitech G500 Gaming Maus ";logitech-g500-gaming-maus;True;True;P-2820;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;59.0000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;40203,8042476852;21;11;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000543-logitech-g500-gaming-maus.jpg;;;2;;False;;;;;False;False;False;;;;;False;;;;;; +5;0;True;Garmin nüvi 205 Navigationssystem DACH;Garmin nüvi 205 Navigationssystem DACH;"
    Garmin nüvi 205 Navigationssystem DACH
     
     
    3,5 Zoll Touchscreen Display, PhotoNavigation, MicroSD-Kartenslot und ecoRoute
     
     
    Bedienerfreundliches Einsteigernavigationsgerät mit elegantem, ultra-schlankem Design
    und brillantem 3,5 Zoll (8,9cm Bilddiagonale) Touchscreen Display
    Detailkarten für Deutschland, Österreich, Schweiz + CZ intern vorinstalliert
    ecoRoute: reduziert den Kraftstoffverbrauch, CO2-Emissionen
    und schont die Umwelt, spart bares Geld und füllt die Reisekasse auf.
    PhotoNavigation mit Garmin Connect: Sie können Sehenswürdigkeiten und Bilder herunterladen und als Ziel auswählen
    Lieferumfang: Garmin nüvi 205 mit Kartenmaterial DACH,
    Saugnapfhalterung für die Windschutzscheibe, Armaturenhalterung, Schnellstartanleitung, KFZ-Anschlusskabel
    ";2;False;0;;;Garmin nüvi 205 Navigationssystem DACH;garmin-nuevi-205-navigationssystem-dach;True;True;P-2110;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;139.0000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;40200,8638078704;67;44;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000542-garmin-nuvi-205-navigationssystem-dach.jpg;;;2;;False;;;;;False;False;False;;;;;False;;;;;; +5;0;True;"AVM FRITZ!Fon C3 VoIP Dect-Telefon ";"AVM FRITZ!Fon C3 VoIP Dect-Telefon ";"
    FRITZ!Fon C3: HD-Telefonie und komfortable Internetdienste mit DECT.
    Telefonieren Sie mit dem Schnurlostelefon FRITZ!Fon C3 in bestechender Qualität über das Internet und nutzen Sie komfortable Webdienste. Als intelligentes Telefon der neuesten DECT-Generation vereint das FRITZ!Fon den Komfort der schnurlosen Telefonie mit den Qualitäts- und Leistungsmerkmalen der Internettelefonie (VoIP) in einem Gerät.
     
    Bei der Internettelefonie mit einem FRITZ!Fon wird durch HD-Telefonie (High Definition) ein brillantes, natürliches Klanggefühl erreicht. Sprache lässt sich mit dem FRITZ!Fon in ihrem gesamten Frequenzspektrum wiedergeben, was die Klangqualität von Festnetzverbindungen deutlich übertrifft.
     
    FRITZ!Fon unterstützt die übertragung großer Bandbreiten. Dies ermöglicht neben HD-Telefonie auch die Nutzung komfortabler Internetdienste wie den Empfang von E-Mails, Podcasts, RSS-Feeds und Internetradio.
     
    Die Steuerung von FRITZ!Box-Anwendungen am Handgerät bietet viel zusätzlichen Komfort. Und durch DECT-Eco wird Funkabstrahlung bei Nichtnutzung der Telefone verhindert.
     
    Die FRITZ!Box-Modelle FRITZ!Box Fon WLAN 7390, 7320, 7270, 7240 sowie FRITZ!Box 6360 Cable stellen mit der integrierten DECT-Basisstation, mehreren Anrufbeantwortern und Telefonbüchern für bis zu 300 Einträge den idealen Partner für das FRITZ!Fon dar. Mit der umfangreichen Prozessor- und Speicherausstattung ist auch der Grundstein für neue Anwendungen gelegt. Denn das FRITZ!Fon ist lernfähig:
     
    Als eines der ersten intelligenten Schnurlostelefone wird es auch künftig per Firmware-Updates aktualisiert und um neue Funktionen erweitert werden können.
     
    Umfangreicher Komfort
    Das FRITZ!Fon C3 ist mit zahlreichen Komfortfunktionen ausgestattet. Dazu zählen Lauthören und Freisprechen in HD-Qualität sowie ISDN-Leistungsmerkmale wie Namensanzeige bei bekannten Rufnummern, Halten, Makeln, Anklopfen, Rufumleitung oder Dreierkonferenz. Die Internettelefonie in HD-Qualität lässt sich so in ihrem vollen Umfang und Komfort nutzen, ohne dass der Computer eingeschaltet sein muss.
     
    FRITZ!Fon informiert zudem aktiv über unbeantwortete Anrufe, Nachrichten auf dem Anrufbeantworter und zeigt eingegangene E-Mails an. An der DECT-Basisstation der FRITZ!Box Fon WLAN 7390, 7320, 7270, 7240 oder FRITZ!Box 6360 Cable lassen sich bis zu 6 FRITZ!Fon-Handgeräte oder andere DECT-Telefone anmelden. Die Erstinstallation und individuelle Einstellungen erfolgen dabei bequem über einfache Assistenten.
     
    FRITZ!Box als idealer Partner
    Das FRITZ!Fon C3 kann als Mobilteil an jeder DECT-Basisstation eingesetzt werden. Im Zusammenspiel mit der FRITZ!Box Fon WLAN 7390, 7320, 7270, 7240 oder FRITZ!Box 6360 Cable kann jedoch das volle Spektrum der Möglichkeiten beim Telefonieren und Surfen über das Internet ausgenutzt werden.
     
    Die FRITZ!Box Fon WLAN 7390 zum Beispiel vereint eine bisher nicht erreichte Vielfalt in einem Gerät: VDSL- und ADSL-Unterstützung, DECT-Basisstation fürs schnurlose Telefonieren sowie WLAN N für die optimale Datenübertragung. über den Mediaserver sind gespeicherte Filme, Musik und Bilder auch bei ausgeschaltetem Computer im gesamten Netzwerk verfügbar. Darüber hinaus kann der Online-Speicher wie eine lokale Festplatte genutzt werden. So wird die FRITZ!Box Fon WLAN 7390 zur idealen Plattform für vernetzte Anwendungen wie IPTV, Video on Demand oder Mediastreaming.
     
    Bedienung
    - Schnelle Anmeldung: Einschalten, Suchtaste der FRITZ!Box drücken, fertig.
     
    - Einfache Bedienung über intuitives Menü.
     
    - Telefonbuch komfortabel über FRITZ!Box-Oberfläche einrichten und anzeigen.
     
    - In FRITZ!Box integrierte Anrufbeantworter einfach am C3 einrichten und abhören.
     
    - Blinkendes Nachrichtensymbol signalisiert eingegangene Anrufe, neue Nachrichten auf dem Anrufbeantworter und neue E-Mails.
     

    Telefonieren Sie mit dem Schnurlostelefon C3 in bestechender Qualität über das Internet und nutzen Sie komfortable Webdienste.
     
    Highlights
    - DECT-Telefon für Internet- und Festnetztelefonie, ideal geeignet für die FRITZ!Box Modelle 7270, 7240, 7390 und 6360 Cable
    - Farbdisplay und beleuchtete Tastatur
    - Telefonbücher für bis zu 300 Einträge, Online-Telefonbuch verfügbar
    - Mehrere Anrufbeantworter mit Menüsteuerung und Fernabfrage
    - Full-Duplex-Freisprechen
    - Unterstützt HD-Telefonie nach CAT-iq
    - Per Software-Update einfach um neue Funktionen erweiterbar
     
    Eigenschaften DECT-Telefon
    - Mobilteilbreite: 49 mm
    - Mobilteilhöhe: 138 mm
    - Mobilteiltiefe: 26 mm
    - Gewicht Mobilteil inkl. Akku: 133 g
    - Feldstärkeanzeige
    - Freisprechfunktion
    - CAT-iq Standard
    - Strahlungsarm
    - GAP-fähig
    - Reichweite im Freien bis zu 300 m
    - Reichweite in Gebäuden bis zu 40 m
     
    Telefoneigenschaften
    - Anruferanzeige (CLIP)
    - Picture-CLIP
    - Anruferliste
    - Anzeige Datum/Uhrzeit
    - Anzeige Gesprächsdauer
    - Polyphone Klingeltöne: ja
    - Hörerlautstärke einstellbar
    - Stummschaltung möglich
    - Bis zu 300 Telefonbucheinträge
    - Wecker
    - Telefontyp: Schnurlostelefon
     
    Grundeigenschaften
    - Farbe: Silber
     
    Lieferumfang
    - FRITZ!Fon C3
    - AAA-Akkupack
    - Ladestation
    - Netzteil zum Anschluss an das 230-Volt-Stromnetz
    - Gedrucktes deutschsprachiges Handbuch
     

    Kompatibel zu:
    FRITZ!Box Fon WLAN 7270, FRITZ!Box Fon WLAN 7240, FRITZ!Box Fon WLAN 7320, FRITZ!Box Fon WLAN 7390, FRITZ!Box 6360 Cable
    ";2;False;0;;;"AVM FRITZ!Fon C3 VoIP Dect-Telefon ";avm-fritzfon-c3-voip-dect-telefon;True;True;P-2750;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;69.0000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;40200,5014467593;20;34;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000537-avm-fritzfon-c3-voip-dect-telefon.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000538-avm-fritzfon-c3-voip-dect-telefon.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000539-avm-fritzfon-c3-voip-dect-telefon.jpg;3;;False;;;;;False;False;False;;;;;False;;;;;; +5;0;True;Canon PIXMA MP560 Multifunktionsgerät 3 in 1;Canon PIXMA MP560 Multifunktionsgerät 3 in 1;"Canon PIXMA MP560 Multifunktionsgerät
     
    3 in 1, Drucken, Kopieren, Scannen

    Multifunktionssystem: Fotodrucker, Farbscanner und Farbkopierer
    Druckgeschwindigkeit: ca. 9,2 (SW) bzw. 6,0 (Farbe) ISO-Seiten/Min; einzelne Tintentanks
    ca. 39 Sek. für den druck eines 10 x 15 cm Randlosprint in Laborqualität
    Benutzerfreundliches und intuitives Interface; 5 cm Display und Easy-Scroll-Bedienrad
    Lieferumfang: PIXMA MP560, Netzkabel, Druckkopf, Tintentanks, Kurzanleitung,CD mit Installations-Software und Benutzerhandbuch, ";2;False;0;;;"Canon PIXMA MP640 ";canon-pixma-mp560-multifunktionsgeraet-3-in-1;True;True;P-2230;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;2,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;139.0000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;40194,5747453704;22;25;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000460-canon-pixma-mp560-multifunktionsgerat-3-in-1.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000461-canon-pixma-mp560-multifunktionsgerat-3-in-1.jpg;;2;;False;;;;;False;False;False;;;;;False;;;;;; +5;0;True;Panasonic Lumix DMC-FS7 Digitalkamera schwarz;"Panasonic Lumix DMC-FS7 Digitalkamera schwarz ";"
    Panasonic Lumix DMC-FS7 Digitalkamera schwarz

    10 Megapixel, 4-fach opt. Zoom, 6,9 cm Display, Bildstabilisator
     
    Im Intelligenten Automatik (iA)-Modus werden die 5 wichtigsten Motivprogramme automatisch optimal auf die jeweilige Szene eingestellt.
    Neben der Motiverkennung kombiniert iA weitere wichtige Funktionen, wie den optischen Bildstabilisator OIS,
    die Bewegungserkennung (Intelligente ISO-Steuerung), eine optimierte Gesichtserkennung mit digitaler Rotaugen-Korrektur. So sind scharfe, natürliche und schöne Fotos selbst für (Neu-)Einsteiger möglich.
     
    Lichtstarkes F2,8 Leica DC Vario-Elmarit Objektiv
    Hochauflösendes 6,9 cm LC-Display [230.000 Pixel]
    4x optischer Zoom [KB: 33-132 mm]
    Intelligente Automatik [u.a. Gesichtserkennung]
     
    Lieferumfang:
    Digitalkamera, Lithium Ionen Akku, Ladegerät, USB-Kabel, Trageriemen, Audio / Video-Kabel, CD-ROM, Sotware
    ";2;False;0;;;"Panasonic Lumix DMC-FS6 ";panasonic-lumix-dmc-fs7-digitalkamera-schwarz;True;True;P-1780;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;169.0000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;40189,6771412037;58;12;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000453-panasonic-lumix-dmc-fs7-digitalkamera-schwarz.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000454-panasonic-lumix-dmc-fs7-digitalkamera-schwarz.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000455-panasonic-lumix-dmc-fs7-digitalkamera-schwarz.jpg;2;;False;;;;;False;False;False;;;;;False;;;;;; +5;0;True;Casio EX-H10 SR Digitalkamera silber;Casio EX-H10 SR Digitalkamera silber;"
    Casio EX-H10 SR Digitalkamera silber
     
    12 Megapixel, 10-fach opt. Zoom, 7,6 cm  Display, Bildstabilisator
     
    Die Kombination aus einem energiesparenden Prozessor und einem extrem leistungsstarken Lithium-Ionen-Akku sorgt dafür, dass der EXILIM EX-H10 auch an langen, erlebnisreichen Tagen nicht der Strom ausgeht und sie mit einer Akkuladung bis zu 1000 Fotos machen kann.
     
    12,1 Megapixel CCD-Chip
    10fach optischer Zoom mit mechanischem Bildstabilisator, 4fach digitaler Zoom, 24 mm Weitwinkel Objektiv
    7,6 cm (3,0 Zoll) TFT-Farbdisplay (Super Clear LCD)
    Bis zu 1000 Fotos mit einer Akkuladung
     
    Lieferumfang:
    Digitalkamera EX-H10 silber, wiederaufladbarer Lithium-Ionen-Akku , Ladegerät, AC-Anschlusskabel, USB-Kabel, AV-Kabel, Trageriemen, CD-ROM
    ";2;False;0;;;"Casio EX-H10 SR Digitalkamera ";casio-ex-h10-sr-digitalkamera-silber;True;True;P-1760;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;289.0000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;40189,6684375;57;9;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000450-casio-ex-h10-sr-digitalkamera-silber.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000451-casio-ex-h10-sr-digitalkamera-silber.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000452-casio-ex-h10-sr-digitalkamera-silber.jpg;2;;False;;;;;False;False;False;;;;;False;;;;;; +5;0;True;BenQ G2420HDBL 61 cm 24 Zoll TFT Monitor schwarz;BenQ G2420HDBL 61 cm (24 Zoll) Full-HD LED-Monitor (DVI, VGA, Reaktionszeit 5ms) schwarz;"
    BenQ G2420HDBL - Der High-End-Entertainer!
    Der G2420HDBL LED-Monitor mit seiner BenQ LED-Edge-Backlight-Technologie im 16:9 Widescreen-Format und einer Bilddiagonale von 61 cm (24 Zoll) verfügt über eine Full-HD-Auflösung (1920 x 1080p), einen dynamischen Kontrast von 5.000.000:1, eine Reaktionszeit von 5 ms sowie eine Helligkeit von 250 cd/m². Zusätzlich sorgt die BenQ Senseye®-Photo-Technologie für eine perfekte Bildqualität bei jeder Anwendung. Mit seinem schwarz glänzenden Design ergänzt dieses PC-Display elegant jedes Büro und jedes Zuhause.
     
    Sparen Sie Energie - und Geld!
    Aufgrund der stetig zunehmenden globalen Erderwärmung wird es immer wichtiger, CO²-Emissionen zu reduzieren. Die LED Monitore von BenQ haben einen um 36% verringerten Energieverbrauch im Vergleich zu herkömmlichen Monitoren. Im Eco-Modus sparen Sie nochmal 30% der Energie! Und schonen zusätzlich auch noch Ihren Geldbeutel!
     
    BenQ Senseye® Human Vision Technology
    Mit 6 proprietären Verfahren für die Kalibrierung eines perfekten Bildes.
    Dank der Senseye® Technologie und der 6 verschiedenen Techniken zur Farbkalibrierung, zeigen BenQ LED Monitore echte Farben.
     
    Comfortable
    Die Helligkeit des Monitors lässt sich so fein einstellen, dass Sie ein perfekt ausgeleuchtetes Bild erhalten.
     
    Clear
    Exakte Ränder und Bilder, die scharf bis ins kleinste Detail sind.
     
    Detailed
    Detaillierte Bilder dank des hohen dynamischen Kontrasts von 5.000.000:1.
     
    Clean
    Sämtliche Darstellungen sind frei von Bildrauschen.
     
    Brilliant
    Klarere Bilder und leuchtend echte Farben lassen die Bilder farbenfroh erscheinen.
     
    Balanced
    Dank eines integrierten Algorithmus enthält die Bilddarstellung ein ausgewogenes Farbbild.
       
    Herausragende LED Farbgestaltung
     
    1080p Full-HD (1920x1080 High Definition)
    Full-HD-Displays bieten ein breitformatiges Vollbild mit 1080p-Auflösung nach dem HD-Standard (High-Definition). So kann z. B. mit Blu-ray-Playern, Multimedia-PCs, Notebooks oder Spielekonsolen der neuesten Generation das volle Bild digital ohne Kompromisse in brillantester Bildqualität dargestellt werden. Mit dem 16:9-Wide-Format, das perfekt für die Darstellung von Full-HD-Filmen ist, wird zudem bis zu 30 % mehr Bildfläche dargestellt als beim 4:3-Format.
     
    Dynamischer Kontrast von 5.000.000:1!
    Der extrem hohe dynamische Kontrast von 5.000.000:1 zeigt - insbesondere in dunkleren und komplexen Bewegungsbildern, wie bei Filmen und Video-Spielen - sogar die kleinsten Details in brillanter Schärfe. Sie erhalten fantastische Bilddetails sowie ein klares Bild auch bei dunklen, komplexen und bewegten Bildern. Noch nie haben Sie ein reineres weiß oder ein tieferes schwarz gesehen!
     
    16:9 Format - Die 10%, die Ihr visuelles Vergnügen vervollständigen!
    Wenn ein traditioneller 16:10 Monitor 16:9 Signale in Full-HD Bilder umwandelt, geschieht dies normalerweise auf zwei Wegen. Die erste Möglichkeit wäre, die Bilder zu strecken, was zu Verzerrungen führt. Eine andere Variante wäre, das überschüssige Bild mit schwarzen Balken zu verdecken. Beide Wege, ob eine Streckung von 10 % oder eineVerdeckung von 10 % des Bildes, haben einen erheblichen Einfluss auf den Bildgenuss.
     
    Die BenQ Full-HD 16:9 LED-Monitore hingegen bieten Ihnen eine Punkt-für-Punkt Full-HD Bildübermittlung, um die Probleme der 16:10 Monitore zu lösen. Nun können Sie endlich eine 100 %-ige Full-HD Performance genießen, auf die Sie gewartet haben!
     
    Für eine saubere Umwelt
     
    Umweltschutz durch Reduzierung des Verpackungsmaterials
    Unser Beitrag zum Umweltschutz: 80% des Verpackungsmaterials besteht aus recyceltem Papier, das Verpackungsmaterial insgesamt wird stark reduziert. Dank der schlanken LED-Panels erhöht sich beim Transport der Monitore das freie Ladevolumen um 56% (im Vergleich zur letzten Modellreihe E2400HD). Wir helfen, die Wälder zu schützen und CO2-Emissionen zu reduzieren!
     
    Wasserressourcen schützen
    Quecksilber-freie LED-Panels reduzieren die Umweltverschmutzung auf der Erde. Da im Produktionsprozess kein Quecksilber verwendet wird und beim Recycling der Altgeräte kein Quecksilber entsorgt werden muss, halten sie die Wasserressourcen frei von giftigen Schadstoffen.
     
    Abfallbelastung reduzieren
    BenQ LED Monitore sind nicht beschichtet und zu 100% recycelbar. Um die Ressourcen zu schonen, besteht der Displayrahmen zu 28% aus recycelten Plastikmaterialien. Für das Bedrucken des Verpackungsmaterials verwendet BenQ Tinte aus einem natürlichen Rohstoff: der Sojabohne. Damit lässt sich der Tintenverbrauch um 70% reduzieren.
     
    ";2;False;0;;;BenQ G2420HDBL 61 cm 24 Zoll TFT Monitor schwarz;benq-g2420hdbl-61-cm-24-zoll-tft-monitor-schwarz;True;True;P-2510;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;2,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;149.0000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;40187,661724537;"10;2095";;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000443-benq-g2420hdbl-61-cm-24-zoll-tft-monitor-schwarz.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000444-benq-g2420hdbl-61-cm-24-zoll-tft-monitor-schwarz.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000445-benq-g2420hdbl-61-cm-24-zoll-tft-monitor-schwarz.jpg;2;;False;;;;;False;False;False;;;;;False;;;;;; +5;0;True;Benq E2220HD 21,5 Zoll TFT Monitor schwarz;Benq E2220HD 21,5 Zoll TFT Monitor schwarz glänzend;"
    1080p Full HD (1920x1080 High-Definition)
    Im Gegensatz zu konventionellen LCD-Monitoren bieten Full-HD-Displays ein breitformatiges Vollbild mit 1080p-Auflösung nach dem HD-Standard (High-Definition). So kann z. B. mit Blu-ray-Playern, Multimedia-PCs, Notebooks oder Spielekonsolen der neuesten Generation das volle Bild digital ohne Kompromisse in brillantester Bildqualität dargestellt werden. Mit dem 16:9-Wide-Format, das perfekt für die Darstellung von Full-HD-Filmen ist, wird zudem bis zu 30 % mehr Bildfläche dargestellt als beim 4:3-Format.
     
    HDMI (High-Definition Multimedia Interface)
    Der HDMI-Anschluss ist eine digitale Schnittstelle, die für den Videobereich entwickelt wurde und neben dem Bild auch den Ton überträgt. HDMI ermöglicht nicht nur Datentransfers von 5 GB/s, sondern verhindert auch Wandlungsverluste und sorgt so für eine ausgezeichnete Bildqualität. Die HDMI-Schnittstelle ist der neue Standard für die digitale Signalübertragung, unter anderem für DVD-Player oder Spielkonsolen. Ab dem Standard HDMI 1.3 sind Übertragungsraten von bis zu 10 GB/s (je nach Kabelqualität und -länge) möglich. Dadurch werden die großen Datenströme ohne Kompressionen und damit ohne Bildstörungen übertragen. Dies ist für die Abbildung von Full-HD (1080p) wichtig, um einen ruckelfreien Bildfluss zu gewährleisten. Das BenQ E2220HD Display verfügt über 2 HDMI 1.3-Schnittstellen.
     
    Vier USB-Schnittstellen
    Das E2220HD verfügt über gleich vier USB-Schnittstellen, so dass Sie gleichzeitig Ihre Tastatur, die Maus, ein Handy und z.B. Game-Controller anschließen können!
     
    Dynamischer Kontrast von 50.000:1
    Mit einem dynamischen Kontrast von 50.000:1 werden Ihre Bilder lebendiger! Sie erhalten fantastische Bilddetails sowie ein klares Bild auch bei dunklen, komplexen und bewegten Bildern. Um die Funktion zu steuern, schalten Sie einfach den Q-Pilot ein.
     
    Stereo-Lautsprecher
    Das E2220HD verfügt über 2 1,5 Watt Stereo-Lautsprecher, die Ihnen ein perfektes Klangerlebnis liefern.
    ";2;False;0;;;Benq E2220HD 21,5 Zoll TFT Monitor schwarz;benq-e2220hd-215-zoll-tft-monitor-schwarz;True;True;P-2500;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;2,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;199.0000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;40187,6466435185;10;;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000438-benq-e2220hd-215-zoll-tft-monitor-schwarz.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000439-benq-e2220hd-215-zoll-tft-monitor-schwarz.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000440-benq-e2220hd-215-zoll-tft-monitor-schwarz.jpg;1;;False;;;;;False;False;False;;;;;False;;;;;; +5;0;True;Apple iPod Touch 32 GB schwarz;Apple iPod Touch 32 GB schwarz;"
    Apple iPod Touch 32 GB schwarz
     
    mit integrierter WiFi Funktion
     
    Ein großartiger iPod. Ein großartiger Taschencomputer. Großartiger mobiler Spielspaß. Und das Ganze in einem unglaublich schlanken, eleganten neuen Design aus Edelstahl. Filme, Videos und Fernsehsendungen auf einem 3,5"" Display ansehen!
     
    Im Web surfen, mailen!
    Multitouch-Oberfläche: Die revolutionäre Technologie des iPhone und die Software Version 3.1 stecken in diesem genialen iPod. Das brillante Breitformat-Display rückt Ihre Videos und Spiele ins beste Licht
     
    Surfen Sie mit Safari im Web und sehen Sie YouTube Videos auf dem iPod mit integrierter Wi-Fi Funktionalität an.
    Mit Ihrem iPod touch können Sie im iTunes Wi-Fi Music Store nach Songs suchen, Hörproben abspielen und Titel kaufen.  Lieferumfang: iPod touch, Ohrhörer, USB 2.0 Kabel, Dock-Adapter, Kurzanleitung
     
    Der iPod touch kann alles, was du am iPod toll findest. Und noch vielmehr.
    Du kannst Filme, Videos und Fernsehsendungen auf einem 3,5"" Display ansehen. Mit der revolutionären Multi-Touch-Technologie kannst du dein Musikarchiv mit Cover Flow durchblättern. Und wenn dir nach mehr ist, tipp einfach auf iTunes, um durch das Angebot zu stöbern und sofort einzukaufen. Hör dir Wiedergabelisten an, die automatisch für dich erstellt werden. Schau Filme auf dem brillanten 3,5"" Display. Und kauf mit einem Fingertipp bei iTunes ein - wann immer du willst. All das und noch viel mehr mit dem iPod touch, den es schon ab 189 € gibt. Wi-Fi ist schon integriert. So kannst du im Web surfen, mailen, deinen Facebook Status aktualisieren, mit AIM chatten und noch viel mehr - und das alles auf einem Gerät, das locker in jede Tasche passt. Hier hast du die Finger im Spiel. Und nicht nur die. Denn mit den Spielen auf dem iPod touch tauchst du richtig in die Action ein - einfach neigen, tippen, drehen. Und via Wi-Fi kannst du jederzeit im App Store neue Spiele kaufen. Die iPhone 3.1 Software ist auf dem iPod touch bereits installiert, sodass der Spaß gleich beginnen kann. Damit kannst du nützliche Funktionen wie Peer-to-Peer-Spiele und Cut, Copy & Paste direkt nach dem Auspacken nutzen.
    Next Level Fun: Der neue iPod touch
     
    Musik
    Stöber durch deine Alben. Hör dir einen einzigartigen Mix an, der nur für dich erstellt wurde. Oder schau das Video deines Lieblingssongs an. Mit dem iPod touch kannst du mehr als nur Musik hören.
     
    Cover Flow
    Auf dem iPod touch gibt's Musik nicht nur auf die Ohren. Mit Cover Flow ist Musik auch etwas für Augen und Finger. Dreh den iPod touch einfach auf die Seite und blätter durch deine Albumcover. Tipp auf ein Albumcover, um es umzudrehen und die Songliste zu sehen. Tipp noch einmal und Musik ab.
     
    Genius Mixe
    Die Genius Funktion wurde weiter verbessert. Jetzt gibt es Genius Mixe. Du brauchst den iPod touch nur mit iTunes zu synchronisieren. Genius durchsucht dann automatisch deine Mediathek nach Songs, die gut zusammenpassen und erstellt bis zu zwölf Mixe.
    Diese Mixe sind wie Radiosender, auf denen nur deine Musik läuft.
     
    Genius Wiedergabelisten
    Angenommen du hörst einen Song auf deinem iPod touch, der dir gut gefällt, und du möchtest weitere Titel hören, die dazu passen. Genius findet weitere Songs auf deinem iPod touch und erstellt eine Genius Wiedergabeliste für dich. Hör dir die Wiedergabeliste sofort an, speichere sie für später oder versuch's noch einmal und sieh, was dabei herauskommt. Verlass dich auf Genius, wenn du einen Mix willst, auf den du selbst nie gekommen wärst.
     
    Shake to Shuffle
    Die Dinge mal aufrütteln. Musikalisch natürlich. Wenn du das nächste Mal Musik hörst, aktiviere die Schüttelfunktion und wenn du den iPod touch dann kurz schüttelst, springt er nach dem Zufallsprinzip zu einem anderen Song aus deiner Sammlung.
     
    iTunes
    Pack Musik und Videos aus der iTunes Mediathek deines Computers auf den iPod touch. Oder kauf und lade neue Songs auf den iPod touch, wenn du über Wi-Fi auf iTunes zugreifst. Wenn du den iPod touch das nächste Mal mit dem Computer verbindest, werden alle Songs, die du auf dem iPod touch gekauft hast, auf den Mac oder PC übertragen.
     
    Bluetooth
    Schau mal, keine Kabel. Der iPod touch enthält die iPhone 3.1 Software, sodass du Bluetooth Stereokopfhörer anschließen kannst. Lass den iPod in deiner Tasche stecken oder auf dem Schreibtisch aufladen, während du weiter Musik hörst.
     
    Filme und Fernsehsendungen
    Ein Kinohit. Ein Video-Podcast. Deine Lieblingsserie. Jetzt laufen sie auch in einer U-Bahn oder einem Flugzeug in deiner Nähe.
    Widescreen-Display
    Du kannst Videos für viele Stunden überallhin mitnehmen und auf dem gestochen scharfen 3,5"" Widescreen-Farbdisplay ansehen. Kauf im iTunes Store und wähle unter tausenden vonFilmen, Fernsehsendungen und Video-Podcasts, die du auf den iPod touch laden kannst. Von Hollywood-Hits bis zu Indie-Streifen - es gibt etwas für jeden Geschmack. Mit wenigen Fingertipps kannst du Filme kaufen und laden. Du magst lieber Fernsehsendungen? Lade eine einzelne Folge oder die gesamte Staffel.
     
    On-Screen Steuerung
    Auch während du Video guckst, kannst du die Steuerung einblenden - ein Fingertipp auf das Display genügt. Du kannst die Wiedergabe starten oder unterbrechen, einzelne Kapitel anzeigen und die Lautstärke anpassen. Natürlich kannst du auch die Lautstärkeregler links am iPod touch verwenden. Du willst zwischen Widescreen und bildschirmfüllender Anzeige wechseln? Einfach aufs Display doppeltippen.
     
    iTunes
    Du brauchst Unterhaltung für deinen nächsten Flug oder die Autofahrt? Mit iTunes auf dem iPod touch und einer Wi-Fi-Verbindung kannst du auch unterwegsFilme und Fernsehsendungen kaufen. Du kannst Filme auch leihen, wenn du dir nicht sicher bist, ob du den Film behalten willst. Und natürlich kannst du Filme und Fernsehsendungen auf dem Mac oder PC kaufen und dann mit dem iPod touch synchronisieren.
     
    App Store
    Kaufe im App Store und entdecke über 65.000 Apps, mit denen du noch mehr auf dem iPod touch machen kannst. Stöbere in tausenden von Apps in verschiedenen Kategorien. Von Spielen über Lifestyle und Soziale Netzwerke bis zu Unterhaltung und mehr.
     
    Apps durchstöbern
    Du kannst auf verschiedene Arten im App Store shoppen. Tipp auf ""Neu"" und ""Topaktuell"", um eine Liste der aktuellen und angesagten Apps zu erhalten. Stöbere nach Kategorien. Schau dir die topaktuellen Apps an. Wenn du genau weißt, wonach du suchst, kannst du auch eine Schnellsuche durchführen.
     
    Genius Empfehlungen für Apps
    Es gibt tausende von Apps im App Store, und jeden Tag kommen mehr dazu. Mit dieser neuen Funktion des iPod touch findest du coole neue Apps noch einfacher. Genius für Apps. Funktioniert genau wie Genius für deine Musik. Tipp auf das Genius Symbol und du bekommst Empfehlungen für Apps anhand der Apps, die du und andere schon geladen haben.
     
    Apps laden
    Wenn du eine App findest, die dich interessiert, kannst du sie überall, wo eine Wi-Fi-Verbindung besteht, drahtlos kaufen, auf den iPod laden und dann sofort loslegen.
     
    Updates für Apps
    iPod touch sagt dir, wenn ein App Update verfügbar ist, damit du immer die neuesten Versionen deiner Lieblings-Apps hast.
     
    iTunes
    Entdecke und lade neue Musik, Filme, Fernsehsendungen, Podcasts und Hörbücher in iTunes auf dem iPod touch.
     
    Einkaufen, immer und überall
    Greif über die im iPod touch integrierte Wi-Fi-Funktion auf den iTunes Store zu. Durchsuche Millionen von iTunes Plus Songs in brillanter Audioqualitätund tausende von Filmen, Fernsehsendungen, Hörbüchern und kostenlosen Podcasts und Vorlesungen von iTunes U. Stöbere nach Neuerscheinungen, Top-Titeln und Genres. Oder finde mit der Schnellsuche genau das, wonach du suchst. Hör in einen Song oder sieh dir eine Videovorschau an. Wenn du dann etwas kaufen möchtest, brauchst du nur darauf zu tippen. Nicht sicher, ob es sich lohnt, den Film zu kaufen? Dann leih ihn einfach. Alles was du auf dem iPod touch kaufst, hat denselben Preis wie im iTunes Store auf deinem Computer.
     
    Synchronisieren mit iTunes
    Sobald du den iPod touch mit dem Computer verbindest, werden die Songs, Filme, Fernsehsendungen, Hörbücher und Podcasts, die du unterwegs geladen hast, mit deiner iTunes Mediathek auf deinem Mac oder PC synchronisiert. Wenn du etwas nur teilweise auf den iPod touch geladen hast, beendet der Computer den Download automatisch für dich.
     
    Sprachsteuerung
    Mit der Sprachsteuerung beim neuen 32 GB und 64 GB iPod touch kannst du deine Musik mit Sprachbefehlen steuern. Und der iPod hört aufs Wort. Auf ""Spiel"", ""Shuffle"" oder ""Wie heißt das Lied?"".
     
    Sagen und abspielen.
    Die Sprachsteuerung kennt die Musik auf deinem iPod touch. Wenn du etwas Bestimmtes hören willst, sag es einfach. Zum Beispiel ""Spiel Bob Dylan"" und der iPod touch hört aufs Wort. Frag ihn, welcher Song grad läuft, und der iPod touch sagt es dir. Sag ihm, dass er dein Lieblingsalbum, deinen Lieblingssänger oder deine Lieblingswiedergabeliste spielen soll. Verwende einfache Befehle wie ""shuffle"", ""nächster Song"" und ""anhalten"". Du kannst dem iPod touch sogar sagen, dass er mehr Songs wie den, der gerade läuft, abspielen soll.
     
    Sprich ins Mikro
    Der neue 32 GB und 64 GB iPod touch wird mit den Apple Earphones mit Fernbedienung und Mikro geliefert. So kannst du die Sprachsteuerung auch dann nutzen, wenn der iPod touch in der Tasche steckt. Zum Aktivieren der Sprachsteuerung über die Kopfhörer hältst du einfach die Mitteltaste der Fernbedienung gedrückt.
     
    Die Sprachsteuerung unterstützt die folgenden Sprachen:
    Chinesisch (China), Chinesisch (Kantonesisch), Chinesisch (Taiwan), Deutsch, Englisch (Großbritannien), Englisch (USA), Finnisch, Französisch (Frankreich), Französisch (Kanada), Italienisch, Japanisch, Koreanisch, Niederländisch, Norwegisch, Polnisch, Portugiesisch (Brasilien), Portugiesisch (Portugal), Russisch, Schwedisch, Spanisch (Mexiko), Spanisch (Spanien)
     
    Fotos
    Der iPod touch hat für bis zu 90.000 deiner Lieblingsfotos Platz. Durch Streichen kannst du sie durchschauen und all die Erinnerst-du-dich-noch-Momente mit anderen teilen.
     
    Fotos sichern
    Wenn dir tolle Bilder gemailt werden, kannst du sie einfach im Fotoarchiv auf dem iPod touch sichern und dann wie jedes andere Foto nutzen. Du kannst sie zum Beispiel als Hintergrundbilder verwenden, im Internet teilen oder weitergeben.
     
    Fotos teilen
    Du hast tausende Fotos immer zur Hand. Blätter durch Streichen auf dem Display durch Miniaturen. Mit einem Fingertipp siehst du Fotos bildschirmfüllend. Spiel Diashows mit Musik und Übergängen ab. Maile Fotos an Freunde oder teile sie in einer MobileMe Galerie.
     
    Fotos synchronisieren
    Fotos aus iPhoto auf einem Mac oder Adobe Photoshop Elements und Adobe Photoshop Album auf einem PC werden via iTunes mit dem iPod touch synchronisiert. Einfach nur die Fotos und Alben aussuchen, die mit dem iPod touch synchronisiert werden sollen. Dann kannst du sie überall ansehen und mit anderen teilen.
     
    Homescreen
    Angenommen du möchtest ""Karten"" als erste App in der zweiten Zeile haben. Oder Mail unten im Dock. Mit den anpassbaren Homescreens kannst du den iPod touch zu deinem iPod touch machen.
     
    Individuelles Anpassen
    Ordne die Symbole auf deinem Homescreen an wie du willst - direkt auf dem iPod touch oder auf deinem Computer in iTunes 9. Bewege eine App eine Zeile nach oben, zwei Apps nach rechts oder auf einen anderen Homescreen. Du kannst bis zu 11 Homescreens erstellen und hast so schnellen Zugriff auf Spiele und Apps, die du aus dem App Store lädst, und auf deine Safari Weblinks.
     
    Hometaste
    Was auch immer du gerade mit deinem iPod touch machst – die Hometaste bringt dich immer zurück zum ersten Homescreen. Wenn du auf die Hometaste drückst, kannst du von jedem Homescreen wieder zurück zum ersten springen.
     
    Apps und Weblinks hinzufügen
    Für jede App, die du aus dem App Store lädst, erscheint ein neues Symbol auf dem Homescreen. Von häufig besuchten Websites kannst du praktische Weblinks erstellen. Sie erscheinen auf dem Homescreen und du kannst per Fingertipp darauf zugreifen.
     
    Spotlight Suche
    Du suchst was? Von einem Ort aus kannst du die gesamten Inhalte des iPod touch durchsuchen. Streich auf dem ersten Homescreen einfach nach rechts, um Spotlight zu öffnen. Sobald du anfängst zu tippen, durchsucht Spotlight deine gesamten Songs, Videos, Kontakte, Mails, Kalender, Notizen und sogar deine Hörbücher und Podcasts.
     
    Safari
    Safari, der fortschrittlichste Webbrowser auf einem Mobilgerät, ist auch auf dem iPod touch integriert. Damit erlebst du das Internet in deiner Hand genauso wie auf dem Computer zuhause. Alles was du brauchst ist eine Wi-Fi-Verbindung.
     
    Überall ins Internet
    Der iPod touch ist der einzige iPod mit integriertem drahtlosen Internetzugriff. Bei bestehender Wi-Fi-Verbindung kannst du im Internet surfen und Nachrichten lesen, Sportergebnisse sehen, Rechnungen bezahlen und online einkaufen. Und beim 32 GB oder 64 GB iPod touch wirst du sehen, dass Webseiten jetzt noch schneller als vorher geladen werden.
     
    Im Web stöbern
    Der iPod touch synchronisiert deine Lesezeichen vom PC oder Mac, sodass du ruckzuck auf deine Lieblingsseiten zugreifen kannst. Außerdem ist die Google- und Yahoo!-Suche schon integriert, sodass du im Web schnell findest, was du suchst.
     
    Weblinks
    Wenn du eine Website öfter besuchst - etwa die einer Zeitung, eines Blogs oder eine Sport-Website - kannst du einfach ein Symbol, einen sogenannten Weblink, auf dem Homescreen erstellen. Wenn du mit Safari Weblinks erstellst, sind deine Lieblingsseiten nur einen Fingertipp entfernt.
     
    Zoom
    Wenn du eine Website öfter besuchst, brauchst du nur mit dem Finger auf das Multi-Touch-Display zu tippen oder die Anzeige aufzuziehen. Websites lassen sich im Hoch- oder Querformat anzeigen. Einfach den iPod touch um 90 Grad drehen, und schon wird auch die Darstellung der Webseite gedreht.
     
    Mail
    Mails auf dem iPod touch funktionieren genau wie auf deinem Computer und sehen auch genau so aus. Und sie funktionieren mit deinen vorhandenen Accounts.
     
    Nachrichten und Anhänge ansehen
    Der iPod touch unterstützt Rich-HTML-E-Mail, sodass Bilder und Fotos zusammen mit dem Text einer E-Mail angezeigt werden. Anhänge siehst du in ihrem Originalformat und nicht als abgespeckte Version. Du kannst in mehr als einem Dutzend standardmäßigen Datei- und Bildformaten drehen, zoomen und schwenken, darunter PDF, Microsoft Word, Excel, PowerPoint und iWork.
     
    Zugriff auf alle Accounts
    Mails von gängigen Anbietern wie MobileMe, Google Mail, Microsoft Exchange, Yahoo! und den meisten standardmäßigen IMAP- und POP-Systemen kannst du mit dem iPod touch ganz einfach abrufen.
     
    Schnellere Eingabe
    Der iPod touch erkennt E-Mail-Adressen in verschiedenen Programmen. Wenn du auf einer Webseite oder in einer Karte eine E-Mail-Adresse siehst, reicht ein Fingertipp auf dem iPod touch, um eine neue Mail zu öffnen, in der die Adresse bereits eingetragen ist.
     
    Intelligente Eingabe
    Die innovative iPod touch Tastatur mit integriertem Wörterbuch* schlägt während der Eingabe Wörter vor. So kannst du ganz schnell und einfach Mails schreiben. Dreh den iPod touch einfach. Dann wird die Tastatur vom Hochformat ins Querformat gedreht und du hast größere Tasten und mehr Platz zum Tippen.
     
    Postfach durchsuchen
    Du musst das Postfach jetzt nicht mehr Mail für Mail durchsuchen. Durch schnelles Abwärtsstreichen wird jetzt ein Suchfeld geöffnet, mit dem du deine Mails nach Absender, Empfänger, Betreff oder Titelzeilen durchsuchen kannst.
     
    Karten
    Finde deinen Weg und die nächste Pizzeria. Mit Karten und einer Wi-Fi-Verbindung kannst du Wegbeschreibungen abrufen, Firmen finden und Verkehrsinformationen prüfen.
     
    Finde dich selbst
    Der iPod touch zeigt dir mithilfe von bekannten Wi-Fi-Hot-Spots, wo du bist. Mit der Stichwortsuche kannst du auch interessante Orte finden. Wenn du z. B. ""Kaffee"" eingibst, werden dir alle Cafés in der Nähe angezeigt.
     
    Wo geht's lang?
    Gib einfach eine Adresse ein, um Wegbeschreibungen abzurufen - von jedem Ort aus. Wähle das Transportmittel wie Auto, öffentliches Verkehrsmittel oder zu Fuß. Die Route lässt sich dann Schritt für Schritt anzeigen. Du kannst dem markierten Weg auf der Karte folgen und selbst die Fahrtdauer wird angezeigt. Oder markiere zwei Orte und lass dir die beste Route zwischen diesen anzeigen.
     
    Verschiedene Kartendarstellungen
    Wie bei Google Karten auf deinem Computer kannst du mit dem Programm ""Karten"" auf dem iPod touch zwischen unterschiedlichen Darstellungen von Google-Karten, Satellitenbildern und einer Hybriddarstellung wechseln. Und mit Multi-Touch kannst du unterwegs zoomen, den Ausschnitt bewegen und die Darstellung ändern.
     
    Verkehrsinformationen
    Die Verkehrsinformationen geben dir anhand der grünen, roten und gelben Markierungen einen Überblick über die Verkehrssituation auf deiner Route.
     
    YouTube
    Skateboard Moves, die so nicht geplant waren. Witzige Werbespots aus anderen Ländern. Was auch immer du gern auf YouTube ansiehst - der iPod touch ist für dich da.
     
    Videogrüße von unterwegs.
    Maile Links deiner Lieblingsvideos an Freunde. Tippe auf der Detailseite des YouTube Videos auf ""Senden"", und schon erstellt der iPod touch eine Mail mit dem zugehörigen Videolink.
     
    Auf YouTube suchen.
    Stöber in Videokategorien wie ""Highlights"", ""Topvideos"", ""Neue Videos"" oder ""Bestwertung"". Du kannst auch per Schlagwort nach einem Video suchen. Etwas Passendes gefunden? Mit einem Lesezeichen kannst du das Video auch vormerken und später ansehen.
     
    Nike + iPod Kompatibilität
    Rock dein Training. Der iPod touch hat eine integrierte Unterstützung für Nike + iPod. Das ist Musik und Motivation in einem.
    Finetuning für dein Lauftraining.
     
    Nike + iPod Sensor
    Der iPod touch hat eine integrierte Unterstützung für Nike + iPod. Einfach den Nike + iPod Sensor (separat erhältlich) in die Nike+ Schuhe stecken und los geht's. Der Sensor überträgt deine Laufdaten drahtlos an den iPod touch und zeichnet Laufzeit, Laufstrecke und Kalorienverbrauch auf. Du erhältst sogar Feedback zum Trainingsfortschritt.
     
    Finetuning für dein Cardio Workout
    Diese Funktion kann auch zusammen mit neuen, in vielen Fitnessstudios vorhandenen Geräten für das Ausdauertraining gekoppelt werden. Such dir einfach ein mit Nike + iPod kompatibles Fitnessgerät wie beispielsweise Laufbänder, Ellipsentrainer, Stepper und Hometrainer.
     
    Synchronisieren mit nikeplus.com
    Später kannst du am Computer den iPod touch via iTunes synchronisieren und deine Trainingsdaten an nikeplus.com übertragen. Auf dieser Website kannst du dein Training verfolgen, dir Ziele setzen und deine Freunde herausfordern.
     
    Sprachmemos
    Du hast vielleicht ein ganz gutes Gedächtnis, aber manchmal ist es besser, kleine (und große) Infos einfach irgendwo festzuhalten. Mit ""Sprachmemos"" kein Problem.
     
    Memos (oder alles andere)aufnehmen
    Nimm eine Aufgabenliste, geniale Ideen oder eine Wette zwischen dir und deinem Freund auf. Mit dem Programm ""Sprachmemos"" kannst du über die Apple Earphones mit Fernbedienung und Mikro oder ein externes Mikrofon aufnehmen, was immer du willst. Sprachmemos kannst du selbst dann aufnehmen, wenn du den iPod touch gerade verwendest, um Mails zu checken oder im Web zu surfen.
     
    Memos bearbeiten
    Aufgenommene Memos kannst du direkt auf dem iPod touch trimmen. So behältst du nur das, was du wirklich brauchst.
     
    Memos sortieren
    Ordne deine Memos mithilfe von Etiketten aus einer vordefinierten Liste oder erstelle eigene Etiketten.
     
    Memos teilen
    Maile Memos an Freunde und Kollegen. Mit dem iPod touch aufgenommene Memos werden via iTunes mit deinem Mac oder PC synchronisiert, damit du sie später mit anderen teilen kannst.
     
    Weitere Funktionen
    Auf dem iPod touch ist die neueste Software schon installiert. Und außerdem gibt's praktische Apps wie Kontakte, Kalender, Notizen, Aktien und Wetter.
     
    iPod touch 3.1 Softwarefunktionen.
     
    Genius Mixe
    Diese neue Funktion ist wie ein privater DJ, der deine iTunes Mediathek durchsucht, um Songs zu finden, die gut zusammenpassen und aus diesen dann tolle Mixe erstellt. Alles ganz automatisch.
     
    Genius Empfehlungen für Apps
    Im App Store gibt's zehntausende Apps. Wie soll man da die richtig collen neuen finden? Mit Genius. Denn Genius sieht sich die Apps an, die du schon hast, und empfiehlt dir weitere.
     
    Peer-to-Peer-Spiele
    Die neusten Spiele kannst du ganz leicht mit Freunden spielen - egal, ob sie neben dir oder in einer anderen Ecke des Landes sitzen.
     
    Kauf Filme, Fernsehsendungen und Hörbücher via Wi-Fi
    Lade via Wi-Fi Filme, Fernsehsendungen, Musikvideos und Hörbücher aus dem iTunes Store auf deinen iPod touch.
     
    Tastatur im Querformat
    Du brauchst mehr Platz zum Tippen? Dreh den iPod touch ins Querformat, um in Mail, Notizen und Safari mit einer größeren Tastatur zu arbeiten.
     
    Cut, Copy & Paste
    Einfach Text und Fotos ausschneiden, kopieren und wieder einsetzen - selbst zwischen Programmen. Du kannst auch Inhalte aus dem Web kopieren.
     
    Spotlight Suche
    Gesucht, gefunden - von einem Ort aus. Spotlight durchsucht alle deine Kontakte, E-Mails, Kalender und Notizen und auch alle Songs und Videos.
     
    Stereo Bluetooth
    Hör Musik und andere Audioinhalte drahtlos. Verbinde den iPod touch mit kompatiblen Bluetooth Stereokopfhörern.
     
    Automatischer Wi-Fi-Login
    Wenn du dich einmal bei einem Wi-Fi-Hotspot anmeldest, loggt der iPod touch sich beim nächsten Mal automatisch ein.
     
    Shake to Shuffle
    Schüttel den iPod kurz, und schon springt er nach dem Zufallsprinzip zu einem anderen Song in deiner Sammlung. Lass dich einfach überraschen.
     
    Bedienungshilfen
    Der neue iPod touch hat standardmäßig Bedienungshilfen integriert, mit denen auch Menschen mit Beeinträchtigungen alles, was der iPod touch zu bieten hat, erleben können. Alle Bedienungshilfen des iPod touch ansehen
     
    Kindersicherung
    Du entscheidest, welche Musik, Videos und Apps auf dem iPod touch für deine Kinder geeignet sind.
    Der iPod touch hat auch die folgenden praktischen Apps:
     
    Kalender
    Das Programm ""Kalender"" funktioniert mit Yahoo!, Google, Microsoft Outlook, iCal, MobileMe und Microsoft Exchange ActiveSync für Unternehmen. Füge Termine hinzu, lass dich an Termine erinnern, und abonniere Kalender, damit du über Feiertage und Sportveranstaltungen auf dem Laufenden bleibst.
     
    Kontakte
    Namen, E-Mail-Adressen, Telefonnummern und mehr - immer zur Hand. Synchronisier Kontakte in iTunes auf dem Mac oder PC mit dem iPod touch. Neue Kontakte kannst du auch unterwegs mit einem einfachen Fingertipp hinzufügen.
     
    Notizen
    Schluss mit Papier und Bleistift. Mach dir mit ""Notizen"" auf dem iPod schnell eine Notiz, damit du wichtige Infos immer parat hast. Maile deine Gedanken mit der integrierten Mail-Funktion an dich oder andere.
     
    Aktien
    Die Aktien App auf dem iPod touch zeigt dir Börseninformationen für die Aktien, die dich interessieren. Wenn du nähere Details über eine Aktie brauchst, tipp auf ""Y!"", um im Handumdrehen Yahoo! Finance zu öffnen.
     
    Wetter
    Informier dich über das Wetter in der ganzen Welt oder zuhause. Füge die gewünschten Städte hinzu und zeige eine sechstägige Vorhersage für alle an. Tipp auf ""Y!"", um den Yahoo! Stadtführer zu öffnen, der dir zeigt, wo was los ist.
     
    Rechner
    Im Programm ""Rechner"" des iPod touch stecken gleich zwei Rechner. Im Hochformat kannst du ihn als einfachen Taschenrechner verwenden. Dreh den iPod touch ins Querformat, um aus ihm einen wissenschaftlichen Rechner zu machen.
     
    iPod touch Technologie
    Dank der revolutionären Hardwaretechnologie im iPod touch kannst du alle Funktionen mit Streichen, Tippen und Auf- oder Zuziehen steuern. Deswegen wirkt das Autorennen so echt. Deswegen kannst du das, was du eben im Café mitbekommen hast, sofort twittern. Und genau deswegen ist der iPod touch der beste iPod aller Zeiten.
     
    Multi-Touch
    Das Multi-Touch-Display besitzt einen Schutzfilm über der kapazitiven Sensorik, die Berührungen anhand elektrischer Felder erkennt. Diese Informationen werden an das darunterliegende LCD-Display übertragen. Dank der Software des iPod touch kannst du mit Cover Flow durch Alben stöbern, durch deine Fotos blättern, mit Auf- und Zuziehen Bildausschnitte von Websites zoomen und Spiele superpräzise steuern.
     
    Beschleunigungssensor
    Der iPod touch reagiert über einen integrierten Beschleunigungssensor auf Bewegungen. Dieser Sensor erkennt, wenn du deinen iPod touch ins Querformat drehst und verändert automatisch den Inhalt des Displays. Die Technologie des Beschleunigungssensors kommt besonders bei Spielen gut, denn damit bist du mitten im Spielgeschehen. Das ist perfekt für Autorennen, bei denen der ganze iPod zum Lenkrad wird, und Geschicklichkeitsspiele wie Rolando, bei denen du das Spiel mit deinen Bewegungen steuerst
     
    Drahtlos
    Der iPod touch hat eine integrierte Unterstützung für drahtlosen 802.11b/g Internetzugriff. Überall, wo es ein Wi-Fi-Netzwerk gibt, kommst du mit deinem iPod touch ins Internet. Im Café mailen. Am Flughafen im Web surfen. Spiele vom Sofa aus kaufen. Im iTunes Store stöbern und Musik kaufen und laden. Der iPod touch findet nahegelegene Wi-Fi-Hot-Spots, auch geschützte Netzwerke. Wenn du ein bestimmtes Netzwerk bisher noch nicht verwendet hast, Drahtlos Symbol musst du beim ersten Mal ein Kennwort eingeben, das sich der iPod touch dann merkt. Wenn du dann das nächste Mal in Reichweite dieses Netzwerks bist, loggt er sich automatisch ein.
     
    Bluetooth
    Bluetooth ist eine drahtlose Technologie, mit der du Geräte ohne lästige Kabel verwenden kannst. Was bedeutet das für den iPod touch? Du kannst jetzt mit dem iPod touch und Bluetooth Kopfhörern Musik hören, ganz egal, wo im Raum der iPod ist. Du kannst also auf dem Bett relaxen, während der iPod auf dem Schreibtisch aufgeladen wird. Bluetooth auf dem iPod touch eignet sich auch besonders für Peer-to-Peer-Spiele.
     
    Design
    Der iPod touch ist von außen genau so großartig wie von innen. Du brauchst nur einen in die Hand zu nehmen. Das Gehäuse des iPod touch ist gerade einmal 8,5 mm hoch. Das optische Glas auf der Vorderseite und die Rückseite aus poliertem Edelstahl geben ihm einen eleganten Touch und fühlen sich in der Hand einfach gut an. Schalte ihn ein und du wirst über das brillante 3,5"" Display einfach staunen. Der iPod touch ist die perfekte Kombination aus großartigem Design und revolutionärer Technologie - das perfekte Paket.
    ";2;False;0;;;Apple iPod Touch schwarz mit integrierter WiFi Funktion;apple-ipod-touch-32-gb-schwarz-2;True;True;P-1290;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;269.9000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;40186,8623263889;44;1;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000434-apple-ipod-touch-64-gb-schwarz.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000435-apple-ipod-touch-64-gb-schwarz.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000436-apple-ipod-touch-64-gb-schwarz.jpg;2;;False;;;;;False;False;False;;;;;False;;;;;; +5;0;True;Apple iPod Touch 64 GB schwarz;Apple iPod Touch 64 GB schwarz;"
    Apple iPod Touch 64 GB schwarz
    mit integrierter WiFi Funktion


    Ein großartiger iPod. Ein großartiger Taschencomputer. Großartiger mobiler Spielspaß. Und das Ganze in einem unglaublich schlanken, eleganten neuen Design aus Edelstahl. Filme, Videos und Fernsehsendungen auf einem 3,5"" Display ansehen!
    Im Web surfen, mailen!
    Multitouch-Oberfläche: Die revolutionäre Technologie des iPhone und die Software Version 3.1 stecken in diesem genialen iPod. Das brillante Breitformat-Display rückt Ihre Videos und Spiele ins beste Licht
    Surfen Sie mit Safari im Web und sehen Sie YouTube Videos auf dem iPod mit integrierter Wi-Fi Funktionalität an.
    Mit Ihrem iPod touch können Sie im iTunes Wi-Fi Music Store nach Songs suchen, Hörproben abspielen und Titel kaufen. Lieferumfang: iPod touch, Ohrhörer, USB 2.0 Kabel, Dock-Adapter, Kurzanleitung
     
    Der iPod touch kann alles, was du am iPod toll findest. Und noch vielmehr.
    Du kannst Filme, Videos und Fernsehsendungen auf einem 3,5"" Display ansehen. Mit der revolutionären Multi-Touch-Technologie kannst du dein Musikarchiv mit Cover Flow durchblättern. Und wenn dir nach mehr ist, tipp einfach auf iTunes, um durch das Angebot zu stöbern und sofort einzukaufen. Hör dir Wiedergabelisten an, die automatisch für dich erstellt werden. Schau Filme auf dem brillanten 3,5"" Display. Und kauf mit einem Fingertipp bei iTunes ein - wann immer du willst. All das und noch viel mehr mit dem iPod touch, den es schon ab 189 € gibt. Wi-Fi ist schon integriert. So kannst du im Web surfen, mailen, deinen Facebook Status aktualisieren, mit AIM chatten und noch viel mehr - und das alles auf einem Gerät, das locker in jede Tasche passt. Hier hast du die Finger im Spiel. Und nicht nur die. Denn mit den Spielen auf dem iPod touch tauchst du richtig in die Action ein - einfach neigen, tippen, drehen. Und via Wi-Fi kannst du jederzeit im App Store neue Spiele kaufen. Die iPhone 3.1 Software ist auf dem iPod touch bereits installiert, sodass der Spaß gleich beginnen kann. Damit kannst du nützliche Funktionen wie Peer-to-Peer-Spiele und Cut, Copy & Paste direkt nach dem Auspacken nutzen.
    Next Level Fun: Der neue iPod touch
     
    Musik
    Stöber durch deine Alben. Hör dir einen einzigartigen Mix an, der nur für dich erstellt wurde. Oder schau das Video deines Lieblingssongs an. Mit dem iPod touch kannst du mehr als nur Musik hören.
     
    Cover Flow
    Auf dem iPod touch gibt's Musik nicht nur auf die Ohren. Mit Cover Flow ist Musik auch etwas für Augen und Finger. Dreh den iPod touch einfach auf die Seite und blätter durch deine Albumcover. Tipp auf ein Albumcover, um es umzudrehen und die Songliste zu sehen. Tipp noch einmal und Musik ab.
     
    Genius Mixe
    Die Genius Funktion wurde weiter verbessert. Jetzt gibt es Genius Mixe. Du brauchst den iPod touch nur mit iTunes zu synchronisieren. Genius durchsucht dann automatisch deine Mediathek nach Songs, die gut zusammenpassen und erstellt bis zu zwölf Mixe.
    Diese Mixe sind wie Radiosender, auf denen nur deine Musik läuft.
     
    Genius Wiedergabelisten
    Angenommen du hörst einen Song auf deinem iPod touch, der dir gut gefällt, und du möchtest weitere Titel hören, die dazu passen. Genius findet weitere Songs auf deinem iPod touch und erstellt eine Genius Wiedergabeliste für dich. Hör dir die Wiedergabeliste sofort an, speichere sie für später oder versuch's noch einmal und sieh, was dabei herauskommt. Verlass dich auf Genius, wenn du einen Mix willst, auf den du selbst nie gekommen wärst.
     
    Shake to Shuffle
    Die Dinge mal aufrütteln. Musikalisch natürlich. Wenn du das nächste Mal Musik hörst, aktiviere die Schüttelfunktion und wenn du den iPod touch dann kurz schüttelst, springt er nach dem Zufallsprinzip zu einem anderen Song aus deiner Sammlung.

    iTunes
    Pack Musik und Videos aus der iTunes Mediathek deines Computers auf den iPod touch. Oder kauf und lade neue Songs auf den iPod touch, wenn du über Wi-Fi auf iTunes zugreifst. Wenn du den iPod touch das nächste Mal mit dem Computer verbindest, werden alle Songs, die du auf dem iPod touch gekauft hast, auf den Mac oder PC übertragen.
     
    Bluetooth
    Schau mal, keine Kabel. Der iPod touch enthält die iPhone 3.1 Software, sodass du Bluetooth Stereokopfhörer anschließen kannst. Lass den iPod in deiner Tasche stecken oder auf dem Schreibtisch aufladen, während du weiter Musik hörst.
     
    Filme und Fernsehsendungen
    Ein Kinohit. Ein Video-Podcast. Deine Lieblingsserie. Jetzt laufen sie auch in einer U-Bahn oder einem Flugzeug in deiner Nähe.
     
    Widescreen-Display
    Du kannst Videos für viele Stunden überallhin mitnehmen und auf dem gestochen scharfen 3,5"" Widescreen-Farbdisplay ansehen. Kauf im iTunes Store und wähle unter tausenden vonFilmen, Fernsehsendungen und Video-Podcasts, die du auf den iPod touch laden kannst. Von Hollywood-Hits bis zu Indie-Streifen - es gibt etwas für jeden Geschmack. Mit wenigen Fingertipps kannst du Filme kaufen und laden. Du magst lieber Fernsehsendungen? Lade eine einzelne Folge oder die gesamte Staffel.
     
    On-Screen Steuerung
    Auch während du Video guckst, kannst du die Steuerung einblenden - ein Fingertipp auf das Display genügt. Du kannst die Wiedergabe starten oder unterbrechen, einzelne Kapitel anzeigen und die Lautstärke anpassen. Natürlich kannst du auch die Lautstärkeregler links am iPod touch verwenden. Du willst zwischen Widescreen und bildschirmfüllender Anzeige wechseln? Einfach aufs Display doppeltippen.
     
    iTunes
    Du brauchst Unterhaltung für deinen nächsten Flug oder die Autofahrt? Mit iTunes auf dem iPod touch und einer Wi-Fi-Verbindung kannst du auch unterwegsFilme und Fernsehsendungen kaufen. Du kannst Filme auch leihen, wenn du dir nicht sicher bist, ob du den Film behalten willst. Und natürlich kannst du Filme und Fernsehsendungen auf dem Mac oder PC kaufen und dann mit dem iPod touch synchronisieren.
     
    App Store
    Kaufe im App Store und entdecke über 65.000 Apps, mit denen du noch mehr auf dem iPod touch machen kannst. Stöbere in tausenden von Apps in verschiedenen Kategorien. Von Spielen über Lifestyle und Soziale Netzwerke bis zu Unterhaltung und mehr.
     
    Apps durchstöbern
    Du kannst auf verschiedene Arten im App Store shoppen. Tipp auf ""Neu"" und ""Topaktuell"", um eine Liste der aktuellen und angesagten Apps zu erhalten. Stöbere nach Kategorien. Schau dir die topaktuellen Apps an. Wenn du genau weißt, wonach du suchst, kannst du auch eine Schnellsuche durchführen.
     
    Genius Empfehlungen für Apps
    Es gibt tausende von Apps im App Store, und jeden Tag kommen mehr dazu. Mit dieser neuen Funktion des iPod touch findest du coole neue Apps noch einfacher. Genius für Apps. Funktioniert genau wie Genius für deine Musik. Tipp auf das Genius Symbol und du bekommst Empfehlungen für Apps anhand der Apps, die du und andere schon geladen haben.
     
    Apps laden
    Wenn du eine App findest, die dich interessiert, kannst du sie überall, wo eine Wi-Fi-Verbindung besteht, drahtlos kaufen, auf den iPod laden und dann sofort loslegen.
     
    Updates für Apps
    iPod touch sagt dir, wenn ein App Update verfügbar ist, damit du immer die neuesten Versionen deiner Lieblings-Apps hast.
     
    iTunes
    Entdecke und lade neue Musik, Filme, Fernsehsendungen, Podcasts und Hörbücher in iTunes auf dem iPod touch.
     
    Einkaufen, immer und überall
    Greif über die im iPod touch integrierte Wi-Fi-Funktion auf den iTunes Store zu. Durchsuche Millionen von iTunes Plus Songs in brillanter Audioqualitätund tausende von Filmen, Fernsehsendungen, Hörbüchern und kostenlosen Podcasts und Vorlesungen von iTunes U. Stöbere nach Neuerscheinungen, Top-Titeln und Genres. Oder finde mit der Schnellsuche genau das, wonach du suchst. Hör in einen Song oder sieh dir eine Videovorschau an. Wenn du dann etwas kaufen möchtest, brauchst du nur darauf zu tippen. Nicht sicher, ob es sich lohnt, den Film zu kaufen? Dann leih ihn einfach. Alles was du auf dem iPod touch kaufst, hat denselben Preis wie im iTunes Store auf deinem Computer.
     
    Synchronisieren mit iTunes
    Sobald du den iPod touch mit dem Computer verbindest, werden die Songs, Filme, Fernsehsendungen, Hörbücher und Podcasts, die du unterwegs geladen hast, mit deiner iTunes Mediathek auf deinem Mac oder PC synchronisiert. Wenn du etwas nur teilweise auf den iPod touch geladen hast, beendet der Computer den Download automatisch für dich.
     
    Sprachsteuerung
    Mit der Sprachsteuerung beim neuen 32 GB und 64 GB iPod touch kannst du deine Musik mit Sprachbefehlen steuern. Und der iPod hört aufs Wort. Auf ""Spiel"", ""Shuffle"" oder ""Wie heißt das Lied?"".
    Sagen und abspielen.
    Die Sprachsteuerung kennt die Musik auf deinem iPod touch. Wenn du etwas Bestimmtes hören willst, sag es einfach. Zum Beispiel ""Spiel Bob Dylan"" und der iPod touch hört aufs Wort. Frag ihn, welcher Song grad läuft, und der iPod touch sagt es dir. Sag ihm, dass er dein Lieblingsalbum, deinen Lieblingssänger oder deine Lieblingswiedergabeliste spielen soll. Verwende einfache Befehle wie ""shuffle"", ""nächster Song"" und ""anhalten"". Du kannst dem iPod touch sogar sagen, dass er mehr Songs wie den, der gerade läuft, abspielen soll.
     
    Sprich ins Mikro
    Der neue 32 GB und 64 GB iPod touch wird mit den Apple Earphones mit Fernbedienung und Mikro geliefert. So kannst du die Sprachsteuerung auch dann nutzen, wenn der iPod touch in der Tasche steckt. Zum Aktivieren der Sprachsteuerung über die Kopfhörer hältst du einfach die Mitteltaste der Fernbedienung gedrückt.
    Die Sprachsteuerung unterstützt die folgenden Sprachen:
    Chinesisch (China), Chinesisch (Kantonesisch), Chinesisch (Taiwan), Deutsch, Englisch (Großbritannien), Englisch (USA), Finnisch, Französisch (Frankreich), Französisch (Kanada), Italienisch, Japanisch, Koreanisch, Niederländisch, Norwegisch, Polnisch, Portugiesisch (Brasilien), Portugiesisch (Portugal), Russisch, Schwedisch, Spanisch (Mexiko), Spanisch (Spanien)
     
    Fotos
    Der iPod touch hat für bis zu 90.000 deiner Lieblingsfotos Platz. Durch Streichen kannst du sie durchschauen und all die Erinnerst-du-dich-noch-Momente mit anderen teilen.
     
    Fotos sichern
    Wenn dir tolle Bilder gemailt werden, kannst du sie einfach im Fotoarchiv auf dem iPod touch sichern und dann wie jedes andere Foto nutzen. Du kannst sie zum Beispiel als Hintergrundbilder verwenden, im Internet teilen oder weitergeben.
     
    Fotos teilen
    Du hast tausende Fotos immer zur Hand. Blätter durch Streichen auf dem Display durch Miniaturen. Mit einem Fingertipp siehst du Fotos bildschirmfüllend. Spiel Diashows mit Musik und Übergängen ab. Maile Fotos an Freunde oder teile sie in einer MobileMe Galerie.
     
    Fotos synchronisieren
    Fotos aus iPhoto auf einem Mac oder Adobe Photoshop Elements und Adobe Photoshop Album auf einem PC werden via iTunes mit dem iPod touch synchronisiert. Einfach nur die Fotos und Alben aussuchen, die mit dem iPod touch synchronisiert werden sollen. Dann kannst du sie überall ansehen und mit anderen teilen.

    Homescreen
    Angenommen du möchtest ""Karten"" als erste App in der zweiten Zeile haben. Oder Mail unten im Dock. Mit den anpassbaren Homescreens kannst du den iPod touch zu deinem iPod touch machen.
     
    Individuelles Anpassen
    Ordne die Symbole auf deinem Homescreen an wie du willst - direkt auf dem iPod touch oder auf deinem Computer in iTunes 9. Bewege eine App eine Zeile nach oben, zwei Apps nach rechts oder auf einen anderen Homescreen. Du kannst bis zu 11 Homescreens erstellen und hast so schnellen Zugriff auf Spiele und Apps, die du aus dem App Store lädst, und auf deine Safari Weblinks.
     
    Hometaste
    Was auch immer du gerade mit deinem iPod touch machst – die Hometaste bringt dich immer zurück zum ersten Homescreen. Wenn du auf die Hometaste drückst, kannst du von jedem Homescreen wieder zurück zum ersten springen.
     
    Apps und Weblinks hinzufügen
    Für jede App, die du aus dem App Store lädst, erscheint ein neues Symbol auf dem Homescreen. Von häufig besuchten Websites kannst du praktische Weblinks erstellen. Sie erscheinen auf dem Homescreen und du kannst per Fingertipp darauf zugreifen.
     
    Spotlight Suche
    Du suchst was? Von einem Ort aus kannst du die gesamten Inhalte des iPod touch durchsuchen. Streich auf dem ersten Homescreen einfach nach rechts, um Spotlight zu öffnen. Sobald du anfängst zu tippen, durchsucht Spotlight deine gesamten Songs, Videos, Kontakte, Mails, Kalender, Notizen und sogar deine Hörbücher und Podcasts.
     
    Safari
    Safari, der fortschrittlichste Webbrowser auf einem Mobilgerät, ist auch auf dem iPod touch integriert. Damit erlebst du das Internet in deiner Hand genauso wie auf dem Computer zuhause. Alles was du brauchst ist eine Wi-Fi-Verbindung.
     
    Überall ins Internet
    Der iPod touch ist der einzige iPod mit integriertem drahtlosen Internetzugriff. Bei bestehender Wi-Fi-Verbindung kannst du im Internet surfen und Nachrichten lesen, Sportergebnisse sehen, Rechnungen bezahlen und online einkaufen. Und beim 32 GB oder 64 GB iPod touch wirst du sehen, dass Webseiten jetzt noch schneller als vorher geladen werden.
     
    Im Web stöbern
    Der iPod touch synchronisiert deine Lesezeichen vom PC oder Mac, sodass du ruckzuck auf deine Lieblingsseiten zugreifen kannst. Außerdem ist die Google- und Yahoo!-Suche schon integriert, sodass du im Web schnell findest, was du suchst.
     
    Weblinks
    Wenn du eine Website öfter besuchst - etwa die einer Zeitung, eines Blogs oder eine Sport-Website - kannst du einfach ein Symbol, einen sogenannten Weblink, auf dem Homescreen erstellen. Wenn du mit Safari Weblinks erstellst, sind deine Lieblingsseiten nur einen Fingertipp entfernt.
     
    Zoom
    Wenn du eine Website öfter besuchst, brauchst du nur mit dem Finger auf das Multi-Touch-Display zu tippen oder die Anzeige aufzuziehen. Websites lassen sich im Hoch- oder Querformat anzeigen. Einfach den iPod touch um 90 Grad drehen, und schon wird auch die Darstellung der Webseite gedreht.
     
    Mail
    Mails auf dem iPod touch funktionieren genau wie auf deinem Computer und sehen auch genau so aus. Und sie funktionieren mit deinen vorhandenen Accounts.
     
    Nachrichten und Anhänge ansehen
    Der iPod touch unterstützt Rich-HTML-E-Mail, sodass Bilder und Fotos zusammen mit dem Text einer E-Mail angezeigt werden. Anhänge siehst du in ihrem Originalformat und nicht als abgespeckte Version. Du kannst in mehr als einem Dutzend standardmäßigen Datei- und Bildformaten drehen, zoomen und schwenken, darunter PDF, Microsoft Word, Excel, PowerPoint und iWork.
     
    Zugriff auf alle Accounts
    Mails von gängigen Anbietern wie MobileMe, Google Mail, Microsoft Exchange, Yahoo! und den meisten standardmäßigen IMAP- und POP-Systemen kannst du mit dem iPod touch ganz einfach abrufen.
     
    Schnellere Eingabe
    Der iPod touch erkennt E-Mail-Adressen in verschiedenen Programmen. Wenn du auf einer Webseite oder in einer Karte eine E-Mail-Adresse siehst, reicht ein Fingertipp auf dem iPod touch, um eine neue Mail zu öffnen, in der die Adresse bereits eingetragen ist.
     
    Intelligente Eingabe
    Die innovative iPod touch Tastatur mit integriertem Wörterbuch* schlägt während der Eingabe Wörter vor. So kannst du ganz schnell und einfach Mails schreiben. Dreh den iPod touch einfach. Dann wird die Tastatur vom Hochformat ins Querformat gedreht und du hast größere Tasten und mehr Platz zum Tippen.
     
    Postfach durchsuchen
    Du musst das Postfach jetzt nicht mehr Mail für Mail durchsuchen. Durch schnelles Abwärtsstreichen wird jetzt ein Suchfeld geöffnet, mit dem du deine Mails nach Absender, Empfänger, Betreff oder Titelzeilen durchsuchen kannst.
     
    Karten
    Finde deinen Weg und die nächste Pizzeria. Mit Karten und einer Wi-Fi-Verbindung kannst du Wegbeschreibungen abrufen, Firmen finden und Verkehrsinformationen prüfen.
     
    Finde dich selbst
    Der iPod touch zeigt dir mithilfe von bekannten Wi-Fi-Hot-Spots, wo du bist. Mit der Stichwortsuche kannst du auch interessante Orte finden. Wenn du z. B. ""Kaffee"" eingibst, werden dir alle Cafés in der Nähe angezeigt.
     
    Wo geht's lang?
    Gib einfach eine Adresse ein, um Wegbeschreibungen abzurufen - von jedem Ort aus. Wähle das Transportmittel wie Auto, öffentliches Verkehrsmittel oder zu Fuß. Die Route lässt sich dann Schritt für Schritt anzeigen. Du kannst dem markierten Weg auf der Karte folgen und selbst die Fahrtdauer wird angezeigt. Oder markiere zwei Orte und lass dir die beste Route zwischen diesen anzeigen.
     
    Verschiedene Kartendarstellungen
    Wie bei Google Karten auf deinem Computer kannst du mit dem Programm ""Karten"" auf dem iPod touch zwischen unterschiedlichen Darstellungen von Google-Karten, Satellitenbildern und einer Hybriddarstellung wechseln. Und mit Multi-Touch kannst du unterwegs zoomen, den Ausschnitt bewegen und die Darstellung ändern.
     
    Verkehrsinformationen
    Die Verkehrsinformationen geben dir anhand der grünen, roten und gelben Markierungen einen Überblick über die Verkehrssituation auf deiner Route.
     
    YouTube
    Skateboard Moves, die so nicht geplant waren. Witzige Werbespots aus anderen Ländern. Was auch immer du gern auf YouTube ansiehst - der iPod touch ist für dich da.
     
    Videogrüße von unterwegs.
    Maile Links deiner Lieblingsvideos an Freunde. Tippe auf der Detailseite des YouTube Videos auf ""Senden"", und schon erstellt der iPod touch eine Mail mit dem zugehörigen Videolink.
     
    Auf YouTube suchen.
    Stöber in Videokategorien wie ""Highlights"", ""Topvideos"", ""Neue Videos"" oder ""Bestwertung"". Du kannst auch per Schlagwort nach einem Video suchen. Etwas Passendes gefunden? Mit einem Lesezeichen kannst du das Video auch vormerken und später ansehen.
     
    Nike + iPod Kompatibilität
    Rock dein Training. Der iPod touch hat eine integrierte Unterstützung für Nike + iPod. Das ist Musik und Motivation in einem.
    Finetuning für dein Lauftraining.
     
    Nike + iPod Sensor
    Der iPod touch hat eine integrierte Unterstützung für Nike + iPod. Einfach den Nike + iPod Sensor (separat erhältlich) in die Nike+ Schuhe stecken und los geht's. Der Sensor überträgt deine Laufdaten drahtlos an den iPod touch und zeichnet Laufzeit, Laufstrecke und Kalorienverbrauch auf. Du erhältst sogar Feedback zum Trainingsfortschritt.
     
    Finetuning für dein Cardio Workout
    Diese Funktion kann auch zusammen mit neuen, in vielen Fitnessstudios vorhandenen Geräten für das Ausdauertraining gekoppelt werden. Such dir einfach ein mit Nike + iPod kompatibles Fitnessgerät wie beispielsweise Laufbänder, Ellipsentrainer, Stepper und Hometrainer.
     
    Synchronisieren mit nikeplus.com
    Später kannst du am Computer den iPod touch via iTunes synchronisieren und deine Trainingsdaten an nikeplus.com übertragen. Auf dieser Website kannst du dein Training verfolgen, dir Ziele setzen und deine Freunde herausfordern.
     
    Sprachmemos
    Du hast vielleicht ein ganz gutes Gedächtnis, aber manchmal ist es besser, kleine (und große) Infos einfach irgendwo festzuhalten. Mit ""Sprachmemos"" kein Problem.

    Memos (oder alles andere)aufnehmen
    Nimm eine Aufgabenliste, geniale Ideen oder eine Wette zwischen dir und deinem Freund auf. Mit dem Programm ""Sprachmemos"" kannst du über die Apple Earphones mit Fernbedienung und Mikro oder ein externes Mikrofon aufnehmen, was immer du willst. Sprachmemos kannst du selbst dann aufnehmen, wenn du den iPod touch gerade verwendest, um Mails zu checken oder im Web zu surfen.
    Memos bearbeiten
    Aufgenommene Memos kannst du direkt auf dem iPod touch trimmen. So behältst du nur das, was du wirklich brauchst.
    Memos sortieren
    Ordne deine Memos mithilfe von Etiketten aus einer vordefinierten Liste oder erstelle eigene Etiketten.
    Memos teilen
    Maile Memos an Freunde und Kollegen. Mit dem iPod touch aufgenommene Memos werden via iTunes mit deinem Mac oder PC synchronisiert, damit du sie später mit anderen teilen kannst.
    Weitere Funktionen
    Auf dem iPod touch ist die neueste Software schon installiert. Und außerdem gibt's praktische Apps wie Kontakte, Kalender, Notizen, Aktien und Wetter.
     
    iPod touch 3.1 Softwarefunktionen.
     
    Genius Mixe
    Diese neue Funktion ist wie ein privater DJ, der deine iTunes Mediathek durchsucht, um Songs zu finden, die gut zusammenpassen und aus diesen dann tolle Mixe erstellt. Alles ganz automatisch.
    Genius Empfehlungen für Apps
    Im App Store gibt's zehntausende Apps. Wie soll man da die richtig collen neuen finden? Mit Genius. Denn Genius sieht sich die Apps an, die du schon hast, und empfiehlt dir weitere.
     
    Peer-to-Peer-Spiele
    Die neusten Spiele kannst du ganz leicht mit Freunden spielen - egal, ob sie neben dir oder in einer anderen Ecke des Landes sitzen.
     
    Kauf Filme, Fernsehsendungen und Hörbücher via Wi-Fi
    Lade via Wi-Fi Filme, Fernsehsendungen, Musikvideos und Hörbücher aus dem iTunes Store auf deinen iPod touch.
     
    Tastatur im Querformat
    Du brauchst mehr Platz zum Tippen? Dreh den iPod touch ins Querformat, um in Mail, Notizen und Safari mit einer größeren Tastatur zu arbeiten.
     
    Cut, Copy & Paste
    Einfach Text und Fotos ausschneiden, kopieren und wieder einsetzen - selbst zwischen Programmen. Du kannst auch Inhalte aus dem Web kopieren.
     
    Spotlight Suche
    Gesucht, gefunden - von einem Ort aus. Spotlight durchsucht alle deine Kontakte, E-Mails, Kalender und Notizen und auch alle Songs und Videos.
     
    Stereo Bluetooth
    Hör Musik und andere Audioinhalte drahtlos. Verbinde den iPod touch mit kompatiblen Bluetooth Stereokopfhörern.

    Automatischer Wi-Fi-Login
    Wenn du dich einmal bei einem Wi-Fi-Hotspot anmeldest, loggt der iPod touch sich beim nächsten Mal automatisch ein.
     
    Shake to Shuffle
    Schüttel den iPod kurz, und schon springt er nach dem Zufallsprinzip zu einem anderen Song in deiner Sammlung. Lass dich einfach überraschen.
     
    Bedienungshilfen
    Der neue iPod touch hat standardmäßig Bedienungshilfen integriert, mit denen auch Menschen mit Beeinträchtigungen alles, was der iPod touch zu bieten hat, erleben können. Alle Bedienungshilfen des iPod touch ansehen
     
    Kindersicherung
    Du entscheidest, welche Musik, Videos und Apps auf dem iPod touch für deine Kinder geeignet sind.
    Der iPod touch hat auch die folgenden praktischen Apps:
     
    Kalender
    Das Programm ""Kalender"" funktioniert mit Yahoo!, Google, Microsoft Outlook, iCal, MobileMe und Microsoft Exchange ActiveSync für Unternehmen. Füge Termine hinzu, lass dich an Termine erinnern, und abonniere Kalender, damit du über Feiertage und Sportveranstaltungen auf dem Laufenden bleibst.
     
    Kontakte
    Namen, E-Mail-Adressen, Telefonnummern und mehr - immer zur Hand. Synchronisier Kontakte in iTunes auf dem Mac oder PC mit dem iPod touch. Neue Kontakte kannst du auch unterwegs mit einem einfachen Fingertipp hinzufügen.
     
    Notizen
    Schluss mit Papier und Bleistift. Mach dir mit ""Notizen"" auf dem iPod schnell eine Notiz, damit du wichtige Infos immer parat hast. Maile deine Gedanken mit der integrierten Mail-Funktion an dich oder andere.
     
    Aktien
    Die Aktien App auf dem iPod touch zeigt dir Börseninformationen für die Aktien, die dich interessieren. Wenn du nähere Details über eine Aktie brauchst, tipp auf ""Y!"", um im Handumdrehen Yahoo! Finance zu öffnen.
     
    Wetter
    Informier dich über das Wetter in der ganzen Welt oder zuhause. Füge die gewünschten Städte hinzu und zeige eine sechstägige Vorhersage für alle an. Tipp auf ""Y!"", um den Yahoo! Stadtführer zu öffnen, der dir zeigt, wo was los ist.
     
    Rechner
    Im Programm ""Rechner"" des iPod touch stecken gleich zwei Rechner. Im Hochformat kannst du ihn als einfachen Taschenrechner verwenden. Dreh den iPod touch ins Querformat, um aus ihm einen wissenschaftlichen Rechner zu machen.
     
    iPod touch Technologie
    Dank der revolutionären Hardwaretechnologie im iPod touch kannst du alle Funktionen mit Streichen, Tippen und Auf- oder Zuziehen steuern. Deswegen wirkt das Autorennen so echt. Deswegen kannst du das, was du eben im Café mitbekommen hast, sofort twittern. Und genau deswegen ist der iPod touch der beste iPod aller Zeiten.
     
    Multi-Touch
    Das Multi-Touch-Display besitzt einen Schutzfilm über der kapazitiven Sensorik, die Berührungen anhand elektrischer Felder erkennt. Diese Informationen werden an das darunterliegende LCD-Display übertragen. Dank der Software des iPod touch kannst du mit Cover Flow durch Alben stöbern, durch deine Fotos blättern, mit Auf- und Zuziehen Bildausschnitte von Websites zoomen und Spiele superpräzise steuern.

    Beschleunigungssensor
    Der iPod touch reagiert über einen integrierten Beschleunigungssensor auf Bewegungen. Dieser Sensor erkennt, wenn du deinen iPod touch ins Querformat drehst und verändert automatisch den Inhalt des Displays. Die Technologie des Beschleunigungssensors kommt besonders bei Spielen gut, denn damit bist du mitten im Spielgeschehen. Das ist perfekt für Autorennen, bei denen der ganze iPod zum Lenkrad wird, und Geschicklichkeitsspiele wie Rolando, bei denen du das Spiel mit deinen Bewegungen steuerst
     
    Drahtlos
    Der iPod touch hat eine integrierte Unterstützung für drahtlosen 802.11b/g Internetzugriff. Überall, wo es ein Wi-Fi-Netzwerk gibt, kommst du mit deinem iPod touch ins Internet. Im Café mailen. Am Flughafen im Web surfen. Spiele vom Sofa aus kaufen. Im iTunes Store stöbern und Musik kaufen und laden. Der iPod touch findet nahegelegene Wi-Fi-Hot-Spots, auch geschützte Netzwerke. Wenn du ein bestimmtes Netzwerk bisher noch nicht verwendet hast, Drahtlos Symbol musst du beim ersten Mal ein Kennwort eingeben, das sich der iPod touch dann merkt. Wenn du dann das nächste Mal in Reichweite dieses Netzwerks bist, loggt er sich automatisch ein.
     
    Bluetooth
    Bluetooth ist eine drahtlose Technologie, mit der du Geräte ohne lästige Kabel verwenden kannst. Was bedeutet das für den iPod touch? Du kannst jetzt mit dem iPod touch und Bluetooth Kopfhörern Musik hören, ganz egal, wo im Raum der iPod ist. Du kannst also auf dem Bett relaxen, während der iPod auf dem Schreibtisch aufgeladen wird. Bluetooth auf dem iPod touch eignet sich auch besonders für Peer-to-Peer-Spiele.
     
    Design
    Der iPod touch ist von außen genau so großartig wie von innen. Du brauchst nur einen in die Hand zu nehmen. Das Gehäuse des iPod touch ist gerade einmal 8,5 mm hoch. Das optische Glas auf der Vorderseite und die Rückseite aus poliertem Edelstahl geben ihm einen eleganten Touch und fühlen sich in der Hand einfach gut an. Schalte ihn ein und du wirst über das brillante 3,5"" Display einfach staunen. Der iPod touch ist die perfekte Kombination aus großartigem Design und revolutionärer Technologie - das perfekte Paket.
    ";2;False;0;;;Apple iPod Touch 64 GB schwarz mit integrierter WiFi Funktion;apple-ipod-touch-64-gb-schwarz;True;True;P-1280;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;349.9000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;40186,8528819444;44;1;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000434-apple-ipod-touch-64-gb-schwarz.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000435-apple-ipod-touch-64-gb-schwarz.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000436-apple-ipod-touch-64-gb-schwarz.jpg;2;;False;;;;;False;False;False;;;;;False;;;;;; +5;0;True;Apple iPod shuffle 2 GB grün;Apple iPod shuffle 2 GB grün;"

    Apple iPod shuffle 2GB grün
     

    Wie seine größeren Geschwister besitzt auch der iPod shuffle kreisförmig angeordnete, ergonomische Bedienelemente.
    Der Kopfhöreranschluss am iPod shuffle dient gleichzeitig als Dock-Anschluss. Drehen Sie den iPod shuffle auf die Seite und setzen Sie ihn in das mitgelieferte Dock ein.
    Dank eines stabilen, integrierten Clips lässt sich der iPod shuffle fast überall befestigen. Klemmen Sie ihn am T-Shirt, am Hemdkragen oder am Trageriemen von Rucksack oder Handtasche fest.
    Lassen Sie sich aufs Ungewisse ein: Verwenden Sie den Schalter für die Zufallswiedergabe, um den Inhalt Ihres iPod shuffle neu zu mischen.
    verbesserte Kopfhörer und das neue iTunes 8.0
     
    Einfach Musik anhaben mit dem Apple iPOD SHUFFLE 2GB.Tragen Sie bis zu 500 Songs am Ärmel. Oder am Gürtel. Oder am Sportoutfit. Das Erkennungszeichen für Musikfans - den Apple iPOD SHUFFLE. Füllen Sie Ihren Apple iPOD SHUFFLE silber 1GB spielend einfach. iTunes ist der Store für Unterhaltungsinhalte. Ihre super organisierte Musiksammlung und Jukebox. Und die Software, mit der Sie Ihren Apple iPOD SHUFFLE mit einem Mausklick füllen. Das farbige Gehäuse aus eloxiertem Aluminium in silber passt zum genial einfachen Design des Apple iPOD SHUFFLE.
     
    Leistungseigenschaften
     
    2 GB Flash-Memory Speicher
    min. Audio-Datenrate: 8 KBit/s
    max. Audio-Datenrate: 320 KBit/s
    Frequenzgang-Untergrenze: 20 Hz
    Frequenzgang-Obergrenze: 20000 Hz
     
    Formate/Standards
     
    MP3-Standard
    AAC + MP3 Standard
    WAV-Dateiformat kompatibel
    Audible-Format kompatibel
    AIFF-Format kompatibel
     
    Bedienung
     
    Musiktitel-Verwaltung
     
    Leistungsaufnahme/Spannungsversorgung

    Li-Polymer Akku
    12 Std. Spieldauer mit Akku
    Ladezeit für Akku: 4 Std.
     
    Anschlüsse
     
    Kopfhörer-Anschluß
    USB-Schnittstelle
    Anschluß für Docking-Station
     
    Gehäuse-Eigenschaften
     
    Breite: 4.12 cm
    Höhe: 2.73 cm
    Tiefe: 1.05 cm
    Gewicht: 15.5 g

    ";2;False;0;;;Apple iPod shuffle 2 GB grün;apple-ipod-shuffle-2-gb-gruen;True;True;P-1140;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;64.9000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;40186,8481481482;37;1;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000429-apple-ipod-shuffle-2-gb-grun.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000430-apple-ipod-shuffle-2-gb-grun.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000431-apple-ipod-shuffle-2-gb-grun.jpg;2;;False;;;;;False;False;False;;;;;False;;;;;; +5;0;True;Apple iPod shuffle 2 GB schwarz;Apple iPod shuffle 2 GB schwarz;"
    Apple iPod shuffle 2GB schwarz
     
     
    Der kleinste iPod der Welt
     
     
    Um den kleinsten iPod der Welt zu bauen, haben wir die Steuerung vom iPod shuffle in das Ohrhörerkabel integriert.
    So wird der iPod shuffle noch kleiner und die Steuerung ist genau da, wo du sie einfach erreichst.
    Wenn du einen Song abspielen, anhalten oder überspringen möchtest,
    musst du nicht lange nach dem iPod shuffle suchen - greif einfach zum Kabel und drücke auf eine der Tasten.
    Dieser Entertainment-Winzling sagt Ihnen auf Knopfdruck, welchen Titel er gerade abspielt
    Organisieren Sie Ihre Musik in verschiedenen Wiedergabeslisten
    Dank eines stabilen, integrierten Clips lässt sich der iPod shuffle fast überall befestigen.
    Lassen Sie sich aufs Ungewisse ein: Verwenden Sie den Schalter für die Zufallswiedergabe,
    um den Inhalt Ihres iPod shuffle neu zu mischen.
    Lieferumfang: Apple Earphones mit Remote Fernbedienung
     
    iPod shuffle - In leuchtenden neuen Farben spricht Musik dich richtig an
     
    Der kleinste iPod der Welt
    Um den kleinsten iPod der Welt zu bauen, haben wir die Steuerung vom iPod shuffle in das Ohrhörerkabel integriert. So wird der iPod shuffle noch kleiner und die Steuerung ist genau da, wo du sie einfach erreichst. Wenn du einen Song abspielen, anhalten oder überspringen möchtest, musst du nicht lange nach dem iPod shuffle suchen - greif einfach zum Kabel und drücke auf eine der Tasten.
     
    Der erste iPod, der mit dir spricht
    Die VoiceOver Funktion ist mit Sicherheit der nächste Hit auf dem iPod shuffle.1 Angenommen du hörst einen Song und willst wissen, wie er heißt oder von wem er ist: Einfach Knopf drücken und VoiceOver sagt es dir. Sogar die Namen deiner Wiedergabelisten verrät es dir. Und wenn die Batterie aufgeladen werden muss, sagt VoiceOver dir das auch.
     
    Leichtbedienung
    Die Steuerung befindet sich am Kabel des rechten Ohrstöpsels. Dadurch, dass die Steuerung jetzt hier angebracht ist, kannst du deine Musiktitel durchsuchen - und die VoiceOver Funktion aktivieren - ohne vom Joggen, Rad fahren oder anderen Aktivitäten abgelenkt zu werden. Der iPod shuffle wird mit dieser einfachen Steuerung geliefert. Du kannst aber auch Kopfhörer mit ähnlichen Bedienelementen von Herstellern wie Scosche, Klipsch, V-MODA und Belkin verwenden.
     

    Dein Musikarchiv. Für unterwegs
    Der iPod shuffle kommt jetzt mit 2 GB oder 4 GB. Mit dem 4 GB Modell hast du jede Menge Platz, um Musik für viele Stunden - bis zu 1.000 Songs - zu speichern.2 Damit bist du im Fitnessstudio oder auf dem Weg zur Arbeit bestens gerüstet. Außerdem kannst du jetzt mehrere Wiedergabelisten und auch Hörbücher verwenden.
     
    Mehrere Wiedergabelisten
    Wahrscheinlich hast du dir in iTunes schon einige Wiedergabelisten zusammengestellt. Eine für unterwegs. Eine fürs Fitnessstudio. Eine zum Chillen. Jetzt kannst du deine Wiedergabelisten auf dem Computer mit dem iPod shuffle synchronisieren und hast immer genau den richtigen Mix - egal, was du gerade machst oder in welcher Stimmung du bist. VoiceOver nennt dir den Namen jeder Wiedergabeliste. So kannst du ganz leicht zwischen ihnen wechseln und genau die auswählen, nach der dir gerade ist.
     
    Farbe bekennen
    Mit dem flachen, robusten Gehäuse aus eloxiertem Aluminium ist der iPod shuffle immer das passende Accessoire. In leuchtendem Pink, Blau, Grün, Schwarz oder Silber ist er ein echtes Fashion Statement. Ganz neu dabei: der iPod shuffle Special Edition in poliertem Edelstahl (So werden Rockstars nun mal behandelt). Sogar der iPod shuffle Clip sieht stylish aus. Er klemmt sicher an Hemd, Jacke, Sportzeug oder am Rucksack. So wird der iPod shuffle zum perfekten Fashtech-Accessoire. Und klar, natürlich ist noch Platz für eine persönliche Gravur.

    Mehrsprachig
    Ein französisches Chanson. Ein spanischer Bolero. Eine italienische Arie. Dein Musikarchiv enthält Musik aus allen Ländern der Welt. Deshalb spricht VoiceOver 20 Sprachen und kann die Namen von Songs und Interpreten mit der richtigen Aussprache sprechen.
     
    Zufall oder kein Zufall?
    Der Schalter am iPod shuffle hat drei Einstellungen. Links wird deine Musik zufällig durcheinander gewürfelt. In der Mitte werden deine Songs in der normalen Reihenfolge gespielt. Rechts wird der iPod shuffle ausgeschaltet.
    ";2;False;0;;;Apple iPod shuffle Tragbarer MP3-Player 4 GB 3. Generation;apple-ipod-shuffle-2-gb-schwarz;True;True;P-1200;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;61.9000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;40186,8421875;39;1;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000585-apple-ipod-shuffle-4-gb-schwarz.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000586-apple-ipod-shuffle-4-gb-schwarz.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000587-apple-ipod-shuffle-4-gb-schwarz.jpg;2;;False;;;;;False;False;False;;;;;False;;;;;; +5;0;True;Apple iPod shuffle 2 GB pink;Apple iPod shuffle 2 GB pink;"

    Apple iPod shuffle 2 GB pink 

    Der kleinste iPod der Welt
     
     
    Um den kleinsten iPod der Welt zu bauen, haben wir die Steuerung vom iPod shuffle in das Ohrhörerkabel integriert.
    So wird der iPod shuffle noch kleiner und die Steuerung ist genau da, wo du sie einfach erreichst.
    Wenn du einen Song abspielen, anhalten oder überspringen möchtest,
    musst du nicht lange nach dem iPod shuffle suchen - greif einfach zum Kabel und drücke auf eine der Tasten.
    Dieser Entertainment-Winzling sagt Ihnen auf Knopfdruck, welchen Titel er gerade abspielt
    Organisieren Sie Ihre Musik in verschiedenen Wiedergabeslisten
    Dank eines stabilen, integrierten Clips lässt sich der iPod shuffle fast überall befestigen.
    Lassen Sie sich aufs Ungewisse ein: Verwenden Sie den Schalter für die Zufallswiedergabe,
    um den Inhalt Ihres iPod shuffle neu zu mischen.
    Lieferumfang: Apple Earphones mit Remote Fernbedienung
     
    iPod shuffle - In leuchtenden neuen Farben spricht Musik dich richtig an
     
    Der kleinste iPod der Welt
    Um den kleinsten iPod der Welt zu bauen, haben wir die Steuerung vom iPod shuffle in das Ohrhörerkabel integriert. So wird der iPod shuffle noch kleiner und die Steuerung ist genau da, wo du sie einfach erreichst. Wenn du einen Song abspielen, anhalten oder überspringen möchtest, musst du nicht lange nach dem iPod shuffle suchen - greif einfach zum Kabel und drücke auf eine der Tasten.
     
    Der erste iPod, der mit dir spricht
    Die VoiceOver Funktion ist mit Sicherheit der nächste Hit auf dem iPod shuffle.1 Angenommen du hörst einen Song und willst wissen, wie er heißt oder von wem er ist: Einfach Knopf drücken und VoiceOver sagt es dir. Sogar die Namen deiner Wiedergabelisten verrät es dir. Und wenn die Batterie aufgeladen werden muss, sagt VoiceOver dir das auch.
     
    Leichtbedienung
    Die Steuerung befindet sich am Kabel des rechten Ohrstöpsels. Dadurch, dass die Steuerung jetzt hier angebracht ist, kannst du deine Musiktitel durchsuchen - und die VoiceOver Funktion aktivieren - ohne vom Joggen, Rad fahren oder anderen Aktivitäten abgelenkt zu werden. Der iPod shuffle wird mit dieser einfachen Steuerung geliefert. Du kannst aber auch Kopfhörer mit ähnlichen Bedienelementen von Herstellern wie Scosche, Klipsch, V-MODA und Belkin verwenden.
     

    Dein Musikarchiv. Für unterwegs
    Der iPod shuffle kommt jetzt mit 2 GB oder 4 GB. Mit dem 4 GB Modell hast du jede Menge Platz, um Musik für viele Stunden - bis zu 1.000 Songs - zu speichern.2 Damit bist du im Fitnessstudio oder auf dem Weg zur Arbeit bestens gerüstet. Außerdem kannst du jetzt mehrere Wiedergabelisten und auch Hörbücher verwenden.
     
    Mehrere Wiedergabelisten
    Wahrscheinlich hast du dir in iTunes schon einige Wiedergabelisten zusammengestellt. Eine für unterwegs. Eine fürs Fitnessstudio. Eine zum Chillen. Jetzt kannst du deine Wiedergabelisten auf dem Computer mit dem iPod shuffle synchronisieren und hast immer genau den richtigen Mix - egal, was du gerade machst oder in welcher Stimmung du bist. VoiceOver nennt dir den Namen jeder Wiedergabeliste. So kannst du ganz leicht zwischen ihnen wechseln und genau die auswählen, nach der dir gerade ist.
     
    Farbe bekennen
    Mit dem flachen, robusten Gehäuse aus eloxiertem Aluminium ist der iPod shuffle immer das passende Accessoire. In leuchtendem Pink, Blau, Grün, Schwarz oder Silber ist er ein echtes Fashion Statement. Ganz neu dabei: der iPod shuffle Special Edition in poliertem Edelstahl (So werden Rockstars nun mal behandelt). Sogar der iPod shuffle Clip sieht stylish aus. Er klemmt sicher an Hemd, Jacke, Sportzeug oder am Rucksack. So wird der iPod shuffle zum perfekten Fashtech-Accessoire. Und klar, natürlich ist noch Platz für eine persönliche Gravur.

    Mehrsprachig
    Ein französisches Chanson. Ein spanischer Bolero. Eine italienische Arie. Dein Musikarchiv enthält Musik aus allen Ländern der Welt. Deshalb spricht VoiceOver 20 Sprachen und kann die Namen von Songs und Interpreten mit der richtigen Aussprache sprechen.
     
    Zufall oder kein Zufall?
    Der Schalter am iPod shuffle hat drei Einstellungen. Links wird deine Musik zufällig durcheinander gewürfelt. In der Mitte werden deine Songs in der normalen Reihenfolge gespielt. Rechts wird der iPod shuffle ausgeschaltet.
    ";2;False;0;;;Apple iPod shuffle 1GB;apple-ipod-shuffle-2-gb-pink-2;True;True;P-1190;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;59.9000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;40186,8385648148;39;1;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000588-apple-ipod-shuffle-2-gb-pink.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000579-apple-ipod-shuffle-4-gb-blau.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000580-apple-ipod-shuffle-4-gb-blau.jpg;2;;False;;;;;False;False;False;;;;;False;;;;;; +5;0;True;Apple iPod shuffle 2 GB blau;Apple iPod shuffle 2 GB blau;"
    Apple iPod shuffle 2GB blau
     
     
    Der kleinste iPod der Welt
     
     
    Um den kleinsten iPod der Welt zu bauen, haben wir die Steuerung vom iPod shuffle in das Ohrhörerkabel integriert.
    So wird der iPod shuffle noch kleiner und die Steuerung ist genau da, wo du sie einfach erreichst.
    Wenn du einen Song abspielen, anhalten oder überspringen möchtest,
    musst du nicht lange nach dem iPod shuffle suchen - greif einfach zum Kabel und drücke auf eine der Tasten.
    Dieser Entertainment-Winzling sagt Ihnen auf Knopfdruck, welchen Titel er gerade abspielt
    Organisieren Sie Ihre Musik in verschiedenen Wiedergabeslisten
    Dank eines stabilen, integrierten Clips lässt sich der iPod shuffle fast überall befestigen.
    Lassen Sie sich aufs Ungewisse ein: Verwenden Sie den Schalter für die Zufallswiedergabe,
    um den Inhalt Ihres iPod shuffle neu zu mischen.
    Lieferumfang: Apple Earphones mit Remote Fernbedienung
     
    iPod shuffle - In leuchtenden neuen Farben spricht Musik dich richtig an
     
    Der kleinste iPod der Welt
    Um den kleinsten iPod der Welt zu bauen, haben wir die Steuerung vom iPod shuffle in das Ohrhörerkabel integriert. So wird der iPod shuffle noch kleiner und die Steuerung ist genau da, wo du sie einfach erreichst. Wenn du einen Song abspielen, anhalten oder überspringen möchtest, musst du nicht lange nach dem iPod shuffle suchen - greif einfach zum Kabel und drücke auf eine der Tasten.
     
    Der erste iPod, der mit dir spricht
    Die VoiceOver Funktion ist mit Sicherheit der nächste Hit auf dem iPod shuffle.1 Angenommen du hörst einen Song und willst wissen, wie er heißt oder von wem er ist: Einfach Knopf drücken und VoiceOver sagt es dir. Sogar die Namen deiner Wiedergabelisten verrät es dir. Und wenn die Batterie aufgeladen werden muss, sagt VoiceOver dir das auch.
     
    Leichtbedienung
    Die Steuerung befindet sich am Kabel des rechten Ohrstöpsels. Dadurch, dass die Steuerung jetzt hier angebracht ist, kannst du deine Musiktitel durchsuchen - und die VoiceOver Funktion aktivieren - ohne vom Joggen, Rad fahren oder anderen Aktivitäten abgelenkt zu werden. Der iPod shuffle wird mit dieser einfachen Steuerung geliefert. Du kannst aber auch Kopfhörer mit ähnlichen Bedienelementen von Herstellern wie Scosche, Klipsch, V-MODA und Belkin verwenden.
     

    Dein Musikarchiv. Für unterwegs
    Der iPod shuffle kommt jetzt mit 2 GB oder 4 GB. Mit dem 4 GB Modell hast du jede Menge Platz, um Musik für viele Stunden - bis zu 1.000 Songs - zu speichern.2 Damit bist du im Fitnessstudio oder auf dem Weg zur Arbeit bestens gerüstet. Außerdem kannst du jetzt mehrere Wiedergabelisten und auch Hörbücher verwenden.
     
    Mehrere Wiedergabelisten
    Wahrscheinlich hast du dir in iTunes schon einige Wiedergabelisten zusammengestellt. Eine für unterwegs. Eine fürs Fitnessstudio. Eine zum Chillen. Jetzt kannst du deine Wiedergabelisten auf dem Computer mit dem iPod shuffle synchronisieren und hast immer genau den richtigen Mix - egal, was du gerade machst oder in welcher Stimmung du bist. VoiceOver nennt dir den Namen jeder Wiedergabeliste. So kannst du ganz leicht zwischen ihnen wechseln und genau die auswählen, nach der dir gerade ist.
     
    Farbe bekennen
    Mit dem flachen, robusten Gehäuse aus eloxiertem Aluminium ist der iPod shuffle immer das passende Accessoire. In leuchtendem Pink, Blau, Grün, Schwarz oder Silber ist er ein echtes Fashion Statement. Ganz neu dabei: der iPod shuffle Special Edition in poliertem Edelstahl (So werden Rockstars nun mal behandelt). Sogar der iPod shuffle Clip sieht stylish aus. Er klemmt sicher an Hemd, Jacke, Sportzeug oder am Rucksack. So wird der iPod shuffle zum perfekten Fashtech-Accessoire. Und klar, natürlich ist noch Platz für eine persönliche Gravur.

    Mehrsprachig
    Ein französisches Chanson. Ein spanischer Bolero. Eine italienische Arie. Dein Musikarchiv enthält Musik aus allen Ländern der Welt. Deshalb spricht VoiceOver 20 Sprachen und kann die Namen von Songs und Interpreten mit der richtigen Aussprache sprechen.
     
    Zufall oder kein Zufall?
    Der Schalter am iPod shuffle hat drei Einstellungen. Links wird deine Musik zufällig durcheinander gewürfelt. In der Mitte werden deine Songs in der normalen Reihenfolge gespielt. Rechts wird der iPod shuffle ausgeschaltet.
    ";2;False;0;;;Apple iPod shuffle Tragbarer MP3-Player 4 GB 3. Generation;apple-ipod-shuffle-2-gb-blau-2;True;True;P-1180;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;59.9000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;40186,8361921296;39;1;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000578-apple-ipod-shuffle-4-gb-blau.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000579-apple-ipod-shuffle-4-gb-blau.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000580-apple-ipod-shuffle-4-gb-blau.jpg;2;;False;;;;;False;False;False;;;;;False;;;;;; +5;0;True;Apple iPod shuffle 2 GB grün;Apple iPod shuffle 2 GB grün;"
    Apple iPod shuffle 2GB grün
     
     
    Der kleinste iPod der Welt
     
     
    Um den kleinsten iPod der Welt zu bauen, haben wir die Steuerung vom iPod shuffle in das Ohrhörerkabel integriert.
    So wird der iPod shuffle noch kleiner und die Steuerung ist genau da, wo du sie einfach erreichst.
    Wenn du einen Song abspielen, anhalten oder überspringen möchtest,
    musst du nicht lange nach dem iPod shuffle suchen - greif einfach zum Kabel und drücke auf eine der Tasten.
    Dieser Entertainment-Winzling sagt Ihnen auf Knopfdruck, welchen Titel er gerade abspielt
    Organisieren Sie Ihre Musik in verschiedenen Wiedergabeslisten
    Dank eines stabilen, integrierten Clips lässt sich der iPod shuffle fast überall befestigen.
    Lassen Sie sich aufs Ungewisse ein: Verwenden Sie den Schalter für die Zufallswiedergabe,
    um den Inhalt Ihres iPod shuffle neu zu mischen.
    Lieferumfang: Apple Earphones mit Remote Fernbedienung
     
    iPod shuffle - In leuchtenden neuen Farben spricht Musik dich richtig an
     
    Der kleinste iPod der Welt
    Um den kleinsten iPod der Welt zu bauen, haben wir die Steuerung vom iPod shuffle in das Ohrhörerkabel integriert. So wird der iPod shuffle noch kleiner und die Steuerung ist genau da, wo du sie einfach erreichst. Wenn du einen Song abspielen, anhalten oder überspringen möchtest, musst du nicht lange nach dem iPod shuffle suchen - greif einfach zum Kabel und drücke auf eine der Tasten.
     
    Der erste iPod, der mit dir spricht
    Die VoiceOver Funktion ist mit Sicherheit der nächste Hit auf dem iPod shuffle.1 Angenommen du hörst einen Song und willst wissen, wie er heißt oder von wem er ist: Einfach Knopf drücken und VoiceOver sagt es dir. Sogar die Namen deiner Wiedergabelisten verrät es dir. Und wenn die Batterie aufgeladen werden muss, sagt VoiceOver dir das auch.
     
    Leichtbedienung
    Die Steuerung befindet sich am Kabel des rechten Ohrstöpsels. Dadurch, dass die Steuerung jetzt hier angebracht ist, kannst du deine Musiktitel durchsuchen - und die VoiceOver Funktion aktivieren - ohne vom Joggen, Rad fahren oder anderen Aktivitäten abgelenkt zu werden. Der iPod shuffle wird mit dieser einfachen Steuerung geliefert. Du kannst aber auch Kopfhörer mit ähnlichen Bedienelementen von Herstellern wie Scosche, Klipsch, V-MODA und Belkin verwenden.
     

    Dein Musikarchiv. Für unterwegs
    Der iPod shuffle kommt jetzt mit 2 GB oder 4 GB. Mit dem 4 GB Modell hast du jede Menge Platz, um Musik für viele Stunden - bis zu 1.000 Songs - zu speichern.2 Damit bist du im Fitnessstudio oder auf dem Weg zur Arbeit bestens gerüstet. Außerdem kannst du jetzt mehrere Wiedergabelisten und auch Hörbücher verwenden.
     
    Mehrere Wiedergabelisten
    Wahrscheinlich hast du dir in iTunes schon einige Wiedergabelisten zusammengestellt. Eine für unterwegs. Eine fürs Fitnessstudio. Eine zum Chillen. Jetzt kannst du deine Wiedergabelisten auf dem Computer mit dem iPod shuffle synchronisieren und hast immer genau den richtigen Mix - egal, was du gerade machst oder in welcher Stimmung du bist. VoiceOver nennt dir den Namen jeder Wiedergabeliste. So kannst du ganz leicht zwischen ihnen wechseln und genau die auswählen, nach der dir gerade ist.
     
    Farbe bekennen
    Mit dem flachen, robusten Gehäuse aus eloxiertem Aluminium ist der iPod shuffle immer das passende Accessoire. In leuchtendem Pink, Blau, Grün, Schwarz oder Silber ist er ein echtes Fashion Statement. Ganz neu dabei: der iPod shuffle Special Edition in poliertem Edelstahl (So werden Rockstars nun mal behandelt). Sogar der iPod shuffle Clip sieht stylish aus. Er klemmt sicher an Hemd, Jacke, Sportzeug oder am Rucksack. So wird der iPod shuffle zum perfekten Fashtech-Accessoire. Und klar, natürlich ist noch Platz für eine persönliche Gravur.

    Mehrsprachig
    Ein französisches Chanson. Ein spanischer Bolero. Eine italienische Arie. Dein Musikarchiv enthält Musik aus allen Ländern der Welt. Deshalb spricht VoiceOver 20 Sprachen und kann die Namen von Songs und Interpreten mit der richtigen Aussprache sprechen.
     
    Zufall oder kein Zufall?
    Der Schalter am iPod shuffle hat drei Einstellungen. Links wird deine Musik zufällig durcheinander gewürfelt. In der Mitte werden deine Songs in der normalen Reihenfolge gespielt. Rechts wird der iPod shuffle ausgeschaltet.
    ";2;False;0;;;Apple iPod shuffle Tragbarer MP3-Player 4 GB 3. Generation;apple-ipod-shuffle-2-gb-gruen-2;True;True;P-1170;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;59.9000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;40186,8328587963;39;1;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000584-apple-ipod-shuffle-4-gb-grun.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000579-apple-ipod-shuffle-4-gb-blau.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000580-apple-ipod-shuffle-4-gb-blau.jpg;2;;False;;;;;False;False;False;;;;;False;;;;;; +5;0;True;Apple iPod shuffle 2 GB silber;Apple iPod shuffle 2 GB silber;"
    Apple iPod shuffle 2GB silber  
     
    Der kleinste iPod der Welt
     
     
    Um den kleinsten iPod der Welt zu bauen, haben wir die Steuerung vom iPod shuffle in das Ohrhörerkabel integriert.
    So wird der iPod shuffle noch kleiner und die Steuerung ist genau da, wo du sie einfach erreichst.
    Wenn du einen Song abspielen, anhalten oder überspringen möchtest,
    musst du nicht lange nach dem iPod shuffle suchen - greif einfach zum Kabel und drücke auf eine der Tasten.
    Dieser Entertainment-Winzling sagt Ihnen auf Knopfdruck, welchen Titel er gerade abspielt
    Organisieren Sie Ihre Musik in verschiedenen Wiedergabeslisten
    Dank eines stabilen, integrierten Clips lässt sich der iPod shuffle fast überall befestigen.
    Lassen Sie sich aufs Ungewisse ein: Verwenden Sie den Schalter für die Zufallswiedergabe,
    um den Inhalt Ihres iPod shuffle neu zu mischen.
    Lieferumfang: Apple Earphones mit Remote Fernbedienung
     
    iPod shuffle - In leuchtenden neuen Farben spricht Musik dich richtig an
     
    Der kleinste iPod der Welt
    Um den kleinsten iPod der Welt zu bauen, haben wir die Steuerung vom iPod shuffle in das Ohrhörerkabel integriert. So wird der iPod shuffle noch kleiner und die Steuerung ist genau da, wo du sie einfach erreichst. Wenn du einen Song abspielen, anhalten oder überspringen möchtest, musst du nicht lange nach dem iPod shuffle suchen - greif einfach zum Kabel und drücke auf eine der Tasten.
     
    Der erste iPod, der mit dir spricht
    Die VoiceOver Funktion ist mit Sicherheit der nächste Hit auf dem iPod shuffle.1 Angenommen du hörst einen Song und willst wissen, wie er heißt oder von wem er ist: Einfach Knopf drücken und VoiceOver sagt es dir. Sogar die Namen deiner Wiedergabelisten verrät es dir. Und wenn die Batterie aufgeladen werden muss, sagt VoiceOver dir das auch.
     
    Leichtbedienung
    Die Steuerung befindet sich am Kabel des rechten Ohrstöpsels. Dadurch, dass die Steuerung jetzt hier angebracht ist, kannst du deine Musiktitel durchsuchen - und die VoiceOver Funktion aktivieren - ohne vom Joggen, Rad fahren oder anderen Aktivitäten abgelenkt zu werden. Der iPod shuffle wird mit dieser einfachen Steuerung geliefert. Du kannst aber auch Kopfhörer mit ähnlichen Bedienelementen von Herstellern wie Scosche, Klipsch, V-MODA und Belkin verwenden.
     

    Dein Musikarchiv. Für unterwegs
    Der iPod shuffle kommt jetzt mit 2 GB oder 4 GB. Mit dem 4 GB Modell hast du jede Menge Platz, um Musik für viele Stunden - bis zu 1.000 Songs - zu speichern.2 Damit bist du im Fitnessstudio oder auf dem Weg zur Arbeit bestens gerüstet. Außerdem kannst du jetzt mehrere Wiedergabelisten und auch Hörbücher verwenden.
     
    Mehrere Wiedergabelisten
    Wahrscheinlich hast du dir in iTunes schon einige Wiedergabelisten zusammengestellt. Eine für unterwegs. Eine fürs Fitnessstudio. Eine zum Chillen. Jetzt kannst du deine Wiedergabelisten auf dem Computer mit dem iPod shuffle synchronisieren und hast immer genau den richtigen Mix - egal, was du gerade machst oder in welcher Stimmung du bist. VoiceOver nennt dir den Namen jeder Wiedergabeliste. So kannst du ganz leicht zwischen ihnen wechseln und genau die auswählen, nach der dir gerade ist.
     
    Farbe bekennen
    Mit dem flachen, robusten Gehäuse aus eloxiertem Aluminium ist der iPod shuffle immer das passende Accessoire. In leuchtendem Pink, Blau, Grün, Schwarz oder Silber ist er ein echtes Fashion Statement. Ganz neu dabei: der iPod shuffle Special Edition in poliertem Edelstahl (So werden Rockstars nun mal behandelt). Sogar der iPod shuffle Clip sieht stylish aus. Er klemmt sicher an Hemd, Jacke, Sportzeug oder am Rucksack. So wird der iPod shuffle zum perfekten Fashtech-Accessoire. Und klar, natürlich ist noch Platz für eine persönliche Gravur.

    Mehrsprachig
    Ein französisches Chanson. Ein spanischer Bolero. Eine italienische Arie. Dein Musikarchiv enthält Musik aus allen Ländern der Welt. Deshalb spricht VoiceOver 20 Sprachen und kann die Namen von Songs und Interpreten mit der richtigen Aussprache sprechen.
     
    Zufall oder kein Zufall?
    Der Schalter am iPod shuffle hat drei Einstellungen. Links wird deine Musik zufällig durcheinander gewürfelt. In der Mitte werden deine Songs in der normalen Reihenfolge gespielt. Rechts wird der iPod shuffle ausgeschaltet.
    ";2;False;0;;;Apple iPod shuffle Tragbarer MP3-Player 4 GB 3. Generation;apple-ipod-shuffle-2-gb-silber;True;True;P-1160;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;61.9000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;40186,8309259259;39;1;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000220-apple-ipod-shuffle-4-gb-silber.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000221-apple-ipod-shuffle-4-gb-silber.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000222-apple-ipod-shuffle-4-gb-silber.jpg;2;;False;;;;;False;False;False;;;;;False;;;;;; +5;0;True;Apple iPod shuffle 4 GB schwarz;Apple iPod shuffle 4 GB schwarz;"
    Apple iPod shuffle 4GB schwarz
     
     
    Der kleinste iPod der Welt
     
     
    Um den kleinsten iPod der Welt zu bauen, haben wir die Steuerung vom iPod shuffle in das Ohrhörerkabel integriert.
    So wird der iPod shuffle noch kleiner und die Steuerung ist genau da, wo du sie einfach erreichst.
    Wenn du einen Song abspielen, anhalten oder überspringen möchtest,
    musst du nicht lange nach dem iPod shuffle suchen - greif einfach zum Kabel und drücke auf eine der Tasten.
    Dieser Entertainment-Winzling sagt Ihnen auf Knopfdruck, welchen Titel er gerade abspielt
    Organisieren Sie Ihre Musik in verschiedenen Wiedergabeslisten
    Dank eines stabilen, integrierten Clips lässt sich der iPod shuffle fast überall befestigen.
    Lassen Sie sich aufs Ungewisse ein: Verwenden Sie den Schalter für die Zufallswiedergabe,
    um den Inhalt Ihres iPod shuffle neu zu mischen.
    Lieferumfang: Apple Earphones mit Remote Fernbedienung
     
    iPod shuffle - In leuchtenden neuen Farben spricht Musik dich richtig an
     
    Der kleinste iPod der Welt
    Um den kleinsten iPod der Welt zu bauen, haben wir die Steuerung vom iPod shuffle in das Ohrhörerkabel integriert. So wird der iPod shuffle noch kleiner und die Steuerung ist genau da, wo du sie einfach erreichst. Wenn du einen Song abspielen, anhalten oder überspringen möchtest, musst du nicht lange nach dem iPod shuffle suchen - greif einfach zum Kabel und drücke auf eine der Tasten.
     
    Der erste iPod, der mit dir spricht
    Die VoiceOver Funktion ist mit Sicherheit der nächste Hit auf dem iPod shuffle.1 Angenommen du hörst einen Song und willst wissen, wie er heißt oder von wem er ist: Einfach Knopf drücken und VoiceOver sagt es dir. Sogar die Namen deiner Wiedergabelisten verrät es dir. Und wenn die Batterie aufgeladen werden muss, sagt VoiceOver dir das auch.
     
    Leichtbedienung
    Die Steuerung befindet sich am Kabel des rechten Ohrstöpsels. Dadurch, dass die Steuerung jetzt hier angebracht ist, kannst du deine Musiktitel durchsuchen - und die VoiceOver Funktion aktivieren - ohne vom Joggen, Rad fahren oder anderen Aktivitäten abgelenkt zu werden. Der iPod shuffle wird mit dieser einfachen Steuerung geliefert. Du kannst aber auch Kopfhörer mit ähnlichen Bedienelementen von Herstellern wie Scosche, Klipsch, V-MODA und Belkin verwenden.
     

    Dein Musikarchiv. Für unterwegs
    Der iPod shuffle kommt jetzt mit 2 GB oder 4 GB. Mit dem 4 GB Modell hast du jede Menge Platz, um Musik für viele Stunden - bis zu 1.000 Songs - zu speichern.2 Damit bist du im Fitnessstudio oder auf dem Weg zur Arbeit bestens gerüstet. Außerdem kannst du jetzt mehrere Wiedergabelisten und auch Hörbücher verwenden.
     
    Mehrere Wiedergabelisten
    Wahrscheinlich hast du dir in iTunes schon einige Wiedergabelisten zusammengestellt. Eine für unterwegs. Eine fürs Fitnessstudio. Eine zum Chillen. Jetzt kannst du deine Wiedergabelisten auf dem Computer mit dem iPod shuffle synchronisieren und hast immer genau den richtigen Mix - egal, was du gerade machst oder in welcher Stimmung du bist. VoiceOver nennt dir den Namen jeder Wiedergabeliste. So kannst du ganz leicht zwischen ihnen wechseln und genau die auswählen, nach der dir gerade ist.
     
    Farbe bekennen
    Mit dem flachen, robusten Gehäuse aus eloxiertem Aluminium ist der iPod shuffle immer das passende Accessoire. In leuchtendem Pink, Blau, Grün, Schwarz oder Silber ist er ein echtes Fashion Statement. Ganz neu dabei: der iPod shuffle Special Edition in poliertem Edelstahl (So werden Rockstars nun mal behandelt). Sogar der iPod shuffle Clip sieht stylish aus. Er klemmt sicher an Hemd, Jacke, Sportzeug oder am Rucksack. So wird der iPod shuffle zum perfekten Fashtech-Accessoire. Und klar, natürlich ist noch Platz für eine persönliche Gravur.

    Mehrsprachig
    Ein französisches Chanson. Ein spanischer Bolero. Eine italienische Arie. Dein Musikarchiv enthält Musik aus allen Ländern der Welt. Deshalb spricht VoiceOver 20 Sprachen und kann die Namen von Songs und Interpreten mit der richtigen Aussprache sprechen.
     
    Zufall oder kein Zufall?
    Der Schalter am iPod shuffle hat drei Einstellungen. Links wird deine Musik zufällig durcheinander gewürfelt. In der Mitte werden deine Songs in der normalen Reihenfolge gespielt. Rechts wird der iPod shuffle ausgeschaltet.
    ";2;False;0;;;Apple iPod shuffle Tragbarer MP3-Player 4 GB 3. Generation;apple-ipod-shuffle-4-gb-schwarz;True;True;P-1240;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;79.9000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;40186,8276273148;40;1;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000585-apple-ipod-shuffle-4-gb-schwarz.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000586-apple-ipod-shuffle-4-gb-schwarz.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000587-apple-ipod-shuffle-4-gb-schwarz.jpg;2;;False;;;;;False;False;False;;;;;False;;;;;; +5;0;True;Apple iPod shuffle 4 GB grün;Apple iPod shuffle 4 GB grün;"
    Apple iPod shuffle 4GB grün
     
     
    Der kleinste iPod der Welt
     
     
    Um den kleinsten iPod der Welt zu bauen, haben wir die Steuerung vom iPod shuffle in das Ohrhörerkabel integriert.
    So wird der iPod shuffle noch kleiner und die Steuerung ist genau da, wo du sie einfach erreichst.
    Wenn du einen Song abspielen, anhalten oder überspringen möchtest,
    musst du nicht lange nach dem iPod shuffle suchen - greif einfach zum Kabel und drücke auf eine der Tasten.
    Dieser Entertainment-Winzling sagt Ihnen auf Knopfdruck, welchen Titel er gerade abspielt
    Organisieren Sie Ihre Musik in verschiedenen Wiedergabeslisten
    Dank eines stabilen, integrierten Clips lässt sich der iPod shuffle fast überall befestigen.
    Lassen Sie sich aufs Ungewisse ein: Verwenden Sie den Schalter für die Zufallswiedergabe,
    um den Inhalt Ihres iPod shuffle neu zu mischen.
    Lieferumfang: Apple Earphones mit Remote Fernbedienung
     
    iPod shuffle - In leuchtenden neuen Farben spricht Musik dich richtig an
     
    Der kleinste iPod der Welt
    Um den kleinsten iPod der Welt zu bauen, haben wir die Steuerung vom iPod shuffle in das Ohrhörerkabel integriert. So wird der iPod shuffle noch kleiner und die Steuerung ist genau da, wo du sie einfach erreichst. Wenn du einen Song abspielen, anhalten oder überspringen möchtest, musst du nicht lange nach dem iPod shuffle suchen - greif einfach zum Kabel und drücke auf eine der Tasten.
     
    Der erste iPod, der mit dir spricht
    Die VoiceOver Funktion ist mit Sicherheit der nächste Hit auf dem iPod shuffle.1 Angenommen du hörst einen Song und willst wissen, wie er heißt oder von wem er ist: Einfach Knopf drücken und VoiceOver sagt es dir. Sogar die Namen deiner Wiedergabelisten verrät es dir. Und wenn die Batterie aufgeladen werden muss, sagt VoiceOver dir das auch.
     
    Leichtbedienung
    Die Steuerung befindet sich am Kabel des rechten Ohrstöpsels. Dadurch, dass die Steuerung jetzt hier angebracht ist, kannst du deine Musiktitel durchsuchen - und die VoiceOver Funktion aktivieren - ohne vom Joggen, Rad fahren oder anderen Aktivitäten abgelenkt zu werden. Der iPod shuffle wird mit dieser einfachen Steuerung geliefert. Du kannst aber auch Kopfhörer mit ähnlichen Bedienelementen von Herstellern wie Scosche, Klipsch, V-MODA und Belkin verwenden.
     

    Dein Musikarchiv. Für unterwegs
    Der iPod shuffle kommt jetzt mit 2 GB oder 4 GB. Mit dem 4 GB Modell hast du jede Menge Platz, um Musik für viele Stunden - bis zu 1.000 Songs - zu speichern.2 Damit bist du im Fitnessstudio oder auf dem Weg zur Arbeit bestens gerüstet. Außerdem kannst du jetzt mehrere Wiedergabelisten und auch Hörbücher verwenden.
     
    Mehrere Wiedergabelisten
    Wahrscheinlich hast du dir in iTunes schon einige Wiedergabelisten zusammengestellt. Eine für unterwegs. Eine fürs Fitnessstudio. Eine zum Chillen. Jetzt kannst du deine Wiedergabelisten auf dem Computer mit dem iPod shuffle synchronisieren und hast immer genau den richtigen Mix - egal, was du gerade machst oder in welcher Stimmung du bist. VoiceOver nennt dir den Namen jeder Wiedergabeliste. So kannst du ganz leicht zwischen ihnen wechseln und genau die auswählen, nach der dir gerade ist.
     
    Farbe bekennen
    Mit dem flachen, robusten Gehäuse aus eloxiertem Aluminium ist der iPod shuffle immer das passende Accessoire. In leuchtendem Pink, Blau, Grün, Schwarz oder Silber ist er ein echtes Fashion Statement. Ganz neu dabei: der iPod shuffle Special Edition in poliertem Edelstahl (So werden Rockstars nun mal behandelt). Sogar der iPod shuffle Clip sieht stylish aus. Er klemmt sicher an Hemd, Jacke, Sportzeug oder am Rucksack. So wird der iPod shuffle zum perfekten Fashtech-Accessoire. Und klar, natürlich ist noch Platz für eine persönliche Gravur.

    Mehrsprachig
    Ein französisches Chanson. Ein spanischer Bolero. Eine italienische Arie. Dein Musikarchiv enthält Musik aus allen Ländern der Welt. Deshalb spricht VoiceOver 20 Sprachen und kann die Namen von Songs und Interpreten mit der richtigen Aussprache sprechen.
     
    Zufall oder kein Zufall?
    Der Schalter am iPod shuffle hat drei Einstellungen. Links wird deine Musik zufällig durcheinander gewürfelt. In der Mitte werden deine Songs in der normalen Reihenfolge gespielt. Rechts wird der iPod shuffle ausgeschaltet.
     
    ";2;False;0;;;Apple iPod shuffle Tragbarer MP3-Player 4 GB 3. Generation;apple-ipod-shuffle-4-gb-gruen;True;True;P-1230;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;77.9000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;40186,8252662037;40;1;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000584-apple-ipod-shuffle-4-gb-grun.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000579-apple-ipod-shuffle-4-gb-blau.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000580-apple-ipod-shuffle-4-gb-blau.jpg;2;;False;;;;;False;False;False;;;;;False;;;;;; +5;0;True;Apple iPod shuffle 4 GB blau;Apple iPod shuffle 4GB blau;"
    Apple iPod shuffle 4GB blau
     
     
    Der kleinste iPod der Welt
     
     
    Um den kleinsten iPod der Welt zu bauen, haben wir die Steuerung vom iPod shuffle in das Ohrhörerkabel integriert.
    So wird der iPod shuffle noch kleiner und die Steuerung ist genau da, wo du sie einfach erreichst.
    Wenn du einen Song abspielen, anhalten oder überspringen möchtest,
    musst du nicht lange nach dem iPod shuffle suchen - greif einfach zum Kabel und drücke auf eine der Tasten.
    Dieser Entertainment-Winzling sagt Ihnen auf Knopfdruck, welchen Titel er gerade abspielt
    Organisieren Sie Ihre Musik in verschiedenen Wiedergabeslisten
    Dank eines stabilen, integrierten Clips lässt sich der iPod shuffle fast überall befestigen.
    Lassen Sie sich aufs Ungewisse ein: Verwenden Sie den Schalter für die Zufallswiedergabe,
    um den Inhalt Ihres iPod shuffle neu zu mischen.
    Lieferumfang: Apple Earphones mit Remote Fernbedienung
     
    iPod shuffle - In leuchtenden neuen Farben spricht Musik dich richtig an
     
    Der kleinste iPod der Welt
    Um den kleinsten iPod der Welt zu bauen, haben wir die Steuerung vom iPod shuffle in das Ohrhörerkabel integriert. So wird der iPod shuffle noch kleiner und die Steuerung ist genau da, wo du sie einfach erreichst. Wenn du einen Song abspielen, anhalten oder überspringen möchtest, musst du nicht lange nach dem iPod shuffle suchen - greif einfach zum Kabel und drücke auf eine der Tasten.
     
    Der erste iPod, der mit dir spricht
    Die VoiceOver Funktion ist mit Sicherheit der nächste Hit auf dem iPod shuffle.1 Angenommen du hörst einen Song und willst wissen, wie er heißt oder von wem er ist: Einfach Knopf drücken und VoiceOver sagt es dir. Sogar die Namen deiner Wiedergabelisten verrät es dir. Und wenn die Batterie aufgeladen werden muss, sagt VoiceOver dir das auch.
     
    Leichtbedienung
    Die Steuerung befindet sich am Kabel des rechten Ohrstöpsels. Dadurch, dass die Steuerung jetzt hier angebracht ist, kannst du deine Musiktitel durchsuchen - und die VoiceOver Funktion aktivieren - ohne vom Joggen, Rad fahren oder anderen Aktivitäten abgelenkt zu werden. Der iPod shuffle wird mit dieser einfachen Steuerung geliefert. Du kannst aber auch Kopfhörer mit ähnlichen Bedienelementen von Herstellern wie Scosche, Klipsch, V-MODA und Belkin verwenden.
     

    Dein Musikarchiv. Für unterwegs
    Der iPod shuffle kommt jetzt mit 2 GB oder 4 GB. Mit dem 4 GB Modell hast du jede Menge Platz, um Musik für viele Stunden - bis zu 1.000 Songs - zu speichern.2 Damit bist du im Fitnessstudio oder auf dem Weg zur Arbeit bestens gerüstet. Außerdem kannst du jetzt mehrere Wiedergabelisten und auch Hörbücher verwenden.
     
    Mehrere Wiedergabelisten
    Wahrscheinlich hast du dir in iTunes schon einige Wiedergabelisten zusammengestellt. Eine für unterwegs. Eine fürs Fitnessstudio. Eine zum Chillen. Jetzt kannst du deine Wiedergabelisten auf dem Computer mit dem iPod shuffle synchronisieren und hast immer genau den richtigen Mix - egal, was du gerade machst oder in welcher Stimmung du bist. VoiceOver nennt dir den Namen jeder Wiedergabeliste. So kannst du ganz leicht zwischen ihnen wechseln und genau die auswählen, nach der dir gerade ist.
     
    Farbe bekennen
    Mit dem flachen, robusten Gehäuse aus eloxiertem Aluminium ist der iPod shuffle immer das passende Accessoire. In leuchtendem Pink, Blau, Grün, Schwarz oder Silber ist er ein echtes Fashion Statement. Ganz neu dabei: der iPod shuffle Special Edition in poliertem Edelstahl (So werden Rockstars nun mal behandelt). Sogar der iPod shuffle Clip sieht stylish aus. Er klemmt sicher an Hemd, Jacke, Sportzeug oder am Rucksack. So wird der iPod shuffle zum perfekten Fashtech-Accessoire. Und klar, natürlich ist noch Platz für eine persönliche Gravur.

    Mehrsprachig
    Ein französisches Chanson. Ein spanischer Bolero. Eine italienische Arie. Dein Musikarchiv enthält Musik aus allen Ländern der Welt. Deshalb spricht VoiceOver 20 Sprachen und kann die Namen von Songs und Interpreten mit der richtigen Aussprache sprechen.
     
    Zufall oder kein Zufall?
    Der Schalter am iPod shuffle hat drei Einstellungen. Links wird deine Musik zufällig durcheinander gewürfelt. In der Mitte werden deine Songs in der normalen Reihenfolge gespielt. Rechts wird der iPod shuffle ausgeschaltet.
    ";2;False;0;;;Apple iPod shuffle Tragbarer MP3-Player 4 GB 3. Generation;apple-ipod-shuffle-4-gb-blau;True;True;P-1220;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;77.9000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;40186,8199537037;40;1;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000578-apple-ipod-shuffle-4-gb-blau.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000579-apple-ipod-shuffle-4-gb-blau.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000580-apple-ipod-shuffle-4-gb-blau.jpg;2;;False;;;;;False;False;False;;;;;False;;;;;; +5;0;True;Canon EOS 1000D SLR-Digitalkamera Kit;"Canon EOS 1000D SLR-Digitalkamera Kit inkl. EF-S 18-55 Objektiv ";"
    Canon EOS 1000D:Anpfiff für den Aufstieg
     
    Wer bislang mit der digitalen Spiegelreflexfotografie nur geliebäugelt hat, wird dieser Canon-Neuheit nur schwerlich widerstehen können: EOS 1000D heißt die neue Kamera. Die Neue punktet mit einem Preis-Leistungsverhältnis, das eine neue Canon- Liga kennzeichnet: 10,1 Megapixel CMOS-Sensor, Sieben-Punkt-Weitbereich- Autofokus und Reihenaufnahmen mit bis zu drei JPEG-komprimierten Bildern pro Sekunde. Die Marke, der die Profis vertrauen, ist also jetzt auch für den Einsteiger in die digitale Spiegelreflexfotografie erschwinglich… und dank benutzerfreundlicher Menüführung auch leicht bedienbar.
     
    Die EOS 1000D ist die bislang leichteste aller digitalen EOS-Kameras und basiert auf intuitiver Bedienung und einer Reihe von innovativen Spitzentechnologien, die auch in der professionellen Serie der Canon EOS-1 Kameras zum Einsatz kommen. Dies sind beispielsweise der DIGIC-III-Bildprozessor, Livebild-Funktion und EOSIntegrated- Cleaning-System, das integrierte Sensor-Reinigungsprogramm von Canon. Die EOS 1000D gibt es auch im kostengünstigen Paket mit dem Objektiv EF-S 18- 55mm IS: Dieses Canon-Objektiv hat einen optischen Bildstabilisator, der eine längere Belichtungszeit erlaubt, weil diese Technologie Verwacklungen entgegenwirkt. Das zahlt sich besonders bei schlechten Lichtverhältnissen aus.
    Intelligenter Fokus und Blitz

    Bei dynamischen Aufnahmesituationen ist eine schnelle Fokussierung sehr wichtig – hier macht sich der Sieben-Punkt-Weitbereich-Autofokus der EOS 1000D durch die Scharfstellung in Sekundenbruchteilen bezahlt. Das zentrale AF-Messfeld ist ein Kreuzsensor, der sich vor allem in Aufnahmesituationen mit wenig Licht beziehungsweise schwach ausgeprägtem Kontrast bewährt. Hinzu kommt ein weiteres von den professionellen EOS-Modellen bekanntes Leistungsmerkmal: das entfernungsgekoppelte Blitzsteuerungssystem E-TTL II.
     
    Konzipiert für mehr Leistung
    Wie bei allen EOS-Modellen werden auch die Kernelemente der EOS 1000D von Canon selbst konzipiert und gefertigt, eine Kombination für bestmögliche Bildqualität. Der 10,1 Megapixel CMOS-Sensor sorgt für präzise, rauscharme Bilder und bietet mehr als genug Auflösung für den Fotodruck bis DIN A4. Zum Schutz vor störenden Staubpartikeln ist der Sensor der Neuen mit dem bekannten EOS Integrated Cleaning System ausgestattet, das den Staub in drei separaten Schritten bekämpft: reduzieren, abweisen und entfernen.
    Die EOS 1000D verfügt mit dem DIGIC III über einen Bildprozessor, der auch bei den professionellen digitalen Canon-Spiegelreflexkameras zum Einsatz kommt. Dies ermöglicht kontinuierliche Reihenaufnahmen bis zur Kapazitätsgrenze der jeweilig eingesetzten SD- oder SDHC-Speicherkarte bei Geschwindigkeiten von bis zu drei Bildern pro Sekunde. Darüber hinaus ist der DIGIC-III-Prozessor für hochwertige Bildwiedergabe, schnelle Signalverarbeitung und nahezu umgehende Startzeiten verantwortlich.
     
     
    Hoher Anwenderkomfort
    Mit gerade einmal 450 Gramm (nur Gehäuse) ist die EOS 1000D die bislang leichteste digitale Canon Spiegelreflexkamera von Canon. Das kompakte, ergonomisch gestaltete Gehäuse ist konsequent auf effiziente Handhabung ausgelegt.^ Auf dem hellen 2,5 Zoll großen LC-Monitor lassen sich die Bilder umgehend überprüfen oder auch – dank des weiten Betrachtungswinkels – von mehreren Personen gleichzeitig einsehen. Ferner bietet das LC-Display Zugriff auf eine intuitive, leicht verständliche Menüstruktur mit praktischen Reitern – das ist übersichtlich und erleichtert das Auffinden von Menüpunkten.
     
    Live View
    Bei Aufnahmen vom Stativ oder wenn sich der Sucher als unpraktisch erweist, ermöglicht die Livebild-Funktion die Kontrolle des Motivs über das Display. Dabei wird das Livebild als Videosequenz mit 30 Bildern pro Sekunde dargestellt. Zur Beurteilung von Bildkomposition oder Belichtungseinstellung lassen sich Gitternetzlinien oder ein Histogramm einblenden. Für die Livebild-Funktion stehen zwei AF-Modi zur Verfügung: Quick AF, der zur Aktivierung des AF-Sensors umgehend den Kameraspiegel hochklappt und Live AF, der Kontrastinformationen für die Scharfstellung wie bei einer Kompaktkamera einsetzt.
     
    Software
    Zum Lieferumfang der EOS 1000D gehört ein umfassendes Softwarepaket mit den notwendigen Tools zur Bearbeitung und Verwaltung der Bilder. Zum Beispiel Digital Photo Professional (DPP), ein leistungsstarkes Programm zur Bearbeitung von RAWBildern. DPP bewährt sich auch im Zusammenspiel mit Kamerafunktionen wie Dust Delete Data und Picture Styles. Die im Lieferumfang enthaltene Software Picture Style Editor kann eingesetzt werden, um individuelle Picture Styles für die Feinabstimmung von Farben zu erstellen. Weitere mitgelieferte Softwareanwendungen sind EOS Utility, Image/Zoom Browser und Photostitch. 
     
    EF-S 18-55 Objektiv
    Speziell für digitale EOS Kameras mit EF-S-Bjonett entwickeltes Standard-Zoom
    Kompakt und leicht
    Hohe Bildqualität bei allen Brennweiten
    Optimierte Vergütungsschichten minimieren Streulicht und Reflexe
    Hohe AF-Geschwindigkeit
    Sehr kurze Naheinstellgrenze
    Bleifreie Optik
    ";2;False;0;;;"Canon EOS 1000D SLR-Digitalkamera Kit inkl. EF-S 18-55 Objektiv ";canon-eos-1000d-slr-digitalkamera-kit;True;True;P-1740;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;429.0000;0.0000;409.9000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;40166,6718402778;"56;2095";25;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000481-canon-eos-1000d-slr-digitalkamera-kit.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000482-canon-eos-1000d-slr-digitalkamera-kit.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000483-canon-eos-1000d-slr-digitalkamera-kit.jpg;1;;False;;;;;False;False;False;;;;;False;;;;;; +5;0;True;Sandisk Sansa Fuze 8 GB schwarz;"Sandisk Sansa Fuze MP3-/Video-Player 8 GB mit Radio schwarz ";"

    Sandisk Sansa Fuze MP3-/Video-Player 8 GB mit Radio schwarz

     
    Mit der verfügbaren Akkuleistung können Sie 24 Stunden lang Musik hören, Bilder anschauen oder spielen.
    Der neue Sansa Fuze von SanDisk ist der ideale tragbare Musikplayer für Sie.
    Er steht mit einer Speicherkapazität 4 GB in schwarz,rot,pink zur Verfügung.
    Sehen Sie sich Ihre Lieblingsvideoclips auf dem 1,9""-Farbdisplay des Sansa Fuze an.
    Lauschen Sie dem FM-Radio mit 40 voreingestellten Sendern oder probieren Sie den integrierten Sprachrekorder aus. Mit einer unglaublich starken Akkuleistung in einem 0,3"" schmalen Gerät setzt der Sansa Fuze Zeichen.
    ";2;False;0;;;Sandisk Sansa Fuze MP3-/Video-Player 4 GB mit Radio;sandisk-sansa-fuze-8-gb-schwarz;True;True;P-1600;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;89.0000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;40166,6556365741;52;8;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000480-sandisk-sansa-fuze-8-gb-schwarz.jpg;;;2;;False;;;;;False;False;False;;;;;False;;;;;; +5;0;True;Apple iPod shuffle 1 GB blau;Apple iPod shuffle 1 GB blau;"

    Apple iPod shuffle 1GB blue 

     
    Wie seine größeren Geschwister besitzt auch der iPod shuffle kreisförmig
    angeordnete, ergonomische Bedienelemente.
    Der Kopfhöreranschluss am iPod shuffle dient gleichzeitig als Dock-Anschluss.
    Drehen Sie den iPod shuffle auf die Seite und setzen Sie ihn in das mitgelieferte Dock ein.
    Dank eines stabilen, integrierten Clips lässt sich der iPod shuffle fast überall befestigen.
    Klemmen Sie ihn am T-Shirt, am Hemdkragen oder am Trageriemen von Rucksack oder Handtasche fest.
    Lassen Sie sich aufs Ungewisse ein: Verwenden Sie den Schalter für die Zufallswiedergabe,
    um den Inhalt Ihres iPod shuffle neu zu mischen.
    verbesserte Kopfhörer und das neue iTunes 8.0
     
    Größe ist relativ
    Natürlich kennen Sie das Sprichwort ""Weniger ist mehr"". Wie wahr dieses Sprichwort ist, beweist der neue iPod shuffle, der gerade einmal 4,1 cm lang ist, nur etwa 15 Gramm wiegt und Platz für bis zu 240 Songs bietet. Hinzu kommt, dass Sie Ihre Musik damit bis zu 12 Stunden lang ohne Unterbrechung hören können.(2) Man kann also mit Fug und Recht behaupten, dass der winzige iPod shuffle bei halber Größe viel mehr zu bieten hat, als man ihm auf den ersten Blick zutraut.
    Immer im Trend
    Klemmen Sie ihn an die Jeans. Oder an Ihre Handtasche. Egal, wo Sie ihn anklippen, mit Ihrem iPod shuffle haben Sie Ihre Musik jederzeit griffbereit. Das Gehäuse aus eloxiertem Aluminium passt übrigens zu jedem Outfit. Einfach festklemmen und einschalten - Sie werden ohne Zweifel viele begehrliche Blicke auf sich ziehen.
     
     
    Perfekt synchronisiert
    Damit Sie Ihren iPod shuffle mit bis zu 240 Songs füllen können, müssen Sie zuerst iTunes gratis laden. Danach können Sie für je 99 Cent Musiktitel aus dem iTunes Store laden oder von Ihren CDs importieren. Zum Synchronisieren schließen Sie das mitgelieferte Dock an den USB-Anschluss Ihres Mac oder PC an und übertragen die Musik aus iTunes, indem Sie den iPod shuffle in das Dock einsetzen.
     
     
    Neu abgemischt
    In Ihrer iTunes Bibliothek befinden sich mehr als 240 Titel? Kein Problem. Überlassen Sie es iTunes, Ihren iPod shuffle automatisch zu füllen und genießen Sie Ihre Musik jedes Mal neu. Pop folgt auf Jazz, Rock auf Ra!

     
    ";2;False;0;;;Apple iPod shuffle 1 GB blau;apple-ipod-shuffle-1-gb-blau;True;True;P-1110;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;49.9000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;40160,8793055556;36;1;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000398-apple-ipod-shuffle-2-gb-blau.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000399-apple-ipod-shuffle-2-gb-blau.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000400-apple-ipod-shuffle-2-gb-blau.jpg;3;;False;;;;;False;False;False;;;;;False;;;;;; +5;0;True;Apple iPod shuffle 1 GB pink;Apple iPod shuffle 1 GB pink;"

    Apple iPod shuffle 1GB pink 

     
    Wie seine größeren Geschwister besitzt auch der iPod shuffle
    kreisförmig angeordnete, ergonomische Bedienelemente.
    Der Kopfhöreranschluss am iPod shuffle dient gleichzeitig als Dock-Anschluss.
    Drehen Sie den iPod shuffle auf die Seite und setzen Sie ihn in das mitgelieferte Dock ein.
    Dank eines stabilen, integrierten Clips lässt sich der iPod shuffle fast überall befestigen.
    Klemmen Sie ihn am T-Shirt, am Hemdkragen oder am Trageriemen von Rucksack oder Handtasche fest.
    Lassen Sie sich aufs Ungewisse ein: Verwenden Sie den Schalter für die Zufallswiedergabe,
    um den Inhalt Ihres iPod shuffle neu zu mischen.
    verbesserte Kopfhörer und das neue iTunes 8.0
     
    Größe ist relativ
    Natürlich kennen Sie das Sprichwort ""Weniger ist mehr"". Wie wahr dieses Sprichwort ist, beweist der neue iPod shuffle, der gerade einmal 4,1 cm lang ist, nur etwa 15 Gramm wiegt und Platz für bis zu 240 Songs bietet. Hinzu kommt, dass Sie Ihre Musik damit bis zu 12 Stunden lang ohne Unterbrechung hören können.(2) Man kann also mit Fug und Recht behaupten, dass der winzige iPod shuffle bei halber Größe viel mehr zu bieten hat, als man ihm auf den ersten Blick zutraut.
    Immer im Trend
    Klemmen Sie ihn an die Jeans. Oder an Ihre Handtasche. Egal, wo Sie ihn anklippen, mit Ihrem iPod shuffle haben Sie Ihre Musik jederzeit griffbereit. Das Gehäuse aus eloxiertem Aluminium passt übrigens zu jedem Outfit. Einfach festklemmen und einschalten - Sie werden ohne Zweifel viele begehrliche Blicke auf sich ziehen.
     
     
    Perfekt synchronisiert
    Damit Sie Ihren iPod shuffle mit bis zu 240 Songs füllen können, müssen Sie zuerst iTunes gratis laden. Danach können Sie für je 99 Cent Musiktitel aus dem iTunes Store laden oder von Ihren CDs importieren. Zum Synchronisieren schließen Sie das mitgelieferte Dock an den USB-Anschluss Ihres Mac oder PC an und übertragen die Musik aus iTunes, indem Sie den iPod shuffle in das Dock einsetzen.
     
     
    Neu abgemischt
    In Ihrer iTunes Bibliothek befinden sich mehr als 240 Titel? Kein Problem. Überlassen Sie es iTunes, Ihren iPod shuffle automatisch zu füllen und genießen Sie Ihre Musik jedes Mal neu. Pop folgt auf Jazz, Rock auf Ra!
    ";2;False;0;;;Apple iPod shuffle 1GB pink;apple-ipod-shuffle-1-gb-pink;True;True;P-1120;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;49.9000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;40158,9546990741;36;1;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000118-apple-ipod-shuffle-2-gb-pink.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000119-apple-ipod-shuffle-2-gb-pink.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000120-apple-ipod-shuffle-2-gb-pink.jpg;2;;False;;;;;False;False;False;;;;;False;;;;;; +5;0;True;Apple iPod shuffle 1 GB grün;Apple iPod shuffle 1 GB grün;"
    Apple iPod shuffle 1GB grün

     
    Wie seine größeren Geschwister besitzt auch der iPod shuffle kreisförmig angeordnete, ergonomische Bedienelemente.
    Der Kopfhöreranschluss am iPod shuffle dient gleichzeitig als Dock-Anschluss.
    Drehen Sie den iPod shuffle auf die Seite und setzen Sie ihn in das mitgelieferte Dock ein.
    Dank eines stabilen, integrierten Clips lässt sich der iPod shuffle fast überall befestigen.
    Klemmen Sie ihn am T-Shirt, am Hemdkragen oder am Trageriemen von Rucksack oder Handtasche fest.
    Lassen Sie sich aufs Ungewisse ein: Verwenden Sie den Schalter für die Zufallswiedergabe, um den Inhalt Ihres iPod shuffle neu zu mischen.
    verbesserte Kopfhörer und das neue iTunes 8.0
     
    Größe ist relativ
    Natürlich kennen Sie das Sprichwort ""Weniger ist mehr"". Wie wahr dieses Sprichwort ist, beweist der neue iPod shuffle, der gerade einmal 4,1 cm lang ist, nur etwa 15 Gramm wiegt und Platz für bis zu 240 Songs bietet. Hinzu kommt, dass Sie Ihre Musik damit bis zu 12 Stunden lang ohne Unterbrechung hören können.(2) Man kann also mit Fug und Recht behaupten, dass der winzige iPod shuffle bei halber Größe viel mehr zu bieten hat, als man ihm auf den ersten Blick zutraut.
    Immer im Trend
    Klemmen Sie ihn an die Jeans. Oder an Ihre Handtasche. Egal, wo Sie ihn anklippen, mit Ihrem iPod shuffle haben Sie Ihre Musik jederzeit griffbereit. Das Gehäuse aus eloxiertem Aluminium passt übrigens zu jedem Outfit. Einfach festklemmen und einschalten - Sie werden ohne Zweifel viele begehrliche Blicke auf sich ziehen.
     
     
    Perfekt synchronisiert
    Damit Sie Ihren iPod shuffle mit bis zu 240 Songs füllen können, müssen Sie zuerst iTunes gratis laden. Danach können Sie für je 99 Cent Musiktitel aus dem iTunes Store laden oder von Ihren CDs importieren. Zum Synchronisieren schließen Sie das mitgelieferte Dock an den USB-Anschluss Ihres Mac oder PC an und übertragen die Musik aus iTunes, indem Sie den iPod shuffle in das Dock einsetzen.
     
     
    Neu abgemischt
    In Ihrer iTunes Bibliothek befinden sich mehr als 240 Titel? Kein Problem. Überlassen Sie es iTunes, Ihren iPod shuffle automatisch zu füllen und genießen Sie Ihre Musik jedes Mal neu. Pop folgt auf Jazz, Rock auf Ra!
    ";2;False;0;;;Apple iPod shuffle 1 GB grün;apple-ipod-shuffle-1-gb-gruen;True;True;P-1100;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;49.9000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;40158,9517476852;36;1;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000429-apple-ipod-shuffle-2-gb-grun.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000430-apple-ipod-shuffle-2-gb-grun.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000431-apple-ipod-shuffle-2-gb-grun.jpg;2;;False;;;;;False;False;False;;;;;False;;;;;; +5;0;True;Panasonic DMR EX 72 SEG DVD HDD RECORDER;Panasonic DMR EX 72 SEG DVD- und HDD-Rekorder 160 GB;"

    Panasonic DMR EX 72 SEG DVD- und HDD-Rekorder 160 GB

    mit integriertem DVB-S Tuner
     
    HDD/DVD Recorder/Farbe: schwarz/ Festplattenspeicher: 160 GB/ Tuner: DVB-S/ Sonderfunktionen: EPG/ Anschlüsse: 2x Scart, 3x Cinch (Komponenten/YUV),
    Cinch (Composite / Video / FBas), HDMI (mit HDCP), S-Video (Hosiden), USB/ B: 430 mm/ H: 59 mm
    Art HDD/DVD Recorder
    Farbe schwarz
    Festplattenspeicher 160 GB
    Tuner DVB-S
    Sonderfunktionen EPG
    Anschlüsse 2x Scart / 3x Cinch (Komponenten/YUV) / Cinch (Composite / Video / FBas) / HDMI (mit HDCP) / S-Video (Hosiden) / USB
    Breite 430 mm
    Höhe   59 mm
    Tiefe  286 mm
    Gewicht netto 3,7 kg
    Aufnahme DVD+R / DVD+RW / DVD-R / DVD-RAM / DVD-RW
    Wiedergabe Audio-CD / CD-R / CD-RW / DVD / DVD+R / DVD+RW / DVD-R / DVD-RAM / DVD-RW / JPEG / MP3 / S-Video CD / WMA
    ";2;False;0;;;Panasonic DMR EX 72 SEG DVD HDD RECORDER;panasonic-dmr-ex-72-seg-dvd-hdd-recorder;True;True;P-1850;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;2,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;399.0000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;40155,86625;62;12;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000471-panasonic-dmr-ex-72-seg-dvd-hdd-recorder.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000472-panasonic-dmr-ex-72-seg-dvd-hdd-recorder.jpg;;1;;False;;;;;False;False;False;;;;;False;;;;;; +5;0;True;Panasonic DMR EH 495 EG K 160 GB DVD/ HDD Rekorder;Panasonic DMR EH 495 EG K 160 GB DVD/ HDD Rekorder;"
    Panasonic DMR EH 495 EG K 160 GB DVD/ HDD Rekorder

    HDMI, DivX-zertifiziert, USB 2.0

    Mit dem DMR-EH495 präsentiert Panasonic, Marktführer bei DVD-Rekordern, neue Multiformat-DVD-Festplatten-Kombinationen. Sie bieten alle Komfortmerkmale der testbewährten Vorjahresmodelle, begeistern mit noch mehr Details sowie einer intuitiven Benutzerführung. Die mit einem analogen Tuner ausgestatteten Geräte verfügen über eine integrierte Festplatte und zeichnen auf alle gängigen DVD-Formate auf. Neben der Aufnahme des Fernsehprogramms überzeugen die neuen Rekorder als digitales Fotoalbum sowie Musik-Jukebox und werden somit zur Unterhaltungszentrale im Wohnzimmer. Komfortfunktionen wie der elektronische Programmführer Guide Plus+ mit Suchfunktion, eine automatische Kapitelerstellung, umfangreiche Anschlussmöglichkeiten sowie ein hochwertiger Upscaler machen die Rekorder zu Multitalenten. Darüber hinaus schont der weiterentwickelte Eco-Modus Umwelt und Geldbeutel.
     
    Die Rekorder DMR-EH495 zeigen sich als wahre Alleskönner und zeichnen auf Festplatte oder DVD auf.
    Sie verarbeiten alle gängigen DVD-Formate wie DVD-RW, -R (DL), DVD+RW/+R (DL) sowie DVD-RAM. Außerdem können CDs, CD-R/-RWs sowie MP3- und JPEG-Daten sowohl von DVD als auch CD abgespielt werden.
    Die integrierte Festplatte erlaubt die Aufzeichnung von Fernsehprogrammen. Somit ist auch bei längerer Abwesenheit genügend Platz für die Lieblingsserie vorhanden.
    Dank des integrierten, elektronischen Programmführers Gemstar Guide Plus+ erfolgen die Programmauswahl und Timerprogrammierung kinderleicht und intuitiv.
    Die übersichtliche Darstellung des Fernsehprogramms bietet neben einer Genre-Auswahl zusätzlich eine gezielte Suche nach Stichworten.
     
    So kann beispielsweise direkt nach Schauspielern, Themen oder Sportarten gesucht werden. Neben dieser Funktion arbeiten die neuen Rekorder mit einer automatischen Kapitelerstellung bei der Aufzeichnung.
    Dadurch können während der anschließenden Wiedergabe unerwünschte Programmsequenzen auf Knopfdruck übersprungen oder eine Szene blitzschnell gefunden werden.
    Mit Pause Live TV kann zudem das laufende Fernsehprogramm jederzeit mit einem Druck auf die Pause-Taste angehalten und zu einem späteren Zeitpunkt weitergeschaut werden.
    Dank Quick Start-Funktion sind die Rekorder innerhalb einer Sekunde einsatzbereit, so dass kein Film und keine Aufzeichnung verpasst werden.
     
    • Multiformat-DVD-Festplatten-Kombination
    • Intuitive Benutzerführung
    • Neben der Aufnahme des Fernsehprogramms überzeugen die neuen Rekorder als digitales Fotoalbum sowie
    • Musik-Jukebox
    • Elektronische Programmführer Guide Plus+ mit Suchfunktion
    • Umfangreiche Anschlussmöglichkeiten
    ";2;False;0;;;Panasonic DMR EH 495 EG K;panasonic-dmr-eh-495-eg-k-160-gb-dvd-hdd-rekorder;True;True;P-1840;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;319.0000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;40155,8616898148;62;12;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000428-panasonic-dmr-eh-495-eg-k-160-gb-dvd-hdd-rekorder.jpg;;;3;;False;;;;;False;False;False;;;;;False;;;;;; +5;0;True;"HP Compaq Mini 110c-1110sg 10.1 Zoll Netbook ";"HP Compaq Mini 110c-1110sg 10.1 Zoll Netbook ";"
    HP Compaq Mini 110c-1110sg 10.1 Zoll Netbook
     
    Intel Atom N270 1.6GHz, 1GB RAM, 160GB HDD, Intel GMA 950, Win XP Home
     
    Leicht und kompakt
    Der Compaq Mini 110c wiegt 1,3 kg (mit 6-Zellen-Akku) und ist ca. 5,5 cm hoch – er ist damit sehr kompakt und fällt ins Auge
     
    Elegantes Design
    Der Compaq Mini 110c glänzt mit einem eleganten Gehäuse im neuem Imprint-Finish ""Unity"", einem Karomuster, das ins Auge fällt.
     
    Ständig in Verbindung
    Webcam und Mikrofon sind im Compaq Mini integriert und bieten per WLAN und optionalem WWAN zahlreiche Möglichkeiten zur Pflege sozialer Kontakte; Video-Chats und Video-Konferenzen, die bislang nur zuhause möglich waren, können jetzt im Park, im Cafe oder am Flughafen geführt werden
     
    Information und Kommunikation auch unterwegs
    Mit dem 10,1-Zoll-BrightView-Display, Original Windows® XP Home, der großen Tastatur (92 % der vollen Größe), drei USB-Anschlüssen und einem 5-in-1 Kartenleser sind Informationen, Kommunikation und Unterhaltung im Internet überall bequem zugänglich.
    ";2;False;0;;;"HP Compaq Mini 110c-1110sg 10.1 Zoll Netbook ";hp-compaq-mini-110c-1110sg-101-zoll-netbook;True;True;P-0870;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;259.9000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;40151,9990046296;6;39;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000598-hp-compaq-mini-110c-1110sg-101-zoll-netbook.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000599-hp-compaq-mini-110c-1110sg-101-zoll-netbook.jpg;;2;;False;;;;;False;False;False;;;;;False;;;;;; +5;0;True;Apple iPod Classic 120 GB schwarz;"Apple iPod Classic 120 GB schwarz ";"

    Apple iPod Classic 120 GB schwarz

     
    iPod classic: Freiraum -Und zwar jede Menge.
    120 GB sind wirklich eine ganze Menge Platz. Da lässt sich eine komplette Mediathek locker unterbringen und überallhin mitnehmen.
     
    Ein musikalisches Genie
    Stellen Sie vor, Sie hören einen Song. Toll wären jetzt andere Titel, die gut dazu passen. Was machen Sie? Ganz einfach: Sie verwenden die neue Funktion ""Genius"". Diese findet die Songs in Ihrer Mediathek, die gut zusammenpassen. Sie erhalten eine Genius Wiedergabeliste, die Sie sofort anhören, sichern oder sogar aktualisieren können. Verlassen Sie sich also auf den Genius von iTunes, wenn Sie einen Mix wollen, auf den Sie selbst nicht gekommen wären.
     
    Platz satt
    Der iPod classic bietet mit seinen 120 GB Speicherkapazität Platz für bis zu 30.000 Songs, 180 Stunden Videos, 20.000 Fotos oder eine beliebige Kombination dieser Inhalte. Und mit bis zu 36 Stunden Batterielaufzeit beweist der iPod classic auch ganz schön viel Kondition.
     
    Spaß auf Knopfdruck
    Sie findeen immer ganz leicht genau das, was Sie sehen oder hören wollen. Mit dem Click Wheel können Sie mit ""Cover Flow"" Ihre Alben durchblättern, oder Sie stöbern über verschiedene Kategorien wie Wiedergabeliste, Künstler, Album oder Musikrichtung in Ihren Songs und Videos. Sie können natürlich auch nach einem bestimmten Titel oder Interpreten suchen. Lust auf einen neuen Mix? Klicken Sie einfach auf ""Zufällige Titel"".
     
    Filme und Fernsehsendungen ansehen
    Auf dem fantastischen 2,5"" Display kommen Videos richtig zur Geltung. Sie können im iTunes Store Filme kaufen oder ausleihen, Fernsehsendungen kaufen und Video-Podcasts laden. Dann können Sie alles mit Ihrem iPod classic synchronisieren und immer und überall ansehen.
     
     
    Spiele auf dem iPod
    Wenige Fingertipps, viele Stunden Spielspaß. Vortex, iQuiz und Klondike sind schon auf dem iPod classic vorinstalliert, im iTunes Store können Sie weitere dazukaufen, z. B. Cake Mania. Alle iPod Spiele sind speziell für die iPod Oberfläche optimiert.
     
    Fotos zeigen
    Ihre Fotos aus iPhoto auf einem Mac oder aus Adobe Photoshop Elements und Adobe Photoshop Album auf einem PC bekommen Sie mit iTunes auf den iPod classic. Sie können Diashows mit Musik und Übergängen auf dem iPod classic oder mit optional erhältlichen Apple Komponenten oder mit einem Composite-AV-Kabel sogar auf dem Fernseher zeigen.
     
    Umweltverträglichkeit
    Der iPod classic steht für das kontinuierliche Engagement von Apple in puncto Umweltschutz. Die folgenden Merkmale tragen zu einer geringen Umweltbelastung bei:
     
        Arsenfreies Displayglas
        Ohne bromhaltige Flammschutzmittel
        Display mit LED-Hintergrundbeleuchtung ohne Quecksilber
        Frei von PVC
        Recyclingfähiges Gehäuse aus Aluminium und Edelstahl
     
    Produktbeschreibungen
    Freiraum. Und zwar jede Menge. 160 GB sind wirklich eine ganze Menge Platz. Da lässt sich eine komplette Mediathek locker unterbringen und überallhin mitnehmen.
     
    > Highlights
    - Click Wheel
    - Frequenzbereich: 20 Hz bis 20.000 Hz
    - Weitere unterstützte Audioformate: Protected AAC (aus dem iTunes Store), MP3 VBR, Audible (Formate 2, 3, 4, Audible Enhanced Audio, AAX und AAX+), Apple Lossless und WAV
    - Platz für bis zu 35.000 Songs im 128 KBit/Sek. AAC-Format
    - Platz für bis zu 20.000 vom iPod anzeigbare Fotos
    - Platz für bis zu 180 Stunden Videomaterial
    - Speichert Daten auf einer USB-Festplatte
    - Akkuladezeit: ca. 4 Std. (schnelles Laden auf 80%ige Kapazität in 2 Std.)
     
    > Grundeigenschaften
    - Breite: 103.5 mm
    - Höhe: 61.8 mm
    - Tiefe: 10.5 mm
    - Gewicht: 140.0 g
    - Farbe: Schwarz
     
    > Wiedergabeformate Audio
    - AAC
    - MP3
    - WAV
     
    > Akku
    - Akkutyp: Li-Ion
     
    > Display
    - Displaytechnologie: LCD
    - 2.5- Display
    - Bilddiagonale: 6.35 cm
    - Auflösung Breite: 320 Pixel
    - Auflösung Höhe: 240 Pixel
    - Hintergrundbeleuchtung: ja
     
    > Speicher
    - Speicherkapazität 120 GB
     
    > Anschlüsse
    - USB
    - USB-Standard 2.0
     
    > Audio-Anschlüsse
    - Headsetanschluss: 3,5 mm Klinke
    - ipod-Anschluss via IPOD Connector
     
    > Lieferumfang
    - iPod classic
    - Apple Earphones
    - USB 2.0 Kabel
    - Dock-Adapter
    - Dokumentation
     
    > Umweltverträglichkeit
    Der iPod nano steht exemplarisch für das Engagement von Apple in puncto Umweltschutz. Die folgenden Merkmale des iPod nano tragen zu seiner geringeren Umweltbelastung bei:
    - Arsenfreies Glas
    - Frei von bromhaltigen Flammschutzmitteln
    - Frei von Quecksilber
    - Frei von PVC
    - Besonders recyclingfähig
    ";2;False;0;;;Apple iPod Classic 120 GB schwarz;apple-ipod-classic-120-gb-schwarz;True;True;P-1420;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;209.9000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;40151,9525462963;50;1;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000284-apple-ipod-classic-160-gb-schwarz.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000285-apple-ipod-classic-160-gb-schwarz.jpg;;2;;False;;;;;False;False;False;;;;;False;;;;;; +5;0;True;"Garmin nüvi 1370T Navigationssystem ";"Garmin nüvi 1370T Navigationssystem Europa USA ";"
    Garmin nüvi 1370T Navigationssystem
     
     

    TMC, 4,3"" Display, Europa / USA / Kanada, ecoRoute, Fußgängernavigation, Bluetooth

     
     
     
    Mobile Navigation für die ganze Familie, dank Fahrspurassistent, intelligentem TMC, und Text-to-Speech eine rund-um-sorglos Navigation
    Übersichtliche und einfache Navigation mit 4,3 Zoll Display mit Fahrspurassistent + TMC Verkehrsfunkempfänger zur Stauumfahrung
    Kartenmaterial für Europa, USA und Canada intern vorinstalliert
    Inklusive ecoRoute die Garmin Spritspar-Funktion und echter Fußgängernavigation mit optionalen CityXplorer Stadtplänen für Bus und Bahn
    Lieferumfang: Garmin nüvi 1370T mit Kartenmaterial Europa/ USA/ Canada, KFZ-Anschlusskabel mit TMC Verkehrsfunkempfänger,
    Saugnapfhalterung für die Windschutzscheibe, Armaturenhalterung, Kurzanleitung
    ";2;False;0;;;"Garmin nüvi 1370T Navigationssystem ";garmin-nuevi-1370t-navigationssystem;True;True;P-2100;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;359.0000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;40148,9306828704;67;44;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000589-garmin-nuvi-1370t-navigationssystem.jpg;;;2;;False;;;;;False;False;False;;;;;False;;;;;; +5;0;True;NAVIGON 8410 Navigationssystem Europa;" NAVIGON 8410 Navigationssystem Europa 5"" Echtglas-Display";"
    NAVIGON 8410 Navigationssystem Europa
     
     
    5"" Echtglas-Display, West & Osteuropa 40 Länder, Bluetooth, TMC Pro, Real City 3D, Voice Interaction Pro
     
     
    5-Zoll-Touchdisplay 16:9
    Fußgängernavigation
    Reality View Pro
    Fahrspurassistent Pro
    Radar-Info
    Geschwindigkeitsassistent
    Reale Beschilderung Pro
    Clever Parking
    Text-to-Speech für Straßennamen
    Bluetooth Freisprecheinrichtung
    Professionelle Sprachsteuerung 2.0
    Landmark View 3D/City View 3D
    Panorama View 3D
    Latest Map Guarantee
    Europakarte (40 Länder)
    Abmessungen: 138 mm x 83,5 mm x 18,7mm (B/H/T)
    Lieferumfang: NAVIGON 8410, Kurzanleitung, KfZ-Ladekabel mit integrierter TMC Antenne,
    Design-Aktivhalterung, USB-Kabel, vorinstalliertes Europa-Kartenmaterial
    ";2;False;0;;;"NAVIGON 8410 Navigationssystem ";navigon-8410-navigationssystem-europa;True;True;P-2170;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;449.0000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;40148,9205902778;"68;2095";14;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000470-navigon-8410-navigationssystem-europa.jpg;;;2;;False;;;;;False;False;False;;;;;False;;;;;; +5;0;True;Apple iPod shuffle 2 GB blau;Apple iPod shuffle 2 GB blue;"

    Apple iPod shuffle 2GB blau 

     
     
    Wie seine größeren Geschwister besitzt auch der iPod shuffle kreisförmig
    angeordnete, ergonomische Bedienelemente.
    Der Kopfhöreranschluss am iPod shuffle dient gleichzeitig als Dock-Anschluss.
    Drehen Sie den iPod shuffle auf die Seite und setzen Sie ihn in das mitgelieferte Dock ein.
    Dank eines stabilen, integrierten Clips lässt sich der iPod shuffle fast überall befestigen.
    Klemmen Sie ihn am T-Shirt, am Hemdkragen oder am Trageriemen von Rucksack oder Handtasche fest.
    Lassen Sie sich aufs Ungewisse ein: Verwenden Sie den Schalter für die Zufallswiedergabe,
    um den Inhalt Ihres iPod shuffle neu zu mischen.
    verbesserte Kopfhörer und das neue iTunes 8.0
     
    Einfach Musik anhaben mit dem Apple iPOD SHUFFLE 2GB.Tragen Sie bis zu 500 Songs am Ärmel. Oder am Gürtel. Oder am Sportoutfit. Das Erkennungszeichen für Musikfans - den Apple iPOD SHUFFLE. Füllen Sie Ihren Apple iPOD SHUFFLE silber 1GB spielend einfach. iTunes ist der Store für Unterhaltungsinhalte. Ihre super organisierte Musiksammlung und Jukebox. Und die Software, mit der Sie Ihren Apple iPOD SHUFFLE mit einem Mausklick füllen. Das farbige Gehäuse aus eloxiertem Aluminium in silber passt zum genial einfachen Design des Apple iPOD SHUFFLE.
     
    Leistungseigenschaften
     
    2 GB Flash-Memory Speicher
    min. Audio-Datenrate: 8 KBit/s
    max. Audio-Datenrate: 320 KBit/s
    Frequenzgang-Untergrenze: 20 Hz
    Frequenzgang-Obergrenze: 20000 Hz
     
    Formate/Standards
     
    MP3-Standard
    AAC + MP3 Standard
    WAV-Dateiformat kompatibel
    Audible-Format kompatibel
    AIFF-Format kompatibel
     
    Bedienung
     
    Musiktitel-Verwaltung
     
    Leistungsaufnahme/Spannungsversorgung

    Li-Polymer Akku
    12 Std. Spieldauer mit Akku
    Ladezeit für Akku: 4 Std.
     
    Anschlüsse
     
    Kopfhörer-Anschluß
    USB-Schnittstelle
    Anschluß für Docking-Station
     
    Gehäuse-Eigenschaften
     
    Breite: 4.12 cm
    Höhe: 2.73 cm
    Tiefe: 1.05 cm
    Gewicht: 15.5 g
    ";2;False;0;Apple iPod shuffle 2 GB blau;Apple iPod shuffle 2 GB blau;Apple iPod shuffle 2 GB blau;apple-ipod-shuffle-2-gb-blau;True;True;P-1150;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;64.9000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;40148,0555902778;37;1;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000398-apple-ipod-shuffle-2-gb-blau.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000399-apple-ipod-shuffle-2-gb-blau.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000400-apple-ipod-shuffle-2-gb-blau.jpg;2;;False;;;;;False;False;False;;;;;False;;;;;; +5;0;True;"Logitech EX 110 Desktop Tastatur/Maus ";Logitech EX 110 Desktop Tastatu / Maus;"
    Logitech EX 110 Desktop Tastatur/Maus
     
     
    Zuverlässig und kabellos:
    Schnelle, kabellose 27-MHz-Leistung
    Sondertasten: Zugriff auf Musik, Video, Lautstärke, E-Mail, Internet und mehr.
    Programmierbare F-Tasten: öffnen häufig genutzter Anwendungen, Websites oder Dateien.
    Spritzwassergeschütztes Design
    Maus: Schnell ansprechende Optik: Erleben Sie eine Auflösung von 800 dpi.
     
    Lieferumfang:
    Logitech Cordless Keyboard und Cordless Optical Mouse,
    kompakter USB-/PS/2-Funkempfänge, USB-PS/2-Adapter
     
    ";2;False;0;;;"Logitech EX 110 Desktop Tastatur/Maus ";logitech-ex-110-desktop-tastaturmaus;True;True;P-2810;;;False;0;False;;False;False;0;False;0;1;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;24.9000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;40143,0133101852;"21;2095";11;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000392-logitech-ex-110-desktop-tastaturmaus.jpg;;;1;;False;;;;;False;False;False;;;;;False;;;;;; +5;0;True;"TomTom GO 940 Live Navigationssystem ";"TomTom Go 940 Live Navigationssystem Europa Nordamerika ";"
    TomTom GO 940 Live Navigationsgerät mit Sprachsteuerung

     
    inkl. Europa-Karten, USA, Kanada, TMC, Live Services

     
    Clevere Navigation mit Echtzeitinfos für Vielfahrer und dem neuesten Kartenmaterial von West- und Osteuropa, USA und Kanada, TomTom IQ Routes -
    jeden Tag zu jeder Tageszeit die optimalste Route, TomTom Map Share, vereinfachte Bedienung durch brillianten 4,3-Zoll-Touchscreen und Sprachsteuerung,
    verbesserter Fahrspurassistent zur einfacheren Orientierung an unübersichtlichen Autobahnkreuzen, hochwertiger Bluetooth-Kfz-Freisprecheinrichtung sowie einem FM-Transmitter und MP3-Player.
    TomTom GO 940 Live inklusive 3 Monate Probe-Abo zu Live-Dienste in allen LIVE Ländern. Echtzeit-Empfang von Premiuminformationen zu Ihrer Route: HD Traffic, Lokale Suche mit Google, Sicherheitswarnungen und mehr
     Sprachsteuerung - mehr als 100 Funktionen einfach per Sprachbefehl aktivieren
    Verbesserte Positionsbestimmung - unterbrechungsfreie Navigation, sogar in Tunneln
    Fahrspurassistent - zum einfachen Navigieren an unübersichtlichen Kreuzungspunkten
    GO 940 LIVE: Karten von Europa (WE u. OE), den USA und Kanada vorinstalliert, LIVE-Services- fahren Sie immer aktuell und zuverlässig informiert mit Echtzeit-Informationen
    sowie mit IQ Routes damit fahren Sie zu jeder Tageszeit auf der cleversten Route
    Lieferumfang: TomTom GO 940 LIVE, aktive Halterung, Autoladegerät, Halterung für Zuhause, Benutzerhandbuch, CD-ROM (TomTom HOME )

     
    ";2;False;0;;;;tomtom-go-940-live-navigationssystem;True;True;P-2010;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;304.9000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;40136,6372800926;66;4;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000391-tomtom-go-940-live-navigationssystem.jpg;;;2;;False;;;;;False;False;False;;;;;False;;;;;; +5;0;True;Apple iPod Touch 8 GB schwarz;"Apple iPod Touch 8 GB schwarz mit integrierter WiFi Funktion ";"
    Apple iPod Touch 32 GB schwarz mit integrierter WiFi Funktion

    Der iPod touch kann alles, was du am iPod toll findest. Und noch vielmehr. Schlankes neues Design. Mit seinem fantastisch flachen Edelstahl-Design liegt der iPod touch mit dem 3.5 Zoll Touch-Display jetzt noch besser in der Hand. Mobil im Spiel. Durch revolutionäre Technologien wie das Multi-Touch-Display, der Beschleunigungssensor und 3D-Grafiken macht das Spielen auf dem iPod touch besonders viel Spaß. Schlaue Musik Mit der neuen Funktion ""Genius"" wird der iPod touch zu Deinem superintelligenten, persönlichen DJ.
    Nur ein paar Fingertipps, und Genius erzeugt eine Wiedergabeliste mit Songs Deiner Mediathek, die gut zusammenpassen. Internet überall Internetzugang überall, wo ein drahtloses Netzwerk zur Verfügung steht, damit Sie immer mit dabei sind. Multitouch-Oberfläche: Die revolutionäre Technologie des iPhone und die Software Version 3.1 stecken in diesem genialen iPod. Das brillante Breitformat-Display rückt Ihre Videos und Spiele ins beste Licht und dank OpenGL sehen die Spiele jetzt noch besser aus Surfen Sie mit Safari im Web und sehen Sie YouTube Videos auf dem iPod mit integrierter Wi-Fi Funktionalität an. Mit Ihrem iPod touch können Sie im iTunes Wi-Fi Music Store nach Songs suchen, Hörproben abspielen und Titel kaufen.
    Lieferumfang: iPod touch, Ohrhörer, USB 2.0 Kabel, Kurzanleitung
     
    Schlankes neues Design
    Mit seinem fantastisch flachen Edelstahl-Design liegt der iPod touch so gut in der Hand wie nie zuvor. Ebenfalls Eindruck machen der neue Lautstärkeregler und der integrierte Lautsprecher.

    Spiele
    Speziell auf die iPod touch Technologie zugeschnittene Spiele sind nur noch einen Fingertipp entfernt. Stöbere in hunderten von Spielen im App Store direkt auf Deinem iPod touch, und wenn Du gefunden hast, was Du suchst, kannst Du es einfach laden und dann kann es losgehen.
     
    Steuerung per Fingertipp
    Viele Spiele auf dem iPod touch nutzen die Multi-Touch-Technologie für besonders exakte Fingertipp-Steuerung der verschiedenen Spielelemente. Beim Schach ziehst Du mit dem Finger die Figuren, bei Würfelspielen bewegst Du die Würfel. Durch Ziehen mit zwei Fingern kannst Du die Anzeige vergrößern und verkleinern, Deine Figur nach links oder rechts drehen, und durch einfaches Antippen triffst Du eine Auswahl.
     
    Musik
    Blättere in den Albumcovern Deiner Musiksammlung. Erstelle immer wieder neue Genius Wiedergabelisten und erweitere Deine Sammlung aus dem iTunes Wi-Fi Music Store überall, wo ein Wi-Fi-Hotspot in der Nähe ist.
    Mit Cover Flow lebt das Flair einer CD- oder Plattensammlung wieder auf. Wer erinnerst sich nicht an das Gefühl beim Durchblättern der Sammlung? Das gibt es jetzt auch auf dem iPod touch: einfach iPod drehen, durch die Cover blättern, ein Album auswählen, fertig. Ein Fingertipp aufs Cover, und schon siehst Du die Titelliste, ein weiterer Tipp spielt die Musik ab, und dabei kannst Du sogar die Songtexte anzeigen.
     
    Ein Musikgenie
    Stell Dir vor, Du hörst einen Song. Toll wären jetzt andere Titel, die gut dazu passen. Was machst du? Ganz einfach: Du verwendest die neue Funktion ""Genius"". Diese findet die Songs in Deiner Mediathek, die gut zusammenpassen. Du erhältst eine Genius Wiedergabeliste, die Du sofort anhören, sichern oder sogar aktualisieren kannst. Verlass Dich also auf den Genius von iTunes, wenn Du einen Mix willst, auf den Du selbst nicht gekommen wärst.
     
    Lautsprecher integriert
    Mit dem integrierten Lautsprecher kannst Du Musik und Gespräche ohne Kopfhörer hören – perfekt für zwangloses Hörvergnügen.

    Längere Batterielaufzeit
    Jetzt kannst Du noch länger rocken (und ansehen und spielen). Der iPod touch hält bis zu 36 Stunden bei Musik oder bis zu 6 Stunden bei Videos durch. Das reicht für drei oder vier Filme zwischen den Ladevorgängen.
     
    Internet
    Surfe im Internet mit Wi-Fi. Du kannst detailgenaue HTML-E-Mails mit Anlagen empfangen und Wegbeschreibungen und aktuelle Verkehrsinformationen abrufen. Auch als YouTube-Fan entgeht Dir nichts.
     
    Überall ins Internet
    Der iPod touch ist der einzige iPod mit kabellosem 802.11b/g Internetzugriff. Bei bestehender Wi-Fi-Verbindung kannst Du im Internet surfen und Nachrichten lesen, Sportergebnisse sehen, Rechnungen bezahlen und online einkaufen.
     
    Wer suchet, der findet
    Der iPod touch synchronisiert Deine Lesezeichen vom PC oder Mac, sodass Du ruck zuck auf Deine Lieblingsseiten zugreifen kannst. Die Google- und Yahoo!-Suche ist schon integriert, sodass Du im Web schnell findest, was Du suchst.
     
    Zoom mit Aussicht
    Jeden beliebigen Ausschnitt einer Webseite kannst Du vergrößern, indem Du mit dem Finger darauf tippst oder mit zwei Fingern die Anzeige aufziehst. Websites lassen sich im Hoch- oder Querformat anzeigen: einfach den iPod touch um 90 Grad drehen, und schon wird auch die Darstellung der Website gedreht.
     
    Eigene Weblinks
    Für häufig besuchte Websites, etwa die einer Zeitung, eines Blogs oder eine Sport-Website, kannst Du einfach ein Symbol auf dem Home-Bildschirm erstellen. Deine Lieblingsseiten sind über mit Safari erstellte Weblinks nur einen Fingertipp entfernt.
     
    Rock 'n' Run mit Nike+
    Im iPod touch ist kabellose Unterstützung für Nike + iPod integriert. Du brauchst nur einen Nike + iPod Sensor in Deinem Schuh, und schon kann's losgehen.
     
    Das optimale Lauftraining
    Im iPod touch ist jetzt Unterstützung für Nike + iPod integriert. Einfach den Nike + iPod Sensor (separat erhältlich) in den Nike+ Laufschuh einsetzen, und es kann losgehen. Der Sensor überträgt die Laufdaten drahtlos an den iPod touch – er erfasst die gelaufene Zeit, die zurückgelegte Strecke und die verbrauchten Kalorien. Außerdem gibt er Dir gesprochenes Feedback zu Deinen Trainingsfortschritten.
     
    Das optimale Fitnesstraining
    Diese Funktion kann auch zusammen mit neuen, in vielen Fitnessstudios vorhandenen Geräten für das Ausdauertraining gekoppelt werden. Suche einfach nach mit Nike + iPod kompatiblen Laufbändern, Elliptical Trainern, Steppern und Hometrainern.
    ";2;False;0;;;Apple iPod Touch 8 GB schwarz mit integrierter WiFi Funktion;apple-ipod-touch-8-gb-schwarz;True;True;P-1270;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;169.9000;169.9000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;40134,2799768519;43;1;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000141-apple-ipod-touch-16-gb-schwarz.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000142-apple-ipod-touch-16-gb-schwarz.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000143-apple-ipod-touch-16-gb-schwarz.jpg;2;;False;;;;;False;False;False;;;;;False;;;;;; +5;0;True;"Philips DVP 5990 / 12 DVD Player ";Philips DVP 5990 / 12 DVD Player schwarz;"
    Philips DVP 5990 / 12 DVD Player schwarz
     
    DivX-zertifiziert, HDMI 1080p, Upscaling 1080i
     
    Der ideale DVD-Player für Ihr HDTV
    mit True High-Definition-HDMI 1080p
    Lassen Sie sich von diesem DVD-Player von Philips mit HDMI Digital Video- und
    Audioverbindung beeindrucken. Erleben Sie wahres Home Entertainment, und tauchen
    Sie in High Definition Video ein (720p / 1080i / 1080p).
    Digitaler HDMI-Ausgang für eine einfache Verbindung mit nur einem Kabel
    DivX Ultra-zertifiziert für verbesserte Wiedergabe von DivX-Videos
    192 kHz/24 Bit Audio-DAC für verbesserte analoge Klangausgabe
    Hochwertige Ausgänge für Analog- und Digital-Audio
     
    Lieferumfang:
    DVD Player; 2 AAA-Batterien; Schnellstartanleitung; Fernbedienung; Benutzerhandbuch
    ";2;False;0;;;"Philips DVP 5990 / 12 DVD Player ";philips-dvp-5990-12-dvd-player;True;True;P-1930;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;2,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;89.0000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;40132,644837963;60;6;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000383-philips-dvp-5990-12-dvd-player.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000384-philips-dvp-5990-12-dvd-player.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000385-philips-dvp-5990-12-dvd-player.jpg;2;;False;;;;;False;False;False;;;;;False;;;;;; +5;0;True;Sandisk Sansa Clip+ schwarz 8GB;Sandisk Sansa Clip+ schwarz 8 GB;"
    Sandisk Sansa Clip+ schwarz 8 GB
     
     
     
    Die neuen Sandisk Sansa Clip+ - Modelle unterstützen nun die Anzeige von sortierbaren Ordnerstrukturen.
    digitaler SanDisk Player für MP3, WMA, Secure WMA, Ogg Vorbis, FLAC-Formate, Hörbücher und FM-Radio
    kleines, kompaktes Design, kaum größer als eine Streichholzschachtel
    microSD-/microSDHC-Slot zur Erweiterung der Speicherkapazität und zum Datentransfer
    FM-Radio mit 40 Stationsspeicherplätzen
    Diktiergerät-Funktion über integriertes Mikrofon
    4-zeiliges OLED-Display
    Sortierung der Titel nach verschiedenen Kriterien möglich, wie z.B. Künstler, Album, Genre, u.a.
    bis zu 15-h-Wiedergabe mittels internem, wiederaufladbaren Akku
    inkl. abnehmbarem Trageclip, Ohrhörer, USB 2.0 Kabel und Bedienungsanleitung
    unterstützt Win 2000, Vista, XP SP2 und Mac OS X 10.3 oder höher
    Speicherkapazität extern: wird über microSD-Karte definiert
    Speicherkapazität intern: 8 GB
    Speicher: intern + extern

    Lieferumfang:
    Sansa Clip+ MP3 Player, Ohrhörer, USB 2.0 Kabel, Quick Start Guide
    ";2;False;0;;;Sandisk Sansa Clip+;sandisk-sansa-clip-schwarz-8gb;True;True;P-1590;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;59.9000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;40125,6367476852;52;8;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000572-sandisk-sansa-clip-schwarz-8gb.jpg;;;2;;False;;;;;False;False;False;;;;;False;;;;;; +5;0;True;"Me2 ME600HD-1000 Multimediafestplatte ";"Me2 ME600HD-1000 Multimediafestplatte1 TB ";"

    Me2 ME600HD-1000  Multimediafestplatte 1 TB

     
     
    3,5 Zoll, USB 2.0,Scart,HDMI Multimedia
     
     
     
    Externe USB 2.0 Multimedia Festplatte• Kapazität: 1000 GB• High-speed
    USB 2.0 Schnittstelle• Aluminium Gehäuse• Stand-alone Media Player zur Wiedergabe von MPEG-1, MPEG-2,
    D ivX/Xvid, JPEG, GMC, Qpel, MP3 (ID3 tag) WAV Media Daten• direkte Wiedergabe von DVD Ordnern&bu
    Ordner-Navigation• Eigene Playlist benutzen und bearbeiten• einfache Dateiführung,
     intuitive Bedienung• unterstützt NTSC und PAL TV Standard• geeignet für HDTV (skaliert auf 10
    ";2;False;0;;;;me2-me600hd-1000-multimediafestplatte;True;True;P-2670;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;169.0000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;40124,2896180556;16;;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000117-me2-me600hd-500-gb-multimediafestplatte.jpg;;;2;;False;;;;;False;False;False;;;;;False;;;;;; +5;0;True;Apple iPod Classic 160 GB silber;"Apple iPod Classic 160 GB silber ";"
    Apple iPod Classic 160 GB silber


    iPod classic: Freiraum -Und zwar jede Menge.
    160 GB sind wirklich eine ganze Menge Platz. Da lässt sich eine komplette Mediathek locker unterbringen und überallhin mitnehmen.
     
    Ein musikalisches Genie
    Stellen Sie vor, Sie hören einen Song. Toll wären jetzt andere Titel, die gut dazu passen. Was machen Sie? Ganz einfach: Sie verwenden die neue Funktion ""Genius"". Diese findet die Songs in Ihrer Mediathek, die gut zusammenpassen. Sie erhalten eine Genius Wiedergabeliste, die Sie sofort anhören, sichern oder sogar aktualisieren können. Verlassen Sie sich also auf den Genius von iTunes, wenn Sie einen Mix wollen, auf den Sie selbst nicht gekommen wären.
     
    Platz satt
    Der iPod classic bietet mit seinen 160 GB Speicherkapazität Platz für bis zu 40.000 Songs, 200 Stunden Videos, 25.000 Fotos oder eine beliebige Kombination dieser Inhalte. Und mit bis zu 36 Stunden Batterielaufzeit beweist der iPod classic auch ganz schön viel Kondition.
     
    Spaß auf Knopfdruck
    Sie findeen immer ganz leicht genau das, was Sie sehen oder hören wollen. Mit dem Click Wheel können Sie mit ""Cover Flow"" Ihre Alben durchblättern, oder Sie stöbern über verschiedene Kategorien wie Wiedergabeliste, Künstler, Album oder Musikrichtung in Ihren Songs und Videos. Sie können natürlich auch nach einem bestimmten Titel oder Interpreten suchen. Lust auf einen neuen Mix? Klicken Sie einfach auf ""Zufällige Titel"".
     
    Filme und Fernsehsendungen ansehen
    Auf dem fantastischen 2,5"" Display kommen Videos richtig zur Geltung. Sie können im iTunes Store Filme kaufen oder ausleihen, Fernsehsendungen kaufen und Video-Podcasts laden. Dann können Sie alles mit Ihrem iPod classic synchronisieren und immer und überall ansehen.
     
     
    Spiele auf dem iPod
    Wenige Fingertipps, viele Stunden Spielspaß. Vortex, iQuiz und Klondike sind schon auf dem iPod classic vorinstalliert, im iTunes Store können Sie weitere dazukaufen, z. B. Cake Mania. Alle iPod Spiele sind speziell für die iPod Oberfläche optimiert.
     
    Fotos zeigen
    Ihre Fotos aus iPhoto auf einem Mac oder aus Adobe Photoshop Elements und Adobe Photoshop Album auf einem PC bekommen Sie mit iTunes auf den iPod classic. Sie können Diashows mit Musik und Übergängen auf dem iPod classic oder mit optional erhältlichen Apple Komponenten oder mit einem Composite-AV-Kabel sogar auf dem Fernseher zeigen.
     
    Umweltverträglichkeit
    Der iPod classic steht für das kontinuierliche Engagement von Apple in puncto Umweltschutz. Die folgenden Merkmale tragen zu einer geringen Umweltbelastung bei:
     
        Arsenfreies Displayglas
        Ohne bromhaltige Flammschutzmittel
        Display mit LED-Hintergrundbeleuchtung ohne Quecksilber
        Frei von PVC
        Recyclingfähiges Gehäuse aus Aluminium und Edelstahl
     
    Produktbeschreibungen
    Freiraum. Und zwar jede Menge. 160 GB sind wirklich eine ganze Menge Platz. Da lässt sich eine komplette Mediathek locker unterbringen und überallhin mitnehmen.
     
    > Highlights
    - Click Wheel
    - Frequenzbereich: 20 Hz bis 20.000 Hz
    - Weitere unterstützte Audioformate: Protected AAC (aus dem iTunes Store), MP3 VBR, Audible (Formate 2, 3, 4, Audible Enhanced Audio, AAX und AAX+), Apple Lossless und WAV
    - Platz für bis zu 40.000 Songs im 128 KBit/Sek. AAC-Format
    - Platz für bis zu 25.000 vom iPod anzeigbare Fotos
    - Platz für bis zu 200 Stunden Videomaterial
    - Speichert Daten auf einer USB-Festplatte
    - Akkuladezeit: ca. 4 Std. (schnelles Laden auf 80%ige Kapazität in 2 Std.)
     
    > Grundeigenschaften
    - Breite: 103.5 mm
    - Höhe: 61.8 mm
    - Tiefe: 10.5 mm
    - Gewicht: 140.0 g
    - Farbe: Schwarz
     
    > Wiedergabeformate Audio
    - AAC
    - MP3
    - WAV
     
    > Akku
    - Akkutyp: Li-Ion
     
    > Display
    - Displaytechnologie: LCD
    - 2.5- Display
    - Bilddiagonale: 6.35 cm
    - Auflösung Breite: 320 Pixel
    - Auflösung Höhe: 240 Pixel
    - Hintergrundbeleuchtung: ja
     
    > Speicher
    - Speicherkapazität 160 GB
     
    > Anschlüsse
    - USB
    - USB-Standard 2.0
     
    > Audio-Anschlüsse
    - Headsetanschluss: 3,5 mm Klinke
    - ipod-Anschluss via IPOD Connector
     
    > Lieferumfang
    - iPod classic
    - Apple Earphones
    - USB 2.0 Kabel
    - Dock-Adapter
    - Dokumentation
     
    > Umweltverträglichkeit
    Der iPod nano steht exemplarisch für das Engagement von Apple in puncto Umweltschutz. Die folgenden Merkmale des iPod nano tragen zu seiner geringeren Umweltbelastung bei:
    - Arsenfreies Glas
    - Frei von bromhaltigen Flammschutzmitteln
    - Frei von Quecksilber
    - Frei von PVC
    - Besonders recyclingfähig
    ";2;False;0;;;Apple iPod Classic 120 GB schwarz;apple-ipod-classic-160-gb-silber;True;True;P-1410;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;249.9000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;40124,2541319444;50;1;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000285-apple-ipod-classic-160-gb-schwarz.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000284-apple-ipod-classic-160-gb-schwarz.jpg;;2;;False;;;;;False;False;False;;;;;False;;;;;; +5;0;True;Apple iPod Nano 16 GB verschiedene Farben;Apple iPod Nano 16 GB;"
    Apple iPod Nano 16 GB
     
     
    Neues gebogenes Design, der dünnste iPod, den es je gab mit neuen Farben zu Auswahl
    Die Bedieung optimiert: ein einziges Handschütteln und ein anderes Lied wird gespielt
    Die neue Funktion ""Genius"" findet die Songs in Ihrer Mediathek, die besonders gut zusammenpassen, und erstellt daraus eine Genius Wiedergabeliste.
    Viele Abspielformate: z.B. MP3, AAC, Apple Lossless, AIFF, WAV, H.264, MPEG-4
    Lieferumfang: iPod Nano, Ohrhörer, USB 2.0 Kabel, Dock-Adapter, Dokumentation
     
    Neues gebogenes Design, der dünnste iPod, den es je gab mit neuen Farben zu Auswahl
    Die Bedieung optimiert: ein einziges Handschütteln und ein anderes Lied wird gespielt
    Die neue Funktion ""Genius"" findet die Songs in Ihrer Mediathek, die besonders gut zusammenpassen, und erstellt daraus eine Genius Wiedergabeliste.
    Viele Abspielformate: z.B. MP3, AAC, Apple Lossless, AIFF, WAV, H.264, MPEG-4
    Lieferumfang: iPod Nano, Ohrhörer, USB 2.0 Kabel, Dock-Adapter, Dokumentation
     
    Ein musikalisches Genie
    Stell Dir vor, Du hörst einen Song. Toll wären jetzt andere Titel, die gut dazu passen. Was machst du? Ganz einfach: Du verwendest die neue Funktion ""Genius"". Diese findet die Songs in Deiner Mediathek, die gut zusammenpassen. Du erhältst eine Genius Wiedergabeliste, zusammengestellt von Deinem persönlichen, superintelligenten DJ.  
    Musik schneller finden
    Auch einen Song, den Du hören willst, findest Du jetzt viel einfacher. Du kannst Deine Alben mit Cover Flow anzeigen oder hältst einfach die mittlere Taste gedrückt und blätterst in Deinen Alben oder Interpreten. Den gewünschten Song gefunden? Einmal auf die mittlere Taste gedrückt, und schon hast Du ihn zur aktuellen Wiedergabeliste hinzugefügt. 
     
    Aufdrehen und rumdrehen
    Neige Deinen iPod nano in die Waagerechte, und schon kannst Du hören, sehen oder spielen wie nie zuvor. Deine Alben kannst Du mit Cover Flow durchblättern und siehst so viel mehr Alben oder Interpreten gleichzeitig auf dem Display.
     
    Shake it, Baby!
    Manchmal hat man einfach Lust auf eine kleine Überraschung. Darum kannst Du jetzt komplett dem Zufall überlassen, welches Lied Du als Nächstes hörst. Einfach den iPod nano kurz schütteln – und er springt zu irgendeinem anderen Song aus Deiner Musik-Bibliothek. Lass dich überraschen, was er Dir als Nächstes präsentiert.   
    Spiel ab!
    Jetzt kannst Du Dir mit Spielen die Zeit vertreiben, die ganz speziell auf den iPod nano und den Beschleunigungssensor zugeschnitten sind. Sie reagieren auf Deine Bewegungen und wirken dadurch so überzeugend, dass sie fast schon süchtig machen können. In jedem Fall wirst Du begeistert sein. Bereits vorinstalliert ist Maze, wo Du Dich durch Neigen, Kippen und allerlei andere Bewegungen durch riesige Labyrinthe manövrieren musst. Im iTunes Store stehen natürlich noch viele weitere Spiele zur Auswahl.
     
    Sogar Deine Fotos rocken
    Jetzt kannst Du gleich hunderte von Fotos aus der Tasche zaubern und überall vorführen. Senkrecht gehalten zeigt der iPod nano Deine Fotos im Hochformat an, wenn Du ihn um 90 Grad drehst, wechseln auch die Fotos ins Querformat. Die Fotos wirken in ihrem richtigen Größen- und Seitenverhältnis auf dem brillanten Display mit 320 x 240 Pixeln einfach hervorragend. 
    Der größte kleine Bildschirm der Welt
    Filme, Fernsehsendungen und Videos auf dem iPod nano anzusehen, ist das pure Vergnügen. Die hochauflösende Anzeige wirkt auf dem kristallklaren 2"" Breitbild-Display besonders brillant und lebendig. So hast Du mit dem iPod nano Dein eigenes Kino im Taschenformat immer dabei.  
     
    Produktbeschreibungen
    Flach, flacher, am flachsten mit nur 6,2mm bringt der iPod nano, in leuchtenden Farben, neuen Schwung ins Leben.
    Mit brilianterem Display, höherer Speicherkapazität und noch längerer Batterielaufzeit schütteln Sie sich einfach durch Ihre Mediathek.
    Leistungsmerkmale
    - Verschieden Menüs: Musik, Fernsehsendungen, Videos, Hörbücher, Podcasts, Diashows, Spiele
    - Geschwungenen Aluminium-Design mit gewölbtem Glas
    - HxBxT: 90,7 x 38,7 x 6,2 mm
    - Gewicht: 36,8 g
    Lieferumfang
    - iPod nano
    - Ohrhörer
    - USB 2.0-Kabel
    - Dock-Adapter
    - Dokumentation
    Display
    - 2- Farb-LCD mit LED-Hintergrundbeleuchtung
    - 320 x 240 Pixel
    Kapazität
    - 8 GB Flash-Laufwerk1 für bis zu 2.000 Songs, 7.000 Fotos, 8 Std. Videomaterial
    Batterie
    - Integrierte, wiederaufladbare Lithium-Ionen-Batterie
    - Musikwiedergabe: bis zu 24 Stunden bei voller Ladung
    - Videowiedergabe: bis zu 4 Stunden bei voller Ladung
    Audio
    - Unterbrechungsfreie Wiedergabe
    - Frequenzbereich: 20 Hz bis 20.000 Hz
    - Unterstützte Audioformate: AAC, Protected AAC, MP3, MP3 VBR, Audible, Apple Lossless, AIFF und WAV
    Systemvoraussetzungen
    - USB 2.0-Anschluss
    - mind. Mac OS X 10.4.11 bzw. mind. Windows Vista oder Windows XP Home oder Professional
    - mind. iTunes 8  

     
     
     
    ";2;False;0;;;Apple iPod Nano 16 GB;apple-ipod-nano-16-gb-verschiedene-farben;True;True;P-1370;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;159.9000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;40123,68375;47;1;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000075-apple-ipod-nano-8-gb-verschiedene-farben.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000076-apple-ipod-nano-8-gb-verschiedene-farben.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000077-apple-ipod-nano-8-gb-verschiedene-farben.jpg;1;;False;;;;;False;False;False;;;;;False;;;;;; +5;0;True;Acer Aspire 1810TZ-412G32n rot 29,5 cm (11,6 Zoll) Notebook;4 GB, 17 Zoll, 400 GB, Intel, 3;"
    Aspire 1810T:
    Das Aspire 1810T bietet die perfekte Balance aus unabhängiger Mobilität und flexibler Anwendung. Dieses handliche 29,46cm (11,6"") Notebook ist weniger als 1"" schmal, wartet aber auf mit einer vollausgestatteten Tastatur, HD Audio/Visual Unterhaltung und bis zu 8 Stunden mobiler Energie. Zusätzlich können Sie unter drei angesagten Farben auswählen: rubinrot, diamantschwarz und saphirblau.
     
     Kompaktes Design, excellente Anwendung
    Dieses Notebook wiegt nur 1,35kg, so daß Sie es mühelos überall mitführen können. Mit der Acer Fine Tip Tastatur können Sie auch auf die übliche Notebook Nutzung zugreifen, dank der fortschrittlichen Kontrolle ohne Maus über das multifunktionale Touchpad.
     
    8 Stunden Batterielaufzeit
    Das Aspire 1810T ist mit einem Niedrig_Volt-Prozessor (ULV) versehen, der weniger Energie verbraucht und Sie von Ihrem Stromanschluß unabhängig macht. Einmal aufladen und Sie haben es von morgens bis abends zur Verfügung.
     
    HD Erfahrung auf dem Vormarsch
    Erleben Sie grandiose visuelle Effekte, brillant in Farbe und Bild, via 3D Grafik und einem 16:9 Bildschirm. Der integrierte HDMI Port ermöglicht Ihnen auch den leichten Anschluß an periphere Displays. Was den Klang angeht, erhalten Sie die optimierte 2. Generation des Dolby Sound Room für eine Tonerfahrung über viele Kanäle, zu empfangen über ein simples Paar Kopfhörer.
     
    Auf den Punkt gekühlt
    Die Acer ComfyTouch Technologie nutzt das innovative Design, um den Prozessor und das Gehäuse luftzukühlen. Auch wenn Sie das Notebook rund um die Uhr in Betrieb haben, bleibt es stets bei optimaler Temperatur.
     

    Umweltbewußtsein als Motiv
    Nehmen Sie die Energieersparnis wahr, ob unterwegs oder zuhause. In der Anwendung braucht das Aspire 1810T bis zu 40% weniger Strom als handelsübliche Notebooks.
     
     Nutzen Sie die Vorteile der mobilen Welt und schreiben Sie E-Mails oder chatten Sie mit Ihren Lieben, wo auch immer Sie gerade sind. Mit der erweiterten Netzwerkverbindung Wi-Fi CERTIFIED™ können Sie sich problemlos auf eine große Zahl von Verbindungen überall auf der Welt verlassen. Sie müssen sich an ein LAN anschließen? Kein Problem! Der Gigabit-Ethernet-Port garantiert eine ultraschnelle Verbindung.
     
     Die Acer Crystal Eye Webcam mit verbesserter Bilderfassung garantiert auch bei nicht optimaler Beleuchtung ein klares Bild bei Video-Chats und Webkonferenzen.
     
     HD-Ready (engl. „Bereit für HD“) ist ein von der der EICTA geschaffenes Label für Geräte (z.B.: Notebooks) die hochauflösendes Fernsehen (High Definition Television (HDTV)) wiedergeben können. Mindestvorsausetzungen für dieses Label sind unter anderem eine native 16:9-Auflösung von wenigstens 720 Zeilen, mindestens ein digitaler Eingang (DVI-D/-I oder HDMI), und eine Auflösung von 1280 × 720 Pixeln (Vollbilder) bzw. 1920 × 1080 Pixeln (Halbbilder). Ein Gerät das diesen Anforderungen gerecht wird kann hochauflösendes Fernsehen wiedergeben und verspricht ein gestochen scharfes Bilderlebnis.
     
    ";2;False;0;;;"Acer Aspire Timeline 1810TZ 11.6 Zoll Notebook ";acer-aspire-1810tz-412g32n-rot-295-cm-116-zoll-notebook;True;True;P-0830;;;False;0;False;;False;False;0;False;0;1;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;1;9999;False;False;0;1;1;0;False;1;10000;;False;False;False;False;547.9000;0.0000;0.0000;499.0000;41640;41820,9999884259;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;40121,6691898148;"5;2095";37;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000527-acer-aspire-1810tz-412g32n-rot-295-cm-116-zoll-notebook.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000528-acer-aspire-1810tz-412g32n-rot-295-cm-116-zoll-notebook.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000529-acer-aspire-1810tz-412g32n-rot-295-cm-116-zoll-notebook.jpg;2;;True;ml;2.0000;1;;False;False;False;;;;;False;;;;;; +5;0;True;Canon PIXMA MP640 Multifunktionsgerät 3 in 1;"Canon PIXMA MP640 Multifunktionsgerät ";"
    Canon PIXMA MP640 Multifunktionsgerät
     
     
    3 in 1, Drucken, Kopieren, Scannen
     
     
    Der PIXMA MP640 ist ein Multifunktionssystem der Spitzenklasse für exzellenten Fotodruck, schnellen Dokumentendruck und mit vielfältigen Scan- und Kopierfunktionen.
    Dank WiFi- und Ethernet-Unterstützung kann er in ein kabelgebundenes und kabelloses Netzwerk integriert werden.

    Multifunktionssystem: Fotodrucker, Farbscanner und Farbkopierer
    Druckgeschwindigkeit: ca. 9,2 (SW) bzw. 8,1 (Farbe) ISO-Seiten/Min; einzelne Tintentanks
    ca. 20 Sek. für den druck eines 10 x 15 cm Randlosprint
    Automatischer Duplexdruck, doppelte Papierzufuhr und DVD/CD-Druck
    Lieferumfang: PIXMA MP640, Netzkabel, Druckkopf, Tintentanks, DVD/CD-Halter, Kurzanleitung, CD mit Installations-Software und Benutzerhandbuch, Garantiekarte,
    Druckmedien-Broschüre, Fotoglanzpapier Plus II PP-201, MP-101 zur Druckkopfausrichtung
    ";2;False;0;;;"Canon PIXMA MP640 ";canon-pixma-mp640-multifunktionsgeraet-3-in-1;True;True;P-2220;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;2,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;219.0000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;40120,6418055556;22;25;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000523-canon-pixma-mp640-multifunktionsgerat-3-in-1.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000524-canon-pixma-mp640-multifunktionsgerat-3-in-1.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000525-canon-pixma-mp640-multifunktionsgerat-3-in-1.jpg;2;;False;;;;;False;False;False;;;;;False;;;;;; +5;0;True;"Trekstor DataStation pocket x.u s ";Trekstor DataStation pocket x.u s 250 GB;"
    Trekstor DataStation pocket x.u s 250 GB
     
     
    Externe 2.5 Zoll Festplatte
    Exklusives Aluminiumgehäuse für optimale Kühlung der Festplatte
    Speichergröße 250 GB
    Geeignet für das neue Windows® Vista
    Lieferumfang: Festplatte, Nero BackItUp 2 Essentials, Software- / Treiber-CD, USB 2.0-Y-Anschlusskabel, Kurzanleitung, Transportetui
    ";2;False;0;;;"Trekstor DataStation pocket x.u s ";trekstor-datastation-pocket-xu-s;True;True;P-2640;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;89.0000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;40120,6286921296;15;2;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000522-trekstor-datastation-pocket-xu-s.jpg;;;2;;False;;;;;False;False;False;;;;;False;;;;;; +5;0;True;Canon Digital IXUS 100 IS Digitalkamera silber;"Canon Digital IXUS 100 IS Digitalkamera silber ";"

    Canon Digital IXUS 100 IS Digitalkamera silber

    12 Megapixel, 3-fach opt. Zoom, 2,5"" Display, HDMI, SLIM
     
    Die Digital Ixus 100 IS präsentiert sich im atemberaubend-exquisiten, nur 18,4 Millimeter flachen Edelstahlgehäuse. Sie ist in den vier Farben Silber, Schwarz, Gold und Rot erhältlich.

    Ob großformatige Fotoprints oder gezielte Ausschnittvergrößerungen: Die hohe Auflösung von 12,1 Megapixeln sorgt für eine überzeugende Detailwiedergabe.
     
    Für hohe Geschwindigkeit und exzellente Bildqualität mit brillanten Farben und minimiertem Bildrauschen steht der aktuelle Canon-Bildprozessor DIGIC 4.
    12,1 Megapixel Sensor
    3-fach optisches Zoom
    Großes hochauflösendes 2,5 Zoll PureColor LCD II
    Superschlank; HD-Movie und HDMI-Anschluß ¿ mehr Details im Film
     
    Lieferumfang:
    Digital IXUS 100 IS, Trageriemen, Akku, Akku-Ladegerät, USB-Kabel, Video-Kabel
    ";2;False;0;;;"Canon Digital IXUS 100 IS Digitalkamera ";canon-digital-ixus-100-is-digitalkamera-silber;True;True;P-1730;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;199.0000;199.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;40119,9167824074;"56;2095";25;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000514-canon-digital-ixus-100-is-digitalkamera-silber.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000515-canon-digital-ixus-100-is-digitalkamera-silber.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000516-canon-digital-ixus-100-is-digitalkamera-silber.jpg;2;;False;;;;;False;False;False;;;;;False;;;;;; +5;0;True;"Samsung N130-@nyNet 10,1 Zoll Netbook ";5 GB, 16 Zoll, 500 GB, AMD, 4;"
    Samsung N130-@nyNet 10.1 Zoll Netbook  schwarz
     
    Intel Atom N270 1.6GHz, 1GB RAM, 160GB HDD, Intel GMA 950, , Win 7 Starter
     
    Mit dem N130 präsentiert Samsung Electronics ein preisgünstiges und leistungsstarkes Netbook der N-Serie. Ultraleicht und funktional arbeitet das N130 mit aktuellster Samsung Technologie und überzeugt durch Qualität, Design und Performance auf hohem Niveau. Das 1,26 kg leichte Netbook ist mit einem spiegelfreien 10,1-Zoll-Non-Gloss-Display ausgestattet. Mit einer Laufzeit von bis zu 6,5 Stunden gehört es zu den Langläufern im Netbook-Markt.
     
    Flaches und elegantes Gehäuse-Design
    Das N130 mit hochwertigen Komponenten und Materialien steckt in einem flachen, eleganten Design-Gehäuse. Mit seiner umfangreichen Funktionalität und gerade einmal 1,26 kg ist das N130 das leichteste Gerät seiner Klasse und bietet damit Mobilität auf höchstem Niveau.
     
    Optimale Mobilität durch geringen Stromverbrauch
    Das 10,1-Zoll-Non-Gloss-Display des N130 ist extrem energieeffizient und brilliert mit einem scharfen und hellen Bild ohne Spiegelungen sogar bei extremer Sonneneinstrahlung. Der geringe Stromverbrauch garantiert optimale Mobilität durch Samsungs führende Lithium-Ionen-Akku-Technik und ermöglicht eine außergewöhnliche Laufzeit von bis zu 6,5 Stunden.
     
    Immer in Verbindung - mit WLAN
    Schnellen Zugriff auf Internet und andere Inhalte gewährleistet das Netbook via 802.11b/g/n WLAN - jederzeit und überall. Darüber hinaus ist das Netbook mit einem eingebauten Mikrofon und Kopfhöreranschluss - beispielsweise für VoIP-Telefonie - ausgestattet. Mit drei USB 2.0-Anschlüssen und einem 3-in-1-Kartenleser erlaubt das N130 die Wahl zwischen zahlreichen Datenaustausch-Optionen. So lassen sich Informationen, Bilder, Musiktitel und Filme mit allen modernen Peripheriegeräten wie Kameras, externen Festplatten oder Audio/Video-Geräten blitzschnell austauschen. 
    ";2;False;0;;;"Samsung N130@nynet-N270BN 10.1 Zoll Netbook ";samsung-n130-nynet-101-zoll-netbook;True;True;P-0810;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;284.9000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;40116,2153125;5;5;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000307-samsung-n130-nynet-101-zoll-netbook.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000308-samsung-n130-nynet-101-zoll-netbook.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000309-samsung-n130-nynet-101-zoll-netbook.jpg;2;;False;;;;;False;False;False;;;;;False;;;;;; +5;0;True;"Asus EEE PC 1005HA-M 10,1 Zoll Netbook ";2 GB, 16 Zoll, 350 GB, Tantel, 4;"
    Asus EEE PC 1005HA-M 10,1 Zoll Netbook mit Windows 7 Starter weiß
     
     
    Langläufer: Eee PC 1005HA. Mit dem Eee PC 1005HA hat ASUS ein stylisches Geräte im Portfolio, das sich durch ihre lange Akkulaufzeit und ein mattes, nicht spiegelndes Display auszeichnen. Der Eee PC 1005HA-M inklusive Intel Atom N270 Prozessor kommt auf eine Akkulaufzeit von 8,5 Stunden. Die Geräte arbeiten mit dem Microsoft Windows 7 Betriebssystem und sind dadurch besonders intuitiv und komfortabel zu bedienen.
     
    Das Betriebssystem Microsoft Windows 7
    Mit Windows 7 stellt Microsoft ein Betriebssystem vor, das sich durch eine leichte Bedienung und einen ressourcensparenden Umgang mit der Hardware auszeichnet. Selbst auf Rechnern mit begrenzter Prozessorpower läuft das Betriebssystem mühelos. So benötigt der PC nur noch wenige Augenblicke zum Hochfahren und auf der übersichtlichen Taskleiste lassen sich anhand von Symbolen schnell die passenden Files erkennen. Spielend leicht wird auch die Verwaltung von Filmen, Bildern und Videos. Mithilfe der Bibliotheken lassen sich diese schnell organisieren. Und in punkto Sicherheit bringt das Betriebssystem einiges mit. Darunter die Benutzerkontensteuerung, die sich individuell konfigurieren lässt. 
     
    Ehe PC 1005HA-M: Klasse Leistung zu unschlagbarem Preis
    Der Eee PC 1005HA-M unterscheidet sich von seinem großen Bruder durch Prozessor, Akkukapazität sowie durch die integrierten Wireless Funktionen. Ausgestattet mit einem Intel Atom N270 Prozessor, einem 4400 mAh 6 Zellen Akku für bis zu 8,5 Stunden Laufzeit, WLAN 802.11n Standard sowie weiteren Top Merkmalen, überzeugt der Eee PC 1005HA-M zu einem unschlagbaren Preis.
     
    Eee PC 1005HA-M: Funktionalität meets Design
    Mit dem kompakten Eee PC 1005HA-M trägt ASUS seinem Anspruch, in den Produkten höchste Funktionalität mit formvollendetem Design zu verbinden, ein weiteres Mal Rechnung. So besticht der Eee PC durch sein elegantes und gleichzeitig unempfindliches Gehäuse, das mit klaren Linien und nach unten schmaler zulaufenden Kanten dem schlanken Design einer Muschel nachempfunden ist. 
      
    Aber auch das Innenleben der Kleinen kommt ganz groß raus. Als gewohnt kontaktfreudig erweisen sich die Neulinge dank VGA Port für den Anschluss eines Monitors sowie drei USB 2.0 Schnittstellen, um Maus, Tastatur oder Digicam anzuschließen. Wer Bilder direkt von der SD oder MMC Speicherkarte auf den Eee PC übertragen möchte, nutzt den integrierten Kartenleser. Für das Speichern der Fotos stehen bei den Modellen eine 160 GB S-ATA Festplatte zur Verfügung. Die Modelle sind - wie alle Eee Familienmitglieder - ausgesprochen einfach zu bedienen. Das 10 Zoll WSVGA Display mit stromsparender LED-Hintergrundbeleuchtung sowie die große Tastatur, die zu 92% einer Standard Notebooktastatur entspricht, gewähren zusätzlichen Komfort. Für Chats oder Videokonferenzen hat ASUS die Minis zudem mit einer 1.3 Megapixel Web-/Videokamera sowie einem Mikrofon ausgestattet.
    ";2;False;0;;;"Asus EEE PC 1005HA-M 10,1 Zoll Netbook ";asus-eee-pc-1005ha-m-101-zoll-netbook;True;True;P-0800;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;291.9000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;40115,7052199074;5;37;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000300-asus-eee-pc-1005ha-m-101-zoll-netbook.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000301-asus-eee-pc-1005ha-m-101-zoll-netbook.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000302-asus-eee-pc-1005ha-m-101-zoll-netbook.jpg;2;;False;;;;;False;False;False;;;;;False;;;;;; +5;0;True;"Trekstor DataStation maxi g.u 1,5 TB ";"Trekstor DataStation maxi g.u externe Festplatte 1,5 TB ";"

    Trekstor DataStation maxi g.u Externe Festplatte 1,5 TB

     
     
    USB 2.0 inkl. Nero BackItUp 2 Essentials
     
     
     
    Optimale Speicherplatzerweiterung
    Die DataStation maxi g.u ist die perfekte Lösung für das
    tägliche Backup oder die Speicherplatzerweiterung Ihres PCs.
    Die externe 3,5“ Festplatte bietet ausreichend Platz
    zum Speichern und Archivieren der heimischen Musik-
    und Videosammlung, digitaler Fotos oder anderer Dateien. 
     Schnell und bedienungsfreundlich
    Mit dem Hi-Speed USB 2.0 Anschluss bietet die
    DataStation maxi g.u einen schnellen Datentransfer.
    Die Festplatte ist zudem bereits vorformatiert und
    ohne Treiber sofort betriebsbereit.
    Unterstützt werden alle gängigen
    Dateisysteme von Windows®, Linux® und Mac® OS X,
    sowie die Betriebssysteme Microsoft
    Windows® 2000 / XP/ Vista, Mac® OS X ab 10.3 und Linux® ab Kernel 2.6.x.
    Die Festplatte wird über das mitgelieferte Netzteil mit Strom versorgt. 
    Der Ein-/Ausschalter am Festplattengehäuse verhindert überflüssigen Stromverbrauch. 
    Exklusives Aluminiumgehäuse
    Das exklusive Aluminiumgehäuse der DataStation maxi g.u
    sorgt für die optimale Kühlung der Festplatte,
    so kommt die externe Festplatte
    ohne Lüfter aus und ist leise während des Betriebs 
    Inklusive Nero Software „BackItUp2 Essentials“
    Die ebenfalls im Lieferumfang enthaltene
    Nero Software rundet das Bild der mobilen, externen Festplatte perfekt ab.
    Mit Nero BackItUp2 Essentials können Sie Backups Ihrer Daten sehr einfach planen.
    So können einzelne Dateien oder ganze Laufwerke gesichert werden.
    Um die Datenmenge gering zu halten, komprimiert die Software die Backups direkt „on the fly“.
    Auf Wunsch lassen sich die gesicherten Daten auch per Passwortschutz vor unbefugtem Zugriff schützen.
    ";2;False;0;;;"Trekstor DataStation maxi g.u-externe Festplatte 1,5 TB ";trekstor-datastation-maxi-gu-15-tb;True;True;P-2630;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;139.0000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;40101,7793981481;15;2;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000129-trekstor-datastation-maxi-gu-1tb.jpg;;;2;;False;;;;;False;False;False;;;;;False;;;;;; +5;0;True;"NAVIGON 2410 Navigationssystem inkl. TMC ";"NAVIGON 2410 Navigationssystem inkl. TMC ";"

    NAVIGON 2410 Navigationssystem inkl. TMC

     
     
    3,5"" Display, EU Kartenmaterial mit 40 Ländern, Fußgängernavigation im Hochformat
     
     
    Fußgänger-Navigation
    bringt Sie ohne Umwege ans Ziel, auch wenn Sie mal nicht im Auto unterwegs sind.
    So können Sie z. B. unbekannte Städte ganz gezielt erkunden und finden auch die verstecktesten Plätze und Sehenswürdigkeiten.
    Dabei halten Sie Ihr NAVIGON übrigens ganz bequem im Hochformat in einer Hand – und haben so die andere jederzeit frei.
     
    NAVIGON Zielgerade
    navigiert Sie nach dem Parken die letzten Meter zu Ihrem eigentlichen Ziel. Denn: Nicht vor jedem geplanten Ziel ist auch ein Parkplatz für Ihr Fahrzeug.
    Deshalb lotst Ihr NAVIGON Sie sicher auf dem letzten Stück zu Fuß. Und findet auf dem Rückweg auch Ihr Auto für Sie wieder.
     
    E-Kompass
    Großstädte können auch zu Fuß sehr unübersichtlich sein. Damit Sie nicht mit den Himmelsrichtungen durcheinander kommen, unterstützt Sie im Fußgängermodus ein elektronischer Kompass.
    So wissen Sie sofort, ob Sie nach links, rechts, oben oder unten laufen müssen. Beziehungsweise nach Westen, Osten, Norden oder Süden.
     
    Clever Parking
    hilft Ihnen bei der Parkplatzsuche. Kurz vor Ihrem Ziel zeigt Ihnen Clever Parking Parkplätze in der näheren Umgebung an.
    In Deutschland, Österreich, Schweiz und Luxemburg werden Sie sogar über Parkgebühren und Öffnungszeiten informiert. So vermeiden Sie langes Suchen und sparen dabei Geld.
     
    NAVIGON MyRoutes
    Je nachdem, welcher Fahrertyp Sie sind, empfiehlt Ihnen NAVIGON MyRoutes die beste Route – zugeschnitten auf Ihren persönlichen Fahrstil, den Wochentag und die Tageszeit.
    Darüber hinaus zeigt Ihnen Ihr NAVIGON bis zu zwei weitere Routen. Das schafft Transparenz. Sie entscheiden, ob Sie unserer Empfehlung folgen oder eine der Alternativen wählen.
     
    TMC-Routeninfo
    zeigt Ihnen im Fall einer Staumeldung eine Alternativroute mit aktualisierter Entfernung und Ankunftszeit.
    Sie entscheiden, ob eine Umfahrung in Ihrem Fall sinnvoll ist oder ob Sie die ursprüngliche Route beibehalten wollen.
     
    Lieferumfang
    NAVIGON 2410, Kurzanleitung, KfZ-Ladekabel mit integrierter TMC Antenne, KfZ Halterung, USB-Kabel, Europa Kartenmaterial
    ";2;False;0;;;"NAVIGON 2410 Navigationssystem inkl. TMC ";navigon-2410-navigationssystem-inkl-tmc;True;True;P-2160;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;169.0000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;40097,6045833333;68;14;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000299-navigon-2410-navigationssystem-inkl-tmc.jpg;;;2;;False;;;;;False;False;False;;;;;False;;;;;; +5;0;True;Adobe Premiere Elements 8;Adobe Premiere Elements 8 deutsch WIN;"

    Adobe Premiere Elements 8 deutsch WIN


    Mit Adobe® Premiere® Elements 8 erstellen Sie ohne Aufwand erstklassige Videos, die Sie mit professionellen Effekten bereichern und auf nahezu jedem Medium präsentieren können.
    Dank eines leistungsfähigen und bedienungsfreundlichen Organizer behalten Sie den Überblick über Ihre Videos und Fotos.
     
    Arbeiten Sie wie die Profis, indem Sie beispielsweise Grafiken und Effekte einfügen, die sich mit den zugehörigen Objekten zusammen bewegen.
    Vielseitigkeit und Benutzerfreundlichkeit
    Filmproduktion in wenigen Schritten
    Filmerstellung per Drag-and-Drop
    Zentrale Umgebung für Bearbeitung und Vorschau
    Professionelle Spezialeffekte und Überblendungen
    Aufwertung von Videos mit Musik
     
    Systemanforderungen:
    Prozessor mit 2 GHz und SSE2-Unterstützung; für HD oder Blu-ray: Prozessor mit 3 GHz; für AVCHD: Dual-Core-Prozessor
     
    Microsoft® Windows® XP mit Service Pack 2, Windows Media Center, Windows Vista® oder Windows 7
    Für Windows XP: 512 MB RAM (2 GB für HD-Bearbeitung einschließlich HDV, AVCHD oder Blu-ray)
    Für Windows Vista and Windows 7: (1 GB RAM (2 GB für HD-Bearbeitung einschließlich HDV, AVCHD oder Blu-ray)
    4,5 GB freier Festplattenspeicher
    Farbmonitor mit 16-Bit-Grafikkarte
    1024 x 768 Punkt Monitorauflösung mit 96 dpi oder geringer
    Mit Microsoft DirectX 9 oder 10 kompatibler Sound- und Grafikkartentreiber
    DVD-ROM-Laufwerk (kompatibler DVD-Brenner für die Erstellung von DVDs, kompatibler Blu-ray-Brenner für die Erstellung von Blu-ray Discs erforderlich)
     
    ";2;False;0;;;Adobe Premiere Elements 8;adobe-premiere-elements-8;True;False;P-3030;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;9200;False;False;0;1;1;0;False;1;10000;;False;False;False;False;112.9000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;40097,5865856481;31;20;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000297-adobe-premiere-elements-8.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000298-adobe-premiere-elements-8.jpg;;2;;True;ml;1.0000;1;;False;False;False;;;;;False;;;;;; +5;0;True;Adobe Photoshop Elements 8;Adobe Photoshop Elements 8 deutsch WIN;"

    Adobe Photoshop Elements 8 deutsch WIN

     

    Adobe® Photoshop® Elements 8 ist die ideale Kombination aus Leistungsfähigkeit und Benutzerfreundlichkeit.
    Verwalten Sie Ihre Bilder und Videos bequem zentral, machen Sie aus alltäglichen Motiven eindrucksvolle Kunstwerke, und gestalten Sie unverwechselbare Kreationen für Print und Web.
    Jetzt können Sie perfekt ausgeleuchtete Bilder erstellen oder mit verschiedenen Bildgrößen experimentieren, ohne dass Verzerrungseffekte auftreten. Mit den erweiterten Suchfunktionen lassen sich Bilder wahlweise nach Qualität oder nach Motiv sortieren.

    Vielseitigkeit und Benutzerfreundlichkeit
    Praktischer Medien-Manager
    Sekundenschnell retuschieren
    Intuitive Anpassung von Farbe und Belichtung
    Praktische Hilfestellungen
    Herausragende Ergebnisse
    Gelungene Präsentation im Web
    Effiziente Umsetzung kreativer Ideen
     
    Systemanforderungen:
    Prozessor mit mindestens 1,6 GHz
    Microsoft® Windows® XP mit Service Pack 2 oder 3, Windows Vista® oder Windows 7
    1 GB RAM
    2 GB freier Festplattenspeicher
    Farbmonitor mit 16-Bit-Grafikkarte
    1024 x 576 Punkt Monitorauflösung mit 96 dpi oder geringer
    Mit Microsoft DirectX 9 kompatibler Grafikkartentreiber
    DVD-ROM-Laufwerk
     
    ";2;False;0;;;Adobe Photoshop Elements 8;adobe-photoshop-elements-8;True;False;P-3020;;;False;0;False;;False;False;0;False;0;1;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;109.0000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;40097,5787731481;31;20;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000295-adobe-photoshop-elements-8.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000296-adobe-photoshop-elements-8.jpg;;2;;False;;;;;False;False;False;;;;;False;;;;;; +5;0;True;"Garmin nüvi 255T Navigationssystem Europa ";"Garmin nüvi 255T Navigationssystem Europa inkl. TMC ";"
    Garmin nüvi 255T Navigationssystem Europa inkl. TMC
     

    3,5"" Touchscreen Display, PhotoNavigation, MicroSD-Kartenslot und ecoRoute 
     
    Bedienerfreundliches Einsteigernavigationsgerät mit elegantem, ultra-schlankem Design und brillantem 3,5 (8,9cm Bilddiagonale)
    Touchscreen Display + TMC Verkehrsfunkempfänger
    Kartenmaterial für 40 Länder in West- und Osteuropa intern vorinstalliert ecoRoute:
    reduziert den Kraftstoffverbrauch, CO2-Emissionen und schont die Umwelt, spart bares Geld und füllt die Reisekasse auf.
    PhotoNavigation mit Garmin Connect: Sie können Sehenswürdigkeiten und Bilder herunterladen und als Ziel auswählen
    Lieferumfang: Garmin nüvi 255T mit Kartenmaterial Europa, TMC Verkehrsfunkempfänger,
    Saugnapfhalterung für die Windschutzscheibe, Armaturenhalterung, Schnellstartanleitung, KFZ-Anschlusskabel
     
    ";2;False;0;;;"Garmin nüvi 255T Navigationssystem Europa ";garmin-nuevi-255t-navigationssystem-europa;True;True;P-2090;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;129.0000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;40096,6680208333;67;44;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000294-garmin-nuvi-255t-navigationssystem-europa.jpg;;;2;;False;;;;;False;False;False;;;;;False;;;;;; +5;0;True;"Logitech Webcam C200 ";"Logitech Webcam C200 ";"
    Sie suchen nach einem Basispaket für eine einfache, klare Videokommunikation? Die preisgünstige Logitech
    Webcam C200 stellt Ihnen alle Funktionen zur Verfügung, die Sie für realitätsnahe Videogespräche benötigen. Sie bezahlen nicht für Zusatzfeatures, die Sie wahrscheinlich ohnehin nicht nutzen. Ihre Webkamera wird mit der Logitech Vid-Software geliefert, die Ihnen mit nur einem Mausklick das Führen von Videogesprächen ermöglicht – schnell, kostenlos, einfach. Der VGA-Sensor erfasst Ihre Live-Videobilder in natürlichen und realistischen Farben. Sie können auch Schnappschüsse machen, die per Software auf eine Auflösung von 1,3 Megapixeln hochgerechnet werden. Und das praktische eingebaute Mikrofon sorgt mit der Logitech RightSound- Technologie dafür, dass Ihre Stimme klar verständlich ist. Dank der Universalmonitorhalterung können Sie diese Webkamera problemlos an jedem Desktopmonitor oder Notebookrechner befestigen.
     

    Seien Sie persönlich dabei - mit dem Basispaket für eine kostenlose und klare Videokommunikation
     
    Ein Besuch bei Ihren Freunden und Verwandten in der Ferne ist ab sofort wesentlich einfacher. Mit der preiswerten Logitech Webcam C200 sind Sie nämlich direkt bei den Menschen, die Ihnen am Herzen liegen. Installieren Sie einfach Ihre Webkamera, und schon können Sie Ihr erstes Videogespräch führen. Dazu ist nur ein einfacher Mausklick erforderlich, wenn Sie die Vid-Software nutzen, die mit Ihrer Webkamera mitgeliefert wird. Plaudern Sie persönlich mit Ihren Enkeln in der Nachbarstadt – oder mit Ihrer besten Freundin am anderen Ende der Welt. Der VGA-Sensor sorgt dafür, dass Ihre Gesprächspartner Sie in ganz natürlichen Farben sehen. Und dank dem eingebauten Mikrofon mit der Logitech RightSound-Technologie, die störende Nebengeräusche herausfiltert, können sie jedes Wort aus Ihrem Mund deutlich verstehen. Wenn Sie ein praktisches Basispaket für Videogespräche suchen und auf komplizierte Zusatzfunktionen verzichten können, ist dies die richtige Webkamera für Sie.
     
    Die wichtigsten Funktionen
     
    Webkameras von Logitech - bessere Videoqualität kommt nicht von ungefähr
     
    Sobald Sie Ihr erstes Videogespräch führen, wird Ihnen klar werden, warum Logitech die erste Wahl von Webkamera-Anwendern auf der ganzen Welt ist. Bei der Entwicklung jeder Webkamera ist das oberste Designziel von Logitech, eine erheblich klarere Bild- und Tonqualität als andere Webkameras zum gleichen Preis zur Verfügung zu stellen. Dabei geht es geht nicht nur um Features wie Qualität des Objektivs, Sensor-Auflösung und Software. Es geht viel mehr darum, wie alle diese Dinge ineinandergreifen, um Ihnen eine Videokommunikation mit mehr Komfort und Vergnügen zu ermöglichen.
       
    Der VGA-Sensor zeigt Ihr wahres Ich
     
    Nur weil Sie nicht so viel Geld ausgeben wollen, heißt das noch lange nicht, dass Sie auf Qualität verzichten müssen. Ihre Logitech-Webkamera bietet Ihnen Extras, die Sie bei einer so preisgünstigen Webkamera wahrscheinlich gar nicht erwarten würden. Dazu zählt ein Sensor, der Live-Videobilder mit echter VGA-Auflösung in realitätsnahen Farben aufnimmt. Keine grünlich-bleichen oder verschwommenen Gesichter. Ihre Gesprächspartner bekommen Ihr wahres, natürliches Ich zu sehen. 
    Auflösung mit bis zu 1,3 Megapixeln – verschicken Sie brillante digitale Schnappschüsse
     
    Sie möchten Ihre Webkamera auch noch anderweitig nutzen? Drücken Sie einfach auf den Schnappschussauslöser, um realitätsnahe Fotos aufzunehmen, die per Software auf 1,3 Megapixel hochgerechnet werden. Und da sich die Schnappschüsse schon auf Ihrem Rechner befinden, können Sie sie ganz einfach per E-Mail an Verwandte oder Freunde verschicken.   
     
    Eingebautes Mikrofon mit geräuschdämpfender RightSound- Technologie
     
    Sprechen Sie ganz natürlich, das eingebaute Mikrofon der Webkamera nimmt jedes Wort, jedes Lachen, jedes Flüstern auf. Die RightSound-Technologie filtert automatisch störende Hintergrundgeräusche heraus, sodass Sie Ihre Gespräche immer mit kristallklarer Tonqualität führen können. 
     
    Vielseitige Universalhalterung für die Befestigung an jedem Desktop- oder Notebook-Rechner
     
    Was das praktische Design anbetrifft, hat Logitech an alles gedacht. Die Webkamera lässt sich problemlos und sicher an LCD-Bildschirmen ebenso wie an ultraflachen Notebook-Monitoren befestigen. Die Halterung kann auch eingeklappt werden, sodass Sie die Kamera auf einer ebenen Oberfläche wie beispielsweise einem Regal über Ihrem Computer aufstellen können.   
     
    Problemlose Videogespräche dank Unterstützung aller Instant-Messaging-Programme
     
     
    Alles, was Sie für Videogespräche benötigen, ist die Webkamera, ein schneller Internet-Zugang und ein Videokommunikations-Programm. Wenn Sie Ihre Freunde und Verwandten schnell, einfach und kostenlos von Angesicht zu Angesicht sprechen wollen, empfehlen wir Ihnen Logitech Vid als Software der Wahl. Sie können aber auch andere IM-Programme vom Internet herunterladen. Im Gegensatz zu den Produkten manch anderer Anbieter funktionieren die Webkameras von Logitech mit allen Instant-Messaging-Programmen, die Sie nutzen und die Ihre Gesprächspartner verwenden. Sie können also ganz problemlos und ohne großen Aufwand Videogespräche führen.
     
    Mit der Logitech Webcam C200 und kostenlosen Video-Anwendungen können Sie „persönlich vor Ort“ sein – in Ihrer Stadt oder an jedem anderen Fleck der Erde. 
     
     
    ";2;False;0;;;"Logitech Webcam C200 ";logitech-webcam-c200;True;True;P-2920;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;34.9000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;40096,6475;"27;2095";11;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000290-logitech-webcam-c200.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000291-logitech-webcam-c200.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000292-logitech-webcam-c200.jpg;2;;False;;;;;False;False;False;;;;;False;;;;;; +5;0;True;Western Digital My Book 1 TB;"Western Digital BAAF0010HBK My Book Essential 1TB ";"
    Western Digital BAAF0010HBK My Book Essential

    1TB externe Festplatte 
     
    Elegantes Design
    Ihre gesamten Daten auf einen Blick und einfache Datei-Wiederherstellung
    Passwortschutz und 256-bit Hardware basierte Verschlüsselung
    Automatische, kontinuierliche Datensicherung für alle Computer in Ihrem Netzwerk
    Lieferumfang: Western Digital My Book Essential 1TB externes Festplattenlaufwerk,
    WD SmartWare-Software, USB-Kabel, Netzteil, Schnellanleitung
    ";2;False;0;;;"Western Digital My Book Essential Edition 1 TB ";western-digital-my-book-1-tb;True;True;P-2600;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;129.0000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;40090,625150463;14;21;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000286-western-digital-my-book-1-tb.jpg;;;2;;False;;;;;False;False;False;;;;;False;;;;;; +5;0;True;Apple iPod Classic 160 GB schwarz;"Apple iPod Classic 160 GB schwarz ";"

    Apple iPod Classic 160 GB schwarz

     
    iPod classic: Freiraum -Und zwar jede Menge.
    160 GB sind wirklich eine ganze Menge Platz. Da lässt sich eine komplette Mediathek locker unterbringen und überallhin mitnehmen.
     
    Ein musikalisches Genie
    Stellen Sie vor, Sie hören einen Song. Toll wären jetzt andere Titel, die gut dazu passen. Was machen Sie? Ganz einfach: Sie verwenden die neue Funktion ""Genius"". Diese findet die Songs in Ihrer Mediathek, die gut zusammenpassen. Sie erhalten eine Genius Wiedergabeliste, die Sie sofort anhören, sichern oder sogar aktualisieren können. Verlassen Sie sich also auf den Genius von iTunes, wenn Sie einen Mix wollen, auf den Sie selbst nicht gekommen wären.
     
    Platz satt
    Der iPod classic bietet mit seinen 160 GB Speicherkapazität Platz für bis zu 40.000 Songs, 200 Stunden Videos, 25.000 Fotos oder eine beliebige Kombination dieser Inhalte. Und mit bis zu 36 Stunden Batterielaufzeit beweist der iPod classic auch ganz schön viel Kondition.
     
    Spaß auf Knopfdruck
    Sie findeen immer ganz leicht genau das, was Sie sehen oder hören wollen. Mit dem Click Wheel können Sie mit ""Cover Flow"" Ihre Alben durchblättern, oder Sie stöbern über verschiedene Kategorien wie Wiedergabeliste, Künstler, Album oder Musikrichtung in Ihren Songs und Videos. Sie können natürlich auch nach einem bestimmten Titel oder Interpreten suchen. Lust auf einen neuen Mix? Klicken Sie einfach auf ""Zufällige Titel"".
     
    Filme und Fernsehsendungen ansehen
    Auf dem fantastischen 2,5"" Display kommen Videos richtig zur Geltung. Sie können im iTunes Store Filme kaufen oder ausleihen, Fernsehsendungen kaufen und Video-Podcasts laden. Dann können Sie alles mit Ihrem iPod classic synchronisieren und immer und überall ansehen.
     
     
    Spiele auf dem iPod
    Wenige Fingertipps, viele Stunden Spielspaß. Vortex, iQuiz und Klondike sind schon auf dem iPod classic vorinstalliert, im iTunes Store können Sie weitere dazukaufen, z. B. Cake Mania. Alle iPod Spiele sind speziell für die iPod Oberfläche optimiert.
     
    Fotos zeigen
    Ihre Fotos aus iPhoto auf einem Mac oder aus Adobe Photoshop Elements und Adobe Photoshop Album auf einem PC bekommen Sie mit iTunes auf den iPod classic. Sie können Diashows mit Musik und Übergängen auf dem iPod classic oder mit optional erhältlichen Apple Komponenten oder mit einem Composite-AV-Kabel sogar auf dem Fernseher zeigen.
     
    Umweltverträglichkeit
    Der iPod classic steht für das kontinuierliche Engagement von Apple in puncto Umweltschutz. Die folgenden Merkmale tragen zu einer geringen Umweltbelastung bei:
     
        Arsenfreies Displayglas
        Ohne bromhaltige Flammschutzmittel
        Display mit LED-Hintergrundbeleuchtung ohne Quecksilber
        Frei von PVC
        Recyclingfähiges Gehäuse aus Aluminium und Edelstahl
     
    Produktbeschreibungen
    Freiraum. Und zwar jede Menge. 160 GB sind wirklich eine ganze Menge Platz. Da lässt sich eine komplette Mediathek locker unterbringen und überallhin mitnehmen.
     
    > Highlights
    - Click Wheel
    - Frequenzbereich: 20 Hz bis 20.000 Hz
    - Weitere unterstützte Audioformate: Protected AAC (aus dem iTunes Store), MP3 VBR, Audible (Formate 2, 3, 4, Audible Enhanced Audio, AAX und AAX+), Apple Lossless und WAV
    - Platz für bis zu 40.000 Songs im 128 KBit/Sek. AAC-Format
    - Platz für bis zu 25.000 vom iPod anzeigbare Fotos
    - Platz für bis zu 200 Stunden Videomaterial
    - Speichert Daten auf einer USB-Festplatte
    - Akkuladezeit: ca. 4 Std. (schnelles Laden auf 80%ige Kapazität in 2 Std.)
     
    > Grundeigenschaften
    - Breite: 103.5 mm
    - Höhe: 61.8 mm
    - Tiefe: 10.5 mm
    - Gewicht: 140.0 g
    - Farbe: Schwarz
     
    > Wiedergabeformate Audio
    - AAC
    - MP3
    - WAV
     
    > Akku
    - Akkutyp: Li-Ion
     
    > Display
    - Displaytechnologie: LCD
    - 2.5- Display
    - Bilddiagonale: 6.35 cm
    - Auflösung Breite: 320 Pixel
    - Auflösung Höhe: 240 Pixel
    - Hintergrundbeleuchtung: ja
     
    > Speicher
    - Speicherkapazität 160 GB
     
    > Anschlüsse
    - USB
    - USB-Standard 2.0
     
    > Audio-Anschlüsse
    - Headsetanschluss: 3,5 mm Klinke
    - ipod-Anschluss via IPOD Connector
     
    > Lieferumfang
    - iPod classic
    - Apple Earphones
    - USB 2.0 Kabel
    - Dock-Adapter
    - Dokumentation
     
    > Umweltverträglichkeit
    Der iPod nano steht exemplarisch für das Engagement von Apple in puncto Umweltschutz. Die folgenden Merkmale des iPod nano tragen zu seiner geringeren Umweltbelastung bei:
    - Arsenfreies Glas
    - Frei von bromhaltigen Flammschutzmitteln
    - Frei von Quecksilber
    - Frei von PVC
    - Besonders recyclingfähig
     
    ";2;False;0;;;Apple iPod Classic 120 GB schwarz;apple-ipod-classic-160-gb-schwarz;True;True;P-1400;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;239.9000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;40089,850162037;50;1;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000284-apple-ipod-classic-160-gb-schwarz.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000285-apple-ipod-classic-160-gb-schwarz.jpg;;2;;False;;;;;False;False;False;;;;;False;;;;;; +5;0;True;"Logitech MK300 schnurlose Tastatur + Maus schwarz ";"Logitech MK300 schnurlose Tastatur + Maus schwarz ";"

    Logitech MK300 schnurlose Tastatur + Maus schwarz
     

     
    Kabellose Technologie für eine schnelle und zuverlässige Verbindung, die sofort einsatzbereit ist
    Sondertasten und programmierbare F-Tasten
    Flüssigere und reaktionsschnellere Abtastung als herkömmliche optische Mäuse
    Automatischer Energiesparmodus
     
    Lieferumfang:
    Logitech MK300 Tastatur schnurlos, Logitech MK300 Maus schnurlos, USB-Empfänger, Batterien vom Typ AA, Handbuch, CD mit Software.
    ";2;False;0;;;;logitech-mk300-schnurlose-tastatur-maus-schwarz;True;True;P-2800;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;49.0000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;40081,7438194444;21;11;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000513-logitech-mk300-schnurlose-tastatur-maus-schwarz.jpg;;;1;;False;;;;;False;False;False;;;;;False;;;;;; +5;0;True;Samsung NC10 anyNet 10,2 Zoll Netbook;"Samsung NC10 anyNet 10,2 Zoll Netbook schwarz ";"
    Samsung NC10 anyNet10,2"" Netbook

    Intel Atom N270 1.6GHz, 1GB RAM, 160GB HDD, Intel GMA 950 XP Home
     
    NC10-anyNet: Entwickelt für das ""mobile Leben"". Entwickelt für höchste Ansprüche in innovativem Design. Das ultrakompakte und leichte Gehäuse bietet eine Reihe von praktischen Features, die das mobile Leben vereinfachen. Brillante Technologie angepasst an das rasante und digitale Leben für noch mehr Mobilität.
     
    Schlankes Design
    Mit einem optimierten 10,2 Zoll Breitbild Display für ein makelloses visuelles Erlebnis, ist das schlanke NC10 lediglich 1,19 cm hoch und passt nahezu in alle Taschen. Das widerstandsfähige Gehäuse bietet ein Maximum an Tragekomfort und Verlässlichkeit sowie hochwertiger Ergonomie und Stil.
     
    Videokonferenz
    Ob Videokonferenzen oder Live Messaging - die integrierte 1,3 Megapixel Kamera lässt sie noch leichter mit Freunden, Familie und Kollegen in Kontakt bleiben. Die Kamera verbindet die Auflösung und die Bildqualität einer Fotokamera mit der nachhaltig hohen Bildfrequenz einer Videokamera.
     
    Robustes Gehäuse, langlebig und verlässlich
    Fühlen Sie sich sicher mit dem robusten Protect-o-Edge Gehäuse, das für Langlebigkeit und Verlässlichkeit steht. Eine aufwendige Serie von 54 Qualitätstests, die von schnellen Temperaturwechseln bis zu elektrischen Überspannungen reichen, gewährleistet neue Standards in Punkto Belastbarkeit und Ausdauer.
     
    Antibakterielle Tastatur
    Die SilverNano Technologie beschichtet die Tastatur mit nano-kleinen Silberionen, die das Überleben und die Neuentstehung von Bakterien verhindern. Innerhalb von 24 Stunden werden 99,9% aller Bakterien abgetötet und es entsteht eine hygienische Arbeitsatmosphäre.
     
    Leichtgewicht
    Als eines der weltweit leichtesten 10,2 Zoll Mini Notebooks seiner Klasse, mit einem Gewicht von nur 1,45 kg, ist das NC10 voll bepackt mit neuester Technologie und garantiert dabei maximale Mobilität und Leistung.
      
    Vollständige Notebook-Tastatur
    Die vollständige Notebook-Tastatur bietet optimalen Schreibkomfort. Ergonomisches Design und optimierte Tastenabstände machen das Arbeiten und Kommunizieren angenehmer und ermöglichen schnelleres sowie fehlerloses Schreiben.
     
    Voll ausgestattet für einfachen Datenaustausch
    Einfacher Datenaustausch dank einer Vielzahl an Anschlussmöglichkeiten, inklusive einem Kartenleser und drei USB-Anschlüssen, so dass Sie problemlos Bilder, Filme und Daten auf und von nahezu allen modernen Kameras, periphären oder audiovisuellen Geräten transferieren können.
    ";2;False;0;;;;samsung-nc10-anynet-102-zoll-netbook;True;True;P-0860;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;329.9000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;40066,9226388889;6;5;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000511-samsung-nc10-anynet-102-zoll-netbook.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000512-samsung-nc10-anynet-102-zoll-netbook.jpg;;2;;False;;;;;False;False;False;;;;;False;;;;;; +5;0;True;Casio EXILIM EX-Z2 Digitalkamera schwarz;"Casio EXILIM EX-Z2 Digitalkamera schwarz ";"
    Casio EXILIM EX-Z2 SR Digitalkamera schwarz
     
    12 Megapixel, 3-fach opt. Zoom, 2,7"" Display


    Die EX-Z2 versteckt in ihrem flachen Designgehäuse leistungsstarke 12,1 Megapixel.
    Der CCD-Chip mit 12,1 Megapixel erlaubt nicht nur brillante Fotos zu machen, sondern auch Bildausschnitte zu bearbeiten, zu vergrößern und im Wunschformat auszudrucken – bei hervorragender Qualität und ohne Verlust von Bildinformationen.
     
    12,0 Megapixel CCD-Chip
    3fach optischer Zoom, 4fach digitaler Zoom
    6,9 cm (2.7 Zoll) Wide Screen TFT- Farbdisplay
    23 BEST SHOT Programme, Gesichtserkennung, Selbstauslöser, Speicherkartenslot für SD-/SDHC, MMC-/MMCplus und Eye-Fi Wireless Speicherkarten
     
    Lieferumfang:
    Digitalkamera, Akku, Ladegerät, USB-Kabel, AV-Kabel, Trageriemen, Grundlegende Referenz, CD-ROM
    ";2;False;0;;;"Casio EXILIM EX-Z2 SR Digitalkamera ";casio-exilim-ex-z2-digitalkamera-schwarz;True;True;P-1750;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;149.0000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;40064,7887268519;"57;2095";9;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000499-casio-exilim-ex-z2-digitalkamera-schwarz.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000500-casio-exilim-ex-z2-digitalkamera-schwarz.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000501-casio-exilim-ex-z2-digitalkamera-schwarz.jpg;2;;False;;;;;False;False;False;;;;;False;;;;;; +5;0;True;Samsung Syncmaster P2250 21,5 Zoll TFT Monitor schwarz;"Samsung Syncmaster P2250 21,5 Zoll TFT Monitor schwarz ";"
    Samsung Syncmaster P2250 21,5 Zoll TFT Monitor schwarz

    DVI ,Kontrast 50000:1, 2ms Reaktionszeit

    DieSyncMaster 50er Serie überzeugt mit schlichtem Design und moderner Technik.
    Der elegant schmale Rahmen in Verbindung mit dem dezenten roten Farbverlauf macht diese Modelle zu einem echten Blickfang.
    Das praktische 16:9-Format bietet eine Full HD Auflösung mit 1.920 x 1.080 Pixel.
    Das sehr hohe dynamische Kontrastverhältnis von 50.000:1 und die schnelle Reaktionszeit von nur 2 ms (G/G) sorgen
    stets für klare und detailreiche Bilder - auch bei schnell bewegten Bildinhalten.
    Das praktische 16:9-Widescreen-Format ermöglicht ein noch angenehmeres Arbeiten bei gleichzeitiger Steigerung Ihrer Produktivität.
    Das Breitbildformat entspricht dem natürlichen Sichtfeld des Betrachters. Somit haben Sie immer alles im Blick, ohne auf wichtige Informationen verzichten zu müssen.
    Dieses SyncMaster Large Format Display verfügt über ein Full HD-Panel mit einer nativen Auflösung von 1.920 x 1.080 Pixel.
    Somit können Bildinhalte im 1.080p-Format, der derzeit besten HD-Auflösung, wiedergegeben werden. 
    Genießen Sie beste Bildqualität mit hoher Bildschärfe und Detailreichtum selbst in dunklen Szenen.
    Mit einem dynamischen Kontrast von 50.000:1 werden Sie jedes Detail auf dem Bildschirm erkennen können.
    Lieferumfang: Monitor, Signalkabel, Netzkabel, Treiber CD, Handbuch (CD)
    ";2;False;0;;;"Samsung Syncmaster P2250 21,5 Zoll ";samsung-syncmaster-p2250-215-zoll-tft-monitor-schwarz;True;True;P-2470;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;2,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;219.9000;219.9000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;40048,6219907407;9;5;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000376-samsung-syncmaster-p2250-215-zoll-tft-monitor-schwarz.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000377-samsung-syncmaster-p2250-215-zoll-tft-monitor-schwarz.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000378-samsung-syncmaster-p2250-215-zoll-tft-monitor-schwarz.jpg;2;;False;;;;;False;False;False;;;;;False;;;;;; +5;0;True;"Panasonic DMR EH 595 EG K DVD-/HDD-Rekorder 250 GB ";"Panasonic DMR EH 595 EG K DVD-/HDD-Rekorder 250 GB ";"

    Panasonic DMR EH 595 EG K DVD-/HDD-Rekorder 250 GB

      
    HDMI, DivX-zertifiziert, USB 2.0
     
      
    Die Rekorder DMR-EH595 zeigen sich als wahre Alleskönner und zeichnen auf Festplatte oder DVD auf.
    Sie verarbeiten alle gängigen DVD-Formate wie DVD-RW, -R (DL), DVD+RW/+R (DL) sowie DVD-RAM. Außerdem können CDs, CD-R/-RWs sowie MP3- und JPEG-Daten sowohl von DVD als auch CD abgespielt werden.
    Die integrierte Festplatte erlaubt die Aufzeichnung von Fernsehprogrammen. Somit ist auch bei längerer Abwesenheit genügend Platz für die Lieblingsserie vorhanden.
    Dank des integrierten, elektronischen Programmführers Gemstar Guide Plus+ erfolgen die Programmauswahl und Timerprogrammierung kinderleicht und intuitiv.
    Die übersichtliche Darstellung des Fernsehprogramms bietet neben einer Genre-Auswahl zusätzlich eine gezielte Suche nach Stichworten.
    So kann beispielsweise direkt nach Schauspielern, Themen oder Sportarten gesucht werden.
    Neben dieser Funktion arbeiten die neuen Rekorder mit einer automatischen Kapitelerstellung bei der Aufzeichnung.
    Dadurch können während der anschließenden Wiedergabe unerwünschte Programmsequenzen auf Knopfdruck übersprungen oder eine Szene blitzschnell gefunden werden.
    Mit Pause Live TV kann zudem das laufende Fernsehprogramm jederzeit mit einem Druck auf die Pause-Taste angehalten und zu einem späteren Zeitpunkt weitergeschaut werden.
    Dank Quick Start-Funktion sind die Rekorder innerhalb einer Sekunde einsatzbereit, so dass kein Film und keine Aufzeichnung verpasst werden.

    Multiformat-DVD-Festplatten-Kombination
    Intuitive Benutzerführung
    Neben der Aufnahme des Fernsehprogramms überzeugen die neuen Rekorder als digitales Fotoalbum sowie Musik-Jukebox
    Elektronische Programmführer Guide Plus+ mit Suchfunktion
    Umfangreiche Anschlussmöglichkeiten
    ";2;False;0;;;Panasonic DMR EH 595 EG K;panasonic-dmr-eh-595-eg-k-dvd-hdd-rekorder-250-gb;True;True;P-1800;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;2,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;379.0000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;40046,702650463;63;12;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000375-panasonic-dmr-eh-595-eg-k-dvd-hdd-rekorder-250-gb.jpg;;;2;;False;;;;;False;False;False;;;;;False;;;;;; +5;0;True;"Garmin Freizeitguide Deutschland ";"Garmin Freizeitguide Deutschland ";"

    Garmin Freizeitguide Deutschland

     
     
    Wander- und Freizeitkarten von 21 Regionen 



    Freizeit- und Wanderkarten von 21 Nationalparks und Freizeitregionen vom Bayrischen Wald bis zur Insel Rügen im Maßstab 1:25.000 (Auflistung der Regionen auf www.garmin.de)
    Kompatibel mit allen aktuellen Garmin nüvi-Straßennavigationsgeräten und kartenfähigen Outdoor-GPS Geräten
    Sonderziele (POIs) wie Freizeitparks, Schlösser, Burgen, Denkmäler, Museen, Zoos, Bäder und Thermen können direkt angesteuert werden
    Micro SD Karte kann einfach in den Kartenslot eingeschoben werden - Installation oder Freischaltung entfällt
    Lieferumfang: Micro SD Karte mit Freizeitguide Deutschland
    ";2;False;0;;;;garmin-freizeitguide-deutschland;True;True;P-2080;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;29.0000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;40041,5175231481;"67;2095";44;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000364-garmin-freizeitguide-deutschland.jpg;;;2;;False;;;;;False;False;False;;;;;False;;;;;; +5;0;True;"Garmin Nüvi 1490 Tpro Navigationssystem Europa ";"Garmin Nüvi 1490 Tpro Navigationssystem Europa ";"

    Garmin Nüvi 1490 Tpro Navigationssystem Europa

     
     
     
    5"" Touchscreen-Display, TMC Pro, ecoRoute, Fußgänger- und PhotoNavigation, Bluetooth
     
     
     
    Mobile Navigation ohne Grenzen im Großformat, im ultra-flachem Design an die Bedürfnisse professioneller Anwender ausgerichtet
    Übersichtliche und einfache Navigation im 5 Zoll Display mit Fahrspurassistent und 3D-Kreuzungsansicht,
    TMC Pro Europa Premium Verkehrsfunkempfänger
    Kartenmaterial für 41 Länder in West- und Osteuropa intern vorinstalliert;
    Inklusive ecoRoute die Garmin Spritspar-Funktion und echter Fußgängernavigation mit optionalen CityXplorer Stadtplänen für Bus und Bahn
    Lieferumfang: Garmin nüvi 1490Tpro mit Kartenmaterial Europa, KFZ-Anschlusskabel mit TMC Pro-Verkehrsfunkempfänger,
    Saugnapfhalterung für die Windschutzscheibe, Armaturenhalterung, Schnellstartanleitung
    ";2;False;0;;;"Garmin Nüvi 1490Tpro Navigationssystem Europa ";garmin-nuevi-1490-tpro-navigationssystem-europa;True;True;P-2070;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;289.0000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;40041,5110416667;67;44;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000363-garmin-nuvi-1490-tpro-navigationssystem-europa.jpg;;;2;;False;;;;;False;False;False;;;;;False;;;;;; +5;0;True;"Garmin nüvi 255WT Navigationssystem Europa ";Garmin nüvi 255WT Navigationssystem Europa inklusive TMC;"

    Garmin nüvi 255WT Navigationssystem Europa

    inklusive TMC, 4,3"" Touchscreen Display, PhotoNavigation, SD-Kartenslot und ecoRoute
     
    Bedienerfreundliches Einsteigernavigationsgerät mit elegantem, ultra-schlankem Design und brillantem 4,3“ großem Touchscreen Display + TMC Verkehrsfunkempfänger Kartenmaterial für 40 Länder in West- und Osteuropa intern vorinstalliert; ecoRoute: reduziert den Kraftstoffverbrauch, CO2-Emissionen und schont die Umwelt, spart bares Geld und füllt die Reisekasse auf. PhotoNavigation mit Garmin Connect: Sie können Sehenswürdigkeiten und Bilder herunterladen und als Ziel auswählen Lieferumfang: Garmin nüvi 255W mit Kartenmaterial Europa, + TMC Verkehrsfunkempfänger (=WT), Saugnapfhalterung für die Windschutzscheibe, Armaturenhalterung, Schnellstartanleitung, KFZ-Anschlusskabel
    ";2;False;0;;;"Garmin nüvi 255WT Navigationssystem Europa ";garmin-nuevi-255wt-navigationssystem-europa;True;True;P-2060;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;169.0000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;40041,5046064815;67;44;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000362-garmin-nuvi-255wt-navigationssystem-europa.jpg;;;2;;False;;;;;False;False;False;;;;;False;;;;;; +5;0;True;"Canon PowerShot SX200 IS ";Canon PowerShot SX200 IS;"

    Canon PowerShot SX200 IS

    12 Megapixel, 12-fach opt. Zoom, 3"" Display

    Das neue Super-Zoom-Modell unter den Canon PowerShot-Digitalkameras zeigt große Stärke im kompakten Format:
    28 Millimeter-Weitwinkelobjektiv, 12-fach optischen Zoom, DIGIC-4-Bildprozessor und starke 12,1 Megapixel machen die PowerShot SX200 IS zu einem idealen Reisebegleiter.
    Für Spitzenqualität können Movieclips in High Definition mit 720p und 30 B/s aufgezeichnet und über die integrierte HDMI™-Schnittstelle auf einem HDFernseher wiedergegeben werden.
    Ein Aufnahmemodus für die vollständig manuelle Steuerung bringt ambitionierten Fotografen kreative Freiheit pur.
     
    Die Leistungsstärke des neuen DIGIC-4-Bildprozessors führt zu einer optimierten Motion- und Face-Detection-Technologie.
    Motion Detection unterscheidet Kameraverwacklungen von bewussten Bewegungen des Motivs und stimmt in Kombination mit dem Servo AF darauf die Einstellungen der Kamera zur Minimierung von Verwacklungsunschärfen ab.
    Face Detection erkennt Gesichter im Motiv, auf die die Kamera dann kontinuierlich scharf stellt.
    Starke Pluspunkte bei der Canon Face Detection sind der FaceSelf-Timer für Gruppenfotos, in denen der Fotograf bequem mit auf das Bild kommt, und die Rote-Augen-Korrektur.
     
    Als weitere Technologie-Komponente spielt die innovative Canon-i-Contrast- Technologie ihre Stärken bei Bildern mit dunklen Bildbereichen aus:
    Sie erhöht den Kontrast ausschließlich in diesen Bildpartien, anstatt lediglich die Gesamthelligkeit zu steigern, was zu überbelichteten Bildern führen würde. Der Canon-DIGIC-4- Prozessor ist zudem die Basis für schnelle Reaktionszeiten, effizientes Pufferspeicher-Handling und minimiertes Bildrauschen.
     
    Manche Motive muss man einfach in bewegten Bildern festhalten:
    Dafür hat die PowerShot SX200 IS einen Movie-Modus, in dem Movieclips sogar in High- Definition-Auflösung (720p) aufgezeichnet werden.
    Ideal für die Wiedergabe der Clips auf einen High-Definition-Fernseher ist die integrierte HDMI™-Schnittstelle für den Anschluss der Kamera.
    Das 3,0 Zoll große LC-Display der Kamera macht nicht nur Bildkomposition und Bildprüfung angenehm einfach, der große Betrachtungswinkel ist auch ideal für das direkte Betrachten von Bildern und Movieclips.
    Die neue Benutzeroberfläche verfügt zudem über eine intelligente Funktion zur Einblendung praktischer Tipps und Tricks für die unterschiedlichen Einstellungen und ihre Auswirkungen auf die Aufnahmen.
     
    Lieferumfang:
    PowerShot SX200 IS, Trageriemen, Akku, Akku-Ladegerät, USB-Kabel, Video-Kabel
    ";2;False;0;;;Canon PowerShot SX200 IS;canon-powershot-sx200-is;True;True;P-1720;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;259.9000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;40039,860474537;"56;2095";25;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000351-canon-powershot-sx200-is.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000352-canon-powershot-sx200-is.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000353-canon-powershot-sx200-is.jpg;2;;False;;;;;False;False;False;;;;;False;;;;;; +5;0;True;"Philips DLA 1619 H/10 Neopren-Tasche für iPod Shuffle ";"Philips DLA 1619 H/10 Neopren-Tasche für iPod Shuffle schwarz ";"

    Philips DLA 1619 H/10 Neopren-Tasche für iPod Shuffle schwarz

    Armband, Sichtfenster und Gürtel-Clip
     
    Ob für Sport oder Erholung, Ihr iPod ist immer dabei. Dafür ist das Action Jacket die allumfassende Lösung.
    Verwenden Sie das verstellbare Armband beim Sport und bewahren Sie den iPod shuffle nach dem Sport in der schützenden Hülle auf.
     
    • Aktiver Schutz
    • Durchsichtiges Fenster zum Schutz des Bildschirms
    • Neopren schützt vor Schweiß
    • Vielseitige Positionierung
    • Anpassbares Sportarmband
    • Das anpassbare Sportarmband ist dehnbar und passt sich so unterschiedlichsten Größen an. Es ist mit einem
    • Klettverschluss versehen, sodass Ihr Gerät bei jeder Aktivität sicher verstaut ist.
    • Sichtfenster für das Display
    • Beim Sport schützt dieses durchsichtige Fenster den Bildschirm des Geräts und ermöglicht gleichzeitig die
    • Bedienung des Geräts.
    • Feuchtigkeitsbeständiges Neopren
    • Diese Neoprentasche bietet eine gepolsterte, feuchtigkeitsbeständige Schicht für Ihr Gerät und schützt es beim
    • Sport vor Schweiß und den Elementen.
    ";2;False;0;;;"Philips DLA 1619 H/10 Neopren-Tasche für iPod Shuffle ";philips-dla-1619-h10-neopren-tasche-fuer-ipod-shuffle;True;True;P-1520;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;24.9000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;40035,8124652778;51;6;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000350-philips-dla-1619-h10-neopren-tasche-fur-ipod-shuffle.jpg;;;2;;False;;;;;False;False;False;;;;;False;;;;;; +5;0;True;Hama MP3-Tasche iPod nano 5G;Hama MP3-Tasche iPod nano 5G Transparent;"
    Hama MP3-Tasche iPod nano 5G Transparent 

     
    robuste, passgenaue Silikontasche; perfekte Passform, sitzt wie eine zweite Haut;
    Ausstattung: Aussparungen für Bedienelemente und Anschlüsse;
    3D-Sticker für bessere clickwheel Steuerung; abnehmbares Trageband
    Displayschutzfolie; Serie: Sport Case; Farbe: Transparent; Material: Silikon;
    Medium: MP3-Player; Typ: Fenstertasche; für MP3-Marke: für iPod Nano 5G
    ";2;False;0;;;;hama-mp3-tasche-ipod-nano-5g;True;True;P-1510;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;14.9000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;40035,80875;"51;2095";18;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000349-hama-mp3-tasche-ipod-nano-5g.jpg;;;2;;False;;;;;False;False;False;;;;;False;;;;;; +5;0;True;Panasonic DMR EH 695 EG DVD- und Festplatten-Rekorder 320 GB;"Panasonic DMR EH 695 EG DVD- und Festplatten-Rekorder 320 GB ";"
    Panasonic DMR EH 695 EG DVD- HDD-Rekorder 320 GB

     
    HDMI, SDHC-Kartenslot, USB 2.0

    Der neue DIGA DVD-Recorder DMR-EH695 mit analogen Kabeltuner steht für hervorragende Aufnahme- und Wiedergabequalität, Musikgenuss sowie ein Maximum an Kompatibilität.
     
    Auf die 320 GB Festplatte können bis zu 567 Stunden (EP Modus) oder aufgrund eines sehr guten Encoders bis zu 284 Stunden Aufnahmekapazität in DVD Qualität (LP-Modus) gespeichert werden.
     
    Die Super Multi Format Aufnahmefähigkeit des DMR-EH695 verarbeitet alle DVD Formate [DVD-RAM, -RW, -R, -R (DL), +RW, +R, +R (DL)] und spielt neben diesen Formaten zusätzlich JPEG, MP3, WMA und DivX Daten ab. Auf die integrierte ""Jukebox"" lassen sich schnell und einfach Ihre Musik CDs in 12-facher Kopiergeschwindigkeit (6min.)
    in unkomprimiertem LPCM auf die Festplatte kopieren.
     
    Die Album, Interpreten und Titelinformationen sind bereits auf der vorinstallierten Gracenote-Datenbank auf der Festplatte hinterlegt, sodass eine lästige Eingabe entfällt.
     
    Über den USB Eingang können Sie Ihre MP3/WMA-Musikinhalte, JPEG Bilder oder MPEG2 Filme vom Camcorder ebenfalls auf die Festplatte kopieren oder abspielen. Neben diesen Formaten können auch DivX-Dateien abgespielt werden. Ebenfalls in Front bietet ein SDHC Slot die Möglichkeit, HD-JPEG oder MPEG2 Aufnahmen auf die Festplatte zu kopieren oder abzuspielen.
     
    Der DMR-EH695 skaliert jedes Bildmaterial über die HDMI-Schnittstelle in eine maximale HDTV Auflösung mit 1080 Zeilen (Full HD).
     
    Die neue praktische VIERA LINK Funktion, ausschließlich über HDMI mit den VIERA Flachbildschirmen nutzbar, bietet Ihnen komfortable Bedienung aller Panasonic Geräte mit nur einer Fernbedienung! Einfach, schnell und problemlos.
     
    HDMI-Ausgang (HDMI Ver. 1.3)
    USB-Anschluss (USB 2.0 High Speed)
    SD-HC Karten-Slot
    DV Eingang (IEEE1394/iLink)
    Komponentenausgang (YUV)
    2x Scart-Anschluss
    Front-AV (S-Video/Video/Audio-IN)
    S-Video Ausgang (Hosiden)
    Video-Ausgang (Cinch)
    Audio Ausgang (Cinch)
    Optischer Digitalausgang (PCM, Dolby Digital, DTS, MPEG)
     
    Lieferumfang:
    Panasonic DMR-EH695EGK, Fernbedienung
    ";2;False;0;;;"Panasonic DMR EH 695 EG DVD- und Festplatten-Rekorder ";panasonic-dmr-eh-695-eg-dvd-und-festplatten-rekorder-320-gb;True;True;P-1790;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;2,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;419.0000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;40035,2792476852;64;12;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000348-panasonic-dmr-eh-695-eg-dvd-und-festplatten-rekorder-320-gb.jpg;;;3;;False;;;;;False;False;False;;;;;False;;;;;; +5;0;True;"Qualitätsakku für Canon EOS 450D, 500D und 1000D ";"Qualitätsakku für Canon EOS 450D, 500D und 1000D Typ: Lithium-Ion-Akku ";"

    Qualitätsakku für Canon EOS 450D, 500D und 1000D

    Typ: Lithium-Ion-Akku
     
    Leistungsstark - hohe Qualität und doch günstig
    Dieser Qualitätsakku zeichnet sich durch seine Langlebigkeit und Zuverlässigkeit aus und steht dem Original von Canon LP-E5 in nichts nach.
    Dieser Akku passt auch in den Batteriegriff Canon BG-E5. Der Akku ist mit einem Chip ausgestattet, welcher Überladung und Überhitzung verhindert.
     
    Technische Details
    • Typ: Lithium-Ion-Akku
    • Spannung: 7,4v
    • Kapazität: 1080mAh
    • Gewicht: 50g
    • Überladungs-/Überspannungsschutz
    ";2;False;0;;;Qualitätsakku für Canon EOS 1000D;qualitaetsakku-fuer-canon-eos-450d-500d-und-1000d;True;True;P-1710;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;29.9000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;40035,2271412037;56;25;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000347-qualitatsakku-fur-canon-eos-450d-500d-und-1000d.jpg;;;2;;False;;;;;False;False;False;;;;;False;;;;;; +5;0;True;"Logitech V150 Laser Mouse ";"Logitech V150 optische Notebook Maus schnurgebunden silber ";"Logitech V150 optische Notebook Maus schnurgebunden silber
     
     
     
    Plug & Play: Die Maus muss nur an einem USB-Anschluss angeschlossen werden und ist sofort einsatzbereit.
    Laserabtastung: Erleben Sie Laser für präzise, flüssige Abtastung auf fast jeder Oberfläche
    Tilt Wheel Plus Zoom¿: Horizontale Bildläufe. Vergrößern und verkleinern Sie mühelos Fotos und Tabellen.
    Handgerechte Form: Komfort für Rechts- und Linkshänder.
    Besonders kompaktes Design: Praktisch für unterwegs. ";2;False;0;;;"Logitech V150 Laser Mouse for Notebooks ";logitech-v150-laser-mouse;True;True;P-2790;;;False;0;False;;False;False;0;False;0;1;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;29.0000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;40028,639212963;21;11;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000346-logitech-v150-laser-mouse.jpg;;;2;;False;;;;;False;False;False;;;;;False;;;;;; +5;0;True;Panasonic DMP-BD60EG-K Blu-ray Player;"Panasonic DMP-BD60EG-K Blu-ray Player schwarz ";"

    Panasonic DMP-BD60EG-K Blu-ray Player schwarz

     
    HDMI, Upscaling 1080p, USB 2.0

     
     Glänzt als wahre Allround-Unterhaltunskünstler
    Moderne Schnittstellen wie SD/SDHC-Slot und USB-Eingang mit Multimediamöglichkeiten
    Über den Ethernet-Port Zugriff auf den I/P-Service VIERA Cast
    Z.B. YouTube-Videos und Fotos über den Online-Bilderdienst Picasa ansehen
    Zahlreiche Komfortmerkmalen wie BD-Live und Bonus View
    Wiedergabe-Formate: Blu-ray Video, Blu-ray Disc (BD-R), Blu-ray Disc wiederbeschreibbar (BD-RE), DVD-Video, DVD+R, DVD-R, DVD+RW, DVD-RW, DVD+R DL, DVD-R DL, DVD-RAM,
    CD-Audio, CD-R, CD-RW, MP3, DivX, Foto-Formate JPEG
    Audio: Dolby Digital Plus, Dolby TrueHD, DTS-HD, MPEG2
    Anschlüsse: Audio-Ausgang, Video-Ausgang, Video-Farbkomponenten-Ausgang (YPbPr / YUV), Digital-Ausgang Optisch, Speicherkarten-Steckplatz, HDMI, USB, Netzwerk
    Farbe: schwarz
    ";2;False;0;;;Panasonic DMP-BD60EG-K Blu-ray Player;panasonic-dmp-bd60eg-k-blu-ray-player;True;True;P-1900;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;2,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;164.9000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;40025,7325578704;"61;2095";12;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000343-panasonic-dmp-bd60eg-k-blu-ray-player.jpg;;;2;;False;;;;;False;False;False;;;;;False;;;;;; +5;0;True;"LG W2261VP 54,6 cm (21,5 Zoll) Widescreen TFT Monitor HDMI/ DVI-D/ VGA ";"LG W2261VP 54,6 cm (21,5 Zoll) Widescreen TFT Monitor HDMI/ DVI-D/ VGA (Kontrastverhältnis 50000:1, Reaktionszeit 2ms) schwarz ";"
    LG Electronics präsentiert: TFT Monitor FLATRON W2261VP
    Multimedia Monitor mit erstklassigen Werten
    Dank HDMI bietet dieser 22 Zoll LG Monitor vielfältige und zukunftssichere Anschlussmöglichkeiten. Mit seinem natürlichen 16:9 Blickfeld-Format eignet er sich perfekt für Gamer und Multimedia-Fans – nicht zuletzt auch aufgrund der schnellen Reaktionszeit von 2ms und dem hohen Kontrast von 50.000:1. Genießen Sie mit den innovativen Fun-Funktionen absoluten Bedienkomfort, dank Full HD und f-Engine perfekte Bildqualität und ein wertiges, edles Design in einem!
     
    Beschreibung der Features
     
    Perfektion in Full HD
    Höchste Präzision und beste Qualität in der Darstellung sind in allen Bereichen – ob für Filme, Computerspiele, Multimedia- und Of?ce-Anwendungen – garantiert. Pixel für Pixel stellt dieser LG Monitor in einer Auflösung von 1920x1080 die Bilder unskaliert genauso dar, wie sie die Quelle liefert. Das sorgt für eine reibungslose Wiedergabe und garantiert extrem scharfe und kristallklare Bilder, die selbst bei Action-Szenen oder Sportübertragungen nicht ins Ruckeln geraten.
     
    Hochgenuss im 16:9 Breitbildformat
    Der W2261VP LG Monitor mit integriertem 16:9 Panel bringt überragende Bildqualität mit Full HD-Au?ösung im Breitbildformat zu Ihnen nach Hause. Das 16:9 Panel ist ein natürliches Blickfeld-Format, das Ihre Augen nicht übermäßig beansprucht. So können Sie Ihren Monitor sowohl für actiongeladene BluRay- oder DVD-Filme, zum digitalen Fernsehen oder für professionelle Aufgaben am PC ideal nutzen. Super bequem beim Arbeiten: Es lassen sich problemlos zwei DIN-A4-Hochformate nebeneinander anzeigen.
     
    Scharfer Kontrast
    Der ultra hohe Kontrast von 50.000:1 mit DFC (Digital Fine Contrast) bringt tiefstes Schwarz und strahlend helles Weiß auf Ihren Bildschirm. Farben zeigen sich brillant und lebensecht, so dass das Filmerlebnis am PC eine neue Dimension erreicht.
     
    Schnelle Reaktionszeit
    Durch die enorm schnelle Reaktionszeit der Hintergrundbeleuchtung von nur 2 Millisekunden werden Bewegungsunschärfen eliminiert und ein ruckelfreies Bilderlebnis garantiert. Bei Action?lmen, Sportübertragen oder Videogames verpassen Sie nun nichts mehr! Und dank des angenehm großen Blickwinkels von 170° kommen auch die richtig anspruchsvollen Multimedia- und Office-Anwender voll auf ihre Kosten.
     
    Connected: HDMI
    HDMI steht für ""High Definition Multimedia Interface"". Hierbei handelt es sich um eine zukunftssichere Schnittstelle für die volldigitale Übertragung von Audio- und Video-Daten in der Unterhaltungselektronik. Dieser Anschluss verbindet portable HDMI-Abspielgeräte mit Ihrem Display und ermöglicht eine verlustfreie High-Definition Bild- und Tonübertragung wobei eine Bildtiefe von bis zu 48-bit erreicht werden kann. Beim W2261VP Monitor haben Sie diesen komfortabel nutzbaren HDMI- sowie einen DVI-D Eingang mit HDCP Kopierschutzunterstützung.
     
    Innovative FUN-Funktionen
    Nutzen Sie praktische Photoeffekte für Farbkorrekturen in Bildern und Filmen oder die ez-Zooming-Funktion zur hochauflösenden Ausschnittvergrößerung von Bild und Text. Die 4:3 Formatumschaltung sorgt zudem für verzerrungsfreien Film- und Spielgenuss.
     
    Alle Daten im Überblick
     
    22"" TFT Monitor für den anspruchsvollen Multimedia Anwender im 16:9 Breitbildformat.
    Funktionelles edles Design in hochglänzendem Schwarz
    Ultra schnelles Panel mit kurzer Reaktionszeit von nur 2 ms (ISO) und sehr großem Blickwinkel von 170°; ideal für Multimedia-Anwender oder Gamer.
    Ultra hoher Kontrast von 50.000:1 mit DFC (Digital Fine Contrast)
    Full HD Auflösung (1920 x 1080 Pixel). Formatfüllende Darstellung von zwei DIN-A4 Seiten gleichzeitig.
    f-Engine – LG's welterster Bildverbesserer Chip garantiert kristallklare und brillante Bilder ohne Farbverfälschung in Echtzeit für Film, Foto oder Anwender.
    Neue ergonomische Menüführung mit Visual OSD
    Fun Taste für Photoeffekte zur kreativen Darstellung von Bildern wie z.B. Sepia, kalt, und Gaussche Unschärfe. ez Zooming zur Änderung der Auflösung, oder ARC Formatumschaltung von 4:3 auf 16:9 zur formatgetreuen Darstellung von älteren Programmen.
    HD fähig und zukunftssicher HDMI Eingang (bis 1080p) und DVI-D Eingang mit HDCP Kopierschutzunterstützung. Zusätzlicher VGA 15 Pin D-Sub Eingang zum Betrieb an zwei Rechnern.
    Integriertes Netzteil
    Kopfhörerausgang
    Externes Netzteil 
    ";2;False;0;;;"LG W2261VP 54,6 cm (21,5 Zoll) Widescreen TFT Monitor HDMI/ DVI-D/ VGA ";lg-w2261vp-546-cm-215-zoll-widescreen-tft-monitor-hdmi-dvi-d-vga;True;True;P-2520;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;2,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;239.0000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;40025,6372800926;"11;2095";19;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000337-lg-w2261vp-546-cm-215-zoll-widescreen-tft-monitor-hdmi-dvi-d-vga.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000338-lg-w2261vp-546-cm-215-zoll-widescreen-tft-monitor-hdmi-dvi-d-vga.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000339-lg-w2261vp-546-cm-215-zoll-widescreen-tft-monitor-hdmi-dvi-d-vga.jpg;2;;False;;;;;False;False;False;;;;;False;;;;;; +5;0;True;"Western Digital My Passport Essential 500 GB ";"Western Digital BAAA5000ABK My Passport Essential 500GB ";"
    Western Digital BAAA5000ABK My Passport Essential 500GB 
     
    Unsere kleinste tragbare Festplatte aller Zeiten
    Ihre gesamten Daten auf einen Blick und mühelose Widerhergestellung Ihrer Daten
    Passwortschutz und 256-bit Hardware basierte Verschlüsselung
    Plug-and-play-bereit für Windows-PCs
    Lieferumfang: Western Digital My Passport Essential 500GB externe Festplatte,
    SmartWare-Software, USB-Kabel, Schnellinstallationsanleitung
    ";2;False;0;;;Western Digital My Passport Ess. 500GB schwarz;western-digital-my-passport-essential-500-gb;True;True;P-2570;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;109.0000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;40015,1174768519;14;21;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000336-western-digital-my-passport-essential-500-gb.jpg;;;2;;False;;;;;False;False;False;;;;;False;;;;;; +5;0;True;LG BD 370 Blu-ray Disc Player schwarz;"LG BD 370 Blu-ray Disc Player schwarz ";"

    LG BD 370 Blu-ray Disc Player schwarz 

    HDMI, Upscaler 1080p, BD live, You Tube-Video Client, Ethernet, USB 2.0

    Der neue BD-370 verbindet wie kein anderer Blu-ray Player das Internet mit dem Fernsehen.
    Über eine LAN-Verbindung können Sie YouTube Video-Streams wiedergeben.
    Die BD-Live Funktion versorgt Sie über das Internet mit Zusatzinformationen zu den Filmen,
    wie z.B. Kommentare oder Extra-Material. Wie von LG gewohnt, liefert der BD-370 perfekte Bildqualität
    und ist, kombiniert mit einem FullHD TV, unschlagbar in Sachen Bildqualität.
     
    Blu-ray Disc Player zur Wiedergabe von: Blu-ray Discs, BD-R(E), Video DVDs (PAL & NTSC), DVD+R(W), DVD-Dual Layer,
    DVD+R Double Layer, Audio-CD, DTS-CD, MP3 CD, WMA CD, PNG, CD, DivX CD, JPEG CD, CD-R(W)
    Unterstützung interaktiver Blu-ray Disc Standard-Inhalte & BD Live 2.0
    YouTube™ Video-Streaming Wiedergabe über LAN
    USB 2.0 und HDMI 1.3 1080p Ausgang mit SIMPLINK & Deep Colour,
    A/V-Ausgang (Cinch), Komponentenausgang YUV, RJ45 LAN-Anschluß
    Dolby TrueHD, Dolby Digital, Dolby Digital Plus, DTS-HD, DTS, LPCM, MP3, WMA, MPEG1/2 L2
    ";2;False;0;;;LG BD 370 Blu-ray Disc Player schwarz;lg-bd-370-blu-ray-disc-player-schwarz;True;True;P-1890;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;2,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;147.9000;147.9000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;40013,6568865741;61;19;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000333-lg-bd-370-blu-ray-disc-player-schwarz.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000334-lg-bd-370-blu-ray-disc-player-schwarz.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000335-lg-bd-370-blu-ray-disc-player-schwarz.jpg;2;;False;;;;;False;False;False;;;;;False;;;;;; +5;0;True;"Samsung DVD-HR 775 A DVD-/Festplatten-Rekorder ";"Samsung DVD-HR 775 A DVD-/Festplatten-Rekorder 250 GB ";"
    Multiformat DVD-Recorder im 55 Millimeter Slim Design mit 250 GB HDD,
     
    USB 2.0, MPEG4 (DivX), HDMI™-Ausgang (1.080p/ 1.080i / 720p),
     
    Anynet+ (HDMI-CEC), TimeShift, TimeSlip und ShowView.
     
     
    Aufnahme auf Festplatte
    Die eingebaute Festplatte mit 320 / 250 / 160 GB im DVD-HDD-Recorder macht‘s möglich: Im EP-Modus können Sie bis zu 534 / 421 / 264 Stunden Filme aufzeichnen.
     
    One-Touch-Aufnahme
    Die Samsung DVD-Recorder machen das Aufzeichnen leichter denn je. Ein Knopfdruck genügt – schon sucht der Samsung Recorder nach dem verfügbaren Aufnahmeplatz auf der Disc und beginnt mit der Aufnahme. Einmal drücken bedeutet Aufnahme bis zu 30 Minuten, zweimal drücken bis zu einer Stunde. Mit jedem Tastendruck zeichnet der Samsung DVD-Recorder weitere 30 Minuten des ausgewählten Programms auf. Die Aufnahmezeit auf einer Disc beträgt je nach Aufnahmemodus maximal 240 Minuten.
     
    Automatische Fehlerkorrektur
    Die Bildqualität der auf DVD gespeicherten Daten kann bei einer verbogenen Disc verzerren. Der Grund: Diese Disc lässt sich aufgrund der Unregelmäßigkeit der Laserreflexion nicht korrekt lesen. Zur Verbesserung der Lesbarkeit sind Samsung Recorder mit einer automatischen Fehlerkorrektur-Technologie ausgestattet. Diese Technik verbessert die Datenleserlichkeit selbst bei Discs, die Unregelmäßigkeiten aufweisen.  VBR-Technologie
    Mit der VBR (Variable Bit Rate)-Technologie kann die Aufnahmezeit durch Einstellen des Aufnahmemodus auf bis zu 16 Stunden verlängert werden. Um Bilder auf DVD-RW und DVD-R aufzuzeichnen, steuert die VBR-Kodiertechnik die Komprimierungsrate von MPEG2 in Echtzeit und maximiert dadurch den verfügbaren Speicherplatz auf der Disc.
     
    Was bedeutet White Strategy?
    Bei der ""Präzise Aufzeichnung und Wiedergabe""-Technologie passen sich die gespeicherten Daten sauber in den optimalen Bereich an. Die Daten, die ohne diese Technik gespeichert werden, viel mehr Platz ein, was zu einer Datenüberlappung führen kann. Dank der ""Präzisen Aufzeichnung und Wiedergabe"" werden die Daten im Samsung DVD-Recorder noch präziser gespeichert. So entstehen kristallklare Bilder.
     
    Was ist HDMI™?
    HDMI™ (kurz für High-Definition Multimedia Interface) ist eine volldigitale Audio/Video-Schnittstelle, die Bild- und Tondaten mit einem einzigen Digitalkabel zwischen Digital- und Audiogeräten überträgt. Es unterstützt die Videoformate Standard, Enhanced oder High-Definition sowie die Audioformate Standard bis mehrkanaligen Surround-Sound. Die Vorteile: unkomprimierte digitale Videodaten (mit Bandbreiten bis zu 5 Gigabyte pro Sekunde), ein Anschluss statt vieler Kabel und Datenaustausch zwischen Bildquelle und DTV. 
    ";2;False;0;;;;samsung-dvd-hr-775-a-dvd-festplatten-rekorder;True;True;P-1940;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;2,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;269.0000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;40013,6237847222;63;5;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000331-samsung-dvd-hr-775-a-dvd-festplatten-rekorder.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000332-samsung-dvd-hr-775-a-dvd-festplatten-rekorder.jpg;;2;;False;;;;;False;False;False;;;;;False;;;;;; +5;0;True;Canon Digital IXUS 95 IS Digitalkamera Silver;"Canon Digital IXUS 95 IS Digitalkamera Silver ";"
    Canon Digital IXUS 95 IS Digitalkamera Silver

    10 Megapixel, 3-fach opt. Zoom, 2,5"" Display, Bildstabilisator
     
    Die Digital IXUS 95 IS vereint exquisiten Schick mit exzellenter Leistung und hohem Komfort.
    Der innovative Smart-Auto-Modus nutzt auf intelligente Art die Scene-Detection-Technologie.
    Das Ergebnis: optimierte Einstellungen für tolle Bilder. Kompaktes und schickes IXUS-Design mit 10 Megapixeln in 3,0fach optisches Zoom

    mit optischem Bildstabilisator Scene-Detection-Technologie Brillante Aufnahmen Face-Detection-Technologie DIGIC 4 2,5-Zoll-PureColor-LCD II i-Contrast 17 Aufnahmemodi VGA-Movieclips
    Technische Daten der Canon Ixus 95 IS : Auflösung (MP) 10 Sensor-Größe 1/2.3 LCD-Größe (cm) 6.35 Speicher SD / SDHC interner Speicher (MB)

    optischer Zoom (x-fach) 3 numerischer Zoom (x-fach) 4 Bildstabilisator Ja Optischer Zoom Nein Brennweite 35 - 105 Lichtstärke 2.8 - 4.9 Video-Modus JA

    Max. Video-Auflösung(Pixel) 640 x 480 Abmessungen (B x H x T mm) 88,5 x 54,8 x 21,8 Gewicht (g) 120 Akku NB-6L
     
    Lieferumfang:
    Digital IXUS 95 IS, Trageriemen, Akku, Akku-Ladegerät, USB-Kabel, Video-Kabel
    ";2;False;0;;;"Canon Digital IXUS 95 IS Digitalkamera ";canon-digital-ixus-95-is-digitalkamera-silver;True;True;P-1700;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;189.0000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;40008,648287037;56;25;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000324-canon-digital-ixus-95-is-digitalkamera-silver.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000325-canon-digital-ixus-95-is-digitalkamera-silver.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000326-canon-digital-ixus-95-is-digitalkamera-silver.jpg;2;;False;;;;;False;False;False;;;;;False;;;;;; +5;0;True;"Garmin TOPO DVD Deutschland Digital 25 ";"Garmin TOPO DVD Deutschland Digital 25 ";"
    Garmin TOPO DVD Deutschland Digital 25 

     
    Topographische Rasterkarte von Deutschland im Maßstab von 1:25.000
     
     
    Topographische Rasterkarte
    Maßstab 1:25.000
    3D-Geländedarstellung mit Flugmodus
    Erstellen von Höhenprofilen
    Übertragen von Routen, Tracks und Wegpunkten
    ";2;False;0;;;;garmin-topo-dvd-deutschland-digital-25;True;True;P-2050;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;159.0000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;40007,1684027778;67;44;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000323-garmin-topo-dvd-deutschland-digital-25.jpg;;;2;;False;;;;;False;False;False;;;;;False;;;;;; +5;0;True;Garmin Topo DVD Deutschland V3;"Garmin Topo DVD Deutschland V3 Gesamt Digitale topographische Karte gesamt Deutschland auf DVD und MircoSD-Karte ";"

    Garmin Topo DVD Deutschland V3 Gesamt

     
    Digitale topographische Karte gesamt Deutschland auf DVD und MircoSD-Karte
     
    .
    Die neue topographische Karte gesamt Deutschland
    enthält zusätzlich zu detaillierten Straßen- und Wegedaten mehr als 8.000 km überregionale Wanderrouten und über 60.000 km Radrouten.
    Innerhalb dieses Routennetzes kann sich der Nutzer von einem bestimmten Ausgangspunkt zu einem Zielpunkt routen lassen.
    Beispiele für Routen: Rothaarsteig, Rennsteig, Altmühltal-Panoramaweg, Harzer Hexensteig, 66 Seen Wanderweg, Premiumwanderwege Saarland und viele mehr.
    Neu ist auch, dass die Kartensoftware erstmals kompatibel mit Apple MacIntosh Computern ist (ab OS X 10.4 aufwärts).
    Ob zu Fuß oder auf dem Mountain-Bike,
    wer viel draußen unterwegs ist, setzte früher Papierkarten ein. Seit mehreren Jahren gibt es von Navigationsspezialist Garmin GPS-Geräte
    die topografische Karten darstellen können (Karten im MapSource-Format). Ein Routing, wie man es von Navis aus dem Auto kennt, war mit diesen Karten bislang aber nicht möglich.
    Die neueste Version der “Topo Deutschland v3” macht nun erstmals das Routing auf 8.000 km Wanderrouten und rund 60.000 km Radrouten möglich!
    Einfach Start- und Zielpunkt eingeben, das Gerät schlägt die Route vor, und los geht’s. Visuelle Abbiegehinweise führen dann bequem und sicher zum Ziel.
    Dies sollte auch den größten GPS-Skeptiker positiv stimmen.
    Ebenfalls praktisch:
    Die neue Topo Deutschland V3 wird mit einer bereits programmierten SD-/microSD Datenkarte ausgeliefert.
    Das erspart ein Freischalten der Karte auf dem PC und das Übertragen der Karte auf das Gerät.
    Die Datenkarte wird einfach in den Slot des GPS-Gerätes geschoben und schon kann es losgehen.
    Eine Verwendung der Daten von der DVD auf dem Computer ist natürlich nach wie vor möglich.

    ";2;False;0;;;Garmin Topo DVD Deutschland V3;garmin-topo-dvd-deutschland-v3;True;True;P-2040;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;209.0000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;40007,1559606481;67;44;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000322-garmin-topo-dvd-deutschland-v3.jpg;;;2;;False;;;;;False;False;False;;;;;False;;;;;; +5;0;True;"NAVIGON 2310 Navigationssystem Europa ";"NAVIGON 2310 Navigationssystem Europa ";"

    NAVIGON 2310 Navigationssystem Europa

     
    40 Länder, inklusive TMC, NAVIGON MyRoutes, Clever Parking , TMC-Routenplanung
     
     
    NAVIGON 2310 Kann noch mehr,als das Äußere verspricht.
    Was macht eigentlich ein Schmuckstück aus? Erstmal muss es natürlich gut aussehen.
    Im ersten Moment könnte man die 23er-Serie von NAVIGON für so ein typisches, kleines Accessoire halten.
    Aber nicht nur das schicke Design begeistert. Denn auch was die Features angeht, kann die 23er-Serie locker mithalten:
    Mit TMC- Routeninfo stehen Sie nie wieder im Stau, NAVIGON MyRoutes findet jederzeit die für Sie beste Strecke und mit dem POI-Klick erhalten Sie alle Infos zu Ihrem gewählten Sonderziel.
    Und wenn Sie das immer noch nicht überzeugt, dann sehen Sie sich mal den Preis an.
     
    NAVIGON MyRoutes
    Je nachdem, welcher Fahrertyp Sie sind, empfiehlt Ihnen NAVIGON MyRoutes die beste Route – zugeschnitten auf Ihren persönlichen Fahrstil, den Wochentag und die Tageszeit.
    Darüber hinaus zeigt Ihnen Ihr NAVIGON bis zu zwei weitere Routen. Das schafft Transparenz. Sie entscheiden, ob Sie unserer Empfehlung folgen oder eine der Alternativen wählen.
     
    TMC-Routeninfo
    zeigt ihnen im Fall einer Staumeldung eine Alternativroute mit aktualisierter Entfernung und Ankunftszeit. Sie entscheiden, ob eine Umfahrung in Ihrem Fall sinnvoll ist oder ob Sie die ursprüngliche Route beibehalten wollen.
     
    Reality View Pro
    zeigt Straßen nicht als Linien, sondern realistisch aus Asphalt und mit Mittelstreifen. So behalten Sie an Autobahnkreuzen und Ausfahrten leichter den Überblick.
     
    Fahrspurassistent Pro
    hilft Ihnen selbst durch den hektischsten Straßenverkehr hindurch. Vorausschauend und übersichtlich zeigt er Ihnen an, auf welche Fahrspur Sie für Ihren nächsten und übernächsten Abbiegepunkt wechseln müssen.
     
    Clever Parking
    hilft Ihnen bei der Parkplatzsuche. Kurz vor Ihrem Ziel zeigt Ihnen Clever Parking Parkplätze in der näheren Umgebung an.
    In Deutschland werden Sie sogar über Parkgebühren informiert. So vermeiden Sie langes Suchen und sparen dabei Geld.
     
    Lieferumfang:
    PNA  2310 (3,5"" im 4:3 Format) | Kurzanleitung | Kfz-Ladekabel mit integrierter TMC-Antenne | Halterung | Vorinstalliertes Kartenmaterial für 40 Länder | USB-Kabel
    ";2;False;0;;;;navigon-2310-navigationssystem-europa;True;True;P-2150;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;159.0000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;39998,914525463;68;14;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000321-navigon-2310-navigationssystem-europa.jpg;;;2;;False;;;;;False;False;False;;;;;False;;;;;; +5;0;True;Panasonic Lumix DMC-FS6 Digitalkamera schwarz;"Panasonic Lumix DMC-FS6 Digitalkamera schwarz ";"

    Panasonic Lumix DMC-FS6 Digitalkamera schwarz

     
    8 Megapixel, 4-fach opt. Zoom, 2,5"" Display, Bildstabilisator
     
     
    Im Intelligenten Automatik (iA)-Modus werden die 5 wichtigsten Motivprogramme automatisch optimal auf die jeweilige Szene eingestellt.
    Neben der Motiverkennung kombiniert iA weitere wichtige Funktionen, wie den optischen Bildstabilisator OIS, die Bewegungserkennung (Intelligente ISO-Steuerung),
    eine optimierte Gesichtserkennung mit digitaler Rotaugen-Korrektur.
    So sind scharfe, natürliche und schöne Fotos selbst für (Neu-)Einsteiger möglich.
    Der reaktionsschnelle Venus Engine IV-Bildprozessor gehört schon bei diesem Einsteigermodell zur Grundausstattung.

    Lichtstarkes F2,8 Leica DC Vario-Elmarit Objektiv
    Hochauflösendes 6,4 cm LC-Display [230.000 Pixel]
    4x optischer Zoom [KB: 33-132 mm]
    Intelligente Automatik [u.a. Gesichtserkennung]
     
    Lieferumfang:
    Digitalkamera, Lithium Ionen Akku, Ladegerät, USB-Kabel, Trageriemen, Audio / Video-Kabel, CD-ROM, Sotware
    ";2;False;0;;;"Panasonic Lumix DMC-FS6 ";panasonic-lumix-dmc-fs6-digitalkamera-schwarz;True;True;P-1770;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;189.0000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;39998,8940393519;58;12;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000317-panasonic-lumix-dmc-fs6-digitalkamera-schwarz.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000318-panasonic-lumix-dmc-fs6-digitalkamera-schwarz.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000319-panasonic-lumix-dmc-fs6-digitalkamera-schwarz.jpg;2;;False;;;;;False;False;False;;;;;False;;;;;; +5;0;True;Western Digital WD TV HD Media Player;Western Digital WD TV HD Media Player;"
    Western Digital WD TV HD Media Player
     
     
    In Kombination mit einem tragbaren My Passport-Laufwerk ist dieser Player die bequemste Methode, Filme oder selbstgedrehte Videos wiederzugeben,
    digitale Musik in hoher Qualität abzuspielen und Diashows Ihrer Familienfotos in hoher Auslösung von der Festplatte in Ihrem Fernseher anzuzeigen.
    Auch mit gängigen USB-Laufwerken und Digitalkameras, Camcordern und tragbaren Media-Playern, die als Massenspeichereinheiten erkannt werden, kompatibel.
    Ideal geeignet für eine störungsfreie Wiedergabe von Filmen, Heimvideos, digitaler Musik und Fotos von der Festplatte auf Ihrem Fernsehgerät.
     
    HDMI- und FBAS-Anschlüsse - Der HDMI-Anschluss (HDMI – High-Definition Multimedia Interface) ermöglicht den Anschluss an HDTV-Geräte der höchsten Qualität oder an ein Heimtheater.
    Zusätzliche kombinierte (RCA-)Ausgänge gewährleisten die Kompatibilität mit praktisch allen Fernsehgeräten.
     
    Highlights
    maximale Transferrate: 480 Mb/s über USB 2.0
    USB 2.0 Anschluss
    für PC oder Macintosh Computer
    Lieferumfang: HD Media Player, kompakte Fernbedienung einschließlich Batterien,
    Software für Medienkonvertierung (nur für Windows), kombiniertes Audio/Video-Kabel, Netzteil, Schnellinstallationsanleitung
    ";2;False;0;;;Western Digital WD TV;western-digital-wd-tv-hd-media-player;True;True;P-2560;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;119.0000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;39997,7782638889;14;21;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000316-western-digital-wd-tv-hd-media-player.jpg;;;2;;False;;;;;False;False;False;;;;;False;;;;;; +5;0;True;"TomTom 220V Netzteil ";"TomTom 220V Netzteil ";
    220V Netzteil TomTom Navigation

    Ladegerät mit abgewinkeltem 90° Spezialstecker

    Steckerlader für Tom Tom Serien: ONE XL Europe HD Traffic Regional,
    Go Serien 520 Go 720 Go 740 Go 920 Live XL XL LIVE IQ Routes
    Netzteil Ladegerät 240 Volt Output: 5.5V +/- 5%
    Mit Ladekontrollleuchte (LED), nur 85 Gramm
    Hochflexibeles, kerbfestes Kabel, beste Qualität
    Auslieferung in Kartonbox und Schutzumschlag
    CE, beste Qualität original von Spartechnik
    ;2;False;0;;;"Reiseladegeraet / Netzteil / Ladegeraet fuer TomTom ";tomtom-220v-netzteil;True;True;P-1970;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;14.9000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;39986,6084953704;66;4;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000311-tomtom-220v-netzteil.jpg;;;2;;False;;;;;False;False;False;;;;;False;;;;;; +5;0;True;"Tom Tom One Hard Case XL schwarz ";"Tom Tom One Hard Case XL schwarz ";"

    Tom Tom One Hard Case XL schwarz
     
     

    Hard Case Tom Tom One XL, Schwarz
    passgenaue, stoßfeste Tasche aus Nylon/EVA
    Farbe: Schwarz
    Ausstattung:
    mit zusätzlichem Staufach für Zubehör
    Handschlaufe für einfachen Tragekomfort
    ";2;False;0;;;"Tom Tom One Hard Case XL schwarz ";tom-tom-one-hard-case-xl-schwarz;True;True;P-1960;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;20.9900;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;39986,6020023148;66;4;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000265-tom-tom-one-hard-case-xl-schwarz.jpg;;;2;;False;;;;;False;False;False;;;;;False;;;;;; +5;0;True;"TomTom XL IQ RoutesTM-Edition Europe ";"TomTom XL IQ RoutesTM-Edition Europe mit TMC ";"

    TomTom XL IQ RoutesTM-Edition Europe mit TMC
     

    42 Länderkarten, Fahrspurassistent, Text-to-Speech, Intelligente Routenberechnung,TMC
     

    TomTom Navigationsgerät XL IQ Routes Edition Europe 42 Traffic mit 4,3 Zoll Farb-Touchscreen, RDS/TMC,
    42 vorinstallierten Karten europäischer Länder sowie vielen Innovationen für eine verbesserte und komfortable Navigation IQ Routes -
    Intelligente Routenberechnung aus aktuellsten Karten unter Berücksichtigung verschiedener Umweltfaktoren wie Tag, Uhrzeit,
     
    Straßenabschnitt, Durchschnittsgeschwindigkeiten etc.
    Fahrspurassistent für komplizierte Spurenführung, zwei Ausfahrten in einer Ansicht und verbesserte Gebietsabdeckung Text-to-Speech zum Ansagen von Straßennamen und Verkehrshinweisen für einen konzentrierten Blick auf die Fahrbahn und ein entspanntes Fahren
     
    Lieferumfang:
    XL IQ Routes Edition Europe 42 Traffic, EasyPort-Halterung, USB-Kabel, Autoladegerät, Dokumentation, RDS/TMC-Verkehrsinfo-Empfänger
     
    ";2;False;0;;;"TomTom XL IQ RoutesTM-Edition Europe ";tomtom-xl-iq-routestm-edition-europe;True;True;P-1950;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;164.9000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;39986,5911689815;66;4;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000264-tomtom-xl-iq-routestm-edition-europe.jpg;;;1;;False;;;;;False;False;False;;;;;False;;;;;; +5;0;True;"Trekstor DataStation maxi g.u 500 GB ";"Trekstor DataStation maxi g.u 500 GB USB 2.0 ";"

    Trekstor DataStation maxi g.u Externe Festplatte 500 GB USB 2.0

     
     
     
    Optimale Speicherplatzerweiterung
    Die DataStation maxi g.u ist die perfekte Lösung für das tägliche Backup oder die Speicherplatzerweiterung Ihres PCs.
    Die externe 3,5“ Festplatte bietet ausreichend Platz zum Speichern und Archivieren der heimischen
    Musik- und Videosammlung, digitaler Fotos oder anderer Dateien.
    Schnell und bedienungsfreundlich
    Mit dem Hi-Speed USB 2.0 Anschluss bietet die DataStation maxi g.u einen schnellen Datentransfer.
    Die Festplatte ist zudem bereits vorformatiert und ohne Treiber sofort betriebsbereit.
    Unterstützt werden alle gängigen Dateisysteme von Windows®, Linux® und Mac® OS X, sowie die Betriebssysteme Microsoft Windows® 2000 / XP/ Vista,
    Mac® OS X ab 10.3 und Linux® ab Kernel 2.6.x. Die Festplatte wird über das mitgelieferte Netzteil mit Strom versorgt.
    Der Ein-/Ausschalter am Festplattengehäuse verhindert überflüssigen Stromverbrauch.
    Inklusive Nero Software „BackItUp2 Essentials“
    Die ebenfalls im Lieferumfang enthaltene Nero Software rundet das Bild der mobilen, externen Festplatte perfekt ab.
    Mit Nero BackItUp2 Essentials können Sie Backups Ihrer Daten sehr einfach planen.
    So können einzelne Dateien oder ganze Laufwerke gesichert werden.
    Um die Datenmenge gering zu halten, komprimiert die Software die Backups direkt „on the fly“.
    Auf Wunsch lassen sich die gesicherten Daten auch per Passwortschutz vor unbefugtem Zugriff schützen.
     
    Lieferumfang: Externes Festplattenlaufwerk, USB 2.0-Kabel, Netzteil, Schnellinstallationsanleitung
    ";2;False;0;;;Trekstor DataStation maxi g.u;trekstor-datastation-maxi-gu-500-gb;True;True;P-2650;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;99.0000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;39982,6066203704;15;2;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000129-trekstor-datastation-maxi-gu-1tb.jpg;;;2;;False;;;;;False;False;False;;;;;False;;;;;; +5;0;True;Canon Digital IXUS 100 IS Digitalkamera schwarz;"Canon Digital IXUS 100 IS Digitalkamera schwarz ";"

    Canon Digital IXUS 100 IS Digitalkamera schwarz

    12 Megapixel, 3-fach opt. Zoom, 2,5""Display, HDMI, SLIM
     
    Die Digital Ixus 100 IS präsentiert sich im atemberaubend-exquisiten, nur 18,4 Millimeter flachen Edelstahlgehäuse. Sie ist in den vier Farben Silber, Schwarz, Gold und Rot erhältlich.
     
    Ob großformatige Fotoprints oder gezielte Ausschnittvergrößerungen: Die hohe Auflösung von 12,1 Megapixeln sorgt für eine überzeugende Detailwiedergabe.
     
    Für hohe Geschwindigkeit und exzellente Bildqualität mit brillanten Farben und minimiertem Bildrauschen steht der aktuelle Canon-Bildprozessor DIGIC 4.
    12,1 Megapixel Sensor
    3-fach optisches Zoom
    Großes hochauflösendes 2,5 Zoll PureColor LCD II
    Superschlank; HD-Movie und HDMI-Anschluß  mehr Details im Film
     
    Lieferumfang:
    Digital IXUS 100 IS, Trageriemen, Akku, Akku-Ladegerät, USB-Kabel, Video-Kabel
    ";2;False;0;;;"Canon Digital IXUS 100 IS Digitalkamera ";canon-digital-ixus-100-is-digitalkamera-schwarz;True;True;P-1690;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;219.9000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;39964,877037037;"56;2095";25;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000251-canon-digital-ixus-100-is-digitalkamera-schwarz.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000252-canon-digital-ixus-100-is-digitalkamera-schwarz.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000253-canon-digital-ixus-100-is-digitalkamera-schwarz.jpg;2;;False;;;;;False;False;False;;;;;False;;;;;; +5;0;True;Apple iPod Touch 32 GB schwarz;"Apple iPod Touch 32 GB schwarz mit integrierter WiFi Funktion ";"
    Apple iPod Touch 32 GB schwarz mit integrierter WiFi Funktion

    Der iPod touch kann alles, was du am iPod toll findest. Und noch vielmehr. Schlankes neues Design. Mit seinem fantastisch flachen Edelstahl-Design liegt der iPod touch mit dem 3.5 Zoll Touch-Display jetzt noch besser in der Hand. Mobil im Spiel. Durch revolutionäre Technologien wie das Multi-Touch-Display, der Beschleunigungssensor und 3D-Grafiken macht das Spielen auf dem iPod touch besonders viel Spaß. Schlaue Musik Mit der neuen Funktion ""Genius"" wird der iPod touch zu Deinem superintelligenten, persönlichen DJ.
     
    Nur ein paar Fingertipps, und Genius erzeugt eine Wiedergabeliste mit Songs Deiner Mediathek, die gut zusammenpassen. Internet überall Internetzugang überall, wo ein drahtloses Netzwerk zur Verfügung steht, damit Sie immer mit dabei sind. Multitouch-Oberfläche: Die revolutionäre Technologie des iPhone und die Software Version 3.1 stecken in diesem genialen iPod. Das brillante Breitformat-Display rückt Ihre Videos und Spiele ins beste Licht und dank OpenGL sehen die Spiele jetzt noch besser aus Surfen Sie mit Safari im Web und sehen Sie YouTube Videos auf dem iPod mit integrierter Wi-Fi Funktionalität an. Mit Ihrem iPod touch können Sie im iTunes Wi-Fi Music Store nach Songs suchen, Hörproben abspielen und Titel kaufen.
     
    Lieferumfang: iPod touch, Ohrhörer, USB 2.0 Kabel, Kurzanleitung
     
    Schlankes neues Design
    Mit seinem fantastisch flachen Edelstahl-Design liegt der iPod touch so gut in der Hand wie nie zuvor. Ebenfalls Eindruck machen der neue Lautstärkeregler und der integrierte Lautsprecher.
     
    Spiele
    Speziell auf die iPod touch Technologie zugeschnittene Spiele sind nur noch einen Fingertipp entfernt. Stöbere in hunderten von Spielen im App Store direkt auf Deinem iPod touch, und wenn Du gefunden hast, was Du suchst, kannst Du es einfach laden und dann kann es losgehen.
     
    Steuerung per Fingertipp
    Viele Spiele auf dem iPod touch nutzen die Multi-Touch-Technologie für besonders exakte Fingertipp-Steuerung der verschiedenen Spielelemente. Beim Schach ziehst Du mit dem Finger die Figuren, bei Würfelspielen bewegst Du die Würfel. Durch Ziehen mit zwei Fingern kannst Du die Anzeige vergrößern und verkleinern, Deine Figur nach links oder rechts drehen, und durch einfaches Antippen triffst Du eine Auswahl.
     
    Musik
    Blättere in den Albumcovern Deiner Musiksammlung. Erstelle immer wieder neue Genius Wiedergabelisten und erweitere Deine Sammlung aus dem iTunes Wi-Fi Music Store überall, wo ein Wi-Fi-Hotspot in der Nähe ist.
     
    Mit Cover Flow lebt das Flair einer CD- oder Plattensammlung wieder auf. Wer erinnerst sich nicht an das Gefühl beim Durchblättern der Sammlung? Das gibt es jetzt auch auf dem iPod touch: einfach iPod drehen, durch die Cover blättern, ein Album auswählen, fertig. Ein Fingertipp aufs Cover, und schon siehst Du die Titelliste, ein weiterer Tipp spielt die Musik ab, und dabei kannst Du sogar die Songtexte anzeigen.
     
    Ein Musikgenie
    Stell Dir vor, Du hörst einen Song. Toll wären jetzt andere Titel, die gut dazu passen. Was machst du? Ganz einfach: Du verwendest die neue Funktion ""Genius"". Diese findet die Songs in Deiner Mediathek, die gut zusammenpassen. Du erhältst eine Genius Wiedergabeliste, die Du sofort anhören, sichern oder sogar aktualisieren kannst. Verlass Dich also auf den Genius von iTunes, wenn Du einen Mix willst, auf den Du selbst nicht gekommen wärst.
     
    Lautsprecher integriert
    Mit dem integrierten Lautsprecher kannst Du Musik und Gespräche ohne Kopfhörer hören – perfekt für zwangloses Hörvergnügen.

    Längere Batterielaufzeit
    Jetzt kannst Du noch länger rocken (und ansehen und spielen). Der iPod touch hält bis zu 36 Stunden bei Musik oder bis zu 6 Stunden bei Videos durch. Das reicht für drei oder vier Filme zwischen den Ladevorgängen.
     
    Internet
    Surfe im Internet mit Wi-Fi. Du kannst detailgenaue HTML-E-Mails mit Anlagen empfangen und Wegbeschreibungen und aktuelle Verkehrsinformationen abrufen. Auch als YouTube-Fan entgeht Dir nichts.
     
    Überall ins Internet
    Der iPod touch ist der einzige iPod mit kabellosem 802.11b/g Internetzugriff. Bei bestehender Wi-Fi-Verbindung kannst Du im Internet surfen und Nachrichten lesen, Sportergebnisse sehen, Rechnungen bezahlen und online einkaufen.
     
    Wer suchet, der findet
    Der iPod touch synchronisiert Deine Lesezeichen vom PC oder Mac, sodass Du ruck zuck auf Deine Lieblingsseiten zugreifen kannst. Die Google- und Yahoo!-Suche ist schon integriert, sodass Du im Web schnell findest, was Du suchst.
     
    Zoom mit Aussicht
    Jeden beliebigen Ausschnitt einer Webseite kannst Du vergrößern, indem Du mit dem Finger darauf tippst oder mit zwei Fingern die Anzeige aufziehst. Websites lassen sich im Hoch- oder Querformat anzeigen: einfach den iPod touch um 90 Grad drehen, und schon wird auch die Darstellung der Website gedreht.
     
    Eigene Weblinks
    Für häufig besuchte Websites, etwa die einer Zeitung, eines Blogs oder eine Sport-Website, kannst Du einfach ein Symbol auf dem Home-Bildschirm erstellen. Deine Lieblingsseiten sind über mit Safari erstellte Weblinks nur einen Fingertipp entfernt.
     
    Rock 'n' Run mit Nike+
    Im iPod touch ist kabellose Unterstützung für Nike + iPod integriert. Du brauchst nur einen Nike + iPod Sensor in Deinem Schuh, und schon kann's losgehen.
     
    Das optimale Lauftraining
    Im iPod touch ist jetzt Unterstützung für Nike + iPod integriert. Einfach den Nike + iPod Sensor (separat erhältlich) in den Nike+ Laufschuh einsetzen, und es kann losgehen. Der Sensor überträgt die Laufdaten drahtlos an den iPod touch – er erfasst die gelaufene Zeit, die zurückgelegte Strecke und die verbrauchten Kalorien. Außerdem gibt er Dir gesprochenes Feedback zu Deinen Trainingsfortschritten.
     
    Das optimale Fitnesstraining
    Diese Funktion kann auch zusammen mit neuen, in vielen Fitnessstudios vorhandenen Geräten für das Ausdauertraining gekoppelt werden. Suche einfach nach mit Nike + iPod kompatiblen Laufbändern, Elliptical Trainern, Steppern und Hometrainern.
    ";2;False;0;;;Apple iPod Touch 32 GB;apple-ipod-touch-32-gb-schwarz;True;True;P-1260;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;277.9000;277.9000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;39915,3405439815;43;1;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000141-apple-ipod-touch-16-gb-schwarz.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000142-apple-ipod-touch-16-gb-schwarz.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000143-apple-ipod-touch-16-gb-schwarz.jpg;2;;False;;;;;False;False;False;;;;;False;;;;;; +5;0;True;Apple iPod shuffle 4 GB silber;Apple iPod shuffle 4GB silber;"
    Apple iPod shuffle 4GB silber
     
     
    Der kleinste iPod der Welt
     
     
    Um den kleinsten iPod der Welt zu bauen, haben wir die Steuerung vom iPod shuffle in das Ohrhörerkabel integriert.
    So wird der iPod shuffle noch kleiner und die Steuerung ist genau da, wo du sie einfach erreichst.
    Wenn du einen Song abspielen, anhalten oder überspringen möchtest,
    musst du nicht lange nach dem iPod shuffle suchen - greif einfach zum Kabel und drücke auf eine der Tasten.
    Dieser Entertainment-Winzling sagt Ihnen auf Knopfdruck, welchen Titel er gerade abspielt
    Organisieren Sie Ihre Musik in verschiedenen Wiedergabeslisten
    Dank eines stabilen, integrierten Clips lässt sich der iPod shuffle fast überall befestigen.
    Lassen Sie sich aufs Ungewisse ein: Verwenden Sie den Schalter für die Zufallswiedergabe,
    um den Inhalt Ihres iPod shuffle neu zu mischen.
    Lieferumfang: Apple Earphones mit Remote Fernbedienung
     
    iPod shuffle - In leuchtenden neuen Farben spricht Musik dich richtig an
     
    Der kleinste iPod der Welt
    Um den kleinsten iPod der Welt zu bauen, haben wir die Steuerung vom iPod shuffle in das Ohrhörerkabel integriert. So wird der iPod shuffle noch kleiner und die Steuerung ist genau da, wo du sie einfach erreichst. Wenn du einen Song abspielen, anhalten oder überspringen möchtest, musst du nicht lange nach dem iPod shuffle suchen - greif einfach zum Kabel und drücke auf eine der Tasten.
     
    Der erste iPod, der mit dir spricht
    Die VoiceOver Funktion ist mit Sicherheit der nächste Hit auf dem iPod shuffle.1 Angenommen du hörst einen Song und willst wissen, wie er heißt oder von wem er ist: Einfach Knopf drücken und VoiceOver sagt es dir. Sogar die Namen deiner Wiedergabelisten verrät es dir. Und wenn die Batterie aufgeladen werden muss, sagt VoiceOver dir das auch.
     
    Leichtbedienung
    Die Steuerung befindet sich am Kabel des rechten Ohrstöpsels. Dadurch, dass die Steuerung jetzt hier angebracht ist, kannst du deine Musiktitel durchsuchen - und die VoiceOver Funktion aktivieren - ohne vom Joggen, Rad fahren oder anderen Aktivitäten abgelenkt zu werden. Der iPod shuffle wird mit dieser einfachen Steuerung geliefert. Du kannst aber auch Kopfhörer mit ähnlichen Bedienelementen von Herstellern wie Scosche, Klipsch, V-MODA und Belkin verwenden.
     

    Dein Musikarchiv. Für unterwegs
    Der iPod shuffle kommt jetzt mit 2 GB oder 4 GB. Mit dem 4 GB Modell hast du jede Menge Platz, um Musik für viele Stunden - bis zu 1.000 Songs - zu speichern.2 Damit bist du im Fitnessstudio oder auf dem Weg zur Arbeit bestens gerüstet. Außerdem kannst du jetzt mehrere Wiedergabelisten und auch Hörbücher verwenden.
     
    Mehrere Wiedergabelisten
    Wahrscheinlich hast du dir in iTunes schon einige Wiedergabelisten zusammengestellt. Eine für unterwegs. Eine fürs Fitnessstudio. Eine zum Chillen. Jetzt kannst du deine Wiedergabelisten auf dem Computer mit dem iPod shuffle synchronisieren und hast immer genau den richtigen Mix - egal, was du gerade machst oder in welcher Stimmung du bist. VoiceOver nennt dir den Namen jeder Wiedergabeliste. So kannst du ganz leicht zwischen ihnen wechseln und genau die auswählen, nach der dir gerade ist.
     
    Farbe bekennen
    Mit dem flachen, robusten Gehäuse aus eloxiertem Aluminium ist der iPod shuffle immer das passende Accessoire. In leuchtendem Pink, Blau, Grün, Schwarz oder Silber ist er ein echtes Fashion Statement. Ganz neu dabei: der iPod shuffle Special Edition in poliertem Edelstahl (So werden Rockstars nun mal behandelt). Sogar der iPod shuffle Clip sieht stylish aus. Er klemmt sicher an Hemd, Jacke, Sportzeug oder am Rucksack. So wird der iPod shuffle zum perfekten Fashtech-Accessoire. Und klar, natürlich ist noch Platz für eine persönliche Gravur.

    Mehrsprachig
    Ein französisches Chanson. Ein spanischer Bolero. Eine italienische Arie. Dein Musikarchiv enthält Musik aus allen Ländern der Welt. Deshalb spricht VoiceOver 20 Sprachen und kann die Namen von Songs und Interpreten mit der richtigen Aussprache sprechen.
     
    Zufall oder kein Zufall?
    Der Schalter am iPod shuffle hat drei Einstellungen. Links wird deine Musik zufällig durcheinander gewürfelt. In der Mitte werden deine Songs in der normalen Reihenfolge gespielt. Rechts wird der iPod shuffle ausgeschaltet.
    ";2;False;0;;;Apple iPod shuffle Tragbarer MP3-Player 4 GB 3. Generation;apple-ipod-shuffle-4-gb-silber;True;True;P-1210;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;79.9000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;39908,3107986111;40;1;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000220-apple-ipod-shuffle-4-gb-silber.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000221-apple-ipod-shuffle-4-gb-silber.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000222-apple-ipod-shuffle-4-gb-silber.jpg;2;;False;;;;;False;False;False;;;;;False;;;;;; +5;0;True;"AVM FRITZ!Fon 7150 ";"AVM FRITZ!Fon 7150 Fritz!Box Router +Telefon + VOiP ";"
    FRITZ!Fon 7150 vereint VoIP-/Festnetz- Telefonanlage, DSL-Modem, WLAN-Router und DECT-Telefon in einem Gerät.

    FRITZ!Fon 7150 kann alles, was eine FRITZ!Box auszeichnet und bringt noch ein DECT-Mobilteil mit. Das Multitalent bietet Festnetz- und Internettelefonie, schnelles Surfen im Internet und kabellosen DSL-Zugang in einem Gerät. Telefongespräche können wahlweise über Internet (Voice over IP) oder Festnetz geführt werden – auch bei ausgeschaltetem Computer. Das zugehörige Mobilteil bietet alle Vorteile der Schnurlostelefonie über DECT. Die Anmeldung von weiteren Mobilteilen an der Basisstation ist problemlos möglich. Bereits vorhandene ISDNTelefone oder ISDN-TK-Anlagen lassen sich ohne weiteres an FRITZ!Fon 7150 anschließen.
     
    Durch die Router-Funktion erhalten alle PCs im Netzwerk Zugang zum Internet über LAN und WLAN. Die WLAN-Funkverbindungen sind ab Werk mit dem sicheren WPA-Standard verschlüsselt und dank der Stick & Surf-Funktion von AVM erfolgt die Konfiguration automatisch. Über die USB-Schnittstelle können auch USB-Drucker und -Speichermedien für die gemeinsame Nutzung komfortabel vernetzt werden. Die Hard- und Software-Firewall schützt alle Geräte im Netzwerk vor Angriffen von außen. Zusätzliche Komfortfunktionen der FRITZ!Fon 7150 wie Nachtschaltung, Klingelsperre oder ein Mailservice ergänzen die Komplettlösung für Telefonie und Internet.
     
    Internettelefonie mit Festnetzqualität
    Intelligentes Codec Management sorgt für eine konstante Sprachqualität beim VoIPen. Dank Bandbreitenmanagement surfen Sie gleichzeitig mit optimaler Qualität im Internet, ohne dass Internettelefonate gestört werden. Mit zwei Mobilteilen an der Station sind auch zwei Gespräche gleichzeitig schnurlos möglich – eines als Festnetz- und eines als Internettelefonat. Neben der exzellenten Sprachqualität bietet FRITZ!Fon 7150 auch bei Internettelefonie ISDN-Leistungsmerkmale wie Makeln, Anklopfen, Rufnummernanzeige, Direktruf oder Dreierkonferenz. Bis zu 10 verschiedene VoIP-Rufnummern – auch unterschiedlicher Provider – lassen sich speichern.
     
    Schnurloses Telefonieren mit DECT-Komfort
    Das DECT-Mobilteil bietet neben einem Farbdisplay mit grafischer Darstellung und einem digitalen Anrufbeantworter ein Telefonbuch für 200 Einträge. Sowohl das Adressbuch als auch die Anrufliste lassen sich bequem über das Mobilteil pflegen. Das ist mit einer Gesprächszeit von bis zu 17 Stunden selbst langen Telefonaten gewachsen. Über das bei DECT eingesetzte GAP-Profil lassen sich bis zu fünf weitere Mobilteile anmelden.
     
    WLAN – sicher und schnell
    FRITZ!Fon 7150 bietet bereits ab Werk eine sichere WLAN-Verbindung dank aktivierter WPA-Verschlüsselung. Mit der von AVM entwickelten Stick & Surf-Technologie wird der Start ins kabellose Surfen vereinfacht. Sobald der FRITZ!WLAN Stick in den USBHost der FRITZ!Fon 7150 gesteckt wird, werden die Konfigurations- und Sicherheitseinstellungen automatisch zwischen beiden Geräten abgeglichen. FRITZ!Fon 7150 unterstützt die neuesten WLAN-Standards und ermöglicht Verbindungen bis zu 125 MBit/s. Auf Wunsch lässt sich WLAN per Tastendruck an der Basisstation abschalten.
     
    ";2;False;0;;;"AVM FRITZ!Fon 7150 (Fritz!Box Router +Telefon + VOiP) ";avm-fritzfon-7150;True;True;P-2760;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;169.0000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;39907,7783680556;20;34;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000218-avm-fritzfon-7150.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000219-avm-fritzfon-7150.jpg;;2;;False;;;;;False;False;False;;;;;False;;;;;; +5;0;True;"AVM FRITZ!Fon MT-D VoIP Dect-Telefon ";"AVM FRITZ!Fon MT-D VoIP Dect-Telefon ";"
    FRITZ!Fon MT-D: HD-Telefonie und komfortable Internetdienste mit DECT.
    Telefonieren Sie mit dem Schnurlostelefon FRITZ!Fon MT-D in bestechender Qualität über das Internet und nutzen Sie komfortable Webdienste. Als intelligentes Telefon der neuesten DECT-Generation vereint das FRITZ!Fon den Komfort der schnurlosen Telefonie mit den Qualitäts- und Leistungsmerkmalen der Internettelefonie (VoIP) in einem Gerät.
     
    Bei der Internettelefonie mit einem FRITZ!Fon wird durch HD-Telefonie (High Definition) ein brillantes, natürliches Klanggefühl erreicht. Sprache lässt sich mit dem FRITZ!Fon in ihrem gesamten Frequenzspektrum wiedergeben, was die Klangqualität von Festnetzverbindungen deutlich übertrifft.
     
    FRITZ!Fon unterstützt die übertragung großer Bandbreiten. Dies ermöglicht neben HD-Telefonie auch die Nutzung komfortabler Internetdienste wie den Empfang von E-Mails, Podcasts, RSS-Feeds und Internetradio.
     
    Die FRITZ!Box-Modelle FRITZ!Box Fon WLAN 7390, 7320, 7270 oder 7240 stellen mit der integrierten DECT-Basisstation, mehreren Anrufbeantwortern und einem Telefonbuch mit 300 Einträgen den idealen Partner für das FRITZ!Fon dar. Mit der umfangreichen Prozessor- und Speicherausstattung ist auch der Grundstein für neue Anwendungen gelegt. Denn das FRITZ!Fon ist lernfähig: Als eines der ersten intelligenten Schnurlostelefone wird es auch künftig per Firmware-Updates aktualisiert und um neue Funktionen erweitert werden können.
     
    Umfangreicher Komfort
    Das FRITZ!Fon MT-D ist mit zahlreichen Komfortfunktionen ausgestattet. Dazu zählen Lauthören und Freisprechen in HD-Qualität sowie ISDN-Leistungsmerkmale wie Namensanzeige bei bekannten Rufnummern, Halten, Makeln, Anklopfen, Rufumleitung oder Dreierkonferenz. Die Internettelefonie in HD-Qualität lässt sich so in ihrem vollen Umfang und Komfort nutzen, ohne dass der Computer eingeschaltet sein muss. FRITZ!Fon informiert zudem aktiv über unbeantwortete Anrufe, Nachrichten auf dem Anrufbeantworter und zeigt eingegangene E-Mails an. An der DECT-Basisstation der FRITZ!Box Fon WLAN 7390, 7320, 7270 und 7240 lassen sich bis zu 6 FRITZ!Fon-Handgeräte oder andere DECT-Telefone anmelden. Die Erstinstallation und individuelle Einstellungen erfolgen dabei bequem über einfache Assistenten.
     
    FRITZ!Box als idealer Partner
    Das FRITZ!Fon MT-D kann als Mobilteil an jeder DECT-Basisstation eingesetzt werden. Im Zusammenspiel mit der FRITZ!Box Fon WLAN 7390, 7320, 7270 oder 7240 kann jedoch das volle Spektrum der Möglichkeiten beim Telefonieren und Surfen über das Internet ausgenutzt werden. Die FRITZ!Box Fon WLAN 7390 zum Beispiel vereint eine bisher nicht erreichte Vielfalt in einem Gerät: VDSL- und ADSL-Unterstützung, DECT-Basisstation fürs schnurlose Telefonieren sowie WLAN N für die optimale Datenübertragung.
     
    Über den Mediaserver sind gespeicherte Filme, Musik und Bilder auch bei ausgeschaltetem Computer im gesamten Netzwerk verfügbar. Darüber hinaus kann der Online-Speicher wie eine lokale Festplatte genutzt werden. So wird die FRITZ!Box Fon WLAN 7390 zur idealen Plattform für vernetzte Anwendungen wie IPTV, Video on Demand oder Mediastreaming.
     
    Bedienung
    - Einfach einschalten und Suchtaste auf FRITZ!Box drücken.
     
    - Einfache Bedienung über intuitives Menü.
     
    - Telefonbuch komfortabel über FRITZ!Box-Oberfläche einrichten und anzeigen.
     
    - In FRITZ!Box integrierte Anrufbeantworter einfach am FRITZ!Fon MT-D einrichten und abhören.
     
    - Blinkende Leuchtdiode signalisiert eingegangene Anrufe, neue Nachrichten auf dem Anrufbeantworter und neue E-Mails.
     
    - Große Schrift und große Tasten.
    ";2;False;0;;;"AVM FRITZ!Fon MT-D VoIP Dect-Telefon ";avm-fritzfon-mt-d-voip-dect-telefon;True;True;;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;49.0000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;39907,7759837963;20;34;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000213-avm-fritzfon-mt-d-voip-dect-telefon.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000214-avm-fritzfon-mt-d-voip-dect-telefon.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000215-avm-fritzfon-mt-d-voip-dect-telefon.jpg;2;;False;;;;;False;False;False;;;;;False;;;;;; +5;0;True;"AVM FRITZ!WLAN USB Stick ";"AVM FRITZ!WLAN USB Stick - mit Stick & Surf Wireless LAN ";"
    AVM FRITZ!WLAN USB Stick - mit Stick & Surf Wireless LAN
     
    Allgemein / Breite [cm]: 2
    Allgemein / Formfaktor: Extern
    Allgemein / Gerätetyp: Netzwerkadapter
    Allgemein / Gewicht [g]: 10
    Allgemein / Höhe [cm]: 1.1
    Allgemein / Schnittstellentyp (Bustyp): Hi-Speed USB
    Allgemein / Tiefe [cm]: 5.3
    Antenne / Antenne: Intern eingebaut
    Erweiterung-Konnektivität / Verbindungen: 1 x Hi-Speed USB - USB Typ A, 4-polig
    Kopf / Hersteller: AVM
    Kopf / Kompatibilität: PC
    Kopf / Modell: USB Stick
    Kopf / Paketierte Menge: 1
    Kopf / Produktlinie: AVM FRITZ!WLAN
    Netzwerk / Anschlusstechnik: Drahtlos
    Netzwerk / Data Link Protocol: IEEE 802.11n;IEEE 802.11b;IEEE 802.11g
    Netzwerk / Datenübertragungsrate [Mbps]: 150
    Netzwerk / Frequenzband: 2.4 GHz
    Netzwerk / Leistungsmerkmale: Stromversorgung über USB;Wi-Fi Protected Setup (WPS);Firmware aktualisierbar
    Netzwerk / Produktzertifizierungen: IEEE 802.11n;IEEE 802.11g;USB 2.0;USB 1.1;IEEE 802.11b;IEEE 802.11i
    Netzwerk / Statusanzeiger: Link/Aktivität
     
    Software-Systemanforderungen / Erforderliches Betriebssystem:
     
    Microsoft Windows XP SP2;Microsoft Windows 7;Microsoft Windows Vista
    Software-Systemanforderungen / Software inbegriffen: Treiber & Utilities
    Verschiedenes / Encryption Algorithm: WPA2;128-Bit WEP;64-Bit WEP;WPA
    Verschiedenes / Enthaltene Kabel: 1 x USB-Kabel ( extern ) - 90 cm
    ";2;False;0;;;"AVM FRITZ!WLAN USB Stick N Standard 300MBit/Sek ";avm-fritzwlan-usb-stick;True;True;P-2720;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;39.9000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;39907,7691203704;19;34;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000208-avm-fritzwlan-usb-stick.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000209-avm-fritzwlan-usb-stick.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000210-avm-fritzwlan-usb-stick.jpg;2;;False;;;;;False;False;False;;;;;False;;;;;; +5;0;True;"Navigon Schutztasche 21|12|22|13|23 Serie ";"Navigon Schutztasche 21|12|22|13|23 Serie ";"

    Navigon Schutztasche 21|12|22|13|23 Serie

     
    Diese Tasche schützt Ihren PNA vor Schmutz, Kratzern und Stößen.
    Einfach den PNA in die Tasche stecken. Textiltasche mit Zipper
    ";2;False;0;;;;navigon-schutztasche-2112221323-serie;True;True;P-2140;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;24.9000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;39887,5982523148;68;14;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000197-navigon-schutztasche-2112221323-serie.jpg;;;2;;False;;;;;False;False;False;;;;;False;;;;;; +5;0;True;Hama MP3-Tasche für Sansa Clip;Hama MP3-Tasche für Sansa Clip;

    Hama MP3-Tasche für Sansa Clip

    passgenaue Silikontasche, sitzt wie eine zweite Haut
    Farbe: Transparent
    Ausstattung:
    rutschfeste Oberfläche
    Aussparung für Kabelverbindungen
    ;2;False;0;;;Hama MP3-Tasche für Sansa Clip;hama-mp3-tasche-fuer-sansa-clip;True;True;P-1580;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;14.9000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;39881,6482638889;52;8;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000196-hama-mp3-tasche-fur-sansa-clip.jpg;;;2;;False;;;;;False;False;False;;;;;False;;;;;; +5;0;True;Apple iPod Nano 16 GB silber;Apple ipod nano 16 GB silber mit Kamera;"
    Apple ipod nano 16 GB silber mit Kamera
     
    Der neue iPod nano. Jetzt mit Videokamera, Gehäuse aus poliertem Aluminium und einem größeren Display und dem neuen FM Radio mit Live-Pause.
     
    Neues gebogenes Design, der dünnste iPod, den es je gab mit neun Farben zu Auswahl
    Die Bedieung optimiert: ein einziges Handschütteln und ein anderes Lied wird gespielt
    Die neue Funktion ""Genius"" findet die Songs in Ihrer Mediathek, die besonders gut zusammenpassen, und erstellt daraus eine Genius Wiedergabeliste.
    Viele Abspielformate: z.B. MP3, AAC, Apple Lossless, AIFF, WAV, H.264, MPEG-4
    Lieferumfang: iPod Nano, Ohrhörer, USB 2.0 Kabel, Dock-Adapter, Dokumentation, iTunes 9.0
     
    Vom beliebtesten Musikplayer der Welt gibt es jetzt noch mehr zu sehen.Vom beliebtesten Musikplayer der Welt gibt es jetzt noch mehr zu sehen.Ein Wettrennen mit Einkaufswagen. Der große Food Fight um das Essen in der Mensa. Jetzt kannst du all das mit der iPod nano Videokamera festhalten. Nimm hochwertige Videos im Hoch- oder Querformat auf, die du ganz einfach ins Web stellen oder an Freunde mailen kannst. Über das im iPod nano integrierte Mikrofon wird das Audiomaterial aufgenommen, das du dann beim Abspielen über die integrierten Lautsprecher hörst.
     
    nano macht video
    Der neue iPod nano. Jetzt mit Videokamera, Gehäuse aus poliertem Aluminium und einem größeren Display. Und dem neuen FM Radio mit Live-Pause.
     
    Mach überall zur Filmkulisse
    Den iPod nano gibt's jetzt mit integrierter Videokamera, mit der Sie überall alles spontan festhalten und dann mit deinen Freunden im Internet teilen können. Diese Videokamera ist so klein, dass Sie sie überallhin mitnehmen können.
     
    Videoaufnahme. So nano kann Video sein
    Blättern Sie durch das Menü zur Videokamera und schon können Sie Videos im Hoch- oder Querformat aufnehmen - ideal zum Mailen oder Posten auf Facebook oder MobileMe. Mit dem integrierten Mikro können Sie auch Ton aufnehmen. Wenn Sie dann Ihr Video auf dem iPod nano abspielen, hören Sie den Ton gleich dazu. Damit wird Ihr Immer-dabei-Musikplayer zur Immer-dabei-Videokamera.
     
    Special Effects Abteilung inklusive
    15 tolle Videoeffekte geben Ihren Videos richtigen Hollywood-Touch. Blättern Sie durch die Effekte, wählen Sie den passenden aus, z. B. Filmkörnung oder Bewegungsunschärfe, und dann Kamera ab! Wenn Sie fertig sind, synchronisieren Sie den iPod nano mit Ihrem Computer und iPhoto (oder eine andere Foto-Software) wird geöffnet. Jetzt brauchen Sie Ihren Videohit nur noch zu mailen oder auf YouTube oder Facebook zu posten.
     
    Synchronisieren - Teilen - Und noch mehr Videos auf YouTube laden
    Wenn Sie den iPod nano an Ihren Mac anschließen, wird iPhoto geöffnet und alle mit dem iPod nano gemachten Videos werden mit Ihrem Computer synchronisiert. Auf dem PC geht das mit Ihrer Fotosoftware genauso einfach. Auf einem Mac können Sie Ihre Videos dann direkt in iPhoto durchsuchen und bearbeiten. Die Dateigrößen der Videos sind perfekt geeignet, um sie auf YouTube hochzuladen oder an Freunde zu mailen.
     
    Das ist Genius
    Steuern Sie Genius selbst. Oder Sie lassen ihm einfach freien Lauf. Egal, wofür Sie sich entscheident, Genius durchsucht Ihr Musikarchiv nach Songs, die gut zusammenpassen.
     
    Genius Wiedergabelisten
    Angenommen Sie haben einen Lieblingssong und möchten weitere Titel hören, die gut dazu passen. Ein paar Klicks auf den iPod nano und Genius sucht anhand dieses Songs weitere Titel in Ihrem Musikarchiv und erstellt eine Genius Wiedergabeliste für Sie. Sie können sie sich sofort anhören, für später speichern oder aktualisieren und nochmal gucken, was dabei rauskommt. Wenn Sie Songmixes suchen, an die Sie selbst nie gedacht hätten, dann überlassen Sie das ruhig Genius.
     
    Genius Mixe
    Und es gibt noch eine tolle Möglichkeit, eine ganz persönliche Songsammlung auf den iPod nano zu bekommen und Genius alles für Sie erledigen zu lassen: Die Genius Mixe. Sie müssen dafür nur den iPod nano mit iTunes synchronisieren. Genius durchsucht dann automatisch Ihr Musikarchiv nach Songs, die gut zusammenpassen und erstellt bis zu 12 Genius Mixe. Diese genrebasierten Mixe sind wie Radiosender, die nur Ihre Musik spielen. So entdecken Sie Songs wieder, die Sie schon ewig nicht mehr gehört haben oder welche, die Sie schon ganz vergessen hatten.
     
    Das ist so Cover Flow
    Blättern Sie mit Cover Flow durch Ihre Alben, um ganz schnell den richtigen Song zu finden. Oder halten Sie die Mitteltaste gedrückt, um das Albumcover umzudrehen und die Songs zu sehen. Wenn Sie den gewünschten Song gefunden haben, drücken Sie auf die Mitteltaste, um ihn zu Ihrer On-the-Go-Wiedergabeliste hinzuzufügen.
     
    Zum Mischen schütteln
    Hören Sie Songs einfach mal nach dem Zufallsprinzip. Einfach die Schüttelfunktion aktivieren, den iPod nano kurz schütteln und schon springt er zu irgendeinem anderen Song. Lassen Sie sich überraschen, was der iPod nano als nächstes für Sie auflegt.
     
    Radio hören - Radio anhalten. Radio weiterhören
    Der neue FM Tuner zeigt Ihnen die Namen von Songs und Interpreten. Und mit der fantastischen neuen Live-Pause Funktion ist Radio hören noch besser als Radio hören.
     
    FM Radio. Noch eine Möglichkeiten zu rocken
    Im Radio läuft immer gute Musik. Und mit dem FM Tuner können Sie Ihre Lieblingssendungen jetzt auf dem Weg zur Arbeit hören oder neue Musik entdecken, während Sie im Fitnessstudio rocken. Sie sehen sogar was und wen Sie gerade hören.
     
    Mit Live-Pause nie mehr einen Beat verpassen
    Angenommen Sie müssen Ihre Lieblingssendung im Radio einmal kurz unterbrechen. Ein Klick auf den iPod nano und schon ist Pause. Noch ein Klick und Sie hören die Sendung weiter. Sie können sogar bis zu 15 Minuten zurückspulen und dann vorspulen, um wieder live dabei zu sein.
     
    VoiceOver. Spricht jeden an
    VoiceOver sagt Ihnen die Namen von Titel und Interpreten der Songs, die Sie gerade hören. Und zwar so gut, dass Sie überrascht sein werden.
     
    Lass mal VoiceOver reden
    Sie hören einen Song und wollen wissen, wie er heißt oder von wem er ist? Benutzen Sie einfach das Click Wheel oder die Steuerung an den optionalen Apple Earphones mit Fernbedienung und Mikro, damit VoiceOver Ihnen Songtitel und Interpreten sagt, ohne dabei die Musik zu unterbrechen. Sie müssen nicht mehr auf das Display schauen, sondern können sich aufs Joggen oder Radfahren konzentrieren.
     
    So funktioniert's
    VoiceOver funktioniert ganz einfach. Wir haben hart daran gearbeitet, damit der iPod nano nicht nur spricht, sondern auch genau das Richtige sagt. Alles beginnt mit iTunes und der engen Zusammenarbeit mit dem iPod nano. iTunes liest zunächst die Songinformationen, und verwendet dann das VoiceOver Kit, um Ansagen für Songs, Interpreten und Wiedergabelisten zu erstellen. Sie müssen einfach nur deinen iPod nano mit deinem Computer synchronisieren und schon spricht er mit Ihnen.
     
    Das Sprachtalent
    Dein Musikarchiv enthält Musik aus allen Ländern der Welt: Chansons aus Frankreich, Sambarhythmen aus Brasilien und Popmusik aus Japan. Zum Glück spricht VoiceOver fließend Songisch.
    iTunes wählt automatisch die Sprache und die beste Stimme für die Songtitel und Interpreten aus. Die Software analysiert Songdaten wie Titel, Interpreten und Albuminfos und nutzt dann intelligente Algorithmen, um die richtige Sprache auszuwählen. ""Ya Viene el Sol"" von Ozomatli erkennt iTunes zum Beispiel als spanischen Song - und schon spricht der iPod den Songtitel und Interpreten automatisch auf Spanisch aus. Sie wollen es lieber in einer anderen Sprache hören? Dann können Sie die VoiceOver Sprache für diesen Song natürlich in iTunes ändern.
     
    Geht sofort los
    Mit dem Nike + iPod Sport Kit und einem integrierten Schrittzähler, das Ihre Fortschritte verfolgt und Sie motiviert, wird das Training mit dem iPod nano nie zur Routine.
     
    Der erste Schritt in Richtung Fitness
    Der iPod nano ist sowieso schon Ihr ständiger Begleiter, warum sollten Sie ihn also nicht auch als Fitnesstrainer nutzen? Denn jetzt wird er auch zum Schrittzähler. Mit dem integrierten Beschleunigungssensor zählt er Ihre Schritte, damit Sie Ihr Fitnessziel nie aus den Augen verlieren. Sie können eine tägliche Schrittvorgabe festlegen oder ""Immer eingeschaltet"" wählen, damit er jeden Ihrer Schritte zählt. Das macht den iPod nano zum idealen Trainingspartner.
     
    Rock'n'Run
    Mit dem iPod nano und Ihren Laufschuhen holen Sie alles aus Sich raus. Sehen Sie wie die Minuten verfliegen und Sie Kilometer für Kilometer zurücklegen. Sie bekommen Sprachfeedback in Echtzeit und hören dabei Ihren Lieblingsmusik und den PowerSong, der Sie jedes Mal wieder antreibt, Ihr Bestes zu geben.
     
    Rock das Training
    Nehmen Sie Nike + iPod mit ins Fitnessstudio und Sie werden Minute für Minute, Kilometer für Kilometer durch mehr als nur Musik motiviert. Schließen Sie den iPod nano an ein Fitnessgerät an, das mit Nike + iPod kompatibel ist. Halten Sie die Geschwindigkeit, die Dauer und die Laufstrecke deines Trainings fest. Mit dem iPod nano wird jeder Besuch im Fitnessstudio zur neuen Herausforderung.
     
    Synchronisieren
    Wenn Sie fertig sind, schließen Sie den iPod nano an Ihren Mac oder PC an. Ihre Workout-Daten werden dann automatisch von iTunes an nikeplus.com gesendet. Dort können Sie dann alle Ihre Workouts und Läufe überprüfen. Holen Sie außerdem neue Motivation für den nächsten Lauf mit empfohlenen Zielvorgaben, persönlichen Trainingsprogrammen und Karten mit neuen Strecken, die Sie ausprobieren können. Oder tauschen Sie sich mit Läufern aus aller Welt aus.
    ";2;False;0;;;Apple ipod nano 16 GB schwarz;apple-ipod-nano-16-gb-silber;True;True;P-1380;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;159.9000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;39876,6815625;48;1;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000087-apple-ipod-nano-8-gb-verschiedene-farben.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000076-apple-ipod-nano-8-gb-verschiedene-farben.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000077-apple-ipod-nano-8-gb-verschiedene-farben.jpg;2;;False;;;;;False;False;False;;;;;False;;;;;; +5;0;True;"Griffin Sports Tempo Armband für iPod nano ";"Griffin Sports Tempo Armband für iPod nano ";"

    Griffin Sports Tempo Armband für iPod nano  

     
    Mit dem Tempo Armband von Griffin ist der iPod Nano sicher geschützt und doch immer erreichbar
    Egal, ob Sie wandern, joggen, reiten, Kanu fahren, Fallschirm springen, im Garten werkeln oder sich einfach nur zu Hause entspannen.

    Das formschöne, unauffällige Design mit Reflektorstreifen sorgt für hohe Sichtbarkeit. 
    Eine Aufwicklung für das Kopfhörerkabel sorgt dafür, dass Kabelsalat vermieden wird. 
    Tempo ist mit einer Abdeckung zum Schutz des iPod Displays und einem weichen Innenfutter ausgestattet.
    Das Armband ist für alle Größen gut geeignet und in der Waschmaschine waschbar.
    ";2;False;0;;;"Griffin Tempo Sports Armband ";griffin-sports-tempo-armband-fuer-ipod-nano;True;True;P-1530;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;35.9000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;39876,600787037;51;28;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000195-griffin-sports-tempo-armband-fur-ipod-nano.jpg;;;2;;False;;;;;False;False;False;;;;;False;;;;;; +5;0;True;Artwizz SeeJacket Crystal Case für iPod Nano 4G;Artwizz SeeJacket Crystal Case für iPod Nano 4G transparent;"

    Artwizz SeeJacket Crystal Case für iPod Nano 4G transparent

     
    Funktionale Schutzhülle aus Polycarbonat - Kristallklare Schutzhülle, speziell für iPod nano 4G
    Hochwertige, robuste und transparente Schutzhülle
    Komplettschutz für Vorder- und Rückseite (inkl. Display)
    Anschlüsse sind ausgespart
    Keine Beeinträchtigung der Bedienbarkeit des iPod nano 4G.
    ";2;False;0;;;Artwizz SeeJacket Crystal Case für iPod Nano 4G;artwizz-seejacket-crystal-case-fuer-ipod-nano-4g;True;True;P-1440;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;19.9000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;39860,7781828704;51;30;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000194-artwizz-seejacket-crystal-case-fur-ipod-nano-4g.jpg;;;2;;False;;;;;False;False;False;;;;;False;;;;;; +5;0;True;"Belkin F8Z 409 Silikonhülle für Apple iPod Classic ";"Belkin F8Z 409 Silikonhülle für Apple iPod Classic ";"

    Belkin F8Z 400 Silikonhülle für Apple iPod Classic

    schwarz/blau/rosa 3er-Pack

    iPod Classic SILICON SLEEVE 3-PACK Schwarz & Blau & Pink
    ";2;False;0;;;;belkin-f8z-409-silikonhuelle-fuer-apple-ipod-classic;True;True;P-1430;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;14.9000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;39860,7754166667;51;;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000193-belkin-f8z-409-silikonhulle-fur-apple-ipod-classic.jpg;;;2;;False;;;;;False;False;False;;;;;False;;;;;; +5;0;True;Garmin DVD City Navigator Europa NT Update 2010;Garmin DVD City Navigator Europa NT Update 2010;"

    Garmin DVD City Navigator Europa NT Update 2010

    Der City Navigator Europa NT 2010 bietet einen erhöhten Detailgrad
    mit über 8 Millionen km Straßenabdeckung in Europa
     
    Volle Länderabdeckung für die Baltischen Staaten + erweiterte Straßenabdeckung
    von Griechenland, Kroatien, Tschechien, Ungarn, Polen, Slowakei
     
    1,2 Millionen POIs und 1 Millionen Städte, Orte und Dörfer,
    über 8.000 Campingplätze in West-Europa
    Update der zulässigen Höchstgeschwindigkeiten
    Lieferumfang: DVD mit City Navigator Europa NT
    ";2;False;0;;;Garmin DVD City Navigator Europa NT Update 2009;garmin-dvd-city-navigator-europa-nt-update-2010;True;True;P-2020;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;99.0000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;39856,6709722222;67;44;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000192-garmin-dvd-city-navigator-europa-nt-update-2010.jpg;;;2;;False;;;;;False;False;False;;;;;False;;;;;; +5;0;True;"Sony MDR EX 35 LPB.AE Stereo-In-Ear-Kopfhörer schwarz ";"Sony MDR EX 35 LPB.AE Stereo-In-Ear-Kopfhörer schwarz ";"

    Sony MDR EX 35 LPB.AE Stereo-In-Ear-Kopfhörer schwarz

     
    Leistungsstarke Kopfhörer, hervorragend geeignet als Ersatz für mp3-Player-Kopfhörer der Einstiegsklasse.>Leistungsmerkmale
    Hybrid-Silikon-Ohrpolster für sicheren Halt und Langzeit-Tragekomfort
    Y-förmiges Kabel mit praktischem Kabel- Reiter zur Vermeidung von Kabelsalat
    Frequenzgang: 6-23,000Hz
    3,5mm Klinkenanschluss
    Kabel: 1,2Y-förmig
     
    Zubehör: Ohrpolster, Kabel-Reiter
    ";2;False;0;;;"Sony MDR EX 35 LPB.AE Stereo-In-Ear-Kopfhörer schwarz ";sony-mdr-ex-35-lpbae-stereo-in-ear-kopfhoerer-schwarz;True;True;P-1500;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;24.9000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;39816,7113541667;51;10;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000187-sony-mdr-ex-35-lpbae-stereo-in-ear-kopfhorer-schwarz.jpg;;;2;;False;;;;;False;False;False;;;;;False;;;;;; +5;0;True;"Creative EP 630 Ohrhörer schwarz ";"Creative EP 630 Ohrhörer schwarz ";"

    Creative EP 630 Ohrhörer schwarz

     
    Silikon-Ohrpolster schirmen Umgebungsgeräusche effektiv ab und verbessern die Basswiedergabe
    Leicht und komfortabel - für maximalen Musikgenuss unterwegs
    Sauerstofffreie Kupferkabel für verlustfreie Signalübertragung
    Lieferumfang: 1 Paar In-Ear-Ohrhörer mit Silikon-Ohrpolstern,
    2 Paar zusätzliche Silikon-Ohrpolster in verschiedenen Größen
    ";2;False;0;;;"Creative EP 630 Ohrhörer ";creative-ep-630-ohrhoerer-schwarz;True;True;P-1470;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;19.9000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;39816,7078009259;51;22;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000186-creative-ep-630-ohrhorer-schwarz.jpg;;;2;;False;;;;;False;False;False;;;;;False;;;;;; +5;0;True;Sandisk Sansa Fuze 4 GB;"Sandisk Sansa Fuze MP3-/Video-Player 4 GB mit Radio ";"

    Sandisk Sansa Fuze MP3-/Video-Player 4 GB mit Radio

     
     
    Mit der verfügbaren Akkuleistung können Sie 24 Stunden lang Musik hören, Bilder anschauen oder spielen.
    Der neue Sansa Fuze von SanDisk ist der ideale tragbare Musikplayer für Sie.
    Er steht mit einer Speicherkapazität 4 GB in schwarz,rot,pink zur Verfügung.
    Sehen Sie sich Ihre Lieblingsvideoclips auf dem 1,9""-Farbdisplay des Sansa Fuze an.
    Lauschen Sie dem FM-Radio mit 40 voreingestellten Sendern oder probieren Sie den integrierten Sprachrekorder aus. Mit einer unglaublich starken Akkuleistung in einem 0,3"" schmalen Gerät setzt der Sansa Fuze Zeichen.
    ";2;False;0;;;Sandisk Sansa Fuze MP3-/Video-Player 4 GB mit Radio;sandisk-sansa-fuze-4-gb;True;True;P-1560;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;89.9000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;39789,5565625;52;8;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000180-sandisk-sansa-fuze-4-gb.jpg;;;2;;False;;;;;False;False;False;;;;;False;;;;;; +5;0;True;Sandisk Sansa Clip 2 GB schwarz;Sandisk Sansa Clip 2 GB mit integriertem FM-Tuner;"

    Sandisk Sansa Clip 2 GB mit integriertem FM-Tuner blau, rot, schwarz, pink

    digitaler SanDisk Player für MP3, WMA, Secure WMA und FM Radio
    kleines, kompaktes Design, kaum größer als eine Streichholzschachtel
    FM-Radio mit 40 Stationsspeicherplätzen
    Diktiergerät-Funktion über integriertes Mikrofon
    4-zeiliges OLED-Display
    Sortierung der Titel nach versch. Kriterien möglich, wie z.B. Künstler, Album, Genre, u.a.
    bis zu 15-h-Wiedergabe mittels internem, wiederaufladbaren Akku
    inkl. abnehmbarem Trageclip, Ohrhörer, USB 2.0 Kabel, Installations-CD mit Bedienungsanleitung
    unterstützt Win 2000 / XP / Vista
     
    Lieferumfang:
    Player inkl. abnehmbarem Trageclip, Ohrhörer, USB 2.0 Kabel, Installations-CD mit Bedienungsanleitung
    ";2;False;0;;;"Sandisk Sansa Clip 2 GB mit integriertem FM-Tuner ";sandisk-sansa-clip-2-gb-schwarz;True;True;P-1550;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;49.9000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;39789,5530092593;52;8;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000163-sandisk-sansa-clip-8-gb-schwarz.jpg;;;2;;False;;;;;False;False;False;;;;;False;;;;;; +5;0;True;Sandisk Sansa Clip 8 GB schwarz;"Sandisk Sansa Clip 8 GB mit integriertem FM-Tuner ";"

    Sandisk Sansa Clip 8 GB mit integriertem FM-Tuner schwarz

     
    digitaler SanDisk Player für MP3, WMA, Secure WMA und FM Radio
    kleines, kompaktes Design, kaum größer als eine Streichholzschachtel
    FM-Radio mit 40 Stationsspeicherplätzen
    Diktiergerät-Funktion über integriertes Mikrofon
    4-zeiliges OLED-Display
    Sortierung der Titel nach versch. Kriterien möglich, wie z.B. Künstler, Album, Genre, u.a.
    bis zu 15-h-Wiedergabe mittels internem, wiederaufladbaren Akku
    inkl. abnehmbarem Trageclip, Ohrhörer, USB 2.0 Kabel, Installations-CD mit Bedienungsanleitung
    unterstützt Win 2000 / XP / Vista
     
    Lieferumfang:
    Player inkl. abnehmbarem Trageclip, Ohrhörer, USB 2.0 Kabel, Installations-CD mit Bedienungsanleitung
    ";2;False;0;;;"Sandisk Sansa Clip 8 GB mit integriertem FM-Tuner ";sandisk-sansa-clip-8-gb-schwarz;True;True;P-1570;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;69.9000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;39789,5485648148;52;8;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000163-sandisk-sansa-clip-8-gb-schwarz.jpg;;;2;;False;;;;;False;False;False;;;;;False;;;;;; +5;0;True;Canon PIXMA MP550 Multifunktionsgerät;Canon PIXMA MP550 Multifunktionsgerät;"
    Canon PIXMA MP550  Multifunktionsgerät
     
     
    3 in 1, Drucken, Kopieren, Scannen
     
     
    Der PIXMA MP550 überzeugt als exzellentes Multifunktionssystem für zu Hause mit starkem Preis-Leistungs-Verhältnis.
    Er kombiniert Komfort mit Klasse beim Dokumenten- und Fotodruck; hohes Tempo bei Druck, Scan und Kopie sind selbstverständlicher Standard.
     
    Drucken, Kopieren und Scannen
    Druckgeschwindigkeit: bis zu 9,2/6,0 ISO-Seiten pro Minute (SW/Farbe)
    Bis zu 9.600 x 2.400 dpi Auflösung, 1 Picoliter feine Tintentröpfchen; 10 x 15 cm Randlosprint in ca. 39 Sek.
    5-Tintensystem
    5,0 cm großes TFT-Farbdisplay und Easy-Scroll-Bedienrad
    Scanner mit bis zu 2.400 dpi
    PictBridge und Speicherkarte
    ChromaLife100+
    Auto Photo Fix II
    ";2;False;0;;;Canon PIXMA MP540 Multifunktionsgerät - All in One Drucker - Drucken - Scannen - Kopieren - Faxen;canon-pixma-mp550-multifunktionsgeraet;True;True;P-2200;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;2,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;109.0000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;39784,3258333333;"22;2095";25;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000161-canon-pixma-mp550-multifunktionsgerat.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000162-canon-pixma-mp550-multifunktionsgerat.jpg;;2;;False;;;;;False;False;False;;;;;False;;;;;; +5;0;True;AVM Fritz! WLAN Repeater;AVM Fritz! WLAN Repeater N/G zur Erhöhung der Reichweite von W-LAN Netzen;"
    AVM Fritz!WLAN Repeater N/G 

    zur Erhöhung der Reichweite von W-LAN Netzen

    Erhöht schnell und einfach die Reichweite von WLAN-Netzen
    Funktioniert in allen WLAN-Funknetzen: 802.11n Draft 2.0 (300 MBit/s), 802.11g/a (54 MBit/s)
    und 802.11b (11 MBit/s)
     
    Sichere Funkverbindungen dank WPA2-, WPA- und WEP-Verschlüsselung
    Integrierter UKW-Minisender (FM-Transmitter 87,5-108 Mhz)
    Perfekt abgestimmt auf WLAN-Produkte der FRITZ!Box-Familie
    .
    ";2;False;0;;;AVM Fritz!WLAN Repeater N/G zur Erhöhung der Reichweite von W-LAN Netzen;avm-fritz-wlan-repeater;True;True;P-2730;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;89.0000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;39775,5815509259;19;34;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000157-avm-fritz-wlan-repeater.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000158-avm-fritz-wlan-repeater.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000159-avm-fritz-wlan-repeater.jpg;2;;False;;;;;False;False;False;;;;;False;;;;;; +5;0;True;Adobe Photoshop Elements 7;Adobe Photoshop Elements 7 deutsch WIN.;"
    Adobe Photoshop Elements 7 deutsch WIN

    Adobe Photoshop Elements 7 kombiniert Leistungsfähigkeit mit einfacher Bedienung,
    sodass Ihnen bei der Bearbeitung von Fotos keine Grenzen gesetzt sind.
    Machen Sie aus alltäglichen Motiven eindrucksvolle Kunstwerke. Innovative Werkzeuge und Funktionen ermöglichen es Ihnen zum Beispiel,
    unerwünschte Objekte mühelos aus einem Foto zu entfernen, mit einer einzigen Mausbewegung gleichzeitig einen Bildbereich auszuwählen und mit Effekten zu versehen,
    Zähne aufzuhellen oder einen Himmel noch intensiver wirken zu lassen. Professionell gestaltete Layouts erleichtern Ihnen die Erstellung von Bildbänden,
    Fotoalben und interaktiven Online-Galerien, und dank der durchdachten Verwaltung finden Sie jedes Foto im Handumdrehen.
    Die wichtigsten Merkmale:
    Intuitive Bearbeitungswerkzeuge zur Gestaltung eindrucksvoller Fotoprojekte
    Einfache Erstellung unverwechselbarer Kreationen für Print und Web
    Effizientes Suchen und Aufrufen von Fotos
    ";2;False;0;;;Adobe Photoshop Elements 7;adobe-photoshop-elements-7;True;False;P-3010;;;False;0;False;;False;False;0;False;0;1;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;1;0;True;False;10;0;1;1;False;1;10000;;False;True;False;False;109.5000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;39774,9070023148;31;20;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000155-adobe-photoshop-elements-7.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000156-adobe-photoshop-elements-7.jpg;;2;;False;ounce;;;;False;False;False;;;;;False;;;;;; +5;0;True;"NAVIGON 1300 Navigationssystem D-A-CH ";"NAVIGON 1300 Navigationssystem D-A-CH ";"

    NAVIGON 1300 Navigationssystem D-A-CH

     
    NAVIGON MyRoutes, Clever Parking , POI Klick, Fahrspurassistent Pro, Reality View Light
     
     
    NAVIGON 1300 Besonders klein und trotzdem voll mit Features.
    Die NAVIGON 13er-Serie kann viel mehr, als Sie vielleicht im ersten Moment denken.
    Denn in dem kleinen smarten Gehäuse stecken überaus nützliche Funktionen.
    Zum Beispiel NAVIGON MyRoutes, das Ihnen jederzeit genau die Route empfiehlt, die zu Ihnen und Ihrem Fahrstil passt.
    Für eine schnelle und sichere Navigation sorgen zudem ein verbesserter Fahrspurassistent Pro, Reality View Light und viele weitere Helfer.
     
    NAVIGON MyRoutes
    Je nachdem, welcher Fahrertyp Sie sind, empfiehlt Ihnen NAVIGON MyRoutes die beste Route – zugeschnitten auf Ihren persönlichen Fahrstil,
    den Wochentag und die Tageszeit. Darüber hinaus zeigt Ihnen Ihr NAVIGON bis zu zwei weitere Routen.
    Das schafft Transparenz. Sie entscheiden, ob Sie unserer Empfehlung folgen oder eine der Alternativen wählen.
     
    Clever Parking
    hilft Ihnen bei der Parkplatzsuche. Kurz vor Ihrem Ziel zeigt Ihnen Clever Parking Parkplätze in der näheren Umgebung an.
    In Deutschland werden Sie sogar über Parkgebühren informiert. So vermeiden Sie langes Suchen und sparen dabei Geld.
     
    Fahrspurassistent Pro
    hilft Ihnen selbst durch den hektischsten Straßenverkehr hindurch.
    Vorausschauend und übersichtlich zeigt er Ihnen an, auf welche Fahrspur Sie für Ihren nächsten und übernächsten Abbiegepunkt wechseln müssen.
     
    POI-Klick
    ermöglicht durch Anklicken die Auswahl eines auf der Karte angezeigten Sonderziels wie zum Beispiel Rastplätze oder Sehenswürdigkeiten.
    Inklusive wissenswerter Informationen wie Adresse, Öffnungszeiten und Telefonnummern. Und auf Wunsch können Sie sich direkt dorthin navigieren lassen.
     
    Lieferumfang:
    PNA  1300 (3,5"" im 4:3 Format) | Kurzanleitung | Kfz-Ladekabel | Halterung | Vorinstalliertes Kartenmaterial | USB-Kabel
    ";2;False;0;;;;navigon-1300-navigationssystem-d-a-ch;True;True;P-2130;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;149.0000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;39760,6629166667;"68;2095";14;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000154-navigon-1300-navigationssystem-d-a-ch.jpg;;;2;;False;;;;;False;False;False;;;;;False;;;;;; +5;0;True;Digitus USB2.0 Hub 7-port;Digitus USB2.0 Hub 7-port;

    Digitus USB2.0 Hub 7-port

    USB 2.0 und USB 1.1 kompatibel 7 x USB A Buchse (USB 1.1 und 2.0 Endgeräte
    Maximale Datenübertragungsrate 480 Mbps
    Überspannungsschutz an allen Ausgängen
    Kompatibel mit PC und MAC
    Lieferung inklusive USB Anschlusskabel und Netzteil
    ;2;False;0;;;Digitus USB2.0 Hub 7-port;digitus-usb20-hub-7-port;True;True;P-0045;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;20.9000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;39757,6835532407;26;;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000153-digitus-usb20-hub-7-port.jpg;;;2;;False;;;;;False;False;False;;;;;False;;;;;; +5;0;True;Logitech USB Hub 4-Port USB;Logitech USB Hub 4-Port USB;"

    Logitech USB Hub 4-Port USB

    Lieferumfang: Logitech Premium 4-Port USB Hub for Notebooks,
    USB-Kabel, Schnellstartanleitung, Etui, Netzteil
     
    Systemvoraussetzungen PC: Windows 2000, Windows XP, Windows Vista:
     
    USB-Anschluss Mac: Mac OS X (10.1 oder höher) USB-Anschluss
    ";2;False;0;;;Logitech USB Hub 4-Port USB;logitech-usb-hub-4-port-usb;True;True;P-0072;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;22.9000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;39757,6788425926;26;11;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000152-logitech-usb-hub-4-port-usb.jpg;;;2;;False;;;;;False;False;False;;;;;False;;;;;; +5;0;True;LogiLink USB HUB mit Netzteil;"LogiLink USB 2.0 Hub 7-Port mit Netzteil ";"

    LogiLink USB 2.0 Hub 7-Port mit Netzteil

     
    Der schnelle Hub von LogiLink unterstützt den modernen USB 2.0-Standard mit bis zu 480 MBit/s
    und erweitert Ihren Anschluss um weitere 7 Ports.
    ";2;False;0;;;LogiLink USB HUB mit Netzteil;logilink-usb-hub-mit-netzteil;True;True;P-0070;;;False;0;False;;False;False;0;False;0;1;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;17.9000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;39757,6744907407;"26;2095";31;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000151-logilink-usb-hub-mit-netzteil.jpg;;;2;;False;;;;;False;False;False;;;;;False;;;;;; +5;0;True;"Artwizz SeeJacket Crystal Hülle für iPod classic ";"Artwizz SeeJacket Crystal Hülle für iPod classic Vers.2009 ";"

    Artwizz SeeJacket Crystal Hülle für iPod classic

    80, 120 und 160 GB (2009 & 2010 Version)

     Das SeeJacket Crystal besteht aus robustem, transparentem Kunststoff und schuetzt zuverlaessig
    vor Stoessen, Erschuetterung und Abnutzung.
    Zugriff auf alle Bedienelemente bleibt natuerlich bestehen.
    Eine Befestigungsmoeglichkeit fuer ein Umhaengeband ermoeglicht bequemes Tragen um den Hals.
    Das optional einsetzbares Silikon-Pad schuetzt das Click Wheel und laesst weiterhin bequemes Bedienen zu.
    ";2;False;0;;;Artwizz SeeJacket Crystal Hülle für iPod classic;artwizz-seejacket-crystal-huelle-fuer-ipod-classic;True;True;P-1450;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;29.9000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;39754,7778009259;51;30;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000150-artwizz-seejacket-crystal-hulle-fur-ipod-classic.jpg;;;2;;False;;;;;False;False;False;;;;;False;;;;;; +5;0;True;Artwizz PowerPlug Steckdose;"Artwizz PowerPlug Steckdose auf USB-Ladegerät ";"

    Artwizz PowerPlug Steckdose

     
    auf USB-Ladegerät für iPods und USB aufladbare MP3-Player Mit diesem USB-Ladegerät kann man den iPod shuffle oder andere MP3 Player,

    beziehungsweise andere USB Geräte, einfach an der Steckdose ohne Computer aufladen
    (das Gerät besitzt einen Steckdosenstecker und einen USB-Schnittstelle).
    In Verbindung mit dem iPod Dock Connector-auf-USB Kabel
    kann man alle iPod Modelle an der Steckdose aufladen.

    Technische Daten: Europäischer Netzstecker
    Eingang: 100-240V AC, 0,15A, 47-63Hz
    Ausgang: 5V DC, 1,0A Lieferumfang: Artwizz PowerPlug Steckdose
    ";2;False;0;;;Artwizz PowerPlug Steckdose;artwizz-powerplug-steckdose;True;True;P-1460;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;17.9000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;39754,709837963;51;30;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000149-artwizz-powerplug-steckdose.jpg;;;2;;False;;;;;False;False;False;;;;;False;;;;;; +5;0;True;Sennheiser CX 300 Ohrkanalhörer schwarz;"Sennheiser CX 300 Ohrkanalhörer ";"

    Sennheiser CX 300 Ohrkanalhörer

    Sennheiser CX 300 Ohrhörer, Kraftvoller, bassbetonter Stereo-Sound
    Optimaler Sitz im Ohrkanal durch Ohradapter
    in unterschiedlichen Größen (im Lieferumfang enthalten)
    Sehr gute Abschirmung von Außengeräuschen
    Ideal für MP3-, CD-, DVD- und MD-Player
    sowie portable Spielekonsolen mit 3,5-mm-Kopfhörerausgang
     
    ";2;False;0;;;;sennheiser-cx-300-ohrkanalhoerer-schwarz;True;True;P-1490;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;29.9000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;39754,705462963;51;29;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000148-sennheiser-cx-300-ohrkanalhorer-schwarz.jpg;;;2;;False;;;;;False;False;False;;;;;False;;;;;; +5;0;True;Gear4 IceBox transparent;Gear4 IceBox für iPod nano 4G, transparent;"
    Gear4 IceBox für iPod nano 4G, transparent
     
     
    Gear4 IceBox für iPod nano 4G, transparent
    Transparente Hülle für iPod nano 4G
    ";2;False;0;;;Gear4 IceBox transparent;gear4-icebox-transparent;True;True;P-1480;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;24.9000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;39754,6834143519;"51;2095";28;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000147-gear4-icebox-transparent.jpg;;;2;;False;;;;;False;False;False;;;;;False;;;;;; +5;0;True;Apple iPod Touch 16 GB schwarz;"Apple iPod Touch 16GB schwarz ";"
    Apple iPod Touch 32 GB schwarz mit integrierter WiFi Funktion

    Der iPod touch kann alles, was du am iPod toll findest. Und noch vielmehr. Schlankes neues Design. Mit seinem fantastisch flachen Edelstahl-Design liegt der iPod touch mit dem 3.5 Zoll Touch-Display jetzt noch besser in der Hand. Mobil im Spiel. Durch revolutionäre Technologien wie das Multi-Touch-Display, der Beschleunigungssensor und 3D-Grafiken macht das Spielen auf dem iPod touch besonders viel Spaß. Schlaue Musik Mit der neuen Funktion ""Genius"" wird der iPod touch zu Deinem superintelligenten, persönlichen DJ.
    Nur ein paar Fingertipps, und Genius erzeugt eine Wiedergabeliste mit Songs Deiner Mediathek, die gut zusammenpassen. Internet überall Internetzugang überall, wo ein drahtloses Netzwerk zur Verfügung steht, damit Sie immer mit dabei sind. Multitouch-Oberfläche: Die revolutionäre Technologie des iPhone und die Software Version 3.1 stecken in diesem genialen iPod. Das brillante Breitformat-Display rückt Ihre Videos und Spiele ins beste Licht und dank OpenGL sehen die Spiele jetzt noch besser aus Surfen Sie mit Safari im Web und sehen Sie YouTube Videos auf dem iPod mit integrierter Wi-Fi Funktionalität an. Mit Ihrem iPod touch können Sie im iTunes Wi-Fi Music Store nach Songs suchen, Hörproben abspielen und Titel kaufen.
    Lieferumfang: iPod touch, Ohrhörer, USB 2.0 Kabel, Kurzanleitung
     
    Schlankes neues Design
    Mit seinem fantastisch flachen Edelstahl-Design liegt der iPod touch so gut in der Hand wie nie zuvor. Ebenfalls Eindruck machen der neue Lautstärkeregler und der integrierte Lautsprecher.

    Spiele
    Speziell auf die iPod touch Technologie zugeschnittene Spiele sind nur noch einen Fingertipp entfernt. Stöbere in hunderten von Spielen im App Store direkt auf Deinem iPod touch, und wenn Du gefunden hast, was Du suchst, kannst Du es einfach laden und dann kann es losgehen.
     
    Steuerung per Fingertipp
    Viele Spiele auf dem iPod touch nutzen die Multi-Touch-Technologie für besonders exakte Fingertipp-Steuerung der verschiedenen Spielelemente. Beim Schach ziehst Du mit dem Finger die Figuren, bei Würfelspielen bewegst Du die Würfel. Durch Ziehen mit zwei Fingern kannst Du die Anzeige vergrößern und verkleinern, Deine Figur nach links oder rechts drehen, und durch einfaches Antippen triffst Du eine Auswahl.
     
    Musik
    Blättere in den Albumcovern Deiner Musiksammlung. Erstelle immer wieder neue Genius Wiedergabelisten und erweitere Deine Sammlung aus dem iTunes Wi-Fi Music Store überall, wo ein Wi-Fi-Hotspot in der Nähe ist.
    Mit Cover Flow lebt das Flair einer CD- oder Plattensammlung wieder auf. Wer erinnerst sich nicht an das Gefühl beim Durchblättern der Sammlung? Das gibt es jetzt auch auf dem iPod touch: einfach iPod drehen, durch die Cover blättern, ein Album auswählen, fertig. Ein Fingertipp aufs Cover, und schon siehst Du die Titelliste, ein weiterer Tipp spielt die Musik ab, und dabei kannst Du sogar die Songtexte anzeigen.
     
    Ein Musikgenie
    Stell Dir vor, Du hörst einen Song. Toll wären jetzt andere Titel, die gut dazu passen. Was machst du? Ganz einfach: Du verwendest die neue Funktion ""Genius"". Diese findet die Songs in Deiner Mediathek, die gut zusammenpassen. Du erhältst eine Genius Wiedergabeliste, die Du sofort anhören, sichern oder sogar aktualisieren kannst. Verlass Dich also auf den Genius von iTunes, wenn Du einen Mix willst, auf den Du selbst nicht gekommen wärst.
     
    Lautsprecher integriert
    Mit dem integrierten Lautsprecher kannst Du Musik und Gespräche ohne Kopfhörer hören – perfekt für zwangloses Hörvergnügen.

    Längere Batterielaufzeit
    Jetzt kannst Du noch länger rocken (und ansehen und spielen). Der iPod touch hält bis zu 36 Stunden bei Musik oder bis zu 6 Stunden bei Videos durch. Das reicht für drei oder vier Filme zwischen den Ladevorgängen.
     
    Internet
    Surfe im Internet mit Wi-Fi. Du kannst detailgenaue HTML-E-Mails mit Anlagen empfangen und Wegbeschreibungen und aktuelle Verkehrsinformationen abrufen. Auch als YouTube-Fan entgeht Dir nichts.
     
    Überall ins Internet
    Der iPod touch ist der einzige iPod mit kabellosem 802.11b/g Internetzugriff. Bei bestehender Wi-Fi-Verbindung kannst Du im Internet surfen und Nachrichten lesen, Sportergebnisse sehen, Rechnungen bezahlen und online einkaufen.
     
    Wer suchet, der findet
    Der iPod touch synchronisiert Deine Lesezeichen vom PC oder Mac, sodass Du ruck zuck auf Deine Lieblingsseiten zugreifen kannst. Die Google- und Yahoo!-Suche ist schon integriert, sodass Du im Web schnell findest, was Du suchst.
     
    Zoom mit Aussicht
    Jeden beliebigen Ausschnitt einer Webseite kannst Du vergrößern, indem Du mit dem Finger darauf tippst oder mit zwei Fingern die Anzeige aufziehst. Websites lassen sich im Hoch- oder Querformat anzeigen: einfach den iPod touch um 90 Grad drehen, und schon wird auch die Darstellung der Website gedreht.
     
    Eigene Weblinks
    Für häufig besuchte Websites, etwa die einer Zeitung, eines Blogs oder eine Sport-Website, kannst Du einfach ein Symbol auf dem Home-Bildschirm erstellen. Deine Lieblingsseiten sind über mit Safari erstellte Weblinks nur einen Fingertipp entfernt.
     
    Rock 'n' Run mit Nike+
    Im iPod touch ist kabellose Unterstützung für Nike + iPod integriert. Du brauchst nur einen Nike + iPod Sensor in Deinem Schuh, und schon kann's losgehen.
     
    Das optimale Lauftraining
    Im iPod touch ist jetzt Unterstützung für Nike + iPod integriert. Einfach den Nike + iPod Sensor (separat erhältlich) in den Nike+ Laufschuh einsetzen, und es kann losgehen. Der Sensor überträgt die Laufdaten drahtlos an den iPod touch – er erfasst die gelaufene Zeit, die zurückgelegte Strecke und die verbrauchten Kalorien. Außerdem gibt er Dir gesprochenes Feedback zu Deinen Trainingsfortschritten.
     
    Das optimale Fitnesstraining
    Diese Funktion kann auch zusammen mit neuen, in vielen Fitnessstudios vorhandenen Geräten für das Ausdauertraining gekoppelt werden. Suche einfach nach mit Nike + iPod kompatiblen Laufbändern, Elliptical Trainern, Steppern und Hometrainern.
    ";2;False;0;;;Apple iPod Touch 16 GB;apple-ipod-touch-16-gb-schwarz;True;True;P-1250;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;229.9000;229.9000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;39754,6690972222;43;1;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000141-apple-ipod-touch-16-gb-schwarz.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000142-apple-ipod-touch-16-gb-schwarz.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000143-apple-ipod-touch-16-gb-schwarz.jpg;2;;False;;;;;False;False;False;;;;;False;;;;;; +5;0;True;Hannspree HL231DPB 58,4 cm (23 Zoll);Hannspree HL231DPB 58,4 cm (23 Zoll) Widescreen LCD Monitor DVI, VGA (Kontrast dyn. 1000:1, 5ms Reaktionszeit) schwarz;Marke: HANNSPREE
    Farbe: schwarz (hochglanz)
    Produkthöhe: 18.8 cm
    Produktbreite: 54.6 cm
    Bildschirm Größe: 23 inches
    Bildschirm Auflösung: 1920x1080 Pixel
    Max. Bildschirmauflösung: 1920 x 1080 pixels
    Weitere Spezifikationen
    Leistung: 27 Watt
    ;2;False;0;;;Hannspree HL231DPB 58,4 cm (23 Zoll);hannspree-hl231dpb-584-cm-23-zoll;True;True;P-2540;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;2,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;149.0000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;39741,7897800926;"12;2095";26;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000137-hannspree-hl231dpb-584-cm-23-zoll.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000138-hannspree-hl231dpb-584-cm-23-zoll.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000139-hannspree-hl231dpb-584-cm-23-zoll.jpg;2;;False;;;;;False;False;False;;;;;False;;;;;; +5;0;True;Canon PIXMA MP270 Multifunktionsgerät;"Canon PIXMA MP270 Multifunktionsgerät ";"
    Canon PIXMA MP270 Multifunktionsgerät
     
     
    3 in 1, Drucken, Kopieren, Scannen
     
     
    Der PIXMA MP270 ist ein kompaktes, günstiges Multifunktionssystem.
    Seine Stärken sind der schnelle Dokumentendruck und der Fotodirektdruck in Laborqualität von PictBridge-kompatiblen Kameras und Fotohandys.
     
    Drucken, Kopieren und Scannen
    Druckgeschwindigkeit: bis zu 8,4/4,8 ISO-Seiten pro Minute (SW/Farbe)
    Bis zu 4.800 dpi Auflösung und 2 Picoliter feine Tintentröpfchen
    10 x 15 cm Randlosprint in ca. 45 Sek.
    Easy-WebPrint EX
    Scanner mit bis zu 1.200 dpi und Auto-Scan-Modus
    PictBridge
    Selbst öffnendes Papierausgabefach
    ChromaLife100+
    ";2;False;0;;;Canon Pixma MX310 - All in One Drucker - Drucken - Scannen - Kopieren - Faxen;canon-pixma-mp270-multifunktionsgeraet;True;True;P-2210;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;2,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;89.0000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;39741,6931365741;22;25;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000132-canon-pixma-mp270-multifunktionsgerat.jpg;;;2;;False;;;;;False;False;False;;;;;False;;;;;; +5;0;True;"TomTom XL Black Edition Europe Traffic ";"TomTom XL Black Edition Europe Traffic ";"

    TomTom XL Black Edition Europe Traffic

    TMC ,4,3"" Display, 42 Länderkarten

     
    TomTom Navigationsgerät XL Classic Black Edition mit 4,3 Zoll Farb-Touchscreen,
    RDS/TMC, 42 vorinstallierten Karten europäischer Länder sowie vielen Innovationen für eine verbesserte und komfortable Navigation
    TMC-Empfänger für einen einfachen Zugriff auf Verkehrsinformationen und verschiedene Routenoptionen für die schnellste oder kürzeste Strecke
    Mit TomTom HOME und TomTom Map Share das Navi auf dem neusten Stand halten und weitere Features am PC/Mac nutzen
    TomTom XL Classic Black Edition in einem edlen schwarzen Gehäuse mit passender EasyPort Halterung für eine einfache Frontscheibenmontage
     
    Lieferumfang:
    TomTom XL Classic Black Edition, EasyPort-Halterung, USB-Kabel, Autoladegerät, Dokumentation, RDS/TMC-Verkehrsinfo-Empfänger
    ";2;False;0;;;;tomtom-xl-black-edition-europe-traffic;True;True;P-2000;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;182.9000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;39724,7946643519;66;4;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000131-tomtom-xl-black-edition-europe-traffic.jpg;;;2;;False;;;;;False;False;False;;;;;False;;;;;; +5;0;True;Western Digital My Passport 320 GB;"Western Digital BAAA3200ABK My Passport Essential 320GB ";"

    Western Digital BAAA3200ABK My Passport Essential 320GB  

     
    Schnittstellen:1 x Hi-Speed USB, Schnittstellen Typ:Hi-Speed USB, Kapazität:320 GB, Merkmale:
    Kennwortauthentifizierung, Details zu Service & Support
    Übertragungsrate Schnittstelle:480 Mbit/s, Software inbegriffen:Smartware,
    Erforderliches Betriebssystem:Microsoft Windows XP, Microsoft Windows 7, Apple MacOS X 10.4,
    Microsoft Windows Vista, Apple MacOS X 10.6, Apple MacOS X 10.5, Stromversorgung:USB-Bus,.
    Enthaltene Kabel:1 x USB-Kabel - extern
    ";2;False;0;;;"Western Digital My Passport 320 GB externe Festplatte ";western-digital-my-passport-320-gb;True;True;P-2590;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;99.0000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;39724,7845023148;14;21;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000130-western-digital-my-passport-320-gb.jpg;;;2;;False;;;;;False;False;False;;;;;False;;;;;; +5;0;True;"Trekstor DataStation maxi g.u 1TB ";"Trekstor DataStation maxi g.u externe Festplatte 1TB ";"

    Trekstor DataStation maxi g.u Externe Festplatte 1 TB

     
    USB 2.0 inkl. Nero BackItUp 2 Essentials
     
     
    Optimale Speicherplatzerweiterung
    Die DataStation maxi g.u ist die perfekte Lösung für das
    tägliche Backup oder die Speicherplatzerweiterung Ihres PCs.
    Die externe 3,5“ Festplatte bietet ausreichend Platz
    zum Speichern und Archivieren der heimischen Musik-
    und Videosammlung, digitaler Fotos oder anderer Dateien. 
     Schnell und bedienungsfreundlich
    Mit dem Hi-Speed USB 2.0 Anschluss bietet die
    DataStation maxi g.u einen schnellen Datentransfer.
    Die Festplatte ist zudem bereits vorformatiert und
    ohne Treiber sofort betriebsbereit.
    Unterstützt werden alle gängigen
    Dateisysteme von Windows®, Linux® und Mac® OS X,
    sowie die Betriebssysteme Microsoft
    Windows® 2000 / XP/ Vista, Mac® OS X ab 10.3 und Linux® ab Kernel 2.6.x.
    Die Festplatte wird über das mitgelieferte Netzteil mit Strom versorgt. 
    Der Ein-/Ausschalter am Festplattengehäuse verhindert überflüssigen Stromverbrauch. 
    Exklusives Aluminiumgehäuse
    Das exklusive Aluminiumgehäuse der DataStation maxi g.u
    sorgt für die optimale Kühlung der Festplatte,
    so kommt die externe Festplatte
    ohne Lüfter aus und ist leise während des Betriebs 
    Inklusive Nero Software „BackItUp2 Essentials“
    Die ebenfalls im Lieferumfang enthaltene
    Nero Software rundet das Bild der mobilen, externen Festplatte perfekt ab.
    Mit Nero BackItUp2 Essentials können Sie Backups Ihrer Daten sehr einfach planen.
    So können einzelne Dateien oder ganze Laufwerke gesichert werden.
    Um die Datenmenge gering zu halten, komprimiert die Software die Backups direkt „on the fly“.
    Auf Wunsch lassen sich die gesicherten Daten auch per Passwortschutz vor unbefugtem Zugriff schützen.
    ";2;False;0;;;"Trekstor DataStation maxi g.u-externe Festplatte 1 TB ";trekstor-datastation-maxi-gu-1tb;True;True;P-2620;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;129.0000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;39720,7329166667;15;2;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000129-trekstor-datastation-maxi-gu-1tb.jpg;;;2;;False;;;;;False;False;False;;;;;False;;;;;; +5;0;True;"Western Digital My Passport 250 GB ";Western Digital My Passport Essential 250GB;"

    Western Digital My Passport Essential 250GB Schwarz

     
    Mobiler Hochleistungsspeicher für Ihren Mac® oder PC.
    Es ist leicht und robust, einfach zu transportieren und erfordert kein externes Netzteil.
    Im Lieferumfang sind eine Software zur Synchronisierung und Verschlüsselung sowie
    Google™-Software enthalten.
    USB-gesteuert Software zur Synchronisation und Verschlüsselung
    Besonders gut tragbare Form
    Zum Transportieren von wichtigen Dateien und E-Mails zwischen Büro und Wohnung sowie unterwegs
    Gemeinsame Nutzung von großen Dateien zwischen Büro und Wohnung, zwischen PC und Mac.
    Kapazität: 250 GB (GigaByte)
    maximale Transferrate: 480 Mb/s über USB 2.0
    USB 2.0 Anschluss
    für PC oder Macintosh Computer
     
    Lieferumfang:
    Tragbares Festplattenlaufwerk, USB 2.0-Kabel, Schnellinstallationsanleitung
    ";2;False;0;;;Western Digital My Passport 250 GB 2,5 Zoll Schwarz;western-digital-my-passport-250-gb;True;True;P-2580;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;89.0000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;39707,7523263889;14;21;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000128-western-digital-my-passport-250-gb.jpg;;;2;;False;;;;;False;False;False;;;;;False;;;;;; +5;0;True;"NAVIGON 4310 max Navigationssystem Europa ";"NAVIGON 4310max Navigationssystem Europa ";"

    NAVIGON 4310max Navigationssystem Europa

     
     
    40 Länder, inklusive TMC, NAVIGON MyRoutes
     
     
    NAVIGON 4310 max Ist nicht nur schön,sondern auch intelligent.
    Egal, wo es gerade langgeht, jetzt haben Sie immer eine gute Aussicht: auf die NAVIGON 43 max Serie mit ihrem edlen Design.
    Doch die Routenplaner glänzen auch durch innere Werte.
    Zum Beispiel empfiehlt Ihnen NAVIGON MyRoutes jederzeit die beste Strecke, zugeschnitten auf Ihren persönlichen Fahrstil, den Wochentag und die Tageszeit.
    Für weiteren Komfort sorgen Features wie Reality View Pro, Clever Parking und die TMC-Routeninfo.
     
    NAVIGON MyRoutes
    Je nachdem, welcher Fahrertyp Sie sind, empfiehlt Ihnen NAVIGON MyRoutes die beste Route – zugeschnitten auf Ihren persönlichen Fahrstil, den Wochentag und die Tageszeit.
    Darüber hinaus zeigt Ihnen Ihr NAVIGON bis zu zwei weitere Routen. Das schafft Transparenz. Sie entscheiden, ob Sie unserer Empfehlung folgen oder eine der Alternativen wählen.
     
    TMC-Routeninfo
    zeigt ihnen im Fall einer Staumeldung eine Alternativroute mit aktualisierter Entfernung und Ankunftszeit.
    Sie entscheiden, ob eine Umfahrung in Ihrem Fall sinnvoll ist oder ob Sie die ursprüngliche Route beibehalten wollen.
     
    Reality View Pro
    zeigt Straßen nicht als Linien, sondern realistisch aus Asphalt und mit Mittelstreifen. So behalten Sie an Autobahnkreuzen und Ausfahrten leichter den Überblick.
     
    Clever Parking
    hilft Ihnen bei der Parkplatzsuche. Kurz vor Ihrem Ziel zeigt Ihnen Clever Parking Parkplätze in der näheren Umgebung an.
    In Deutschland werden Sie sogar über Parkgebühren informiert. So vermeiden Sie langes Suchen und sparen dabei Geld.
     
    Lieferumfang:
    PNA 4310 max (4,3"" im 16:9 Format) | Kurzanleitung | Halterung Kfz-Ladekabel mit integrierter TMC-Antenne |Vorinstalliertes Kartenmaterial für 40 Länder | USB-Kabel
    ";2;False;0;;;;navigon-4310-max-navigationssystem-europa;True;True;P-2120;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;199.0000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;39661,6380787037;68;14;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000127-navigon-4310-max-navigationssystem-europa.jpg;;;2;;False;;;;;False;False;False;;;;;False;;;;;; +5;0;True;Logitech G5 Laser Mouse refresh;"Logitech G5 Laser Mouse refresh ";"
    Logitech G5 Laser Mouse refresh
     
     
    Kabelgebundene 7-Tasten Tuningmaus mit Laser-Engine
     
     
    Spieletaugliche Laser Engine mit 2000 dpi
    1.000 Meldungen/Sekunde ermöglichen Präzision bei jeder Geschwindigkeit
    Gewichtstuning mit bis zu 38 Gramm
    Die Oberfläche mit DryGrip-Technologie beugt müden, verschwitzten Händen vor
    Füße aus Polytetrafluorethylen bieten eine besonders gute Gleitfähigkeit der Maus
    ";2;False;0;;;Logitech G5 Laser Mouse Neu;logitech-g5-laser-mouse-refresh;True;True;P-2770;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;59.0000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;39656,6560300926;21;11;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000124-logitech-g5-laser-mouse-refresh.jpg;;;2;;False;;;;;False;False;False;;;;;False;;;;;; +5;0;True;"Microsoft Bluetooth Mouse 5000 ";"Microsoft Bluetooth Notebook Mouse 5000 ";"
    Microsoft Bluetooth Notebook Mouse 5000
     
    Bluetooth- und Lasertechnik in Microsoft-Qualität 
     
    Mehr Komfort und Sicherheit mit modernen Bluetooth-Notebooks:
    Das lästige Empfängermodul für die USB-Schnittstelle entfällt,
    die Maus nimmt direkt Kontakt auf mit dem fest eingebauten Bluetooth-Empfänger des Notebooks
    Stets informiert: Batteriestandsanzeige auf der Oberseite des Gehäuses (Grün/Rot für Batteriestand OK und niedrig)
    Geringe Abmessungen und niedriges Gewicht machen die Maus zum idealen Reisebegleiter.
    Bei Nichtverwendung wird die Maus sicher im formschönen Transportcase aufbewahrt
    Für Rechts- und Linkshänder geeignetes Gehäuse mit 4 leichtgängigen Maustasten inklusive Scrollrad
    Microsoft High Defi nition Laser Technologie für maximale Präzision auch Unterwegs
    ";2;False;0;;;Microsoft Bluetooth Notebook Mouse 5000;microsoft-bluetooth-mouse-5000;True;True;P-2780;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;49.0000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;39656,6470949074;"21;2095";3;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000123-microsoft-bluetooth-mouse-5000.jpg;;;2;;False;;;;;False;False;False;;;;;False;;;;;; +5;0;True;Apple iPod shuffle 2 GB pink;Apple iPod shuffle 2 GB pink;"

    Apple iPod shuffle 2GB pink
     

     
    Wie seine größeren Geschwister besitzt auch der iPod shuffle kreisförmig
    angeordnete, ergonomische Bedienelemente.
    Der Kopfhöreranschluss am iPod shuffle dient gleichzeitig als Dock-Anschluss.
    Drehen Sie den iPod shuffle auf die Seite und setzen Sie ihn in das mitgelieferte Dock ein.
    Dank eines stabilen, integrierten Clips lässt sich der iPod shuffle fast überall befestigen.
    Klemmen Sie ihn am T-Shirt, am Hemdkragen oder am Trageriemen von Rucksack oder Handtasche fest.
    Lassen Sie sich aufs Ungewisse ein: Verwenden Sie den Schalter für die Zufallswiedergabe,
    um den Inhalt Ihres iPod shuffle neu zu mischen.
    verbesserte Kopfhörer und das neue iTunes 8.0
     
    Einfach Musik anhaben mit dem Apple iPOD SHUFFLE 2GB.Tragen Sie bis zu 500 Songs am Ärmel. Oder am Gürtel. Oder am Sportoutfit. Das Erkennungszeichen für Musikfans - den Apple iPOD SHUFFLE. Füllen Sie Ihren Apple iPOD SHUFFLE silber 1GB spielend einfach. iTunes ist der Store für Unterhaltungsinhalte. Ihre super organisierte Musiksammlung und Jukebox. Und die Software, mit der Sie Ihren Apple iPOD SHUFFLE mit einem Mausklick füllen. Das farbige Gehäuse aus eloxiertem Aluminium in silber passt zum genial einfachen Design des Apple iPOD SHUFFLE.
     
    Leistungseigenschaften
     
    2 GB Flash-Memory Speicher
    min. Audio-Datenrate: 8 KBit/s
    max. Audio-Datenrate: 320 KBit/s
    Frequenzgang-Untergrenze: 20 Hz
    Frequenzgang-Obergrenze: 20000 Hz
     
    Formate/Standards
     
    MP3-Standard
    AAC + MP3 Standard
    WAV-Dateiformat kompatibel
    Audible-Format kompatibel
    AIFF-Format kompatibel
     
    Bedienung
     
    Musiktitel-Verwaltung
     
    Leistungsaufnahme/Spannungsversorgung

    Li-Polymer Akku
    12 Std. Spieldauer mit Akku
    Ladezeit für Akku: 4 Std.
     
    Anschlüsse
     
    Kopfhörer-Anschluß
    USB-Schnittstelle
    Anschluß für Docking-Station
     
    Gehäuse-Eigenschaften
     
    Breite: 4.12 cm
    Höhe: 2.73 cm
    Tiefe: 1.05 cm
    Gewicht: 15.5 g

     
    ";2;False;0;;;Apple iPod shuffle 2 GB pink;apple-ipod-shuffle-2-gb-pink;True;True;P-1130;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;64.9000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;39650,6338888889;37;1;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000118-apple-ipod-shuffle-2-gb-pink.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000119-apple-ipod-shuffle-2-gb-pink.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000120-apple-ipod-shuffle-2-gb-pink.jpg;2;;False;;;;;False;False;False;;;;;False;;;;;; +5;0;True;"Me2 ME600HD 500 GB Multimediafestplatte ";"Me2 ME600HD Multimediafestplatte 500 GB ";"

    Me2 ME600HD Multimediafestplatte 500 GB

     
     
    3,5 Zoll USB 2.0 / Scart / HDMI Multimedia
     
     
    Komplett-Lösung für Film- & TV-in Top-Qualität
    Direkter Anschluss an das Fernsehgerät zur sofortigen
    Wiedergabe von Filmen, Musik oder Fotos -
    kein Computer erforderlich 
    Mit der Fernbedienung durch die Medien navigieren
    Das Bild kann bis zu HDTV-Auflösungen von 1080i skaliert werden -
    HDMI, Scart, Component-Video und Digital-Audio Anschlüsse -
    Externe USB 2.0 Multimedia Festplatte - Kapazitäten: bis 1000 GB -
    High-speed USB 2.0 Externe USB 2.0 Multimedia Festplatte -
    Aluminium Gehäuse - Stand-alone Media Player zur Wiedergabe
    von MPEG-1, MPEG-2, DivX/Xvid, JPEG, GMC, Qpel, MP3 (ID3 tag),
    WAW Media Daten - direkte Wiedergabe von DVD Ordnern - Orderner-Navigation - 
    Eigene Playlist benutzen und bearbeiten - einfache Dateiführung, intuitive Bedienung -
    unterstützt Progressive Scan (NTSC-480p, PAL-576p)
    unterstützt NTFS und FAT32 Dateisysteme geeignet für HDTV (skaliert auf 1080i)
     
    Lieferumfang: TV-Infrarotfernbedienung Hi-Speed USB 2.0-Kabel, HDMI-Anschluss
    A/V-Kombikabel Component-Kabel Software-CD Bedienungsanleitung
    AC Netzteil (100-240V) + Netzkabel
    ";2;False;0;Me2 ME600HD 500 GB Multimediafestplatte;Me2 ME600HD 500 GB Multimediafestplatte;"Me2 ME600HD 500 GB Multimediafestplatte ";me2-me600hd-500-gb-multimediafestplatte;True;True;P-2660;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;129.0000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;39650,625474537;"16;2095";;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000117-me2-me600hd-500-gb-multimediafestplatte.jpg;;;2;;False;;;;;False;False;False;;;;;False;;;;;; +5;0;True;Samsung P2450H 24 Zoll HD LCD-Monitor;Samsung P2450H 24 Zoll HD LCD schwarz;"

    Samsung P2450H 24 Zoll HD LCD schwarz


    HDMI ,Kontrastverhältnis 70000:1, Reaktionszeit 2ms
     

     
    Das Modell überzeugt neben dem eleganten ""Touch of Color"" Design auch durch die technischen Features: Neben der VGA- und DVI-D-Schnittstelle bietet das Display auch einen HDMI-Anschluss.
    Das sehr hohe dynamische Kontrastverhältnis von 70.000:1 und die Reaktionszeit von 2 ms (G/G) machen den SyncMaster P2450H ebenfalls für Gamer interessant.
    Hochwertiges 24"" Display mit Full HD Auflösung und HDMI
    Kontrast (dynamisch): 70000:1
    Reaktionszeit: 2 ms (G/G)
    Lieferumfang: Monitor, Signalkabel, Netzkabel, Treiber CD, Handbuch (CD)
    ";2;False;0;;;;samsung-p2450h-24-zoll-hd-lcd-monitor;True;True;P-2460;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;2,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;249.0000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;39650,5278472222;9;5;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000114-samsung-p2450h-24-zoll-hd-lcd-monitor.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000115-samsung-p2450h-24-zoll-hd-lcd-monitor.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000116-samsung-p2450h-24-zoll-hd-lcd-monitor.jpg;2;;False;;;;;False;False;False;;;;;False;;;;;; +5;0;True;Microsoft Windows Vista Home Premium OEM 32 Bit;Microsoft Windows Vista Home Premium OEM 32Bit;"
    Mit Windows Vista erledigen Nutzer sicherer und einfacher ihre täglichen Aufgaben und finden sofort, was sie benötigen. Es bietet neue Möglichkeiten für die digitale Unterhaltung und einfachere Kommunikationswege mit anderen Menschen, sowohl zu Hause als auch unterwegs.
    Sicherheit und Bedienkomfort standen im Zentrum der Entwicklung von Windows Vista. Nutzer können sich auf die neu gestaltete Bedienoberfläche freuen – im neuen Look and Feel. Außerdem kümmert sich Vista noch mehr darum, Ordnung in die Datenflut auf der Festplatte zu bringen. Es wird leichter, Dokumente zu finden oder Multimedia-Daten zu verwalten und zu nutzen.
     
    Neue Benutzeroberfläche
    Windows Vista vereinfacht deutlich das Arbeiten mit dem PC. So sorgt eine benutzerfreundliche Oberfläche dafür, dass der Anwender jederzeit sofort auf die gewünschten Daten zugreifen kann. Integrierte, systemweite Suchfunktionen vereinfachen das Speichern, Auffinden, Verwalten und Organisieren wichtiger Dateien und Programme.
     
    Damit bleiben E-Mails, Dokumente, Bilder, Videos, Musik, Spiele und Websites immer im Griff. Bei der Suche auf dem Desktop-PC braucht der Nutzer nicht mehr den Namen einer Datei zu kennen, es reicht ein Wort im Dokument, der Musikinterpret oder das Datum der Fotografie, um sie zu finden.
     
     
    Das neue Vista Start-Menü mit integrierter Schnellsuche 
     
    Mit „Flip“ lässt sich von einem geöffneten Fenster komfortabel zum nächsten wechseln, wobei für jedes Fenster eine Live-Miniaturansicht angezeigt wird. Mit Hilfe der Miniaturansichten kann der Nutzer das gewünschte Fenster schnell ermitteln, insbesondere wenn mehrere Fenster desselben Typs geöffnet sind. „Flip 3D“ ermöglicht das Verwenden des Bildlaufrads der Maus zum Sichten mehrerer geöffneter Fenster und anschließenden Auswählen des gewünschten Fensters.
     
    Damit Informationen nur einen Mausklick entfernt sind, bietet Windows Vista Minianwendungen. Diese verbinden sich mit Web Services zur Wiedergabe von ständig aktualisierten Informationsdiensten wie Wetterberichte, Nachrichten oder Internet-Radio-Programme. Sie können auch alle Instant-Messaging-Kontakte und Tagesaufgaben anzeigen sowie als Taschenrechner oder Notizzettel fungieren. Alle Minianwendungen werden über die am rechten Bildschirmrand befindliche Windows Sidebar organisiert und aufgerufen.
     
    Windows Aero
    Windows Vista ist das erste Windows-Betriebssystem mit einer Benutzerumgebung, die mühelos an die Hardwaremöglichkeiten des Computers angepasst werden kann, auf dem sie installiert ist. Auf allen Computern, welche die Mindestanforderungen an die Hardware erfüllen, wird die Basisbenutzerumgebung von Windows Vista angezeigt, in der Sie die bereits erwähnten optimierten Oberflächenfunktionen finden.
     
    Windows Aero ist eine Umgebung mit einem zusätzlichen Grad an visueller Ausgereiftheit, die reaktionsschneller und verwaltbarer ist und Windows-Benutzern mehr Übersichtlichkeit und Benutzerfreundlichkeit bietet.
     
     
    Windows Vista Aero bietet spektakuläre visuelle Effekte, wie zum Beispiel transparente Bedienelemente 
     
    Jederzeit verbunden
    Windows Vista-basierte Heimcomputer, Laptops oder Tablet-PCs sind nach dem Einschalten so schnell einsatzbereit wie herkömmliche Elektronikgeräte und lassen sich auch genauso schnell ausschalten. Damit können Privatnutzer sofort auf ihre Anwendungen zugreifen, im Internet surfen oder mit ihren Freunden und Bekannten kommunizieren.
     
    Mit dem neuen „Ruhezustand“ von Windows Vista dauert trotz niedrigen Stromverbrauchs die Reaktivierung des PCs nur zwei bis drei Sekunden. Dadurch braucht der Anwender seinen Computer weniger häufig herunterfahren und neu starten. Außerdem passt das Betriebssystem seine Leistung automatisch an verschiedene Nutzer an, indem es die jeweils am häufigsten genutzten Anwendungen bereits vor dem Aufruf lädt.
     
     
    Die Windows Sidebar bietet schnellen Zugriff auf Minianwendungen, wie etwa Wetterberichte oder Nachrichten 
     
    Über das Windows Synchronisierungscenter gleicht er die Inhalte tragbarer Geräte wie Telefone, PDAs und Musik-Player mit PCs ab. Über das Windows Mobilitätscenter kann er sogar auf Einstellungen mobiler Computer zugreifen und diese ändern.
     
    Plattform für Digitale Unterhaltung
    Windows Vista enthält ein Media Center mit Zugriff per Fernbedienung auf alle wichtigen Unterhaltungsmöglichkeiten wie Musik, Bilder, Filme, TV, aufgezeichnete Sendungen und Services. Da die Software HD TV und HD DVD unterstützt, wurde die Oberfläche für High-Definiton (HD) Breitwand-Bildschirme optimiert und überarbeitet. Sie bietet eine einfache und übersichtliche Suche nach allen digitalen Medien. Das Media Center lässt sich über die Media Center Extender-Funktionalität der Xbox 360 auf das gesamte Heim erweitern.
     
    Microsoft treibt gemeinsam mit Intel und AMD die weitere Entwicklung des digitalen Heims voran. Die Intel Viiv-Technologie bietet eine neue Plattform für digitale Unterhaltung, die leistungsstarke Dual-Core-Prozessoren nutzt. AMD bietet AMD Live! auf Multimedia-Desktop-PCs und -Notebooks an, die rechtzeitig zum Erscheinen von Windows Vista auf den Markt kommen.
     
     
    Mit Flip und Flip 3D navigiert man dank übersichtlicher Miniaturansichten mühelos durch die geöffneten Fenster 
     
    Musik, Bilder und Spiele
    Der in Windows Vista integrierte Media Player 11 enthält eine aufgefrischte Oberfläche mit neuen Navigationsmöglichkeiten. Damit durchsuchen Musikfans noch schneller und effizienter ihre Sammlungen: Während der Eingabe zeigt der Media Player 11 sofort eine aktualisierte Auswahl möglicher Begriffe an.
     
    Mit der Windows Fotogalerie können Nutzer ihre Fotos und Videos von Digitalkameras miteinander tauschen und ansehen. Sie vereinfacht die Verwaltung von Bildern und enthält grundlegende Schneide- und Korrekturfunktionen. Für das Importieren, Schneiden und Organisieren von Videos steht der Windows Movie Maker zur Verfügung.
     
    Die persönlichen Lieblingsspiele lassen sich über den Games Explorer einfacher aufrufen. Die aktuelle Version der Programmier-Schnittstelle DirectX 10 bietet größeren Detailreichtum und mehr Tiefenschärfe bei Spielegrafiken sowie eine fünffach höhere Leistungsfähigkeit. Außerdem stehen viele neue und überarbeitete Games zur Verfügung wie „Halo 2 für Windows Vista“, „Flight Simulator X“ und „Mahjong-Giganten“.
     
     
    Über das Windows Media Center lassen sich Fernsehprogramme, Filme, Musik und Bilder bequem per Fernbedienung steuern 
     
    Sicherheit und Jugendschutz
    Das neue Sicherheitskonzept von Windows Vista hat zu zahlreichen Innovationen geführt. So schützt der Windows Defender den PC vor aktuellen Gefahren wie Würmer, Viren und Spyware. Der integrierte Internet Explorer 7 verhindert unter anderem Schäden durch gefälschte Websites und E-Mails.
     
    Der neue Benutzerkontoschutz unterscheidet Standardaktivitäten von besonders kritischen Aktionen. Standardaktivitäten wie das Surfen im Web, das Senden von E-Mails oder das Verwenden von Office-Programmen sind wenig sicherheitskritisch und erfordern daher keine besonderen Berechtigungen. Wenn der Anwender jedoch eine kritische Aktion durchführen will, zum Beispiel die Installation eines neuen Programms, fordert Windows Vista die Eingabe eines eigenen Kennworts. Dadurch wird es für bösartige Programme schwieriger, den PC zu befallen.
     
    Außerdem verhindert der Benutzerkontoschutz, dass PC-unerfahrene Familienmitglieder unbeabsichtigt sicherheitskritische Aktionen durchführen oder heruntergeladene Programme installieren. Mit speziellen Sicherheitseinstellungen in Windows Vista können Eltern zudem die Computernutzung ihrer Kinder kontrollieren.
     
    Komfortabler Surfen
    Internet Explorer 7 bietet nicht nur wichtige neue Sicherheits- und Datenschutzfeatures, sondern erleichtert auch gängige Aufgaben durch Features wie Registernavigation (Anzeige von Fenstern im Registerkartenformat), Onlinesuche und an die Blattgröße angepasste Druckvorgänge.
     
    Gleichzeitig werden neue Tools bereitgestellt, um einen direkten Zugriff auf die gewünschten Informationen zu ermöglichen, mit integrierter Unterstützung von Webfeeds (auch als RSS oder Really Simple Syndication bezeichnet). RSS ist eine Technologie zum Abonnieren von Informationen, damit Sie nicht nach diesen suchen müssen. Über RSS-Abonnements erhalten Sie automatisch Listen (Feeds) von Überschriften aus Websites.
     
    Internet Explorer erkennt diese Feeds zu Websites und ermöglicht, diese in einer Vorschau anzuzeigen und zu abonnieren. Nach der Abonnierung fasst Internet Explorer 7 Überschriften in jedem Feed automatisch in einer Liste zusammen. Dadurch können Sie neue Informationen auf verschiedenen Websites schnell durchsuchen, ohne die Websites einzeln besuchen zu müssen.
     
    Features:
     
    Ideal für private Anwender, begeisterte Mediennutzer, mobile Anwender und Familien
    Die neue Oberfläche Windows Aero sorgt für mehr Übersichtlichkeit und Benutzerfreundlichkeit
    Leistungsstarke integrierte Desktopsuchfunktionen, mit denen nahezu alles auf dem PC schnell gefunden werden kann
    Unterstützt Minianwendungen, die sich mit Webdiensten verbinden, um Wetterberichte, aktualisierte Nachrichten, Straßenkarten oder Internetradio bereitzustellen
    Schnelles und gezieltes Wechseln zwischen verschiedenen Fenstern mit Hilfe von Windows Flip 3D
    Unterstützung neuester Spiele-Technologie durch DirectX 10
    Windows Media Center bietet Zugriff auf Live- und aufgezeichnete Fernsehprogramme, Filme, Musik und Bilder - über Media Center-Erweiterungen sogar überall im Haus
    Enthält Windows Media Player 11, die digitale Musiksoftware der nächsten Generation
    Windows Defender schützt vor Spyware, Viren und Würmern
    Der neue Benutzerkontoschutz verbindet die Flexibilität eines Administratorkontos mit der Sicherheit eines Benutzerkontos
    Mehr Sicherheit und Komfort beim Surfen mit dem neuen Internet Explorer 7
    Reaktivierung des PCs aus dem Ruhezustand in nur 2 bis 3 Sekunden
    Unterstützt leistungsstarke Dual-Core-Systeme
    ";2;False;0;;;" Windows Vista Home Premium 32 Bit OEM ";microsoft-windows-vista-home-premium-oem-32-bit;True;True;P-2970;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;49.9000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;39650,5243865741;"80;30;2095";3;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000109-microsoft-windows-vista-home-premium-oem-32-bit.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000110-microsoft-windows-vista-home-premium-oem-32-bit.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000111-microsoft-windows-vista-home-premium-oem-32-bit.jpg;2;;False;;;;;False;False;False;;;;;False;;;;;; +5;0;True;"Garmin Topo Österreich V2 ";"Garmin Topo Österreich V2 ";"

    Garmin Topo  Österreich V2

     
    Digitale topographische Vektorkarte-Originallizenz
     
     
    Topo Österreich ist die perfekte Ergänzung für Ihr Garmin GPS!
    Die neueste Version der beliebten Outdoor-Karte ist auf allen kartenfähigen Garmin GPS-Geräten lauffähig.
    Die Topo Österreich bietet eine Vielzahl an Informationen wie Wanderwege, Straßen, Seen, Flüsse, Wälder,
    Berggipfel sowie Höhenlinien im Abstand von 20m und mehr als 800 gespeicherte Positionen von Schutzhütten.
    Die neue Topo Österreich ist mit einem digitalen Höhenmodell hinterlegt und erstmals auch routingfähig!
    Planen Sie Ihre Touren, Routen und Wegpunkte am PC oder direkt am GPS-Gerät -
    die Topo Österreich ist die perfekte Kartengrundlage für Wanderungen und Touren abseits der Straße!Tausende Points of Interest (Gasthäuser, Hotels, Parkplätze, Gemeindeämter ...)
    Suchmöglichkeiten für Geonamen, POIs und Städte/Orte.
    Auch abseits von Straßen auf Wegen und Pfaden routingfähig, sie folgt beim Anlegen von Routen automatisch den auf der Karte verzeichneten Wegen, was die Navigation deutlich vereinfacht
    Dank der mitgelieferten MicroSD-Karte ist die Handhabung der Topo Österreich V2 sehr einfach:
    MicroSD-Karte in Garmin Navigationsgerät einlegen ¿ fertig. Eine Onlinefreischaltung ist für die Nutzung mit MicroSD-Karte nicht erforderlich.
    Höhenlinien im Abstand von 20m, mit anschaulicher Geländedarstellung
    Komfortable Routen- & Wegpunktverwaltung
    Einfache Übertragen von Wegpunkten, Routen & Tracks auf Garmin GPS Geräte
    Gesamtdatenvolumen ca. 175 MB. Die Karte ist in 196 einzelne Kartenabschnitte unterteilt,
    die zwischen 100 kB und 1,6 MB groß sind.
    Lizenz zur Freischaltung eines Gerätes. Registrierung über Internet erforderlich.
    Digitale topographische Vektorkarte Routenplanung: MapSource-Produkt -
    die Kartendaten werden mit der Software MapSource bearbeitet.
    ";2;False;0;;;Garmin Topo CD Österreich;garmin-topo-oesterreich-v2;True;True;P-2030;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;189.0000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;39650,5216550926;"67;2095";44;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000108-garmin-topo-osterreich-v2.jpg;;;2;;False;;;;;False;False;False;;;;;False;;;;;; +5;0;True;"TomTom ONE Europe Classic Edition TMC ";"TomTom ONE Europe Classic Edition TMC ";"

    TomTom ONE Europe Classic Edition TMC 
     

    TomTom ONE Classic Europe 42 Traffic mit RDS/TMC-Empfänger

     

    Der neue ONE Classic Europe 42 Traffic mit EasyPort passt mit Saugnapfhalterung in jede Hemdtasche.
    Ein 3,5-Zoll-Touchscreen, hervorragende Sprachqualität, TMC zur Stauumfahrung, TomTom Map Share, Hilfe!-Menü für Notfälle 
    für die neueste Kartenversion und Kartenmaterial von West- und Osteuropa (42 Länder) machen dieses TomTom ONE Classic so einzigartig.
    TomTom ONE Classic Europe 42 Traffic mit 3,5 Zoll Touchscreen, USB-Heimladegerät, einem RDS/TMC-Empfänger und QuickGPSfix-Funktion für eine sekundenschnelle Navigationsbereitschaft
    vorinstalliertes Kartenmaterial von 32 Ländern aus Ost- und Westeuropa mit Kartenaktualisierung und eigener Kartenanpassung über TomTom HOME und Map Share
    Navigieren von Haustür zu Haustür mit Details zu Adressen, Hausnummern, Tankstellen sowie Orten von besonderem Interesse (Points of Interest, POI), 3D- / 2D-Ansicht mit Tages- und Nachtansichtmodus
    RDS/TMC-Verkehrsinfo-Empfänger für aktuelle Staumeldungen und Verkehrshinweise zum Umfahren schwieriger Verkehrssituationen und alternative Routen
    Lieferumfang: TomTom One Classic Europe 42 Traffic, EasyPort-Halterung, USB-Kabel, Autoladegerät, Dokumentation, RDS/TMC-Empfänger
    ";2;False;0;;;;tomtom-one-europe-classic-edition-tmc;True;True;P-1990;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;130.9000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;39650,5188541667;66;4;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000107-tomtom-one-europe-classic-edition-tmc.jpg;;;2;;False;;;;;False;False;False;;;;;False;;;;;; +5;0;True;"TomTom Go 740 Live Navigationssystem ";"TomTom Go 740 Live Navigationssystem schwarz ";"
    TomTom Go 740 Live Navigationssystem  schwarz
     
    4,3 Zoll Touchscreen, 32+10 Länderkarten, TMC, Bluetooth

    GO 740 LIVE mit 4,3 Zoll Farb-Touchscreen, 42 vorinstallierten Karten europäischer Länder (davon 10 Hauptverkehrsstraßen-Karten), Bluetooth,
    Kfz-Freisprecheinrichtung sowie vielen Innovationen für eine verbesserte und komfortable Navigation
    Sprachsteuerung, LIVE Services mit HD Traffic, Sicherheitswarnungen, Lokale Suche mit Google, Wetter, QuickGPSfix sowie Fahrspurassistent für komplizierte Spurenführungen
    IQ Routes - Intelligente Routenberechnung aus aktuellsten Karten unter Berücksichtigung verschiedener Umweltfaktoren wie Tag, Uhrzeit, Straßenabschnitt, Durchschnittsgeschwindigkeiten etc.
    Text-to-Speech zum Ansagen von Straßennamen und Verkehrshinweisen für einen konzentrierten Blick auf die Fahrbahn und ein entspanntes Fahren
    Lieferumfang: TomTom GO 740 LIVE,Active-Dock Kfz-Halterung, Dockinghalterung für PC/Mac, Autoladegerät, Benutzerhandbuch, CD-ROM (TomTom HOME-Software)
    ";2;False;0;;;;tomtom-go-740-live-navigationssystem;True;True;P-1980;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;249.9000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;39650,5165162037;66;4;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000106-tomtom-go-740-live-navigationssystem.jpg;;;2;;False;;;;;False;False;False;;;;;False;;;;;; +5;210;True;SmartStore Office;;"

    Der Marketing- und Verkaufsmanager für ein erfolgreiches Online-Business

    Kunden gewinnen, Kunden binden, Umsatz steigern


    SmartStore Office ist die leistungsstarke Software-Lösung zur Steuerung Ihrer Online-Verkaufs- und Marketings-Aktivitäten. Auf bahnbrechend einfache und intelligente Weise ermöglicht sie:

     

     

    • Die Planung und Durchführung hocheffektiver Email-Marketing-Kampagnen zur Neukundengewinnung
    • Die Verwaltung und Abwicklung von Bestellungen für störungsfreie Abläufe in Ihrem BackOffice
    • Die rasche Umsetzung von Maßnahmen zur Kundenbindung
    • Eine wirksame Optimierung Ihres Online-Angebotes dank umfangreicher statistischer Auswertungen

    SmartStore Office bietet eine hochmoderne und -intuitive Bedienerführung, die den Aufbau und das Organisieren des "perfekten" Online-Business zu einem Kinderspiel macht. Im SmartStore-typischen Point&Click-Verfahren können Sie auf einfachste Weise:

     

     

    • Professionelle HTML-Newsletter und Serien-Emails erstellen und an tausende Kontakte gleichzeitig versenden
    • Ihre Kunden, Interessenten, Partner und Mitglieder mit den neuesten Informationen rund um Ihr Angebot versorgen
    • Ihre Top-(Produkt)-Angebote mitsamt Abbildungen, Beschreibungen und Preisen mit einem Klick in Ihre Emailings integrieren
    • Den Inhalt Ihrer Emailings personalisieren
    • View- und Klick-Raten Ihrer Emailings auswerten
    • Durch gezielte Nachfassaktionen Folge-Geschäfte generieren
    • Ihre Online-Bestellungen abrufen und bearbeiten
    • Rechnungen, Lieferscheine und sonstige Berichte drucken oder direkt als Emails an Ihren Kunden senden

    SmartStore Office ist die unverzichtbare Ergänzung zu unserer marktführenden und mehrfach ausgezeichneten Ecommerce-Komplettlösung SmartStore.biz. Die einzigartige Interaktion zwischen beiden Anwendungen erhöht die Erfolgsrate Ihres Online-Business erheblich:

    • Kunden, Interessenten und Newsletter-Abonnenten werden in einer zentralen Datenbank gespeichert. Sie verfügen dadurch automatisch über "reiche" Kontaktdaten, die absolut zielgerichtete und hocheffektive Email-Personalisierung ermöglichen.
    • Produkt-Informationen aus einem bestehenden SmartStore.biz Produktkatalog lassen sich automatisch in ein Emailing einfügen. Dabei kann jedes Produkt mit den Produkt-Detail-Informationen in Ihrem Online-Shop verlinkt werden.
    • Aussagefähige Auswertungen zu Newslettern, Kunden, Produkten, Umsätzen etc. geben Ihnen wertvolle Hinweise zur weitergehenden Optimierung Ihres Angebotes. Sie können bspw. das Klick-Verhalten Ihrer Leser auswerten, und so wertvolle Erkentnisse über evtl. geplante Nachfassaktionen gewinnen.
    • Keine Reibungsverluste, keine Insellösungen, keine lästige "Datenschieberei" mehr von Anwendung A nach B!
    ";2;False;0;;;SmartStore Office;smartstore-office;True;True;P-2950;;;False;0;False;;False;False;0;False;0;1;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;2;10000;False;False;5;1;1;0;False;1;10000;;False;False;False;False;99.0000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;38938,5373611111;"2095;81";42;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000095-smartstore-office.gif;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000096-smartstore-office.gif;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000097-smartstore-office.gif;1;;True;kg;2.0000;1;;False;False;False;;;;;False;;;;;; +5;210;True;SmartStore eBay SmartSeller;;"

    Der clevere Verkaufsmanager für eBay!


    eBay SmartSeller ist eine eCommerce-Anwendung, mit der Sie Ihre Produkte auf einfache und bequeme Weise auf dem Online-Marktplatz von eBay anbieten können. Verschiedene Module wie Kundenverwaltung, Fakturierung oder Nachrichten-Manager unterstützen Sie bei der Abwicklung verkaufter Produkte und übernehmen Aufgaben, die Sie sonst manuell erledigen müssten.

    Direkter Zugang

    eBay SmartSeller ermöglicht Ihnen einen direkten Zugang zum größten Online-Marktplatz der Welt, ohne langwieriges Mausklicken oder Suchen. Profitieren Sie von den allerneuesten eBay-Technologien; vereint in einer - durch eBay zertifizierten - Anwendung.

    Kosten minimieren

    Minimieren Sie Ihre Kosten, die Ihnen rund um Ihre eBay-Geschäfte entstehen. Mit eBay SmartSeller ist ein für alle mal Schluss mit versteckten oder zusätzlichen Kosten. Keine Drittanbieter, die an Ihren Umsätzen partizipieren. eBay berechnet Ihnen lediglich die allgemein üblichen Gebühren fürs Einstellen einer Auktion und die Provision, die bei einem erfolgreichen Abschluss anfällt. Über den eBay SmartSeller sind diese Gebühren voll transparent und zu jedem Zeitpunkt durch Sie nachvollziehbar.

    Auktionen verwalten

    Legen Sie beliebig viele Artikel an, wahlweise mit oder ohne Assistenten. Die Ordneransicht hilft Ihnen dabei, die Artikel zu ordnen, um selbst bei einer großen Artikelanzahl nicht den Überblick zu verlieren.

    Starten Sie eine beliebige Anzahl von Auktionen, Festpreisverkäufen oder eBay-Shop-Einträgen. Der Clou dabei: Die Listings erscheinen im Datengitter schräg unterhalb Ihrer Artikel, d.h. Sie können ganz genau den Verlauf Ihrer Artikel über den Lebenszyklus von eBay-Auktionen hinweg mitverfolgen. Zusätzlich gewährleistet der Auktionsstatus, dass Sie stets den Überblick über Ihre eBay-Verkaufsaktivitäten behalten und sofort wissen, wann neue Auktionen gestartet werden müssen.

    Zeitsparend abwickeln

    eBay SmartSeller verfügt über eine umfangreiche Kundenverwaltung, in der Kunden und deren Rechnungen hierarchisch und übersichtlich präsentiert werden. Mit dem Rechnungsassistenten lassen sich komfortabel Rechnungen erstellen, drucken und betrachten. Und mit dem Mahnungsassistenten benachrichtigen Sie mit wenigen Klicks säumige Käufer. Darüber hinaus ermöglicht der Bewertungs-Manager die zügige Bewertungs-Abgabe: wahlweise für ausgewählte oder alle noch nicht bewerteten Transaktionen.

    Professionelle Auktionsvorlagen

    Im eBay SmartSeller integriert ist ein vollwertiger HTML-Editor, mit dem Sie das Aussehen Ihrer Auktionen gestalten können. Oder nutzen Sie einfach die mitgelieferten HTML-Vorlagen, die speziell für die Gestaltung von Auktionen entwickelt und auf das Kategorie-Angebot von eBay abgestimmt wurden. Einer professionellen Präsentation Ihrer Produkte und höherer Erfolgschancen Ihrer Auktionen stehen hier nichts mehr im Wege.

    Beobachten und Bieten

    Zum Beobachten und Bieten von Auktionen steht eine separates Modul zur Verfügung, über das individuelle Suchanfragen erstellt werden können. So filtern Sie gezielt alle für Sie relevanten Angebote aus dem Gesamtangebot bei eBay heraus und behalten die Übersicht über den Online-Marktplatz.

    SmartStore.biz und SmartStore Office enabled

    eBay SmartSeller kommuniziert reibungslos mit dem Shopsystem SmartStore.biz und dem Marketing- und Verkaufs-Manager SmartStore Office: Mit wenigen Klicks lassen sich in SmartStore.biz bereits erfasste Artikel-Daten übernehmen; ebenso einfach lassen sich Kunden und Bestellungen zur weiteren Abwicklung nach SmartStore Office übergeben. ";2;False;0;;;SmartStore eBay SmartSeller;smartstore-ebay-smartseller;True;False;P-2940;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;79.0000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;38938,5365625;"29;2095;81";42;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000090-smartstore-ebay-smartseller.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000091-smartstore-ebay-smartseller.gif;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000092-smartstore-ebay-smartseller.gif;1;;False;;;;;False;False;False;;;;;False;;;;;; +5;210;True;SmartStore.biz 5;;"
    Achtung, Fertig, Klick!
    Das Mega-Update SmartStore.biz 5

    Es ist soweit! Mit SmartStore.biz 5 geht eine Revolution im Bereich Desktop- basierender Online-Shop-Systeme an den Start.

    Alles ist neu, besser, größer, einfacher!

    SmartStore.biz ist in der Version 5 komplett neu entwickelt worden. Dabei wurden bewährte Programmabschnitte ausgebaut, viele bahnbrechend neue Funktionen implementiert und verbesserte Bedienungsabläufe ausgearbeitet. Nie zuvor war es so einfach, einen hochwertigen und modernen Online-Shop zu gestalten und zu organisieren.

    SmartStore.biz 5 bietet für das individuelle Erscheinungsbild eines Online-Shops unzählige Variationen im Bereich Layout & Design, eine schnelle und unkomplizierte Produktverwaltung und darüber hinaus ein herausragendes Content-Management.

    Eines der größten Highlights ist das integrierte WYSIWYG-Redaktionssystem mit nahezu unbegrenzten Möglichkeiten, den eigenen Online-Shop inhaltlich zu gestalten. Hand in Hand mit dem neuen Designer und einer Auswahl mitgelieferter Designvorlagen verleihen Sie Ihrem Shop per Klick ein höchst anspruchsvolles Look & Feel.

    Nahtlos in die inhaltliche Gestaltung eingebunden ist auch der stark ausgebaute Produktmanager. Auf einfachste Weise sorgt das Zusammenspiel beider Bereiche für eine perfekte Produktpräsentation und ist die optimale Voraussetzung für einen erfolgreichen Online-Shop.

    SmartStore.biz 5 ist von Haus bereits optimal für Suchmaschinen optimiert und erstellt für die maximale Präsenz zudem Webpfade aus lesbaren und völlig frei konfigurierbaren Namen für Verzeichnisse und Dateien. Die aussagekräftigen Linkpfade unterstützen dabei auch den Besucher der Seiten bei seiner Navigation durch den Katalog.

    ";2;False;0;;;SmartStore.Biz 5;smartstorebiz-5;True;True;P-2930;;;False;0;False;169;True;False;0;False;0;1;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;1;10000;False;True;1;1;1;0;False;1;10000;;False;False;False;False;149.0000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;38938,536400463;"29;81;2095";42;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000088-smartstorebiz-5.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000089-smartstorebiz-5.png;;1;;False;ounce;;;;False;False;False;;;;;False;;;;;; From a2e5001f85843bd6620da79b0bbe77a6ea869dda Mon Sep 17 00:00:00 2001 From: Marcus Gesing Date: Thu, 10 Dec 2015 15:01:15 +0100 Subject: [PATCH 155/707] Git ignore temp import files --- .gitignore | 1 + .../Content/1-165-0001-produktcsvexport.csv | 219 ------------------ 2 files changed, 1 insertion(+), 219 deletions(-) delete mode 100644 src/Presentation/SmartStore.Web/App_Data/ImportProfiles/produkte-importieren/Content/1-165-0001-produktcsvexport.csv diff --git a/.gitignore b/.gitignore index 460b0b95df..da52db8b44 100644 --- a/.gitignore +++ b/.gitignore @@ -201,6 +201,7 @@ Kopie von* /src/Presentation/SmartStore.Web/Plugins /src/Presentation/SmartStore.Web/App_Data/_temp/ /src/Presentation/SmartStore.Web/App_Data/ExportProfiles/ +/src/Presentation/SmartStore.Web/App_Data/ImportProfiles/ /src/Presentation/SmartStore.Web/App_Data/Settings.txt /src/Presentation/SmartStore.Web/App_Data/InstalledPlugins.txt /src/Presentation/SmartStore.Web/App_Data/Licenses.lic diff --git a/src/Presentation/SmartStore.Web/App_Data/ImportProfiles/produkte-importieren/Content/1-165-0001-produktcsvexport.csv b/src/Presentation/SmartStore.Web/App_Data/ImportProfiles/produkte-importieren/Content/1-165-0001-produktcsvexport.csv deleted file mode 100644 index 4750e5d752..0000000000 --- a/src/Presentation/SmartStore.Web/App_Data/ImportProfiles/produkte-importieren/Content/1-165-0001-produktcsvexport.csv +++ /dev/null @@ -1,219 +0,0 @@ -ProductTypeId;ParentGroupedProductId;VisibleIndividually;Name;ShortDescription;FullDescription;ProductTemplateId;ShowOnHomePage;HomePageDisplayOrder;MetaKeywords;MetaDescription;MetaTitle;SeName;AllowCustomerReviews;Published;SKU;ManufacturerPartNumber;Gtin;IsGiftCard;GiftCardTypeId;RequireOtherProducts;RequiredProductIds;AutomaticallyAddRequiredProducts;IsDownload;DownloadId;UnlimitedDownloads;MaxNumberOfDownloads;DownloadActivationTypeId;HasSampleDownload;SampleDownloadId;HasUserAgreement;UserAgreementText;IsRecurring;RecurringCycleLength;RecurringCyclePeriodId;RecurringTotalCycles;IsShipEnabled;IsFreeShipping;AdditionalShippingCharge;IsEsd;IsTaxExempt;TaxCategoryId;ManageInventoryMethodId;StockQuantity;DisplayStockAvailability;DisplayStockQuantity;MinStockQuantity;LowStockActivityId;NotifyAdminForQuantityBelow;BackorderModeId;AllowBackInStockSubscriptions;OrderMinimumQuantity;OrderMaximumQuantity;AllowedQuantities;DisableBuyButton;DisableWishlistButton;AvailableForPreOrder;CallForPrice;Price;OldPrice;ProductCost;SpecialPrice;SpecialPriceStartDateTimeUtc;SpecialPriceEndDateTimeUtc;CustomerEntersPrice;MinimumCustomerEnteredPrice;MaximumCustomerEnteredPrice;Weight;Length;Width;Height;CreatedOnUtc;CategoryIds;ManufacturerIds;Picture1;Picture2;Picture3;DeliveryTimeId;QuantityUnitId;BasePriceEnabled;BasePriceMeasureUnit;BasePriceAmount;BasePriceBaseAmount;BundleTitleText;BundlePerItemShipping;BundlePerItemPricing;BundlePerItemShoppingCart;BundleItemSkus;AvailableStartDateTimeUtc;AvailableEndDateTimeUtc;StoreIds;LimitedToStores;Name[DE];ShortDescription[DE];FullDescription[DE];Name[en];ShortDescription[en];FullDescription[en] -5;0;True;_Zero Price;;"

    Optisch zum Verwechseln ähnlich, ebenso kompakt und leicht wie die erfolgreiche SD19, aber mit noch besserer Auflösung, präsentiert sich die brandneue AEE SD21 PRO Action-Cam. Die SD21 PRO ist eine komplette Neuentwicklung, mit Innovationen und einer Ausstattung, die es bisher in diesem Preissegment noch nicht gab.
    Bei der SD21 PRO ist die Monitor-Rückwand wie auch die Fernbedienung ebenso selbstverständlich wie der aufsteckbare Zusatzakku für noch längere Power.
    Für einfaches, unkompliziertes Justieren der Kamera ist ein Laserpointer integriert. Der 10-fach Digitalzoom und die hochwertige Optik garantieren für optimale Aufnahmeergebnisse bei allen Bedingungen.

    Highlights SD21 PRO:

    • 1/3 Zoll CMOS-Sensor 8,0 Megapixel
    • 170° Weitwinkel-Objektiv, Blende F/3.0
    • 10x Digitalzoom
    • Automatische Belichtung und Weissabgleich
    • Externes TFT-Display mit Echtzeit-Anzeige für Video und das Abspielen aufgezeichneter Inhalte
    • Laserpointer als Aufnahmeorientierung
    • Selbst-/Zeit-Auslöser mit Kontroll-LED
    • Eingebautes Mikrofon für hochwertige Stereo-Voice-Aufnahmen
    • Wasserdichtes Gehäuse bis 60 Meter (IP68-Standard)
    • Hochleistungs-Lithium-Batterie
    • Aufsteckbarer Zusatzakku mit eigener Ladestandsanzeige - verdoppelt die Aufnahmedauer
    • Auto Stand-by zur Energieeinsparung
    • Funktionen: HD-Videoaufnahme / Foto
    • Recording MOV Videos können direkt am PC wiedergegeben oder auf Video-Websites hochgeladen werden
    • Photo 180-Grad-Umkehr-Funktion
    • Externe Micro SD/MMC-Speicherkarte, unterstützt bis max. 64GB (nicht enthalten)
    • Speicherkapazität Alarm
    • Schneller Vor- und Rücklauf, Funktion zum Überspringen von Inhalten in das nächste Segment
    • Unterstützung USB2.0
    • HDMI-Ausgang, AV-OUT-Funktion
    • Support-System: Windows 98SE/2000/Me/XP/Vista/Win 7/Mac OS

    Grösse: ca. 61x43x40mm (BxHxT)

    Gewicht: 88g ohne Bildschirm, 112g mit Bildschirm

    Technische Daten SD21 PRO:

    • Auflösung/Sensor: 8.0M CMOS-Sensor (3200 * 2400)
    • Optik / Linse: 170° Weitwinkel-Objektiv, Blende F/3.0
    • Gehäuse: IP68 wasserdichtes Gehäuse bis 60m
    • Memory-Karte: Micro SD unterstützt bis 64GB (nicht enthalten)
    • Photo-Modus: 3M (2048 * 1536) / 5M (2560 * 1920) / 8M (3200 * 2400)
    • Video-Aufnahmemodus: 1080P 720P WVGA QVGA
    • Bildrate: 1080P/30fps 720P/30fps WVGA/60fps QVGA/30fps
    • Video-Aufnahmeformat: MOV (H.264-Video-Kompression)
    • Photo-Format: JPEG
    • Aufnahmekapazität (2GB SDKarte):
    • Photos 3M (1900pcs), 5M (1160pcs), 8M (770pcs) /
    • Videos: 720P/60min, WVGA/135min
    • Laserpointer/Laserleistung: 1MW
    • AV OUT: Unterstützung NTSC / PAL VGA und HDMI
    • USB: USB2.0
    • Mikrofon: 2 Mikrofone, eingebaute
    • Leistungsaufnahme: 500mA@3.7V (MAX)
    • Lithium-Batterie: 1000mAh
    • Batterielaufzeit: 2.5h / Batterie
    • Betriebssystem: Windows XP SP2/Vista oder höher / Mac OS. CPU:
    • Pentium4 1.5GHZ oder höher RAM: min. 1GB
    • RTC-Funktion: Unterstützung
    • Lagertemperatur: -20 bis -60 
    • Betriebstemperatur: -10 bis -50 
    • Luftfeuchtigkeit bei Betrieb: 15 85% RH

     

    ";2;True;0;;;_Wasser;_zero-price-3;True;True;;;;False;0;False;;False;False;0;False;0;1;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;0;False;False;0;0;1;0;False;1;10000;;False;True;False;False;0.0000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;42302,5461930208;"1;2095";;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000696-_zero-price.jpg;;;2;;True;l;35.0000;100;;False;False;False;;;;1;True;;;;;; -5;0;True;Bundle Item 2;;;2;False;0;;;;bundle-item-2;True;True;;;;False;0;False;;False;False;0;True;10;1;False;;False;;False;100;0;10;True;False;0,0000;False;False;1;0;10000;False;False;0;0;0;0;False;1;10000;;False;False;False;False;19.9000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;41965,4767811343;;;;;;;;False;ounce;;;;False;False;False;;;;;False;;;;;; -5;0;True;Bundle Item 1;;;2;False;0;;;;bundle-item-1;True;True;;;;False;0;False;;False;False;0;True;10;1;False;;False;;False;100;0;10;True;False;0,0000;False;False;1;0;0;False;False;0;0;0;0;False;1;10000;;False;False;False;False;84.9000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;41965,4671613079;;;;;;;;False;ounce;;;;False;False;False;;;;;False;;;;;; -5;0;True;_Download;;"

    Downloadable product.

    ";2;False;0;;;;_download;True;True;;;;False;0;False;;False;True;8;True;10;1;False;;False;;False;100;0;10;False;False;0,0000;False;False;1;0;10000;False;False;0;0;1;0;False;1;10000;;False;False;False;False;3.8000;0.0000;0.0000;;0.0;0.0;False;0.0000;1000.0000;0.0000;0.0000;0.0000;0.0000;41863,7438013542;"1;2095";;;;;;;False;ounce;;;;False;False;False;;;;;False;;;;;; -5;0;True;_Attribut Test;;"

    Continually incubate standards compliant content vis-a-vis multifunctional portals. Dynamically exploit collaborative strategic theme areas vis-a-vis extensive partnerships. Monotonectally maximize user friendly relationships for backward-compatible alignments. Objectively deliver covalent opportunities after exceptional scenarios. Objectively drive backend paradigms via excellent meta-services. Uniquely customize sticky core competencies rather than leveraged internal or "organic" sources. Objectively conceptualize client-based users without customer directed applications. Continually generate backend processes and market-driven markets. Proactively evisculate visionary testing procedures with fully tested networks. Collaboratively facilitate B2C schemas vis-a-vis covalent meta-services. Proactively recaptiualize progressive quality vectors vis-a-vis frictionless supply chains. Distinctively synthesize revolutionary leadership vis-a-vis strategic e-markets. Distinctively pontificate principle-centered benefits with pandemic resources. Professionally pontificate multifunctional strategic theme areas via low-risk high-yield data. Uniquely underwhelm technically sound information before functional synergy. Progressively utilize 24/365 ROI whereas client-based interfaces. Seamlessly reintermediate alternative customer service through plug-and-play quality vectors. Professionally repurpose one-to-one scenarios without visionary supply chains. Enthusiastically unleash timely applications after an expanded array of e-commerce. Monotonectally pursue virtual intellectual capital after high standards in scenarios. Professionally benchmark end-to-end internal or "organic" sources with maintainable supply chains. Authoritatively disseminate high-payoff imperatives for stand-alone infomediaries. Completely network stand-alone initiatives for market positioning intellectual capital. Appropriately deliver process-centric collaboration and idea-sharing after multifunctional leadership. Energistically unleash open-source vortals vis-a-vis transparent niches.

    ";2;False;0;;;;ab-22;True;True;SKU-Tester;;;False;0;False;;False;False;7;True;10;1;False;;False;;False;100;0;10;True;False;0,0000;False;False;1;2;10000;True;False;0;1;1;0;False;1;10000;;False;False;False;False;0.0000;0.0000;0.0000;;0.0;0.0;False;0.0000;1000.0000;0.0000;0.0000;0.0000;0.0000;41833,6856570949;"1;2095";;;;;2;;False;ounce;;;;False;False;False;;;;;False;;;;;; -5;0;True;_GiftCard;;

    GiftCart for testing.

    ;2;False;0;;;;_giftcard-2;True;True;;;;True;0;False;;False;False;0;True;10;1;False;;False;;False;100;0;10;False;False;0,0000;False;False;1;0;10000;False;False;0;0;1;0;False;1;10000;;False;False;False;False;10.0000;0.0000;0.0000;;0.0;0.0;False;0.0000;1000.0000;0.0000;0.0000;0.0000;0.0000;41701,4763476505;1;;;;;;;False;ounce;;;;False;False;False;;;;;False;;;;;; -5;0;True;GiftCard;;;2;False;0;;;;_giftcard;True;True;;;;True;0;False;;False;False;0;True;10;1;False;;False;;False;100;0;10;True;False;0,0000;False;False;1;0;10000;False;False;0;0;1;0;False;1;10000;;False;False;False;False;10.0000;0.0000;0.0000;;0.0;0.0;False;0.0000;1000.0000;0.0000;0.0000;0.0000;0.0000;41671,8425473727;2095;;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000666-giftcard.jpg;;;;;False;ounce;;;;False;False;False;;;;;False;;;;;; -15;0;True;_SmartStore Bundle;;"

    SmartStore Test Bundle

    ";2;False;0;;;_SmartStore Bundle;_smartstore-bundle;True;True;PD-01097;;;False;0;False;;False;False;0;False;0;1;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;888.0000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;41656,6659837963;"81;2095";;;;;1;;False;;;;Bestehend aus;False;False;True;;;;;False;;;;;; -15;0;True;_Bundle;;"

    My product bundle.

    ";2;False;0;;;;_bundle;True;True;SKU-1001;;;False;0;False;;False;False;0;True;10;1;False;;False;;False;100;0;10;True;False;0,0000;False;False;1;1;9999;False;False;10;0;1;1;False;1;10000;;False;False;False;False;499.0000;0.0000;260.6000;;0.0;0.0;False;0.0000;1000.0000;0.0000;0.0000;0.0000;0.0000;41656,5811581829;"81;2095";;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000665-_bundle.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000667-_bundle.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000668-_bundle.jpg;2;;False;kg;3.0000;1;Bestehend aus;False;False;True;P-6000,P-2930,P-2940,P-2950;;;;False;;;;;; -10;0;True;_Gruppenprodukt;Grouped product;"

    Tortor dis facilisis augue eros. Porta turpis! Augue! Magna mattis porttitor aliquet eu, montes magna nunc pulvinar hac, augue porttitor, ridiculus! Pulvinar, in tortor risus in scelerisque platea, pulvinar pid! Dapibus proin diam. Pellentesque cum! Tincidunt, tempor a magna turpis, mid amet, aenean, placerat. Phasellus? Tempor, cursus lacus porttitor ac, in tincidunt sociis vel? Eu velit dapibus integer enim risus augue phasellus odio turpis, sociis, eros dapibus et sed auctor, nec nisi montes, egestas integer eu rhoncus tortor integer montes sit scelerisque nec integer! Vel aliquet vut aliquet dis integer sed urna lectus sed habitasse etiam! Nunc purus augue dictumst, lectus platea? Turpis montes cras ultricies, adipiscing? Nunc. Cursus in! In ultricies parturient etiam augue, tempor mauris pellentesque purus rhoncus.

    Vut vut et amet, phasellus? Et in integer enim, aenean elit, montes cum elementum nascetur a penatibus! Ac magna lorem ac placerat, lectus. Scelerisque habitasse elementum sociis scelerisque rhoncus. Natoque mattis parturient tempor dictumst turpis, hac placerat dolor nunc penatibus. Facilisis tristique massa facilisis? Rhoncus habitasse sit! Aenean aliquet ut quis ut in amet ut, phasellus augue sit tempor nunc dictumst eu, porta amet augue, mattis facilisis ac! Turpis egestas ridiculus, lacus in, sed placerat, odio lundium tincidunt nisi amet rhoncus. Augue cras! Velit, mattis! Auctor nisi mus? Amet nunc elementum placerat vut! Porttitor pid porta amet sit magnis, nisi ut cursus. Egestas sed auctor amet nec sit dapibus amet dis? Odio velit ac, hac cum ridiculus, amet ac.

    Integer nisi natoque dictumst, facilisis! Phasellus turpis, pellentesque in! Dictumst pid, nisi a porttitor nec. Nunc natoque magnis etiam odio a diam vut integer aenean magnis cum lundium aenean, risus scelerisque, penatibus! Enim enim, scelerisque non placerat ut auctor, ac parturient auctor tincidunt, porttitor a est sit, nascetur scelerisque lorem in turpis sagittis mus! Enim turpis hac dis? Sit, porta nunc rhoncus ac? Integer tincidunt est porttitor, tincidunt natoque facilisis, facilisis, hac lorem elementum pulvinar tincidunt odio, dignissim cursus, urna auctor magna aliquam! Dolor duis ac tincidunt, magna! A! Urna, enim nascetur cursus, tincidunt aenean ac dis odio vel, ut lacus, duis sed in porttitor massa penatibus enim penatibus integer, augue urna scelerisque nunc elementum tincidunt duis tortor etiam.

    Parturient pulvinar, lacus ut ultrices rhoncus massa! Velit et elementum pulvinar. Urna, magna integer. Nunc hac rhoncus? Amet eu? Sit in ac tortor. Lundium, pulvinar porttitor, tortor! Eros eu. Enim velit tristique elementum? Risus auctor tincidunt vut phasellus pellentesque! Turpis rhoncus vut, purus vel. Nunc ac augue! Ac sagittis pulvinar, in, duis adipiscing, velit sagittis? Penatibus mus scelerisque, nec! Dapibus scelerisque, augue turpis aenean, platea, urna integer risus a aliquet sagittis mid est elementum. Scelerisque? Tincidunt, vel vel natoque. Proin pulvinar sed placerat, cum amet nascetur scelerisque penatibus, ut, amet mus, duis placerat ac mus nec turpis facilisis dolor. Ultrices platea! Et magna enim rhoncus adipiscing odio, platea velit. Purus nunc duis! Enim velit integer facilisis nec? Diam mus.

    Habitasse purus, sed vut cras non porta tincidunt facilisis, tristique, urna integer risus risus magna dictumst dignissim etiam mid! Vut risus lacus placerat, nunc a tincidunt, sociis est elementum, rhoncus pid, ridiculus quis nunc? In est scelerisque dignissim proin tortor sed, quis aenean! Et placerat in vut, risus! Augue. Lundium pid. Sit elit! Sed lorem mus ac pulvinar sit integer odio dignissim montes, adipiscing magna adipiscing porta nunc nascetur sit. Quis tortor ridiculus, in, vut tincidunt urna mus, pulvinar a! Enim arcu nec ultricies lacus sagittis mattis mauris dictumst, magna amet habitasse ut et ac! Ac amet dolor scelerisque. Auctor sit eu vut ac, velit massa tempor! Montes, dis odio quis, magna ac, phasellus purus scelerisque etiam odio penatibus.

    Nec habitasse rhoncus. Pulvinar, et porta, porta tristique odio ut, massa! Purus phasellus eros porttitor, aliquet nascetur, montes turpis? Magna scelerisque rhoncus in dapibus, lundium porttitor, augue, ut placerat. Habitasse dictumst ac cursus pulvinar pid platea. Nascetur cum augue urna nunc? Magnis, arcu, pid pulvinar, natoque sed? In parturient porttitor facilisis mauris sed? Nec cras, urna et augue tristique, tincidunt tortor auctor non? Amet magna et aliquam sit sed, mid, augue pid massa sit tincidunt placerat placerat massa montes magna dapibus, ut pulvinar hac urna parturient nec dolor nunc, tristique nec proin amet ultricies magna, sociis vel etiam dolor? Augue vel augue rhoncus rhoncus enim pid tristique sit porta sit augue, tristique adipiscing! Dignissim, dictumst aliquam lundium rhoncus turpis.

    Mattis platea mauris, etiam duis amet, phasellus massa, mattis, nunc sed massa integer etiam mid dis velit in sagittis vel? Mauris. Enim mid integer, lundium! Mid pid aenean mattis elementum, nunc dis etiam augue augue vel, vel rhoncus tincidunt purus porta pellentesque, pid eu aliquet, ultricies tempor sociis? Dolor! Ac ultrices ultricies! Nec enim! Mauris lorem duis magna tincidunt, vel cursus dis. Pellentesque, urna, mid integer et ac lectus elit velit lectus scelerisque mauris nunc. Aliquet platea adipiscing, sagittis urna dolor vel rhoncus a duis, ac nec diam tincidunt odio! Hac porttitor sed ac parturient purus mauris, urna etiam, nec diam magna pellentesque turpis placerat magnis eros ridiculus, elementum lorem, tempor natoque? Ultrices sed nec dapibus eu rhoncus penatibus? Urna.

    Quis dolor elementum mauris! Ridiculus, auctor in, tortor ut risus velit pulvinar, porta urna rhoncus magna ultrices! Proin integer, cras rhoncus pid integer, nec odio ac, et? Dictumst pulvinar enim adipiscing facilisis ac mid nec? Pulvinar et non tristique! Sit pulvinar, pulvinar penatibus tincidunt, habitasse integer nunc! Tincidunt amet natoque facilisis aliquam tortor. Etiam duis tristique arcu egestas, et, sagittis nec ac aliquam pulvinar aliquet, adipiscing, nisi, sit sit, egestas risus. Ac. Adipiscing elit sit turpis in nec amet, nec in porta sed. Vel in in sit ultricies. Risus. Cum nascetur integer risus phasellus? Lacus mid auctor enim, enim scelerisque elementum vut a, diam eros sit duis, nascetur magna, est in dignissim adipiscing. Quis. Enim sociis egestas? Ut scelerisque.

    Elit placerat turpis, porttitor penatibus phasellus! In magnis eros ut, turpis? Pid? Odio et et, mauris aenean, purus turpis, adipiscing aliquet sed tortor! Turpis dapibus amet augue ut turpis montes mauris aliquam! Penatibus est, sagittis amet nunc ultrices ultrices, amet massa enim aliquam vel odio? Purus turpis? Urna tincidunt! Elementum magna integer enim, porttitor sed aenean mus phasellus vut lorem in ac sociis, in aenean, est! Adipiscing placerat tristique, nec nunc risus turpis. Ut, porta tincidunt dapibus, dignissim? Rhoncus turpis, enim massa massa platea magnis augue amet? Sit, rhoncus, augue magna aenean lorem a et. Cum lorem. Ultrices, duis! Ultrices etiam augue ridiculus! Adipiscing? Egestas elementum magna pulvinar augue, porta elementum aliquet et facilisis phasellus auctor adipiscing lacus tincidunt.

    Nec porta scelerisque ut ac etiam ac lorem cursus urna risus, amet egestas, tristique, etiam vut, adipiscing! Nunc cum habitasse pulvinar eros purus eros turpis in nascetur, habitasse adipiscing. Mattis. Nisi augue turpis, tortor, integer? Velit dis et, tristique augue. Scelerisque elementum adipiscing velit phasellus cras risus tincidunt ut rhoncus montes, scelerisque, ultricies. Et nascetur? Dis adipiscing. Natoque, turpis? Augue facilisis, dapibus augue? Elementum, tortor ac. Integer, nunc dictumst, diam nunc, augue nec non. Risus odio. Odio amet ultrices! Et urna nisi magna nisi nunc pulvinar habitasse facilisis in nunc velit natoque placerat rhoncus auctor? Magna pulvinar pulvinar augue, elementum adipiscing! Nascetur augue! Eros mus, nisi porta integer sed cras porttitor scelerisque. Pulvinar lorem turpis! Etiam, dictumst ac elit.

    Vel augue placerat tempor nunc tortor purus, egestas ut lacus massa quis nec non odio amet, tincidunt parturient nunc urna eros turpis ridiculus cursus penatibus mattis penatibus augue sed! Montes scelerisque. Et dictumst adipiscing lundium, tristique, enim nascetur, cum? Non pellentesque! Mauris magna sit, porttitor, magnis, vel, nisi ultrices velit! Pellentesque, amet augue mid placerat dignissim ac etiam scelerisque, ultrices purus etiam enim, scelerisque sit turpis montes porta nunc cras enim. Non risus in enim mattis nunc. Etiam adipiscing porttitor. Massa, nunc ultricies placerat enim. Est phasellus egestas porttitor. Et et elementum tempor ac? Proin! Augue tempor cras, eros! Rhoncus scelerisque auctor eu eu, diam? Nunc egestas, lectus cum, scelerisque, elementum, scelerisque magna, tempor elit arcu dictumst? Dis elementum.

    Nascetur, cras cras ridiculus lorem ac lectus enim proin odio sit lectus lorem dapibus enim. Ac nisi porttitor aliquet aliquam aenean non lacus, rhoncus pulvinar tempor dapibus dolor aliquam. In, in tincidunt penatibus cras et, lundium, sed turpis sit nunc odio, phasellus rhoncus urna facilisis platea adipiscing, mid etiam nascetur, enim, vut elementum, duis et ridiculus, penatibus urna non? Aliquam turpis augue phasellus risus diam egestas penatibus vel dignissim dignissim, ut! Elementum pulvinar et nascetur dapibus enim lundium hac platea scelerisque pellentesque facilisis! Quis, scelerisque pulvinar aliquet tincidunt elementum aliquam velit? Eros mid in facilisis, porttitor augue mattis ut, elementum placerat! Adipiscing ut augue! Facilisis in facilisis porttitor penatibus! Vel urna ridiculus magna, integer? Amet, penatibus cursus porttitor nisi.

    ";1;False;0;;;;_gruppenprodukt-2;True;True;SKU-1000;;;False;0;False;;False;False;0;True;10;1;False;;False;;False;100;0;10;True;False;0,0000;False;False;1;0;9999;False;False;0;0;1;0;False;1;10000;;False;False;False;False;0.0000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;41645,6860016551;"2095;1;81";;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000672-_gruppenprodukt.jpg;;;;;False;;;;;False;False;False;;;;;False;;;;;; -5;0;True;_Wasser;;"

    Optisch zum Verwechseln ähnlich, ebenso kompakt und leicht wie die erfolgreiche SD19, aber mit noch besserer Auflösung, präsentiert sich die brandneue AEE SD21 PRO Action-Cam. Die SD21 PRO ist eine komplette Neuentwicklung, mit Innovationen und einer Ausstattung, die es bisher in diesem Preissegment noch nicht gab.
    Bei der SD21 PRO ist die Monitor-Rückwand wie auch die Fernbedienung ebenso selbstverständlich wie der aufsteckbare Zusatzakku für noch längere Power.
    Für einfaches, unkompliziertes Justieren der Kamera ist ein Laserpointer integriert. Der 10-fach Digitalzoom und die hochwertige Optik garantieren für optimale Aufnahmeergebnisse bei allen Bedingungen.

    Highlights SD21 PRO:

    • 1/3 Zoll CMOS-Sensor 8,0 Megapixel
    • 170° Weitwinkel-Objektiv, Blende F/3.0
    • 10x Digitalzoom
    • Automatische Belichtung und Weissabgleich
    • Externes TFT-Display mit Echtzeit-Anzeige für Video und das Abspielen aufgezeichneter Inhalte
    • Laserpointer als Aufnahmeorientierung
    • Selbst-/Zeit-Auslöser mit Kontroll-LED
    • Eingebautes Mikrofon für hochwertige Stereo-Voice-Aufnahmen
    • Wasserdichtes Gehäuse bis 60 Meter (IP68-Standard)
    • Hochleistungs-Lithium-Batterie
    • Aufsteckbarer Zusatzakku mit eigener Ladestandsanzeige - verdoppelt die Aufnahmedauer
    • Auto Stand-by zur Energieeinsparung
    • Funktionen: HD-Videoaufnahme / Foto
    • Recording MOV Videos können direkt am PC wiedergegeben oder auf Video-Websites hochgeladen werden
    • Photo 180-Grad-Umkehr-Funktion
    • Externe Micro SD/MMC-Speicherkarte, unterstützt bis max. 64GB (nicht enthalten)
    • Speicherkapazität Alarm
    • Schneller Vor- und Rücklauf, Funktion zum Überspringen von Inhalten in das nächste Segment
    • Unterstützung USB2.0
    • HDMI-Ausgang, AV-OUT-Funktion
    • Support-System: Windows 98SE/2000/Me/XP/Vista/Win 7/Mac OS

    Grösse: ca. 61x43x40mm (BxHxT)

    Gewicht: 88g ohne Bildschirm, 112g mit Bildschirm

    Technische Daten SD21 PRO:

    • Auflösung/Sensor: 8.0M CMOS-Sensor (3200 * 2400)
    • Optik / Linse: 170° Weitwinkel-Objektiv, Blende F/3.0
    • Gehäuse: IP68 wasserdichtes Gehäuse bis 60m
    • Memory-Karte: Micro SD unterstützt bis 64GB (nicht enthalten)
    • Photo-Modus: 3M (2048 * 1536) / 5M (2560 * 1920) / 8M (3200 * 2400)
    • Video-Aufnahmemodus: 1080P 720P WVGA QVGA
    • Bildrate: 1080P/30fps 720P/30fps WVGA/60fps QVGA/30fps
    • Video-Aufnahmeformat: MOV (H.264-Video-Kompression)
    • Photo-Format: JPEG
    • Aufnahmekapazität (2GB SDKarte):
    • Photos 3M (1900pcs), 5M (1160pcs), 8M (770pcs) /
    • Videos: 720P/60min, WVGA/135min
    • Laserpointer/Laserleistung: 1MW
    • AV OUT: Unterstützung NTSC / PAL VGA und HDMI
    • USB: USB2.0
    • Mikrofon: 2 Mikrofone, eingebaute
    • Leistungsaufnahme: 500mA@3.7V (MAX)
    • Lithium-Batterie: 1000mAh
    • Batterielaufzeit: 2.5h / Batterie
    • Betriebssystem: Windows XP SP2/Vista oder höher / Mac OS. CPU:
    • Pentium4 1.5GHZ oder höher RAM: min. 1GB
    • RTC-Funktion: Unterstützung
    • Lagertemperatur: -20 bis -60 
    • Betriebstemperatur: -10 bis -50 
    • Luftfeuchtigkeit bei Betrieb: 15 85% RH

     

    ";2;True;0;;;_Wasser;_wasser;True;True;;;;False;0;False;;False;False;0;False;0;1;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;2;0;False;False;0;0;1;0;False;1;10000;;False;True;False;False;0.9900;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;41540,3761458333;"1;2095";;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000673-_wasser.jpg;;;2;;True;l;35.0000;100;;False;False;False;;;;1;True;;;;;; -5;0;True;Apple MacBook Pro MD313D/A 13,3 Zoll Notebook;3 GB, 18 Zoll, 500 GB, Intel, 4;"
    Apple MacBook Pro MD313D/A 13,3 Zoll Notebook
    Intel Core i5  2x 2,40 GHz
     
    Bis zu 2x schnellere Prozessoren. Bis zu 3x schnellere Grafik.
    Quad-Core und Dual-Core Intel Prozessoren der nächsten Generation.
    Das 13"" MacBook Pro gibt es jetzt mit einem 2,4 GHz Intel Core i5 Prozessor oder dem schnellsten Dual-Core Prozessor, den es gibt: dem 2,8 GHz Intel Core i7. Diese Prozessoren bieten Turbo Boost Geschwindigkeiten und machen das 13"" MacBook Pro bis zu doppelt so schnell wie die Vorgängergeneration.
     
    Aber nur schnell ist uns nicht genug. Deshalb bieten die neuen 15"" und 17"" Modelle Quad-Core Leistung für praktisch alles, was du machen willst. Auch ein 2,4 GHz Quad-Core Intel Core i7 Prozessor mit Turbo Boost Geschwindigkeiten und bis zu 8 MB gemeinsam genutztem L3-Cache ist verfügbar. Auf MacBook Pro Modellen mit diesem Prozessor laufen Programme bis zu doppelt so schnell wie auf der besten Vorgängerkonfiguration.
     
    Die Grafikleistung, die du brauchst, wenn du sie brauchst.
    Alle MacBook Pro Modelle haben jetzt einen integrierten Intel HD Graphics 3000 Prozessor für die täglichen Aufgaben. Er codiert Videos schnell, ermöglicht HD Videotelefonate mit FaceTime und vieles mehr. Und auch Decodieren erledigt er effizienter, was bedeutet, dass du richtig lange DVDs und iTunes Filme schauen kannst.
     
    Bei anspruchsvollen Grafikprogrammen wechseln die 15"" und 17"" MacBook Pro Modelle automatisch den Grafikprozessor und arbeiten mit den neuen leistungsstarken AMD Radeon Grafikprozessoren. Diese bieten verglichen mit den Vorgängermodellen die bis zu 3-fache Leistung.3 So siehst du bei 3D Spielen mehr Bilder pro Sekunde oder kannst schneller als je zuvor an HD Videoprojekten arbeiten.
     
    Das neue Thunderbolt. Die schnellste, vielseitigste I/O Technologie in einem Notebook.
    Stell dir vor, du könntest auf deinem Notebook auf mehrere unkomprimierte HD Videostreams zugreifen - und zwar so schnell, dass du einen HD Spielfilm in Echtzeit schneiden kannst. Thunderbolt macht genau das möglich. Mit Thunderbolt lassen sich superschnelle Peripheriegeräte der nächsten Generation an die Computer der nächsten Generation anschließen - angefangen beim MacBook Pro. Die Thunderbolt Pipeline ist ultraschnell und ultraflexibel. Sie ist über 12 Mal schneller als FireWire 800 und bis zu 20 Mal schneller als USB 2.0. Und sie bietet beispiellose Erweiterungsmöglichkeiten. Kurzum: Sie verändert alles, was du auf deinem Notebook machen kannst.
     
    Der Thunderbolt Anschluss gibt dir Plug&Play Anschluss für eine völlig neue Welt von Thunderbolt Peripheriegeräten sowie für das Apple LED Cinema Display und andere Mini DisplayPort Peripheriegeräte. Du kannst bis zu sechs Thunderbolt Geräte in Reihenschaltung anschließen, darunter auch dein Display. Außerdem unterstützt Thunderbolt Video und Achtkanal-Audio, sodass es auch möglich ist, HDMI-kompatible Geräte wie Fernseher oder Stereoanlagen über einen HDMI-Adapter anzuschließen. Auch aktuelle VGA-, DVI- und DisplayPort Adapter werden unterstützt.
     
    Die neue FaceTime HD Kamera. Der Unterschied ist ganz klar.
    Sieh mehr von deinen Freunden mit dem HD Widescreenformat - und zwar gestochen scharf. Die neue FaceTime HD Kamera bietet die dreifache Auflösung der vorherigen Kamera, was perfekt für das brillante Display mit LED-Hintergrundbeleuchtung ist. Außerdem arbeitet sie jetzt bei schwachem Licht noch besser. Du kannst mit deinen Freunden HD Telefonate in 720p von einem neuen MacBook Pro zu einem anderen führen. Außerdem sind auch Videotelefonate zu anderen Macs mit Intel Prozessor5, zum iPhone 4 oder zum neuen iPod touch möglich.
     
    Multi-Touch Trackpad. Fürs tägliche Handwerk.
    Mit dem Multi-Touch Trackpad interagierst du auf ganz natürliche Art mit den Inhalten auf deinem Display. Und die glatte Glasoberfläche bietet jede Menge Platz für Gesten. Durch Auf- und Zuziehen kannst du ein- und auszoomen, durch Streichen in deinen Fotos blättern, durch Drehen ein Bild anpassen und vieles mehr. Das Trackpad kommt ohne Taste aus, sodass du überall klicken kannst. Wenn du aus der Welt des rechten Mausklicks kommst, kannst du diesen entweder mit zwei Fingern auslösen, oder du konfigurierst einen physischen Rechtsklick-Bereich auf dem Trackpad. Je mehr du mit dem Multi-Touch Trackpad vertraut bist, desto mehr wirst du dich fragen, wie du jemals ohne ausgekommen bist.
     
    Lange Laufzeit. Weniger aufladen. Mehr machen.
    Das neue MacBook Pro bietet eine fantastische Batterielaufzeit und das mit leistungsstärkeren Prozessoren und schnelleren Grafikprozessoren. Die energieeffiziente Prozessorarchitektur mit integriertem Video-Encoder sowie das automatische Umschalten zwischen den Grafikprozessoren bei den 15"" und 17"" Modellen helfen, die Batterielaufzeit weiter zu verbessern. So kannst du pro Ladung bis zu 7 Stunden ohne Kabel im Web surfen6 oder es für Liveauftritte oder auf ein Shooting mitnehmen. Die fortschrittlichen chemischen Eigenschaften und die Adaptive Charging Technologie sorgen dafür, dass die Batterie bis zu 1000 Ladezyklen durchlaufen kann.7 Und da die Batterie des MacBook Pro bis zu fünf Jahre hält, kommt das MacBook Pro in einem Zeitraum, in dem ein herkömmliches Notebook drei Batterien verbraucht, mit nur einer aus. Das ist für die Benutzer genauso gut, wie für die Umwelt.
     
    Apple verwendet eine neue, strengere Testmethode, um zu messen, welche Ergebnisse du unter realen Bedingungen erzielst, z. B. beim Surfen in einem Café oder wenn du die neuesten Webvideos ansiehst. Und wie schneidet dieses MacBook Pro dabei verglichen mit der Vorgängergeneration ab? Es liefert die gleiche fantastische Leistung.
     
    Hat beste Verbindungen.
    Unterwegs hast du mit der 802.11n Technologie im MacBook Pro immer Verbindung.8 Das MacBook Pro findet automatisch verfügbare Netzwerke und du kannst dich mit einem Klick verbinden. Auch die drahtlose Bluetooth Technologie ist integriert, sodass du drahtloses Zubehör sofort nach dem Auspacken verwenden kannst.
     
    Immer Anschluss finden.
    Mit dem neuen Thunderbolt Anschluss kannst du bis zu sechs Geräte in Reihenschaltung anschließen, darunter auch dein Display. So bekommst du eine vollwertige Workstation. Für die Anbindung von iPad, iPod, iPhone, Digitalkameras und externen Festplatten gibt es zwei USB 2.0 Anschlüsse (drei beim 17"" MacBook Pro) und einen FireWire 800 Anschluss.
     
    Der neue SDXC Kartensteckplatz der 13"" und 15"" MacBook Pro Modelle unterstützt bis zu 64 GB Karten und macht es leicht, alle deine Fotos auf und von deinem MacBook Pro zu übertragen, damit du sie sofort bearbeiten und teilen kannst. Und der ExpressCard/34 Steckplatz am 17"" MacBook Pro ist perfekt für einen eSATA Adapter geeignet oder sogar für eine 3G Karte für die drahtlose Kommunikation, wenn kein Wi-Fi Netzwerk vorhanden ist.
     
    DVDs superschnell brennen.
    Homevideos, die du mit iMovie und iDVD gemacht hast, kannst du mit dem 8-fach SuperDrive Laufwerk des MacBook Pro superschnell auf eine DVD brennen. Das SuperDrive kann auch Double-Layer-DVDs (also DVDs mit fast 9 GB Speicherplatz) beschreiben, sodass es auch hervorragend für Datensicherungen geeignet ist.
    ";2;False;0;;;Apple MacBook Pro MD313D/A 13,3 Zoll Notebook;apple-macbook-pro-md313da-133-zoll-notebook-2;True;True;PD-01095;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;1099.9000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;41389,3991782407;5;1;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000456-apple-macbook-pro-md313da-133-zoll-notebook.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000457-apple-macbook-pro-md313da-133-zoll-notebook.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000458-apple-macbook-pro-md313da-133-zoll-notebook.jpg;2;;False;;;;;False;False;False;;;;;False;;;;;; -5;0;True;Apple MacBook Pro MC721D/A 15,4 Zoll Notebook;3 GB, 16 Zoll, 350 GB, AMD, 4;"
    Apple MacBook Pro MC721D/A
    Intel Core i7 2635QM, 2 GHz

    Unibody-Gehäuse. Am Anfang jedes MacBook Pro steht ein Werkstück aus Aluminium.Stark, leicht und schön in einem.
    Das MacBook Pro ist aus einem einzigen Aluminiumblock gefertigt - eine technische Meisterleistung, bei der viele Bauteile durch ein einziges ersetzt werden. Das Ganze nennt sich Unibody. Gleich beim ersten Mal, wenn Sie ein MacBook Pro in der Hand haben, werden Sie den Unterschied spüren. Das Gehäuse ist dünner und leichter als andere Notebooks. Es sieht elegant aus. Und es fühlt sich stabil und robust an: perfekt für die Aktentasche, den Rucksack und natürlich auch für draußen.
     
    Ein Display voll brillanter Ideen.
    Alles, was Apple Designer und Ingenieure tun, ist von A bis Z durchdacht. Sie entschieden sich beim MacBook Pro für die LED-Hintergrundbeleuchtung, weil das Display damit sofort seine volle Helligkeit erreicht und trotzdem unglaublich dünn ist. Sie verwendeten eine durchgehende Oberfläche aus Glas, nicht nur weil es schön aussieht, sondern weil es dem ganzen Display Struktur verleiht. Und über dem Bildschirm haben sie die neue, integrierte FaceTime HD Kamera versteckt. So siehst du Freunde und Familie im Großformat - und dabei so gut wie nichts von der Kamera.
     
    Magnetverschluss
    Da der magnetische Verschluss keine beweglichen Teile hat, die abbrechen können oder an denen man hängen bleibt, ist das Öffnen und Schließen so einfach wie alles beim MacBook Pro.
     
    Einfach auf alle Anschlüsse zugreifen.
    Alle Anschlüsse am MacBook Pro - der MagSafe Netzanschluss, der Gigabit Ethernetanschluss, der Thunderbolt Anschluss, der USB Anschluss, der Karten-Steckplatz und der Audioeingang und -ausgang - sind ganz auf einer Seite des Notebooks integriert. So bleiben die Kabel schön geordnet und Geräte lassen sich schnell und einfach anschließen und auch wieder trennen.
     
    Hinterlässt Eindruck. Aber nicht auf die Umwelt.
    Weil Apple die vollständige Kontrolle über Design, Fertigung und Verpackung des MacBook Pro hat, hat Apple einen Vorsprung beim Umweltschutz. Die Technologie zur Hintergrundbeleuchtung des Displays spart Energie. Glas und Aluminium sind besonders recyclingfähig. Das MacBook Pro kommt fast ohne Giftstoffe aus. Und die Verpackung des 39,11 cm / 15,4"" Modells ist im Vergleich zum Vorgängermodell 34 Prozent kleiner. Das bedeutet nicht nur, dass für die Verpackungen weniger Bäume gefällt werden, es werden für den Transport auch weniger Flugzeugen, Güterzügen und LKWs benötigt.
     
    Thunderbolt AnschlussDie Grafikleistung, die Sie brauchen, wenn Sie sie brauchen.
    Alle MacBook Pro Modelle haben jetzt einen integrierten Intel HD Graphics 3000 Prozessor für die täglichen Aufgaben. Er codiert Videos schnell, ermöglicht HD Videotelefonate mit FaceTime und vieles mehr. Und auch Decodieren erledigt er effizienter, was bedeutet, dass Sie richtig lange DVDs und iTunes Filme schauen können. Bei anspruchsvollen Grafikprogrammen wechseln die 39,11 cm / 15,4"" MacBook Pro Modelle automatisch den Grafikprozessor und arbeiten mit den neuen leistungsstarken AMD Radeon Grafikprozessoren. Diese bieten verglichen mit den Vorgängermodellen die bis zu 3-fache Leistung. So sehen Sie bei 3D Spielen mehr Bilder pro Sekunde oder können schneller als je zuvor an HD Videoprojekten arbeiten.
     
    Das neue Thunderbolt. Die schnellste, vielseitigste I/O Technologie in einem Notebook.
    Stellen Sie sich vor, Sie könnten auf deinem Notebook auf mehrere unkomprimierte HD Videostreams zugreifen - und zwar so schnell, dass Sie einen HD Spielfilm in Echtzeit schneiden können. Thunderbolt macht genau das möglich. Mit Thunderbolt lassen sich superschnelle Peripheriegeräte der nächsten Generation an die Computer der nächsten Generation anschließen - angefangen beim MacBook Pro. Die Thunderbolt Pipeline ist ultraschnell und ultraflexibel. Sie ist über 12 Mal schneller als FireWire 800 und bis zu 20 Mal schneller als USB 2.0. Und sie bietet beispiellose Erweiterungsmöglichkeiten. Kurzum: Sie verändert alles, was Sie auf Ihrem Notebook machen können. Der Thunderbolt Anschluss gibt Ihnen Plug&Play Anschluss für eine völlig neue Welt von Thunderbolt Peripheriegeräten sowie für das Apple LED Cinema Display und andere Mini DisplayPort Peripheriegeräte. Sie können bis zu sechs Thunderbolt Geräte in Reihenschaltung anschließen, darunter auch Ihr Display. Außerdem unterstützt Thunderbolt Video und Achtkanal-Audio, sodass es auch möglich ist, HDMI-kompatible Geräte wie Fernseher oder Stereoanlagen über einen HDMI-Adapter anzuschließen. Auch aktuelle VGA-, DVI- und DisplayPort Adapter werden unterstützt.
     
    Die neue FaceTime HD Kamera. Der Unterschied ist ganz klar.
    Sehen Sie mehr von Ihren Freunden mit dem HD Widescreenformat - und zwar gestochen scharf. Die neue FaceTime HD Kamera bietet die dreifache Auflösung der vorherigen Kamera, was perfekt für das brillante Display mit LED-Hintergrundbeleuchtung ist. Außerdem arbeitet sie jetzt bei schwachem Licht noch besser. Sie können mit Ihren Freunden HD Telefonate in 720p von einem neuen MacBook Pro zu einem anderen führen. Außerdem sind auch Videotelefonate zu anderen Macs mit Intel Prozessor, zum iPhone 4 oder zum neuen iPod touch möglich.
     
    Multi-Touch Trackpad - Jede Menge Platz für GestenMulti-Touch Trackpad. Fürs tägliche Handwerk.
    Mit dem Multi-Touch Trackpad interagieren Sie auf ganz natürliche Art mit den Inhalten auf deinem Display. Und die glatte Glasoberfläche bietet jede Menge Platz für Gesten. Durch Auf- und Zuziehen können Sie ein- und auszoomen, durch Streichen in deinen Fotos blättern, durch Drehen ein Bild anpassen und vieles mehr. Das Trackpad kommt ohne Taste aus, sodass Sie überall klicken können. Wenn Sie aus der Welt des rechten Mausklicks kommen, können Sie diesen entweder mit zwei Fingern auslösen, oder Sie konfigurieren einen physischen Rechtsklick-Bereich auf dem Trackpad. Je mehr Sie mit dem Multi-Touch Trackpad vertraut sind, desto mehr werden Sie sich fragen, wie Sie jemals ohne ausgekommen sind.
     
    Lange Laufzeit. Weniger aufladen. Mehr machen.
    Das neue MacBook Pro bietet eine fantastische Batterielaufzeit und das mit leistungsstärkeren Prozessoren und schnelleren Grafikprozessoren. Die energieeffiziente Prozessorarchitektur mit integriertem Video-Encoder sowie das automatische Umschalten zwischen den Grafikprozessoren bei den 39,11 cm / 15,4"" Modellen helfen, die Batterielaufzeit weiter zu verbessern. So können Sie pro Ladung bis zu 7 Stunden ohne Kabel im Web surfen oder es für Liveauftritte oder auf ein Shooting mitnehmen. Die fortschrittlichen chemischen Eigenschaften und die Adaptive Charging Technologie sorgen dafür, dass die Batterie bis zu 1000 Ladezyklen durchlaufen kann. Und da die Batterie des MacBook Pro bis zu fünf Jahre hält, kommt das MacBook Pro in einem Zeitraum, in dem ein herkömmliches Notebook drei Batterien verbraucht, mit nur einer aus. Das ist für die Benutzer genauso gut, wie für die Umwelt. Apple verwendet eine neue, strengere Testmethode, um zu messen, welche Ergebnisse Sie unter realen Bedingungen erzielen, z. B. beim Surfen in einem Cafe oder wenn Sie die neuesten Webvideos ansehen. Und wie schneidet dieses MacBook Pro dabei verglichen mit der Vorgängergeneration ab? Es liefert die gleiche fantastische Leistung.
     
    Hat beste Verbindungen.
    Unterwegs haben Sie mit der 802.11n Technologie im MacBook Pro immer Verbindung. Das MacBook Pro findet automatisch verfügbare Netzwerke und Sie können sich mit einem Klick verbinden. Auch die drahtlose Bluetooth Technologie ist integriert, sodass Sie drahtloses Zubehör sofort nach dem Auspacken verwenden können.
     
    DVDs superschnell brennen.
    Homevideos, die Sie mit iMovie und iDVD gemacht haben, können Sie mit dem 8-fach SuperDrive Laufwerk des MacBook Pro superschnell auf eine DVD brennen. Das SuperDrive kann auch Double-Layer-DVDs (also DVDs mit fast 9 GB Speicherplatz) beschreiben, sodass es auch hervorragend für Datensicherungen geeignet ist.
     
    Neue Intel Core i7 Prozessoren.
    Neue Quad-Core Intel Core i7 Prozessoren sind Standard beim 39,11 cm / 15,4"" MacBook Pro. Alle Modelle verwenden die kürzlich optimierten Chipsets von Intel. Was heißt das für die neuen MacBook Pro Modelle? Kurz gesagt: Sie sind bis zu zwei Mal schneller als die Vorgängergeneration und erledigen auch anspruchsvolle Aufgaben wie HD Videoschnitt, Audiokompilierung oder Rendering mehrschichtiger Bilddateien unglaublich schnell. Und da Mac OS X Snow Leopard darauf ausgelegt ist, jeden Prozessorkern zu nutzen, holt das Betriebssystem wirklich alles an Leistung aus dem Prozessor heraus.
     
    Schnellere Einzelchip-Mikroarchitektur.
    Ob Sie einen Film ansehen, Ihren Blog auf den neuesten Stand bringen oder Fotos bearbeiten - die Daten müssen von A nach B gelangen, um verarbeitet werden zu können. Die neueste Intel Core Architektur bringt den Prozessor, den Cache, den Speichercontroller und den Grafikprozessor auf einem einzigen Chip unter. Deswegen müssen die Daten keine weiten Wege zurücklegen, was für Sie schnellere Performance und höhere Effizienz bedeutet.
     
    Turbo Boost 2.0.
    Angenommen, Sie arbeiten mit einem prozessorintensiven Programm wie Aperture 3 oder Final Cut Pro, das von einem Leistungsschub profitiert würde. Turbo Boost ist eine dynamische Technologie, die automatisch die Geschwindigkeit der aktiven Prozessorkerne auf 3,4 GHz erhöht. Turbo Boost 2.0 ist noch dynamischer und effizienter. Es wechselt die Kernfrequenz in kleineren Schritten als bisher, sodass der Prozessor die Leistung ohne Effizienzeinbußen verwalten kann. All das passiert im Hintergrund. Sie arbeiten einfach nur schneller.
     
    Hyper-Threading.
    Hyper-Threading ist jetzt Standard auf jedem MacBook Pro. Mit dieser Technologie können auf jedem Kern zwei Threads gleichzeitig laufen, Mac OS X erkennt also bei einem Quad-Core Prozessor acht und bei einem Dual-Core Prozessor vier virtuelle Kerne. Wenn Sie mehrere Programme gleichzeitig verwenden, verteilt der Prozessor die Aufgaben gleichmäßiger über eine größere Anzahl Kerne.
     
    Integrierter Speichercontroller.
    Mit schnellerem Speicherzugriff legt jeder Kern direkt mit der Verarbeitung der Daten los, statt auf ihr Eintreffen zu warten. Genau deshalb nutzt die neue Intel Core Architektur einen integrierten Speichercontroller, der den schnellen 1333 MHz Speicher direkt mit dem Prozessor verbindet und Ihre Programme immer die maximale Prozessorleistung zur Verfügung haben.
     
    Energieeffiziente Grafik.
    Dank der neuen Mikroarchitektur ist der Grafikprozessor auf dem gleichen Chip wie der Zentralprozessor und hat direkten Zugriff auf den L3-Cache. Kurze Wege bedeuten mehr Leistung. Der Grafikprozessor erhöht auch automatisch die Taktrate für noch höhere Auslastung. Ein integrierter Video-Encoder ermöglicht jetzt HD Videotelefonate mit FaceTime, und der effiziente Decoder sorgt für lange Batterielaufzeit, wenn Sie sich DVDs oder iTunes Filme ansiehen.
     
    Mac OS X. Das fortschrittlichste Betriebssystem der Welt.
    Mac OS X ist das Herz jedes MacBook Pro und Mac. Dieses Betriebssystem ist genau auf die integrierten Intel Multicore-Prozessoren und fortschrittlichen Grafikprozessoren zugeschnitten. Die neueste Version, Mac OS X Snow Leopard, basiert komplett auf einer 64-Bit-Architektur, genau wie alle anderen Programme, die mit dem Mac kommen. Das bedeutet: Alles, was Sie auf Ihrem MacBook Pro machen, passiert superschnell und mit einer unglaublichen Gesamtleistung.
     
    Hat eine ganze Menge draufProgramme, ebenso leistungsstark wie benutzerfreundlich.
    Weil Apple sowohl das MacBook Pro, wie auch die integrierte Software entwickelt, arbeitet alles perfekt zusammen. Und mit den Apple Programmen sind Sie ganz schnell vertraut, weil alle ähnlich funktionieren. Das heißt, wenn Sie ein Programm kennen, sind Sie auch schnell mit allen anderen vertraut. Außerdem weiß Apple genau, was mobile Produktivität bedeutet. Darum haben wir Funktionen wie Expose und Spaces hinzugefügt. Damit können Sie ganz einfach auf alles auf Ihrem MacBook Pro zugreifen. Expose zeigt sämtliche geöffneten Fenster nebeneinander, verkleinert sie und ordnet sie so, dass Sie den Inhalt jedes Fensters sehen können - ein Tastendruck oder eine Geste genügt. Und mit Spaces können Sie Fenster zusammen auf ihrem eigenen Schreibtisch oder Bereich gruppieren und ganz einfach zwischen diesen wechseln. Legen Sie einen Bereich zum Arbeiten fest, einen zum Spielen und einen für was auch immer. Mit Expose und Spaces haben Sie beim Multitasking auf einem Notebookdisplay einen riesigen Vorteil.
     
    Darauf verzichten Sie beim Mac: PC-Viren.
    Trojaner, Würmer, E-Mail Viren. Die digitale Welt kann ganz schön beängstigend sein. Zum Glück ist der Mac immun gegen die tausenden von Viren, die Windows Computer plagen. Denn Mac OS X kommt mit integrierten Sicherheitsmechanismen, die Sie schützen - ohne dass Sie etwas machen müssen. Und sollten doch mal potenzielle Sicherheitsrisiken auftreten, reagiert Apple sofort und stellt neue Softwareaktualisierungen und Sicherheitsverbesserungen bereit, die Sie automatisch laden und mit einem Klick installieren können.
     
    Das automatische Backup rettet Ihren Tag. Und die Woche, den Monat ...
    Backups müssen sein. Trotzdem vergissen Sie sie bestimmt hin und wieder. Deshalb kümmert sich jetzt das MacBook Pro um die Datensicherung. Time Machine, ein Programm, das auf jedem Mac dabei ist, sichert automatisch Ihr ganzes System auf einer externen Festplatte oder Time Capsule. Time Machine speichert eine Kopie von jeder Datei. Und es merkt sich, wie Ihr System an einem bestimmten Tag ausgesehen hat. So können Sie, wenn Sie wollen, die Zeit zurückdrehen und Ihren Mac wie in der Vergangenheit sehen.
     
    Mit iMovie können Sie aus Ihren Videos großartige Filme machenAuch die täglichen Sachen machen mehr Spaß.
    Anders als viele PC-Notebooks kommt das MacBook Pro mit allem, was Sie brauchen, um E-Mails zu senden, Kalender zu verwalten, Kontakte zu organisieren und mehr. Und Sie können schon wenige Minuten nach dem Auspacken damit loslegen. Denn jeder Mac kommt mit Mail, um E-Mails zu senden und empfangen, iCal zum Organisieren von Terminen und wichtigen Ereignissen, dem Adressbuch zum Verwalten von Kontakten, iTunes für alles, was mit Unterhaltung zu tun hat, und weiteren tollen und nützlichen Programmen, die Sie jeden Tag verwenden werden.
     
    Der Mac App Store. Tausend weitere Gründe, den Mac zu lieben.
    Über tausend Mac Apps sind nur einen Klick entfernt - im Mac App Store. Suchen Sie einfach Apps, die Ihnen gefallen, und klicken Sie einfach, um sie zu laden und zu installieren. Ohne Verpackung. Ohne CDs oder DVDs. Und ohne Probleme. Sie können die Apps nach Kategorien durchstöbern oder direkt etwas Bestimmtes suchen. Und Sie können einfach dafür sorgen, dass Ihre Apps up-to-date sind, denn Ihr Mac zeigt Ihnen an, wann Updates verfügbar sind.
     
    iPhoto. Fotos ganz einfach verwalten, bearbeiten und teilen.
    iPhoto ist ein benutzerfreundliches Programm für Fotos, mit dem Sie Ihre Bilder schnell organisieren, wiederfinden und verbessern können - sodass sie immer perfekt aussehen. Mit den iPhoto Funktionen ""Gesichter"", ""Orte"" und ""Ereignisse"" behalten Sie den Überblick über Ihre Fotos. Sie sagen Ihnen, wen Sie fotografiert haben, wo und wann. Und all das in den neuen Vollbildmodi.
     
    iMovie. Und aus Homevideos werden Home-Blockbuster.
    Homevideos müssen nicht langweilig sein. Mit iMovie können Sie aus Ihren Videos großartige Filme machen. Zum Beispiel Trailer im Hollywoodstil, mit denen Sie Ihr Publikum begeistern.
     
    GarageBand. Großartige Musik machen, ganz einfachissimo.
    Egal, ob Sie Musiktalent haben oder einfach nur neugierig sind - GarageBand ist genau das richtige Programm für Sie. Schließ einfach eine elektrische Gitarre oder ein USB Keyboard an. Und schon können Sie mit virtuellen Nachbildungen der bekanntesten Amps und Stompboxes der Welt sowie mit 100 Software-Instrumenten spielen.
    ";2;False;0;;;Apple MacBook Pro MC721D/A 15,4 Zoll Notebook;apple-macbook-pro-mc721da-154-zoll-notebook-2;True;True;PD-01093;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;2,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;1483.9000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;41389,3991666667;5;1;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000545-apple-macbook-pro-mc721da-154-zoll-notebook.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000546-apple-macbook-pro-mc721da-154-zoll-notebook.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000547-apple-macbook-pro-mc721da-154-zoll-notebook.jpg;2;;False;;;;;False;False;False;;;;;False;;;;;; -5;0;True;Apple MacBook Pro MC725D/A 17 Zoll Notebook;4 GB, 17 Zoll, 500 GB, Tantel, 3;"
    Apple MacBook Pro MC725D/A
    Intel Core i7 2720QM, 2,2 GHz
     
    Stark, leicht und schön in einem.
    Das MacBook Pro ist aus einem einzigen Aluminiumblock gefertigt - eine technische Meisterleistung, bei der viele Bauteile durch ein einziges ersetzt werden. Das Ganze nennt sich Unibody. Gleich beim ersten Mal, wenn Sie ein MacBook Pro in der Hand haben, werden Sie den Unterschied spüren. Das Gehäuse ist dünner und leichter als andere Notebooks. Es sieht elegant aus. Und es fühlt sich stabil und robust an: perfekt für die Aktentasche, den Rucksack und natürlich auch für draußen.
     
    Ein Display voll brillanter Ideen.
    Alles, was Apple Designer und Ingenieure tun, ist von A bis Z durchdacht. Sie entschieden sich beim MacBook Pro für die LED-Hintergrundbeleuchtung, weil das Display damit sofort seine volle Helligkeit erreicht und trotzdem unglaublich dünn ist. Sie verwendeten eine durchgehende Oberfläche aus Glas, nicht nur weil es schön aussieht, sondern weil es dem ganzen Display Struktur verleiht. Und über dem Bildschirm haben sie die neue, integrierte FaceTime HD Kamera versteckt. So siehst du Freunde und Familie im Großformat - und dabei so gut wie nichts von der Kamera.
     
    Magnetverschluss
    Da der magnetische Verschluss keine beweglichen Teile hat, die abbrechen können oder an denen man hängen bleibt, ist das Öffnen und Schließen so einfach wie alles beim MacBook Pro.
     
    Einfach auf alle Anschlüsse zugreifen.
    Alle Anschlüsse am MacBook Pro - der MagSafe Netzanschluss, der Gigabit Ethernetanschluss, der Thunderbolt Anschluss, der USB Anschluss, der Karten-Steckplatz und der Audioeingang und -ausgang - sind ganz auf einer Seite des Notebooks integriert. So bleiben die Kabel schön geordnet und Geräte lassen sich schnell und einfach anschließen und auch wieder trennen.
     
    Hinterlässt Eindruck. Aber nicht auf die Umwelt.
    Weil Apple die vollständige Kontrolle über Design, Fertigung und Verpackung des MacBook Pro hat, hat Apple einen Vorsprung beim Umweltschutz. Die Technologie zur Hintergrundbeleuchtung des Displays spart Energie. Glas und Aluminium sind besonders recyclingfähig. Das MacBook Pro kommt fast ohne Giftstoffe aus. Und die Verpackung des 43,18 cm / 17"" Modells ist im Vergleich zum Vorgängermodell 34 Prozent kleiner. Das bedeutet nicht nur, dass für die Verpackungen weniger Bäume gefällt werden, es werden für den Transport auch weniger Flugzeugen, Güterzügen und LKWs benötigt.
     
    Thunderbolt AnschlussDie Grafikleistung, die Sie brauchen, wenn Sie sie brauchen.
    Alle MacBook Pro Modelle haben jetzt einen integrierten Intel HD Graphics 3000 Prozessor für die täglichen Aufgaben. Er codiert Videos schnell, ermöglicht HD Videotelefonate mit FaceTime und vieles mehr. Und auch Decodieren erledigt er effizienter, was bedeutet, dass Sie richtig lange DVDs und iTunes Filme schauen können. Bei anspruchsvollen Grafikprogrammen wechseln die 43,18 cm / 17"" MacBook Pro Modelle automatisch den Grafikprozessor und arbeiten mit den neuen leistungsstarken AMD Radeon Grafikprozessoren. Diese bieten verglichen mit den Vorgängermodellen die bis zu 3-fache Leistung. So sehen Sie bei 3D Spielen mehr Bilder pro Sekunde oder können schneller als je zuvor an HD Videoprojekten arbeiten.
     
    Das neue Thunderbolt. Die schnellste, vielseitigste I/O Technologie in einem Notebook.
    Stellen Sie sich vor, Sie könnten auf deinem Notebook auf mehrere unkomprimierte HD Videostreams zugreifen - und zwar so schnell, dass Sie einen HD Spielfilm in Echtzeit schneiden können. Thunderbolt macht genau das möglich. Mit Thunderbolt lassen sich superschnelle Peripheriegeräte der nächsten Generation an die Computer der nächsten Generation anschließen - angefangen beim MacBook Pro. Die Thunderbolt Pipeline ist ultraschnell und ultraflexibel. Sie ist über 12 Mal schneller als FireWire 800 und bis zu 20 Mal schneller als USB 2.0. Und sie bietet beispiellose Erweiterungsmöglichkeiten. Kurzum: Sie verändert alles, was Sie auf Ihrem Notebook machen können. Der Thunderbolt Anschluss gibt Ihnen Plug&Play Anschluss für eine völlig neue Welt von Thunderbolt Peripheriegeräten sowie für das Apple LED Cinema Display und andere Mini DisplayPort Peripheriegeräte. Sie können bis zu sechs Thunderbolt Geräte in Reihenschaltung anschließen, darunter auch Ihr Display. Außerdem unterstützt Thunderbolt Video und Achtkanal-Audio, sodass es auch möglich ist, HDMI-kompatible Geräte wie Fernseher oder Stereoanlagen über einen HDMI-Adapter anzuschließen. Auch aktuelle VGA-, DVI- und DisplayPort Adapter werden unterstützt.
     
    Die neue FaceTime HD Kamera. Der Unterschied ist ganz klar.
    Sehen Sie mehr von Ihren Freunden mit dem HD Widescreenformat - und zwar gestochen scharf. Die neue FaceTime HD Kamera bietet die dreifache Auflösung der vorherigen Kamera, was perfekt für das brillante Display mit LED-Hintergrundbeleuchtung ist. Außerdem arbeitet sie jetzt bei schwachem Licht noch besser. Sie können mit Ihren Freunden HD Telefonate in 720p von einem neuen MacBook Pro zu einem anderen führen. Außerdem sind auch Videotelefonate zu anderen Macs mit Intel Prozessor, zum iPhone 4 oder zum neuen iPod touch möglich.
     
    Multi-Touch Trackpad - Jede Menge Platz für GestenMulti-Touch Trackpad. Fürs tägliche Handwerk.
    Mit dem Multi-Touch Trackpad interagieren Sie auf ganz natürliche Art mit den Inhalten auf deinem Display. Und die glatte Glasoberfläche bietet jede Menge Platz für Gesten. Durch Auf- und Zuziehen können Sie ein- und auszoomen, durch Streichen in deinen Fotos blättern, durch Drehen ein Bild anpassen und vieles mehr. Das Trackpad kommt ohne Taste aus, sodass Sie überall klicken können. Wenn Sie aus der Welt des rechten Mausklicks kommen, können Sie diesen entweder mit zwei Fingern auslösen, oder Sie konfigurieren einen physischen Rechtsklick-Bereich auf dem Trackpad. Je mehr Sie mit dem Multi-Touch Trackpad vertraut sind, desto mehr werden Sie sich fragen, wie Sie jemals ohne ausgekommen sind.
     
    Lange Laufzeit. Weniger aufladen. Mehr machen.
    Das neue MacBook Pro bietet eine fantastische Batterielaufzeit und das mit leistungsstärkeren Prozessoren und schnelleren Grafikprozessoren. Die energieeffiziente Prozessorarchitektur mit integriertem Video-Encoder sowie das automatische Umschalten zwischen den Grafikprozessoren bei den 43,18 cm / 17"" Modellen helfen, die Batterielaufzeit weiter zu verbessern. So können Sie pro Ladung bis zu 7 Stunden ohne Kabel im Web surfen oder es für Liveauftritte oder auf ein Shooting mitnehmen. Die fortschrittlichen chemischen Eigenschaften und die Adaptive Charging Technologie sorgen dafür, dass die Batterie bis zu 1000 Ladezyklen durchlaufen kann. Und da die Batterie des MacBook Pro bis zu fünf Jahre hält, kommt das MacBook Pro in einem Zeitraum, in dem ein herkömmliches Notebook drei Batterien verbraucht, mit nur einer aus. Das ist für die Benutzer genauso gut, wie für die Umwelt. Apple verwendet eine neue, strengere Testmethode, um zu messen, welche Ergebnisse Sie unter realen Bedingungen erzielen, z. B. beim Surfen in einem Cafe oder wenn Sie die neuesten Webvideos ansehen. Und wie schneidet dieses MacBook Pro dabei verglichen mit der Vorgängergeneration ab? Es liefert die gleiche fantastische Leistung.
     
    Hat beste Verbindungen.
    Unterwegs haben Sie mit der 802.11n Technologie im MacBook Pro immer Verbindung. Das MacBook Pro findet automatisch verfügbare Netzwerke und Sie können sich mit einem Klick verbinden. Auch die drahtlose Bluetooth Technologie ist integriert, sodass Sie drahtloses Zubehör sofort nach dem Auspacken verwenden können.
     
    DVDs superschnell brennen.
    Homevideos, die Sie mit iMovie und iDVD gemacht haben, können Sie mit dem 8-fach SuperDrive Laufwerk des MacBook Pro superschnell auf eine DVD brennen. Das SuperDrive kann auch Double-Layer-DVDs (also DVDs mit fast 9 GB Speicherplatz) beschreiben, sodass es auch hervorragend für Datensicherungen geeignet ist.
     
    Neue Intel Core i7 Prozessoren.
    Neue Quad-Core Intel Core i7 Prozessoren sind Standard beim 43,18 cm / 17"" MacBook Pro. Alle Modelle verwenden die kürzlich optimierten Chipsets von Intel. Was heißt das für die neuen MacBook Pro Modelle? Kurz gesagt: Sie sind bis zu zwei Mal schneller als die Vorgängergeneration und erledigen auch anspruchsvolle Aufgaben wie HD Videoschnitt, Audiokompilierung oder Rendering mehrschichtiger Bilddateien unglaublich schnell. Und da Mac OS X Snow Leopard darauf ausgelegt ist, jeden Prozessorkern zu nutzen, holt das Betriebssystem wirklich alles an Leistung aus dem Prozessor heraus.
     
    Schnellere Einzelchip-Mikroarchitektur.
    Ob Sie einen Film ansehen, Ihren Blog auf den neuesten Stand bringen oder Fotos bearbeiten - die Daten müssen von A nach B gelangen, um verarbeitet werden zu können. Die neueste Intel Core Architektur bringt den Prozessor, den Cache, den Speichercontroller und den Grafikprozessor auf einem einzigen Chip unter. Deswegen müssen die Daten keine weiten Wege zurücklegen, was für Sie schnellere Performance und höhere Effizienz bedeutet.
     
    Turbo Boost 2.0.
    Angenommen, Sie arbeiten mit einem prozessorintensiven Programm wie Aperture 3 oder Final Cut Pro, das von einem Leistungsschub profitiert würde. Turbo Boost ist eine dynamische Technologie, die automatisch die Geschwindigkeit der aktiven Prozessorkerne auf 3,4 GHz erhöht. Turbo Boost 2.0 ist noch dynamischer und effizienter. Es wechselt die Kernfrequenz in kleineren Schritten als bisher, sodass der Prozessor die Leistung ohne Effizienzeinbußen verwalten kann. All das passiert im Hintergrund. Sie arbeiten einfach nur schneller.
     
    Hyper-Threading.
    Hyper-Threading ist jetzt Standard auf jedem MacBook Pro. Mit dieser Technologie können auf jedem Kern zwei Threads gleichzeitig laufen, Mac OS X erkennt also bei einem Quad-Core Prozessor acht und bei einem Dual-Core Prozessor vier virtuelle Kerne. Wenn Sie mehrere Programme gleichzeitig verwenden, verteilt der Prozessor die Aufgaben gleichmäßiger über eine größere Anzahl Kerne.
     
    Integrierter Speichercontroller.
    Mit schnellerem Speicherzugriff legt jeder Kern direkt mit der Verarbeitung der Daten los, statt auf ihr Eintreffen zu warten. Genau deshalb nutzt die neue Intel Core Architektur einen integrierten Speichercontroller, der den schnellen 1333 MHz Speicher direkt mit dem Prozessor verbindet und Ihre Programme immer die maximale Prozessorleistung zur Verfügung haben.
     
    Energieeffiziente Grafik.
    Dank der neuen Mikroarchitektur ist der Grafikprozessor auf dem gleichen Chip wie der Zentralprozessor und hat direkten Zugriff auf den L3-Cache. Kurze Wege bedeuten mehr Leistung. Der Grafikprozessor erhöht auch automatisch die Taktrate für noch höhere Auslastung. Ein integrierter Video-Encoder ermöglicht jetzt HD Videotelefonate mit FaceTime, und der effiziente Decoder sorgt für lange Batterielaufzeit, wenn Sie sich DVDs oder iTunes Filme ansiehen.
     
    Mac OS X. Das fortschrittlichste Betriebssystem der Welt.
    Mac OS X ist das Herz jedes MacBook Pro und Mac. Dieses Betriebssystem ist genau auf die integrierten Intel Multicore-Prozessoren und fortschrittlichen Grafikprozessoren zugeschnitten. Die neueste Version, Mac OS X Snow Leopard, basiert komplett auf einer 64-Bit-Architektur, genau wie alle anderen Programme, die mit dem Mac kommen. Das bedeutet: Alles, was Sie auf Ihrem MacBook Pro machen, passiert superschnell und mit einer unglaublichen Gesamtleistung.
     
    Hat eine ganze Menge draufProgramme, ebenso leistungsstark wie benutzerfreundlich.
    Weil Apple sowohl das MacBook Pro, wie auch die integrierte Software entwickelt, arbeitet alles perfekt zusammen. Und mit den Apple Programmen sind Sie ganz schnell vertraut, weil alle ähnlich funktionieren. Das heißt, wenn Sie ein Programm kennen, sind Sie auch schnell mit allen anderen vertraut. Außerdem weiß Apple genau, was mobile Produktivität bedeutet. Darum haben wir Funktionen wie Expose und Spaces hinzugefügt. Damit können Sie ganz einfach auf alles auf Ihrem MacBook Pro zugreifen. Expose zeigt sämtliche geöffneten Fenster nebeneinander, verkleinert sie und ordnet sie so, dass Sie den Inhalt jedes Fensters sehen können - ein Tastendruck oder eine Geste genügt. Und mit Spaces können Sie Fenster zusammen auf ihrem eigenen Schreibtisch oder Bereich gruppieren und ganz einfach zwischen diesen wechseln. Legen Sie einen Bereich zum Arbeiten fest, einen zum Spielen und einen für was auch immer. Mit Expose und Spaces haben Sie beim Multitasking auf einem Notebookdisplay einen riesigen Vorteil.
     
    Darauf verzichten Sie beim Mac: PC-Viren.
    Trojaner, Würmer, E-Mail Viren. Die digitale Welt kann ganz schön beängstigend sein. Zum Glück ist der Mac immun gegen die tausenden von Viren, die Windows Computer plagen. Denn Mac OS X kommt mit integrierten Sicherheitsmechanismen, die Sie schützen - ohne dass Sie etwas machen müssen. Und sollten doch mal potenzielle Sicherheitsrisiken auftreten, reagiert Apple sofort und stellt neue Softwareaktualisierungen und Sicherheitsverbesserungen bereit, die Sie automatisch laden und mit einem Klick installieren können.
     
    Das automatische Backup rettet Ihren Tag. Und die Woche, den Monat ...
    Backups müssen sein. Trotzdem vergissen Sie sie bestimmt hin und wieder. Deshalb kümmert sich jetzt das MacBook Pro um die Datensicherung. Time Machine, ein Programm, das auf jedem Mac dabei ist, sichert automatisch Ihr ganzes System auf einer externen Festplatte oder Time Capsule. Time Machine speichert eine Kopie von jeder Datei. Und es merkt sich, wie Ihr System an einem bestimmten Tag ausgesehen hat. So können Sie, wenn Sie wollen, die Zeit zurückdrehen und Ihren Mac wie in der Vergangenheit sehen.
     
    Mit iMovie können Sie aus Ihren Videos großartige Filme machenAuch die täglichen Sachen machen mehr Spaß.
    Anders als viele PC-Notebooks kommt das MacBook Pro mit allem, was Sie brauchen, um E-Mails zu senden, Kalender zu verwalten, Kontakte zu organisieren und mehr. Und Sie können schon wenige Minuten nach dem Auspacken damit loslegen. Denn jeder Mac kommt mit Mail, um E-Mails zu senden und empfangen, iCal zum Organisieren von Terminen und wichtigen Ereignissen, dem Adressbuch zum Verwalten von Kontakten, iTunes für alles, was mit Unterhaltung zu tun hat, und weiteren tollen und nützlichen Programmen, die Sie jeden Tag verwenden werden.
     
    Der Mac App Store. Tausend weitere Gründe, den Mac zu lieben.
    Über tausend Mac Apps sind nur einen Klick entfernt - im Mac App Store. Suchen Sie einfach Apps, die Ihnen gefallen, und klicken Sie einfach, um sie zu laden und zu installieren. Ohne Verpackung. Ohne CDs oder DVDs. Und ohne Probleme. Sie können die Apps nach Kategorien durchstöbern oder direkt etwas Bestimmtes suchen. Und Sie können einfach dafür sorgen, dass Ihre Apps up-to-date sind, denn Ihr Mac zeigt Ihnen an, wann Updates verfügbar sind.
     
    iPhoto. Fotos ganz einfach verwalten, bearbeiten und teilen.
    iPhoto ist ein benutzerfreundliches Programm für Fotos, mit dem Sie Ihre Bilder schnell organisieren, wiederfinden und verbessern können - sodass sie immer perfekt aussehen. Mit den iPhoto Funktionen ""Gesichter"", ""Orte"" und ""Ereignisse"" behalten Sie den Überblick über Ihre Fotos. Sie sagen Ihnen, wen Sie fotografiert haben, wo und wann. Und all das in den neuen Vollbildmodi.
     
    iMovie. Und aus Homevideos werden Home-Blockbuster.
    Homevideos müssen nicht langweilig sein. Mit iMovie können Sie aus Ihren Videos großartige Filme machen. Zum Beispiel Trailer im Hollywoodstil, mit denen Sie Ihr Publikum begeistern.
     
    GarageBand. Großartige Musik machen, ganz einfachissimo.
    Egal, ob Sie Musiktalent haben oder einfach nur neugierig sind - GarageBand ist genau das richtige Programm für Sie. Schließ einfach eine elektrische Gitarre oder ein USB Keyboard an. Und schon können Sie mit virtuellen Nachbildungen der bekanntesten Amps und Stompboxes der Welt sowie mit 100 Software-Instrumenten spielen.  
    ";2;False;0;;;Apple MacBook Pro MC725D/A 17 Zoll Notebook;apple-macbook-pro-mc725da-17-zoll-notebook-2;True;True;PD-01094;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;2,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;2299.9000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;41389,3991666667;5;1;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000312-apple-macbook-pro-mc725da-17-zoll-notebook.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000313-apple-macbook-pro-mc725da-17-zoll-notebook.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000314-apple-macbook-pro-mc725da-17-zoll-notebook.jpg;2;;False;;;;;False;False;False;;;;;False;;;;;; -5;0;True;Asus Eee PC 1001HA 10,1 Zoll Netbook;3 GB, 17 Zoll, 400 GB, AMDl, 3;"
    Eee PC™ 1001HA: Klasse Leistung zu unschlagbarem Preis
     
    Der Eee PC™ 1001HA unterscheidet sich von seinen großen Brüdern durch Prozessor und Akkukapazität. Ausgestattet mit einem Intel® Atom™ N270 Prozessor, einem 3 Zellen Akku für bis zu 4 Stunden Laufzeit, WLAN 802.11n Standard sowie weiteren Top Merkmalen, überzeugt der Eee PC™ 1001HA zu einem wirklich unschlagbaren Preis.
     
    Eee PC™ 1001HA: Funktionalität meets Design
     
    Mit dem kompakten Eee PC™ 1001HA trägt ASUS seinem Anspruch, in den Produkten höchste Funktionalität mit formvollendetem Design zu verbinden, ein weiteres Mal Rechnung. So besticht der neue Eee PC™ durch sein elegantes und gleichzeitig unempfindliches Gehäuse, das mit klaren Linien und nach unten schmaler zulaufenden Kanten dem schlanken Design einer Muschel nachempfunden ist. Aber auch das Innenleben der Kleinen kommt ganz groß raus. Als gewohnt kontaktfreudig erweisen sich die Neulinge dank VGA Port für den Anschluss eines Monitors sowie drei USB 2.0 Schnittstellen, um Maus, Tastatur oder Digicam anzuschließen. Wer Bilder direkt von der SD oder MMC Speicherkarte auf den Eee PC™ übertragen möchte, nutzt den integrierten Kartenleser. Für das Speichern der Fotos stehen bei beiden Modellen eine 160 GB S-ATA Festplatte zur Verfügung.. Das Modell basiert auf Microsoft® Windows® XP Home und ist – wie alle Eee Familienmitglieder – ausgesprochen einfach zu bedienen. Das 10 Zoll WSVGA Display mit stromsparender LED-Hintergrundbeleuchtung sowie die große Tastatur, die zu 92% einer Standard Notebooktastatur entspricht, gewähren zusätzlichen Komfort. Für Chats oder Videokonferenzen hat ASUS die Minis zudem mit einer 0.3 Megapixel Web-/Videokamera sowie einem Mikrofon ausgestattet.
     
     
    ";2;False;0;;;Asus Eee PC 1001HA 10,1 Zoll;asus-eee-pc-1001ha-101-zoll-netbook-2;True;True;PD-01090;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;243.9000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;41389,3988657407;5;37;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000563-asus-eee-pc-1001ha-101-zoll-netbook.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000564-asus-eee-pc-1001ha-101-zoll-netbook.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000565-asus-eee-pc-1001ha-101-zoll-netbook.jpg;2;;False;;;;;False;False;False;;;;;False;;;;;; -5;0;True;"HP Compaq Mini 110c-1110sg 10.1 Zoll Netbook ";4 GB, 18 Zoll, 800 GB, Intel, 2;"
    HP Compaq Mini 110c-1110sg 10.1 Zoll Netbook
     
    Intel Atom N270 1.6GHz, 1GB RAM, 160GB HDD, Intel GMA 950, Win XP Home
     
    Leicht und kompakt
    Der Compaq Mini 110c wiegt 1,3 kg (mit 6-Zellen-Akku) und ist ca. 5,5 cm hoch – er ist damit sehr kompakt und fällt ins Auge
     
    Elegantes Design
    Der Compaq Mini 110c glänzt mit einem eleganten Gehäuse im neuem Imprint-Finish ""Unity"", einem Karomuster, das ins Auge fällt.
     
    Ständig in Verbindung
    Webcam und Mikrofon sind im Compaq Mini integriert und bieten per WLAN und optionalem WWAN zahlreiche Möglichkeiten zur Pflege sozialer Kontakte; Video-Chats und Video-Konferenzen, die bislang nur zuhause möglich waren, können jetzt im Park, im Cafe oder am Flughafen geführt werden
     
    Information und Kommunikation auch unterwegs
    Mit dem 10,1-Zoll-BrightView-Display, Original Windows® XP Home, der großen Tastatur (92 % der vollen Größe), drei USB-Anschlüssen und einem 5-in-1 Kartenleser sind Informationen, Kommunikation und Unterhaltung im Internet überall bequem zugänglich.
    ";2;False;0;;;"HP Compaq Mini 110c-1110sg 10.1 Zoll Netbook ";hp-compaq-mini-110c-1110sg-101-zoll-netbook-2;True;True;PD-01091;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;259.9000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;41389,3988657407;"5;2095";39;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000598-hp-compaq-mini-110c-1110sg-101-zoll-netbook.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000599-hp-compaq-mini-110c-1110sg-101-zoll-netbook.jpg;;2;;False;;;;;False;False;False;;;;;False;;;;;; -5;0;True;Samsung NC10 anyNet 10,2 Zoll Netbook;2 GB, 15 Zoll, 400 GB, AMDl, 4;"
    Samsung NC10 anyNet10,2"" Netbook

    Intel Atom N270 1.6GHz, 1GB RAM, 160GB HDD, Intel GMA 950 XP Home
     
    NC10-anyNet: Entwickelt für das ""mobile Leben"". Entwickelt für höchste Ansprüche in innovativem Design. Das ultrakompakte und leichte Gehäuse bietet eine Reihe von praktischen Features, die das mobile Leben vereinfachen. Brillante Technologie angepasst an das rasante und digitale Leben für noch mehr Mobilität.
     
    Schlankes Design
    Mit einem optimierten 10,2 Zoll Breitbild Display für ein makelloses visuelles Erlebnis, ist das schlanke NC10 lediglich 1,19 cm hoch und passt nahezu in alle Taschen. Das widerstandsfähige Gehäuse bietet ein Maximum an Tragekomfort und Verlässlichkeit sowie hochwertiger Ergonomie und Stil.
     
    Videokonferenz
    Ob Videokonferenzen oder Live Messaging - die integrierte 1,3 Megapixel Kamera lässt sie noch leichter mit Freunden, Familie und Kollegen in Kontakt bleiben. Die Kamera verbindet die Auflösung und die Bildqualität einer Fotokamera mit der nachhaltig hohen Bildfrequenz einer Videokamera.
     
    Robustes Gehäuse, langlebig und verlässlich
    Fühlen Sie sich sicher mit dem robusten Protect-o-Edge Gehäuse, das für Langlebigkeit und Verlässlichkeit steht. Eine aufwendige Serie von 54 Qualitätstests, die von schnellen Temperaturwechseln bis zu elektrischen Überspannungen reichen, gewährleistet neue Standards in Punkto Belastbarkeit und Ausdauer.
     
    Antibakterielle Tastatur
    Die SilverNano Technologie beschichtet die Tastatur mit nano-kleinen Silberionen, die das Überleben und die Neuentstehung von Bakterien verhindern. Innerhalb von 24 Stunden werden 99,9% aller Bakterien abgetötet und es entsteht eine hygienische Arbeitsatmosphäre.
     
    Leichtgewicht
    Als eines der weltweit leichtesten 10,2 Zoll Mini Notebooks seiner Klasse, mit einem Gewicht von nur 1,45 kg, ist das NC10 voll bepackt mit neuester Technologie und garantiert dabei maximale Mobilität und Leistung.
      
    Vollständige Notebook-Tastatur
    Die vollständige Notebook-Tastatur bietet optimalen Schreibkomfort. Ergonomisches Design und optimierte Tastenabstände machen das Arbeiten und Kommunizieren angenehmer und ermöglichen schnelleres sowie fehlerloses Schreiben.
     
    Voll ausgestattet für einfachen Datenaustausch
    Einfacher Datenaustausch dank einer Vielzahl an Anschlussmöglichkeiten, inklusive einem Kartenleser und drei USB-Anschlüssen, so dass Sie problemlos Bilder, Filme und Daten auf und von nahezu allen modernen Kameras, periphären oder audiovisuellen Geräten transferieren können.
    ";2;False;0;;;;samsung-nc10-anynet-102-zoll-netbook-2;True;True;PD-01092;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;329.9000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;41389,3988657407;5;5;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000511-samsung-nc10-anynet-102-zoll-netbook.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000512-samsung-nc10-anynet-102-zoll-netbook.jpg;;2;;False;;;;;False;False;False;;;;;False;;;;;; -5;0;True;Germot GM 205 Integralhelm Dekor;Der GM 205 ist der Preisgünstige einsteiger Motorradhelm mit kratzfestem Außenvisier.;"
    Germot GM 205 Integralhelm
    Ideal für Rollerfahrer oder kurze touren
     
    klare, getönte und verspiegelte Visiere zu diesem Modell sind in unserem Shop erhältlich!
     
    Eigenschaften: klares, kratzfestes Visier mit Verstellraster, einfacher und schneller Visierwechsel, Visier- und Kopfbelüftung, großes Gesichtsfeld, Nasenspoiler, hautfreundliche Innenausstattung, hochwertige Mehrschichtlackierung mit UV-Schutz, Drucktastensteckschloss, ECE 22 05.

    Material: ABS/Polycarbonat Mix

    Gewicht: 1.400g +/-50g

    Größen: XS (53-54) / S (55-56) / M (57-58) / L (59-60) / XL (61-62) / 2XL (63-64)
    Größenangabe in Klammer= Kopfumfang in cm.
    ";2;False;0;GM205, rollerhelm, integralhelm,germot,motorradhelm;Der GM 205 ist der Preisgünstige einsteiger Motorradhelm und Rollerhelm mit kratzfestem Außenvisier.;Germot GM 205 Integralhelm Dekor;germot-gm-205-integralhelm-dekor;True;True;20596;;5000111105392;False;0;False;;False;False;0;False;0;1;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;2;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;79.9000;79.9000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;41129,4577083333;"1;22";1;;;;5;;False;kg;;;;False;False;False;;;;;False;;;;;; -5;0;True;Apple iPod Nano 16 GB 6. Gen. verschiedene Farben;Apple iPod Nano 16 GB 6. Generation verschiedene Farben;"
    Der Remix für Ihre Finger
    Der iPod nano mit Multi-Touch ist einfach, intuitiv und macht jede Menge Spaß - wie Ihre Musik. Und er ist jetzt noch kleiner, damit Musik bei allem, was Sie machen, eine größere Rolle spielen kann.
     
    Musik. Fühlen Sie den Beat
    Ihre Greatest Hits. Zum Anfassen
    Die besten Dinge im Leben kommen mit Soundtrack. Und genau da glänzt der iPod nano. Mit dem Multi-Touch Display können Sie Ihre Musik ganz neu erleben. Ein Tipp genügt und er spielt, was Sie hören wollen. Stöbern Sie in Ihrer Musik nach Songs, Alben, Interpreten, Wiedergabelisten, Genres oder Komponisten - streichen Sie dazu über den Homescreen. Sie können sogar die Symbole auf dem Homescreen neu ordnen, damit alles so ist, wie Sie es wollen.
     
    Das ist ein echter Musikclip
    Mit dem neuen integrierten Clip können Sie mit Ihren Lieblingssongs am Ärmel (oder in der Tasche, Jacke oder Hose) wandern, laufen, Rad fahren und abrocken. Und das Cover zum Song, der gerade läuft, passt perfekt auf das Display.
     
    Rock around the clock
    Die integrierte aufladbare Lithium-Ionen-Batterie sorgt für 24 Stunden Musik nonstop. Wenn Sie sich den 8 GB oder 16 GB iPod nano anklippen, haben Sie genug Songs für den Weg zur Arbeit, fürs Training und mehr.
     
    Songs aus dem Finger schütteln
    Überlassen Sie alles dem Zufall. Einfach den iPod nano kurz schütteln und er springt zu einem anderen Song aus Ihrer Sammlung. Schütteln ist perfekt, wenn Ihnen gerade nicht nach einer bestimmten Musik ist. Lassen Sie sich einfach überraschen.
     
    Genius. Ihr Mixmaster
     
    Eingebauter Clip

     
    Ihr persönlicher DJ
    Angenommen, Sie hören einen Song, der Ihnen gut gefällt, und möchten ähnliche hören. Ein Tipp auf Genius genügt. Genius findet weitere Songs auf Ihrem iPod nano, die gut dazu passen und erstellt eine Genius Wiedergabeliste für Sie. Wenn Sie einen Mix wollen, auf den Sie selbst nie gekommen wären, erstellen Sie einen Genius Mix in iTunes und synchronisieren ihn mit Ihrem iPod nano. Tippen Sie auf das Symbol für Genius Mixe und entdecken Sie Songs, die Sie lange nicht mehr gehört haben, oder Musik, von der Sie gar nicht mehr wussten, dass Sie sie haben.
     
    FM Radio. Und Sie haben alles auf dem Sender
    Radio nano
    Mit dem iPod nano können Sie auf der Radiowelle surfen. Der FM Tuner zeigt Ihnen den Interpreten, Song oder Sender, der gerade läuft. Ein Tipp genügt und Sie sehen die Radiosteuerungen. Streichen Sie über den Tuner, um den Sender zu wechseln, und stellen Sie dann Ihre Lieblingssender per Fingertipp ein.
     
    Live-Pause
    Wenn Sie Ihre Lieblingssendung im Radio einmal kurz unterbrechen müssen, verpassen Sie dank Live-Pause trotzdem keinen einzigen Beat. Einfach Tippen und Sendung oder Song werden angehalten. Noch mal Tippen und es geht da weiter, wo Sie aufgehört haben. Sie können sogar bis zu 15 Minuten zurückspulen und dann vorspulen, um wieder live dabei zu sein.
     
    Fitness. Treffen Sie Ihren neuen Trainer
     
    Anklippen und los geht´s
    Das neue Design des iPod nano hilft Ihnen fit zu bleiben. Weil er so klein und tragbar ist, ist er auch beim Joggen, Wandern und im Fitnessstudio immer dabei. Klippen Sie ihn an und steuern Sie Ihre Musik mit nur einem Tippen oder Streichen, sodass Sie sich voll auf Ihr Workout konzentrieren können. Ob Laufen, Walken oder der Weg zum Fitnessstudio - für den kleinen iPod nano ist kein Weg zu weit.
     
    Schritte zum Fitbleiben
    Sie können den iPod nano auch als Schrittzähler verwenden. Er zählt Ihre Schritte und hilft Ihnen beim Erreichen Ihrer Fitnessziele. Einfach anklippen und los geht´s. Sie können eine tägliche Schrittvorgabe festlegen und Ihre Fortschritte sehen, wenn Sie Ihre Daten auf die Nike+ Website laden.
     
    Rocken Sie Ihr Training
    Ob beim Joggen oder im Fitnessstudio, mit dem Nike + iPod Sport Kit (separat erhältlich) motiviert Sie der iPod nano vom Warm Up bis zum Cool Down. Ziehen Sie Ihre Nike+ Joggingschuhe an und klippen Sie sich den iPod nano an. Sehen Sie wie Sie Kilometer für Kilometer zurücklegen und hören Sie das Sprachfeedback in Echtzeit, während Ihre Songs laufen. Schließen Sie den iPod nano im Fitnessstudio an ein Gerät an, das mit Nike + iPod kompatibel ist. So zeichnet er Ihre Geschwindigkeit, die Dauer und die Laufstrecke auf, während Sie Ihr Training rocken.
     
    iTunes. Damit der iPod was zu spielen hat
    Alles für gute Unterhaltung
    iTunes ist der beste Weg, Ihren iPod nano mit den neuesten Hits, Podcasts, Hörbüchern und vielem mehr zu füllen. Und auch die beste Art, Ihre immer weiter wachsende Sammlung digitaler Medien zu durchstöbern und auf dem Mac oder PC zu organisieren. Alle im iTunes Store gekauften Inhalte und alle von CDs importierten Songs werden in Ihrer Mediathek in iTunes angezeigt. Sie können Ihre eigenen oder Genius Wiedergabelisten erstellen, Genius Mixe auswählen und alles mit Ihrem iPod nano synchronisieren. Und iTunes ist als kostenloser Download verfügbar.
     
    Der beste Music Store der Welt
    Laden Sie Ihre Lieblingssongs auf Ihren iPod nano. Oder stöbern Sie in über 13 Millionen Songs und finden Sie weitere Hits. Sie können nach dem Namen eines Interpreten, Songs oder Albums suchen und so genau die richtigen Songs finden. Sie suchen neue Musik und brauchen Hilfe? Die Genius Seitenleiste empfiehlt Ihnen neue Musik, die auf Ihren Lieblingssongs basiert. Sie können in jeden Song kostenlos 30 Sekunden reinhören. Und mit einem Klick können Sie einen Song kaufen. Er wird dann sofort geladen. Schneller und einfacher können Sie Ihre digitale Musiksammlung für den iPod nicht zusammenstellen.
     
    Bedienungshilfen
    Integrierte Bedienungshilfen.
    iPod nano kommt mit Bedienungshilfen, die Menschen mit Handicaps helfen Musik, Hörbücher und mehr zu erleben.
     
    VoiceOver
    Der iPod touch bietet VoiceOver, die weltweit erste Bildschirmlesefunktion, die auf Gesten basiert. Tippen Sie auf das Display und Sie hören eine Beschreibung des Objekts, das Sie gerade berühren. Steuern Sie den iPod nano durch Doppeltippen, Bewegen oder Streichen. Mit den optionalen Apple Earphones mit Fernbedienung und Mikrofon können Sie Ihre Musik steuern, ohne auf das Display zu sehen. VoiceOver nennt Ihnen den Song und Interpreten und spricht auch noch 29 Sprachen.
     
    Weiß auf Schwarz
    Wenn Sie stärkeren Kontrast möchten, stellen Sie das Display des iPod nano so ein, dass Weiß auf Schwarz angezeigt wird. Sie können diese Funktion in jeder App und auch auf dem Homescreen verwenden.
     
    Mono Audio
    Wenn Sie nur auf einem Ohr gut hören können, können Sie ""Mono-Audio"" aktivieren, damit die Audioausgabe auf beide Ohrhörer geleitet wird und Sie beide Kanäle mit dem gesunden Ohr hören können.

    Produktbeschreibungen
     
    Highlights
    - Multi-Touch Display
    - Genius - dein Mixmaster
    - FM Radio
    - iTunes
    - Integrierte Bedienungshilfen (VoiceOver und Weiß auf Schwarz)
     
    Akku
    - Akkutyp: Li-Ion
    - Akkulaufzeit bis zu 24 Stunden
     
    Display
    - Farbdisplay
    - Bilddiagonale: 3,91 cm
    - 1,54- Display
    - Auflösung Breite: 240 Pixel
    - Auflösung Höhe: 240 Pixel
     
    Speicher
    - Interner Speicher 8.000 MB
     
    Stromversorgung
    - USB-Lader
     
    Wiedergabeformate Audio
    - AAC
    - MP3
    - WAV
     
    Grundeigenschaften
    - Breite: 40,9 mm
    - Höhe: 37,5 mm
    - Tiefe: 8,78 mm
    - Gewicht: 21,1 g
    - Gewicht: 21,1 g
    - Farbe: Dunkelgrau
     
    Lieferumfang
    - iPod nano
    - Apple Earphones
    -Dock Connector auf USB Kabel
    - Dokumentation und wichtige Produktinformationen
    ";2;False;0;;;Apple iPod Nano 16 GB 6. Gen. verschiedene Farben;apple-ipod-nano-16-gb-6-gen-verschiedene-farben;True;True;PD-01087;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;179.0000;179.0000;179.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;40900,5013078704;49;1;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000266-apple-ipod-nano-16-gb-6-gen-verschiedene-farben.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000267-apple-ipod-nano-16-gb-6-gen-verschiedene-farben.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000268-apple-ipod-nano-16-gb-6-gen-verschiedene-farben.jpg;1;;False;;;;;False;False;False;;;;;False;;;;;; -5;0;True;Microsoft Windows XP Professional SP3 OEM;"Microsoft Windows XP Professional SP3 OEM ";"

    Microsoft Windows XP Professional SP3 OEM

    auf jedem PC installierbar-OEM
     
     
    Windows XP Professional ist das bewährte Windows-Betriebssystem für Unternehmen und Heimanwender.
    Auf der soliden Grundlage von Windows 2000 bietet Windows XP Professional verbesserte Zuverlässigkeit,
    Sicherheit, Leistung und Benutzerfreundlichkeit und setzt zugleich neue Maßstäbe in der Datenverarbeitung.
    Mit den professionellen Features zur Administration und zur Netzwerkanbindung erweitert
    Windows XP Professional den Funktionsumfang von Windows XP Home Edition.
    Windows XP Professional basiert auf einer 32-Bit-PC-Architektur und umfasst ein vollständig geschütztes Speichermodell.
     
    Dies alles macht Windows XP Professional zur zuverlässigen Version. Die Funktion ""Systemwiederherstellung""
    ermöglicht es Benutzern und Systemverwaltern, den Status eines PCs wiederherzustellen, den er vor einem Ausfall hatte,  ohne dass dabei Daten verloren gehen.
    Bei der Systemwiederherstellung werden problemlos erkennbare Wiederherstellungspunkte erstellt,
    anhand derer Sie das System auf eine bestimmte Uhrzeit wiederherstellen können. 
    ";2;False;0;;;Microsoft Windows XP Professional SP3 OEM;microsoft-windows-xp-professional-sp3-oem;True;True;P-2960;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;57.9900;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;40889,6330208333;"30;80";3;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000181-microsoft-windows-xp-professional-sp3-oem.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000182-microsoft-windows-xp-professional-sp3-oem.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000183-microsoft-windows-xp-professional-sp3-oem.jpg;2;;False;;;;;False;False;False;;;;;False;;;;;; -5;0;True;Windows 7 32 Bit;Windows 7 32 Bit;"
    Windows 7  
     
    Die umfassendste Edition von Windows 7
    Windows 7 Ultimate ist die vielseitigste und leistungsfähigste Edition von Windows 7. Sie kombiniert die bemerkenswerte Benutzerfreundlichkeit der Unterhaltungsfunktionen von Home Premium mit den unternehmensorientierten Funktionen von Professional, wozu auch die Fähigkeit zum Ausführen zahlreicher Windows XP-Produktivitätsprogramme im Windows XP-Modus gehört.
     
    Für mehr Sicherheit können Sie Ihre Daten auch mit BitLocker und Bitlocker To Go verschlüsseln. Und zur Erhöhung der Flexibilität können Sie in einer beliebigen von 35 Sprachen arbeiten. Mit Windows 7 Ultimate müssen Sie auf nichts verzichten.
     
    Windows 7 vereinfacht alltägliche Aufgaben
     
    Desktop
    Unter Windows 7 ist es nun einfacher, noch mehr Aufgaben direkt auf dem Desktop zu erledigen: Verbesserte Taskleistenvorschau, größere Symbole, Anheften und kreative Möglichkeiten der Personalisierung.
     
    Neue Möglichkeiten, mit Fenstern zu jonglieren
    Überwältigt von der Zahl der geöffneten Fenster? Windows 7 bietet drei einfache und dennoch leistungsfähige neue Funktionen, die wie folgt bezeichnet werden: Aero Shake, Aero Peek und Snap. Sie unterstützen Sie dabei, sofort den Weg durch den Desktop zu finden.
     
     
    Die verschiedenen Windows 7 Editionen im Vergleich 
     
    Spektakuläre neue Hintergrundbilder
    Seien wir ehrlich: Wir verbringen jede Menge Zeit damit, auf unsere PCs zu starren. Die Ästhetik sollte daher nicht zu kurz kommen. Darum enthält Windows 7 viele neue Desktophintergründe, so genannte Hintergrundbilder, unter denen sich alle möglichen Motive von beeindruckend bis unterhaltsam befinden. Oder probieren Sie doch einmal die neue Desktopdiashow aus, in der eine wiederkehrende Reihe von Bildern (unserer oder Ihrer) angezeigt wird. Desktop und langweilig? Das ist vorbei.
     
    Schauen Sie sich die ""Superleiste"" an
    Schon unter Windows 95 hat die Taskleiste als Ausgangspunkt zum Starten von Programmen und Umschalten zwischen Fenstern gedient. Nicht nur die Zeiten, auch die Arbeitsweisen am PC haben sich geändert. Unter Windows 7 wurde die Taskleiste daher komplett neu gestaltet, damit Sie noch mehr Aufgaben erledigen können. Sie ist ansprechender, kann besser angepasst werden und vereinfacht das Multitasking.
     
    Heimnetzgruppe
    Dank der Heimnetzgruppe brauchen Sie sich keine Gedanken mehr über die Datei- und Druckerfreigabe in einem Heimnetzwerk zu machen. Verbinden Sie mindestens zwei Windows 7-PCs, und schon kann mit der Heimnetzgruppe ganz einfach die automatische Freigabe von Musik, Bildern, Videos und Dokumentbibliotheken für andere Personen im Haus starten. Und das neue Menü ""Freigeben für"" ermöglicht die schnelle Freigabe einzelner Dateien.
     
    Machen Sie sich Sorgen um den Datenschutz? Wir auch. Und deshalb ist die Heimnetzgruppe kennwortgeschützt, sodass Sie die volle Kontrolle über den Zugriff haben. Sie entscheiden, welche Dateien freigegeben werden und welche nicht. Außerdem können Sie Ihre Dateien mit Schreibschutz versehen, d. h., der Inhalt kann von anderen angesehen, aber nicht geändert werden. Einer Heimnetzgruppe beizutreten, ist in jeder Edition von Windows 7 möglich. Das Erstellen einer Heimnetzgruppe ist jedoch nur in den Editionen Home Premium, Professional und Ultimate möglich.
     
     
    Die verbesserte Taskleiste verschafft mit Hilfe der neuen Vollbild-Vorschaufenster schnellen Überblick 
     
    Sprunglisten
    Über die in Windows 7 neu eingeführten Sprunglisten gelangen Sie nun direkt zu den Dokumenten, Bildern, Songs oder Websites, die Sie tagtäglich nutzen. Zum Öffnen einer Sprungliste klicken Sie auf der Taskleiste von Windows 7 einfach mit der rechten Maustaste auf ein Programm (Sie sind auch im Startmenü zu finden.).
     
    Der Inhalt einer Sprungliste hängt vom Programm ab. In der Sprungliste für Internet Explorer 8 werden häufig besuchte Websites angezeigt. Windows Media Player 12 enthält häufig abgespielte Musiktitel. Fehlt in der Sprungliste ein Favorit? Sie können dort beliebige Dateien ""anheften"". In Sprunglisten werden nicht nur Verknüpfungen zu Dateien angezeigt. Manchmal bieten sie auch Schnellzugriff auf Befehle für Aufgaben wie das Verfassen neuer E-Mail-Nachrichten oder das Wiedergeben von Musik.
     
    Snap
    Snap bietet eine schnelle neue Möglichkeit, die Größe geöffneter Fenster einfach durch Ziehen an die Bildschirmränder zu ändern. Je nach Rand, also, oben oder unten, rechts oder links, wird das Fenster verbreitert, oder es füllt den ganzen Bildschirm aus. Und Sie können Fenster auch nebeneinander anordnen. Mit Snap wird das Lesen, das Anordnen und das Vergleichen von Fenstern zum Kinderspiel.
     
     
    Den Desktop jederzeit im Blick dank transparenter Fenster 
     
    Windows Live Essentials
    Was ist Windows Live Essentials? Einfach ausgedrückt, handelt es sich um kostenlose Software, die einen Windows 7-PC mit noch mehr tollen Funktionen ausstattet, z. B. für E-Mail, Instant Messaging, Fotobearbeitung und Blogs. Windows Live Windows Live Essentials ist auf der Windows Live-Website verfügbar. Der kostenlose Download enthält folgende Komponenten: Messenger, Fotogalerie, Mail, Writer, Movie Maker, Symbolleiste und Family Safety.
     
    Windows Search
    Unter Windows 7 finden Sie noch schneller noch mehr Dinge an noch mehr Orten. Sobald Sie im Suchfeld des Startmenüs mit der Eingabe beginnen, wird eine Liste relevanter Dokumente, Bilder, Musiktitel und E-Mails auf dem PC angezeigt. Die Ergebnisse sind nun nach Kategorie gruppiert und enthalten hervorgehobene Stichwörter und Textausschnitte, um die Suche zu vereinfachen.
     
    Dateien werden heutzutage nur noch selten an einem Ort abgelegt. Also ist Windows 7 auch darauf ausgelegt, externe Festplatten, Netzwerk-PCs und Bibliotheken zu durchsuchen. Zu viele Suchergebnisse? Sie können die Suche direkt nach Datum, Dateityp und anderen hilfreichen Kategorien eingrenzen.
     
    Windows 7 funktioniert Ihren Vorstellungen entsprechend
     
    Leistungsverbesserungen
    Niemand wartet gerne. Darum ist Windows 7 nun noch schneller und immer bereit, wenn Sie es sind. Zu den wichtigen Leistungsverbesserungen zählen u. a. schneller Wechsel in und aus dem Energiesparmodus, weniger Speicherbedarf und schnelle Erkennung von USB-Geräten:
     
    Standbymodus
    Windows 7 kann in den Energiesparmodus versetzt und wiederhergestellt werden und die Verbindung mit dem Drahtlosnetzwerk wieder schneller herstellen.
     
     
    Sprunglisten ermöglichen schnellen Zugriff auf häufig anstehende Aufgaben 
     
    Suchen
    Wenn Sie auf der Suche nach Informationen sind, dann möchten Sie nicht lange warten, sondern Antworten bekommen. Unter Windows 7 werden Suchergebnisse schneller angezeigt. Auch das Sortieren und Gruppieren von Suchergebnissen geht viel rascher vonstatten.
     
    USB-Geräte
    Wenn Sie zum ersten Mal ein tragbares Flashlaufwerk oder ein anderes USB-Gerät anschließen, stellt Windows 7 es innerhalb weniger Sekunden für Sie bereit. Und wenn Sie es bereits zuvor verwendet haben, dann geht es sogar noch schneller.
     
    Rationaler und geringere Auslastung
    Anders als seine Vorgänger ist Windows 7 darauf ausgelegt, verlangsamende Hintergrunddienste nur dann auszuführen, wenn Sie sie benötigen. Sie verwenden kein Bluetooth-Gerät? Dann bleibt der Bluetooth-Dienst von Windows 7 ausgeschaltet. Windows 7 benötigt auch weniger Arbeitsspeicher als Windows Vista: eine weitere versteckte Optimierung, mit der die Gesamtleistung gesteigert werden kann.
     
    64-Bit-Unterstützung
    Wenn Sie sich kürzlich nach einem neuen PC umgesehen haben, dann ist Ihnen sicherlich aufgefallen, dass es mehr Computer mit 64-Bit-Prozessoren gibt. Und möglicherweise haben Sie sich gefragt, welche Vorteile sie bieten. Einfach ausgedrückt, kann ein 64-Bit-PC größere Datenmengen verarbeiten als ein 32-Bit-System. Da mehr RAM (4 GB und mehr) verwendet werden kann, kann ein 64-Bit-Computer schneller reagieren, wenn Sie viele Programme gleichzeitig ausführen.
     
    Welchen sollen Sie kaufen? Wenn Sie beabsichtigen, viele Programme gleichzeitig geöffnet zu haben oder häufig zwischen Programmen wechseln müssen und auch wenn Sie lediglich sicherstellen möchten, dass Ihr PC die derzeit größeren Speicher nutzen kann, dann ist ein 64-Bit-Computer die richtige Wahl für Sie. Wenn Sie hingegen höchstens zwei Programme gleichzeitig ausführen oder ältere Hardware und Software verwenden, die von einem 64-Bit-PC nicht unterstützt wird, ist ein 32-Bit-System geeignet. Egal, ob Sie sich für ein 32-Bit- oder ein 64-Bit-System entscheiden, Windows 7 ist bereit.
     
     
    Die verbesserte Windows Suche liefert Ergebnisse mit mehr Relevanz 
     
    Energieverwaltung
    Sie haben es satt, dass sich der Akku Ihres Laptops immer dann verabschiedet, wenn Sie ihn dringend benötigen? Unter Windows 7 können Sie die Akkulaufzeit verlängern. Wie? Zunächst einmal ist die Anzahl von unter Windows 7 ausgeführten Hintergrundaktivitäten viel kleiner, d. h., der PC-Prozessor ist weniger stark ausgelastet und damit die Stromaufnahme geringer.
     
    Zudem ist die DVD-Wiedergabe stromsparender (praktisch auf langen Flügen), der Bildschirm wird automatisch abgedunkelt, nicht verwendete Ports werden abgeschaltet, und die Anzeige für die Akkulaufzeit ist genauer. Es ist also unwahrscheinlicher, dass Sie plötzlich mit einem leeren Akku dastehen.
     
    Windows 7 macht neue Dinge möglich
     
    Netzwerk
    Mit Windows 7 wird es zum Kinderspiel, auf dem Laptop an jedem beliebigen Ort Netzwerke anzuzeigen und eine Verbindung mit diesen herzustellen. Klicken Sie einfach nur auf das Netzwerksymbol auf der Taskleiste. Mit ""Verfügbare Netzwerke anzeigen"" werden alle Optionen für Drahtlos- und verkabelte Netzwerke aufgerufen: WiFi, mobiles Breitband, DFÜ oder Unternehmens-VPN. Nur noch ein Klick, und schon steht die Verbindung.
     
    Windows Media Center
    Live-TV anschauen, anhalten und aufnehmen. Musik hören. Mit der Fotosammlung Eindruck schinden. Onlineunterhaltung genießen. Und das vom Sofa im Wohnzimmer aus. Wundert es da noch, dass Media Center von Kritikern als das verborgene Juwel von Windows bezeichnet wird?
     
    Unter Windows 7 wurde das Programm sogar noch erweitert: mit neuen, tollen Features (viele auf Ihre Anregung hin) und visuellen Verbesserungen. Windows Media Center ist in den Editionen Home Premium, Professional und Ultimate von Windows 7 enthalten. Zu den wichtigsten Neuerungen zählen u. a.:
     
     
    Komponenten wie Dateien oder Drucker gemeinsam im Heimnetzwerk nutzen 
     
    Fernsehen total ...
    Windows Media Center unterstützt mehr globale TV-Standards und TV-Tuner (z. B. Digitalfernsehen und HD). Zudem können Sie mit dem Programm nun mehr häufig verwendete Audio- und Videoformate wiedergeben, z. B. 3GP, AAC, AVCHD, DivX, MOV und Xvid.
     
    ... ohne langes Warten
    Haben Sie es satt, sich durch Fernsehprogramme oder eine umfangreiche Musikbibliothek zu quälen? Wechseln Sie schneller zu Titeln und Sendungen mit dem neuen Feature für schnelles Blättern.
     
    Atemberaubende neue Diashows
    Stellen Sie mit der neuen Diashowerstellung ansprechende Fotocollagen (mit Hintergrundmusik) zusammen. Die sind perfekt geeignet für Partys oder Familienfeiern. Und probieren Sie unbedingt den neuen Diashow-Bildschirmschoner aus: Dafür finden Sie keine Worte!
     
    Einfachere Medienfreigabe
    Schauen Sie sich aufgezeichnete TV-Sendungen, Musiktitel und Videos an, auch wenn diese nicht auf Ihrem PC gespeichert sind. Mit dem neuen Feature Heimnetzgruppe stehen Medien auf jedem PC unter Windows 7 im gesamten Haus zur Verfügung.
     
    Neue Minianwendungen, größere Vorschau
    Es gibt eine neue Media Center-Minianwendung. Videos im Schnelldurchlauf anschauen. Mehr Titel- und Sendungsdetails. Größere, besser erkennbare Vorschauminiaturansichten. Und das sind noch längst nicht alle Verbesserungen.
     
     
    Windows BitLocker verschlüsselt komplette Laufwerke 
     
    Windows Touch
    Es hat sich ""ausgemaust"": Mit Windows 7 und einem Kontaktbildschirm können Sie einfach nur mit Ihren Fingern die Onlineausgabe der Tageszeitung durchsehen, die Seiten in einem Fotoalbum durchblättern und Dateien und Ordner zufällig anordnen.
     
    Eine eingeschränkte Touchtechnologie ist bereits seit Jahren unter Windows verfügbar. Aber unter Windows 7 erobert sie jede Ecke Ihres PC. Das Startmenü und die Taskleiste weisen nun größere, fingerfreundliche Symbole auf. Auch die vertrauten Windows 7-Programme unterstützen die Fingereingabe. In Paint können Sie jetzt sogar mit dem Finger malen!
     
    Windows Touch, nur in den Editionen Home Premium, Professional und Ultimate von Windows 7 enthalten, erkennt auch Mehrfingerbewegungen (geeigneten Monitor vorausgesetzt). Sie möchten ein Bild vergrößern? Bewegen Sie Ihre Finger aufeinander zu. Sie möchten einen Rechtsklick ausführen? Berühren Sie das entsprechende Element mit einem Finger, und tippen Sie mit einem anderen Finger auf den Bildschirm.
     
    Zusätzliche Profi-Funktionen
     
    Windows XP-Modus
    Besser geht's nicht: Mit dem neuen Windows XP-Modus können Sie ältere Windows XP-Geschäftsprogramme direkt auf dem Windows 7-Desktop ausführen. Das Feature, das in erster Linie für kleine und mittelständische Unternehmen entwickelt wurde, steht als separater Download zur Verfügung und kann nur in Verbindung mit Windows 7 Professional und Ultimate eingesetzt werden. Der Windows XP-Modus setzt zudem auch eine Virtualisierungssoftware wie Windows Virtual PC voraus. Beides kann kostenlos von der Microsoft-Website heruntergeladen werden.
     
    Domänenbeitritt
    Nutzen Sie Ihren PC im Büro, oder planen Sie, ihn für die Heimarbeit zu verwenden? Dann müssen Sie ihn ggf. mit einer Domäne verbinden. Eine Domäne ist eine Art Computernetzwerk, das häufig am Arbeitsplatz vorgefunden wird. (Technisch gesehen, handelt es sich um eine Gruppe von Computern, die zentral verwaltet und unter Einhaltung allgemeiner Regeln betrieben wird.)
     
    Windows 7 Professional und Ultimate ermöglichen einen schnellen und sicheren Domänenbeitritt. Führen Sie einfach den benutzerfreundlichen Assistenten aus, und geben Sie Ihre Anmeldeinformationen für das Netzwerk ein. Einen kurzen Moment später sind Sie schon drin.
     
    BitLocker-Laufwerkverschlüsselung
    Wie können Sie zum Schutz Ihrer Daten vor Datenverlust, Diebstahl oder Hackern beitragen? Die Antwort lautet: BitLocker. Das für Windows 7 verbesserte und in der Ultimate Edition verfügbare BitLocker-Feature hilft Ihnen, alles zu schützen, von Dokumenten bis hin zu Kennwörtern, indem das gesamte Laufwerk, auf dem sich Windows und Ihre Daten befinden, verschlüsselt wird. Sobald BitLocker aktiviert ist, wird jede auf dem Laufwerk gespeicherte Datei automatisch verschlüsselt. BitLocker To Go, ein neues Feature von Windows 7, ermöglicht die Sperrung von leicht verlegten tragbaren Speichergeräten wie USB-Flashlaufwerken und externen Festplatten.
     
    Features:
     

    Inklusive 32- und 64-Bit-Version
    Handbuch: mit Installationsanleitung, Schnelleinstieg und Erklärung der wichtigsten Neuerungen von Windows 7.
    Installationssupport: telefonischer Support ist enthalten.
    Schneller und einfacher zu bedienen
    Verbesserte Taskleiste und Vollbild-Vorschaufenster
    Sprunglisten für schnellen Zugriff auf die Programme und Dateien
    Verbesserter Desktop vereinfacht das Arbeiten mit Fenstern
    Verbesserte Windows Suche
    Bessere Geräteverwaltung
    Automatisches Einrichten von Heimnetzgruppen
    Verbesserte Energieverwaltung
    Höchste Kompatibilität
    Windows Media Center mit optimierter Benutzeroberfläche
    Im ganzen Haus auf Musik, Fotos und Videos zugreifen
    Immer auf dem neuesten Stand mit Windows Live
    Windows Touch für berührungsempfindliche Bildschirme
    Location Aware Printing
    Domänenunterstützung und Gruppenrichtlinien
    Remote Desktop Host
    Erweiterte Datensicherung (Netzwerk und Gruppenrichtlinien)
    Windows XP Mode
    Verschlüsselndes Dateisystem (EFS)
    BitLocker & BitLocker To Go
    AppLocker
    DirectAccess
    BranchCache
    Mehrsprachige Bedienerführung (MUI)
     
    ";2;False;0;;;Windows 7 32 Bit;windows-7-32-bit;True;True;P-2980;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;74.9000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;40889,6296990741;"30;80";3;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000393-windows-7-32-bit.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000394-windows-7-32-bit.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000395-windows-7-32-bit.jpg;1;;False;;;;;False;False;False;;;;;False;;;;;; -5;0;True;Windows 7 64 Bit;Windows 7 64 Bit;"
    Windows 7  
     
    Die umfassendste Edition von Windows 7
    Windows 7 Ultimate ist die vielseitigste und leistungsfähigste Edition von Windows 7. Sie kombiniert die bemerkenswerte Benutzerfreundlichkeit der Unterhaltungsfunktionen von Home Premium mit den unternehmensorientierten Funktionen von Professional, wozu auch die Fähigkeit zum Ausführen zahlreicher Windows XP-Produktivitätsprogramme im Windows XP-Modus gehört.
     
    Für mehr Sicherheit können Sie Ihre Daten auch mit BitLocker und Bitlocker To Go verschlüsseln. Und zur Erhöhung der Flexibilität können Sie in einer beliebigen von 35 Sprachen arbeiten. Mit Windows 7 Ultimate müssen Sie auf nichts verzichten.
     
    Windows 7 vereinfacht alltägliche Aufgaben
     
    Desktop
    Unter Windows 7 ist es nun einfacher, noch mehr Aufgaben direkt auf dem Desktop zu erledigen: Verbesserte Taskleistenvorschau, größere Symbole, Anheften und kreative Möglichkeiten der Personalisierung.
     
    Neue Möglichkeiten, mit Fenstern zu jonglieren
    Überwältigt von der Zahl der geöffneten Fenster? Windows 7 bietet drei einfache und dennoch leistungsfähige neue Funktionen, die wie folgt bezeichnet werden: Aero Shake, Aero Peek und Snap. Sie unterstützen Sie dabei, sofort den Weg durch den Desktop zu finden.
     
     
    Die verschiedenen Windows 7 Editionen im Vergleich 
     
    Spektakuläre neue Hintergrundbilder
    Seien wir ehrlich: Wir verbringen jede Menge Zeit damit, auf unsere PCs zu starren. Die Ästhetik sollte daher nicht zu kurz kommen. Darum enthält Windows 7 viele neue Desktophintergründe, so genannte Hintergrundbilder, unter denen sich alle möglichen Motive von beeindruckend bis unterhaltsam befinden. Oder probieren Sie doch einmal die neue Desktopdiashow aus, in der eine wiederkehrende Reihe von Bildern (unserer oder Ihrer) angezeigt wird. Desktop und langweilig? Das ist vorbei.
     
    Schauen Sie sich die "Superleiste" an
    Schon unter Windows 95 hat die Taskleiste als Ausgangspunkt zum Starten von Programmen und Umschalten zwischen Fenstern gedient. Nicht nur die Zeiten, auch die Arbeitsweisen am PC haben sich geändert. Unter Windows 7 wurde die Taskleiste daher komplett neu gestaltet, damit Sie noch mehr Aufgaben erledigen können. Sie ist ansprechender, kann besser angepasst werden und vereinfacht das Multitasking.
     
    Heimnetzgruppe
    Dank der Heimnetzgruppe brauchen Sie sich keine Gedanken mehr über die Datei- und Druckerfreigabe in einem Heimnetzwerk zu machen. Verbinden Sie mindestens zwei Windows 7-PCs, und schon kann mit der Heimnetzgruppe ganz einfach die automatische Freigabe von Musik, Bildern, Videos und Dokumentbibliotheken für andere Personen im Haus starten. Und das neue Menü "Freigeben für" ermöglicht die schnelle Freigabe einzelner Dateien.
     
    Machen Sie sich Sorgen um den Datenschutz? Wir auch. Und deshalb ist die Heimnetzgruppe kennwortgeschützt, sodass Sie die volle Kontrolle über den Zugriff haben. Sie entscheiden, welche Dateien freigegeben werden und welche nicht. Außerdem können Sie Ihre Dateien mit Schreibschutz versehen, d. h., der Inhalt kann von anderen angesehen, aber nicht geändert werden. Einer Heimnetzgruppe beizutreten, ist in jeder Edition von Windows 7 möglich. Das Erstellen einer Heimnetzgruppe ist jedoch nur in den Editionen Home Premium, Professional und Ultimate möglich.
     
     
    Die verbesserte Taskleiste verschafft mit Hilfe der neuen Vollbild-Vorschaufenster schnellen Überblick 
     
    Sprunglisten
    Über die in Windows 7 neu eingeführten Sprunglisten gelangen Sie nun direkt zu den Dokumenten, Bildern, Songs oder Websites, die Sie tagtäglich nutzen. Zum Öffnen einer Sprungliste klicken Sie auf der Taskleiste von Windows 7 einfach mit der rechten Maustaste auf ein Programm (Sie sind auch im Startmenü zu finden.).
     
    Der Inhalt einer Sprungliste hängt vom Programm ab. In der Sprungliste für Internet Explorer 8 werden häufig besuchte Websites angezeigt. Windows Media Player 12 enthält häufig abgespielte Musiktitel. Fehlt in der Sprungliste ein Favorit? Sie können dort beliebige Dateien "anheften". In Sprunglisten werden nicht nur Verknüpfungen zu Dateien angezeigt. Manchmal bieten sie auch Schnellzugriff auf Befehle für Aufgaben wie das Verfassen neuer E-Mail-Nachrichten oder das Wiedergeben von Musik.
     
    Snap
    Snap bietet eine schnelle neue Möglichkeit, die Größe geöffneter Fenster einfach durch Ziehen an die Bildschirmränder zu ändern. Je nach Rand, also, oben oder unten, rechts oder links, wird das Fenster verbreitert, oder es füllt den ganzen Bildschirm aus. Und Sie können Fenster auch nebeneinander anordnen. Mit Snap wird das Lesen, das Anordnen und das Vergleichen von Fenstern zum Kinderspiel.
     
     
    Den Desktop jederzeit im Blick dank transparenter Fenster 
     
    Windows Live Essentials
    Was ist Windows Live Essentials? Einfach ausgedrückt, handelt es sich um kostenlose Software, die einen Windows 7-PC mit noch mehr tollen Funktionen ausstattet, z. B. für E-Mail, Instant Messaging, Fotobearbeitung und Blogs. Windows Live Windows Live Essentials ist auf der Windows Live-Website verfügbar. Der kostenlose Download enthält folgende Komponenten: Messenger, Fotogalerie, Mail, Writer, Movie Maker, Symbolleiste und Family Safety.
     
    Windows Search
    Unter Windows 7 finden Sie noch schneller noch mehr Dinge an noch mehr Orten. Sobald Sie im Suchfeld des Startmenüs mit der Eingabe beginnen, wird eine Liste relevanter Dokumente, Bilder, Musiktitel und E-Mails auf dem PC angezeigt. Die Ergebnisse sind nun nach Kategorie gruppiert und enthalten hervorgehobene Stichwörter und Textausschnitte, um die Suche zu vereinfachen.
     
    Dateien werden heutzutage nur noch selten an einem Ort abgelegt. Also ist Windows 7 auch darauf ausgelegt, externe Festplatten, Netzwerk-PCs und Bibliotheken zu durchsuchen. Zu viele Suchergebnisse? Sie können die Suche direkt nach Datum, Dateityp und anderen hilfreichen Kategorien eingrenzen.
     
    Windows 7 funktioniert Ihren Vorstellungen entsprechend
     
    Leistungsverbesserungen
    Niemand wartet gerne. Darum ist Windows 7 nun noch schneller und immer bereit, wenn Sie es sind. Zu den wichtigen Leistungsverbesserungen zählen u. a. schneller Wechsel in und aus dem Energiesparmodus, weniger Speicherbedarf und schnelle Erkennung von USB-Geräten:
     
    Standbymodus
    Windows 7 kann in den Energiesparmodus versetzt und wiederhergestellt werden und die Verbindung mit dem Drahtlosnetzwerk wieder schneller herstellen.
     
     
    Sprunglisten ermöglichen schnellen Zugriff auf häufig anstehende Aufgaben 
     
    Suchen
    Wenn Sie auf der Suche nach Informationen sind, dann möchten Sie nicht lange warten, sondern Antworten bekommen. Unter Windows 7 werden Suchergebnisse schneller angezeigt. Auch das Sortieren und Gruppieren von Suchergebnissen geht viel rascher vonstatten.
     
    USB-Geräte
    Wenn Sie zum ersten Mal ein tragbares Flashlaufwerk oder ein anderes USB-Gerät anschließen, stellt Windows 7 es innerhalb weniger Sekunden für Sie bereit. Und wenn Sie es bereits zuvor verwendet haben, dann geht es sogar noch schneller.
     
    Rationaler und geringere Auslastung
    Anders als seine Vorgänger ist Windows 7 darauf ausgelegt, verlangsamende Hintergrunddienste nur dann auszuführen, wenn Sie sie benötigen. Sie verwenden kein Bluetooth-Gerät? Dann bleibt der Bluetooth-Dienst von Windows 7 ausgeschaltet. Windows 7 benötigt auch weniger Arbeitsspeicher als Windows Vista: eine weitere versteckte Optimierung, mit der die Gesamtleistung gesteigert werden kann.
     
    64-Bit-Unterstützung
    Wenn Sie sich kürzlich nach einem neuen PC umgesehen haben, dann ist Ihnen sicherlich aufgefallen, dass es mehr Computer mit 64-Bit-Prozessoren gibt. Und möglicherweise haben Sie sich gefragt, welche Vorteile sie bieten. Einfach ausgedrückt, kann ein 64-Bit-PC größere Datenmengen verarbeiten als ein 32-Bit-System. Da mehr RAM (4 GB und mehr) verwendet werden kann, kann ein 64-Bit-Computer schneller reagieren, wenn Sie viele Programme gleichzeitig ausführen.
     
    Welchen sollen Sie kaufen? Wenn Sie beabsichtigen, viele Programme gleichzeitig geöffnet zu haben oder häufig zwischen Programmen wechseln müssen und auch wenn Sie lediglich sicherstellen möchten, dass Ihr PC die derzeit größeren Speicher nutzen kann, dann ist ein 64-Bit-Computer die richtige Wahl für Sie. Wenn Sie hingegen höchstens zwei Programme gleichzeitig ausführen oder ältere Hardware und Software verwenden, die von einem 64-Bit-PC nicht unterstützt wird, ist ein 32-Bit-System geeignet. Egal, ob Sie sich für ein 32-Bit- oder ein 64-Bit-System entscheiden, Windows 7 ist bereit.
     
     
    Die verbesserte Windows Suche liefert Ergebnisse mit mehr Relevanz 
     
    Energieverwaltung
    Sie haben es satt, dass sich der Akku Ihres Laptops immer dann verabschiedet, wenn Sie ihn dringend benötigen? Unter Windows 7 können Sie die Akkulaufzeit verlängern. Wie? Zunächst einmal ist die Anzahl von unter Windows 7 ausgeführten Hintergrundaktivitäten viel kleiner, d. h., der PC-Prozessor ist weniger stark ausgelastet und damit die Stromaufnahme geringer.
     
    Zudem ist die DVD-Wiedergabe stromsparender (praktisch auf langen Flügen), der Bildschirm wird automatisch abgedunkelt, nicht verwendete Ports werden abgeschaltet, und die Anzeige für die Akkulaufzeit ist genauer. Es ist also unwahrscheinlicher, dass Sie plötzlich mit einem leeren Akku dastehen.
     
    Windows 7 macht neue Dinge möglich
     
    Netzwerk
    Mit Windows 7 wird es zum Kinderspiel, auf dem Laptop an jedem beliebigen Ort Netzwerke anzuzeigen und eine Verbindung mit diesen herzustellen. Klicken Sie einfach nur auf das Netzwerksymbol auf der Taskleiste. Mit "Verfügbare Netzwerke anzeigen" werden alle Optionen für Drahtlos- und verkabelte Netzwerke aufgerufen: WiFi, mobiles Breitband, DFÜ oder Unternehmens-VPN. Nur noch ein Klick, und schon steht die Verbindung.
     
    Windows Media Center
    Live-TV anschauen, anhalten und aufnehmen. Musik hören. Mit der Fotosammlung Eindruck schinden. Onlineunterhaltung genießen. Und das vom Sofa im Wohnzimmer aus. Wundert es da noch, dass Media Center von Kritikern als das verborgene Juwel von Windows bezeichnet wird?
     
    Unter Windows 7 wurde das Programm sogar noch erweitert: mit neuen, tollen Features (viele auf Ihre Anregung hin) und visuellen Verbesserungen. Windows Media Center ist in den Editionen Home Premium, Professional und Ultimate von Windows 7 enthalten. Zu den wichtigsten Neuerungen zählen u. a.:
     
     
    Komponenten wie Dateien oder Drucker gemeinsam im Heimnetzwerk nutzen 
     
    Fernsehen total ...
    Windows Media Center unterstützt mehr globale TV-Standards und TV-Tuner (z. B. Digitalfernsehen und HD). Zudem können Sie mit dem Programm nun mehr häufig verwendete Audio- und Videoformate wiedergeben, z. B. 3GP, AAC, AVCHD, DivX, MOV und Xvid.
     
    ... ohne langes Warten
    Haben Sie es satt, sich durch Fernsehprogramme oder eine umfangreiche Musikbibliothek zu quälen? Wechseln Sie schneller zu Titeln und Sendungen mit dem neuen Feature für schnelles Blättern.
     
    Atemberaubende neue Diashows
    Stellen Sie mit der neuen Diashowerstellung ansprechende Fotocollagen (mit Hintergrundmusik) zusammen. Die sind perfekt geeignet für Partys oder Familienfeiern. Und probieren Sie unbedingt den neuen Diashow-Bildschirmschoner aus: Dafür finden Sie keine Worte!
     
    Einfachere Medienfreigabe
    Schauen Sie sich aufgezeichnete TV-Sendungen, Musiktitel und Videos an, auch wenn diese nicht auf Ihrem PC gespeichert sind. Mit dem neuen Feature Heimnetzgruppe stehen Medien auf jedem PC unter Windows 7 im gesamten Haus zur Verfügung.
     
    Neue Minianwendungen, größere Vorschau
    Es gibt eine neue Media Center-Minianwendung. Videos im Schnelldurchlauf anschauen. Mehr Titel- und Sendungsdetails. Größere, besser erkennbare Vorschauminiaturansichten. Und das sind noch längst nicht alle Verbesserungen.
     
     
    Windows BitLocker verschlüsselt komplette Laufwerke 
     
    Windows Touch
    Es hat sich "ausgemaust": Mit Windows 7 und einem Kontaktbildschirm können Sie einfach nur mit Ihren Fingern die Onlineausgabe der Tageszeitung durchsehen, die Seiten in einem Fotoalbum durchblättern und Dateien und Ordner zufällig anordnen.
     
    Eine eingeschränkte Touchtechnologie ist bereits seit Jahren unter Windows verfügbar. Aber unter Windows 7 erobert sie jede Ecke Ihres PC. Das Startmenü und die Taskleiste weisen nun größere, fingerfreundliche Symbole auf. Auch die vertrauten Windows 7-Programme unterstützen die Fingereingabe. In Paint können Sie jetzt sogar mit dem Finger malen!
     
    Windows Touch, nur in den Editionen Home Premium, Professional und Ultimate von Windows 7 enthalten, erkennt auch Mehrfingerbewegungen (geeigneten Monitor vorausgesetzt). Sie möchten ein Bild vergrößern? Bewegen Sie Ihre Finger aufeinander zu. Sie möchten einen Rechtsklick ausführen? Berühren Sie das entsprechende Element mit einem Finger, und tippen Sie mit einem anderen Finger auf den Bildschirm.
     
    Zusätzliche Profi-Funktionen
     
    Windows XP-Modus
    Besser geht's nicht: Mit dem neuen Windows XP-Modus können Sie ältere Windows XP-Geschäftsprogramme direkt auf dem Windows 7-Desktop ausführen. Das Feature, das in erster Linie für kleine und mittelständische Unternehmen entwickelt wurde, steht als separater Download zur Verfügung und kann nur in Verbindung mit Windows 7 Professional und Ultimate eingesetzt werden. Der Windows XP-Modus setzt zudem auch eine Virtualisierungssoftware wie Windows Virtual PC voraus. Beides kann kostenlos von der Microsoft-Website heruntergeladen werden.
     
    Domänenbeitritt
    Nutzen Sie Ihren PC im Büro, oder planen Sie, ihn für die Heimarbeit zu verwenden? Dann müssen Sie ihn ggf. mit einer Domäne verbinden. Eine Domäne ist eine Art Computernetzwerk, das häufig am Arbeitsplatz vorgefunden wird. (Technisch gesehen, handelt es sich um eine Gruppe von Computern, die zentral verwaltet und unter Einhaltung allgemeiner Regeln betrieben wird.)
     
    Windows 7 Professional und Ultimate ermöglichen einen schnellen und sicheren Domänenbeitritt. Führen Sie einfach den benutzerfreundlichen Assistenten aus, und geben Sie Ihre Anmeldeinformationen für das Netzwerk ein. Einen kurzen Moment später sind Sie schon drin.
     
    BitLocker-Laufwerkverschlüsselung
    Wie können Sie zum Schutz Ihrer Daten vor Datenverlust, Diebstahl oder Hackern beitragen? Die Antwort lautet: BitLocker. Das für Windows 7 verbesserte und in der Ultimate Edition verfügbare BitLocker-Feature hilft Ihnen, alles zu schützen, von Dokumenten bis hin zu Kennwörtern, indem das gesamte Laufwerk, auf dem sich Windows und Ihre Daten befinden, verschlüsselt wird. Sobald BitLocker aktiviert ist, wird jede auf dem Laufwerk gespeicherte Datei automatisch verschlüsselt. BitLocker To Go, ein neues Feature von Windows 7, ermöglicht die Sperrung von leicht verlegten tragbaren Speichergeräten wie USB-Flashlaufwerken und externen Festplatten.
     
    Features:
     

    Inklusive 32- und 64-Bit-Version
    Handbuch: mit Installationsanleitung, Schnelleinstieg und Erklärung der wichtigsten Neuerungen von Windows 7.
    Installationssupport: telefonischer Support ist enthalten.
    Schneller und einfacher zu bedienen
    Verbesserte Taskleiste und Vollbild-Vorschaufenster
    Sprunglisten für schnellen Zugriff auf die Programme und Dateien
    Verbesserter Desktop vereinfacht das Arbeiten mit Fenstern
    Verbesserte Windows Suche
    Bessere Geräteverwaltung
    Automatisches Einrichten von Heimnetzgruppen
    Verbesserte Energieverwaltung
    Höchste Kompatibilität
    Windows Media Center mit optimierter Benutzeroberfläche
    Im ganzen Haus auf Musik, Fotos und Videos zugreifen
    Immer auf dem neuesten Stand mit Windows Live
    Windows Touch für berührungsempfindliche Bildschirme
    Location Aware Printing
    Domänenunterstützung und Gruppenrichtlinien
    Remote Desktop Host
    Erweiterte Datensicherung (Netzwerk und Gruppenrichtlinien)
    Windows XP Mode
    Verschlüsselndes Dateisystem (EFS)
    BitLocker & BitLocker To Go
    AppLocker
    DirectAccess
    BranchCache
    Mehrsprachige Bedienerführung (MUI)
    ";2;False;0;;;Windows 7 64 Bit;windows-7-64-bit;True;True;P-2990;;;False;0;False;;False;False;0;False;0;1;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;59.9000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;40889,6295138889;"30;80";3;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000393-windows-7-32-bit.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000397-windows-7-32-bit.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000396-windows-7-32-bit.jpg;2;;False;ounce;;;;False;False;False;;;;;False;;;;;; -5;0;True;Toshiba Satellite L775-11K 43,9 cm (17,3 Zoll) Notebook;4 GB, 18 Zoll, 300 GB, Intel, 2;"
    Der Satellite L775 bietet Ihnen die perfekte Mischung aus schickem Design und starker Leistung. Hier bekommen Sie nicht nur eine umfangreiche Ausstattung, sondern auch echte High-Definition-Performance. Intel®-Prozessoren der zweiten Generation sorgen für zügiges Arbeiten in all Ihren Anwendungen. Das 43,9 cm (17,3"") TruBrite® HD+ Display mit LED-Hintergrundbeleuchtung liefert in Kombination mit der NVIDIA® ein umwerfendes Bild. Dolby® AdvancedAudio-Technologie und integrierte Onkyo®-Lautsprecher mit guter Klangqualität runden die Multimedia-Ausstattung ab. Dazu noch ein Multitouch-Touchpad, 2und ein attraktives Matrix-Design in der Farbvariante Zinkgrau – bei diesem Notebook bleiben wirklich keine Wünsche offen.
     
    Attraktives Design
    Modernes Hochglanzgehäuse mit Matrix-Finish in Zinkgrau.
     
    Beste Bildqualität
    Das riesige 43,9 cm (17,3"") TruBrite® HD+ Display mit LED-Hintergrundbeleuchtung bietet beste High-Definition-Qualität. Eine hoch auflösende Bildwiedergabe wird dadurch selbst bei DVDs möglich.
     
    Optimaler Klang
    Integrierte Onkyo®-Lautsprecher sorgen in Kombination mit der Dolby® Advanced Audio-Technologie für einen vollen Sound.
     
    Ultra schnell
    USB 3.0-Technologie ermöglicht für ihre Multimedia-Dateien einen schnelleren Datentransfers als je zuvor.
     
    ""USB Sleep-and-Charge""-Funktion
    Sie können Ihr Handy oder MP3 Player aufladen – und zwar selbst, wenn das Notebook ausgeschaltet ist.
     
    Bedienerfreundlich
    Touchpad mit Multitouch Gestensteuerung, Touch Pad an/aus Taste, Multi-Kartenleser und Tastatur mit 10er Nummernblock.
     
    Entertainment
    Kinoerlebnis auf einem externen Fernseher genießen über RGB (VGA) Anschluss oder in High Definition Qualität mit HDMI Anschluss.
     
    Umweltfreundlich
    Eco Stromsparfunktion, ENERGY STAR 5.0 qualifiziert und ein energieeffizientes Display mit LED Hintergrundbeleuchtung. 
    ";2;False;0;;;Toshiba Satellite L775-11K 43,9 cm (17,3 Zoll) Notebook;toshiba-satellite-l775-11k-439-cm-173-zoll-notebook;True;True;P-0840;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;539.9000;539.9000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;40889,5852777778;5;40;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000590-toshiba-satellite-l775-11k-439-cm-173-zoll-notebook.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000591-toshiba-satellite-l775-11k-439-cm-173-zoll-notebook.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000592-toshiba-satellite-l775-11k-439-cm-173-zoll-notebook.jpg;2;;False;;;;;False;False;False;;;;;False;;;;;; -5;0;True;"Logitech HD Webcam C615 ";"Logitech HD Webcam C615 ";"
    Logitech HD Webcam C615
    Mit dieser flexibel zusammenklappbaren Webcam führen Sie HD-Videogespräche in 720p und laden Full HD-Videos in 1080p mit nur einem Klick auf Facebook hoch. Inhalte, Ort und Setup wählen Sie.
     
    Full HD-Videoaufnahmen in 1080p und HD-Videogespräche in 720p
    Zeichnen Sie Ihr Videos in Full HD 1080p und im atemberaubenden Breitbildformat auf. Sie können Videogespräche in 720p mit den meisten Instant Messengern und Logitech Vid™ HD führen.* Dank des eingebauten Autofokus bleiben Ihre Bilder selbst bei Nahaufnahmen (ab einer Entfernung von 10 cm vom Objektiv) gestochen scharf. Machen Sie hochauflösende Schnappschüsse mit bis zu 8 Megapixeln (Software-interpoliert).
     

    1-Klick-Upload auf Facebook
    Mit nur einem Klick können Sie Full HD-Videoaufnahmen in 1080p-Auflösung erfassen und auf Facebook, Twitter™ oder YouTube® hochladen.
     

    Flexibles, tragbares Design
    Dank des zusammenklappbaren Designs und des kurzen USB-Kabels ist die Webcam leicht zu transportieren. Das USB-Verlängerungskabel bietet Ihnen bei Bedarf zusätzlichen Spielraum.
     
    Drehbares Design mit Stativhalterung
    Wenn Sie die Webcam an einem Stativ befestigen, haben Sie noch mehr Stellmöglichkeiten. Dank der 360-Grad-Schwenkfunktion sind Gespräche und Aufnahmen aus jedem Winkel möglich. Das Stativ selbst ist nicht im Lieferumfang enthalten.
     
    Kompatibel mit Windows und Mac
    Windows? Mac? iChat®? Skype™? Google Voice™ und Chat? Ganz egal. Ihre Webcam funktioniert mit allen. Für die Bearbeitung Ihrer Fotos ist sie außerdem mit iPhoto®, iMovie® und sogar mit Photo Booth® kompatibel.
     

    Beinhaltet Logitech Vid™ HD
    Jetzt sind HD-Videogespräche kostenlos, schnell und einfach. Die Software wird bei der Einrichtung Ihrer Webcam mitinstalliert. Und Sie können sogar Videonachrichten für Freunde und Familie hinterlassen, wenn diese Ihren Anruf nicht entgegennehmen können.
     
    Kostenlose Videobearbeitungssoftware
    Logitech und MAGIX machen Ihnen ein besonderes Angebot: Sie erhalten jetzt mit Ihrer neuen Logitech-Webcam auch gleich MAGIX™ Photo Manager 9 und MAGIX™ Video Easy. Und zwar kostenlos.****
     
    Anmeldung über Gesichtserkennung
    Melden Sie sich bei Ihrem Computer und auf Ihren Lieblings-Internetseiten mit der eingebauten Gesichtserkennungssoftware an. Damit sparen Sie Zeit und imponieren Ihren Freunden.*****
     

    * Für Mac® sind HD-Videogespräche mit Logitech Vid™ HD verfügbar. Für HD-Videogespräche mit anderer Software überprüfen Sie bitte die Verfügbarkeit.
    ** Nicht für Mac verfügbar.
    *** Nur für Windows-Computer. Intel® Pentium® 4 (2,8 GHz) empfohlen.
    **** E-Mail-Registrierung erforderlich. Es gelten zusätzliche Bestimmungen. Nur für Windows-Computer.
    ***** 60-Tage-Probeangebot. Es gelten zusätzliche Bestimmungen. Nicht für Mac verfügbar.
    ";2;False;0;;;"Logitech HD Webcam C615 ";logitech-hd-webcam-c615;True;True;P-2910;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;89.9000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;40889,4833449074;27;11;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000240-logitech-hd-webcam-c615.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000241-logitech-hd-webcam-c615.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000242-logitech-hd-webcam-c615.jpg;2;;False;;;;;False;False;False;;;;;False;;;;;; -5;0;True;"Microsoft Wired LifeCam VX-3000 ";"Microsoft Wired LifeCam VX-3000 ";"
    LifeCam VX-3000
     
    Die LifeCam VX-3000 begeistert mit leichter Installation und nahtloser Integration in den Windows Live-Messenger. Die kompakte Webcam bietet Top-Bildqualität, kombiniert mit innovativen Features wie der praktischen Windows Live Call-Taste und dem multifunktionalem Standfuß, der sich mit einem Handgriff in eine Halterung für Flachbildschirme verwandeln lässt. Dank integriertem Mikrofon muss kein externes Mikrofon für unterhaltsame Video-Gespräche angeschlossen werden.
     
      Hochauflösende Fotos
    Mit hochauflösenden Fotos (1,3 Megapixel interpoliert) zeigen Sie sich von Ihrer besten Seite.
     
    Integriertes Mikrofon
    Das integrierte Mikrofon erfasst Ihre Stimme automatisch und mit außergewöhnlicher Klarheit.
     
    Windows Live Call-Taste
    Um einen Videoanruf zu starten, drücken Sie einfach diese Taste, und wählen Sie dann einen Onlinekontakt aus.
     
    Software für automatisches Face-Tracking*
    Sie können sich bewegen, ohne vom Bildschirm zu verschwinden. Dank modernster Software bleibt Ihr Gesicht stets im Bildmittelpunkt.
     
     
    Universalhalterung
    Die LifeCam lässt sich problemlos an jedem Monitor befestigen.
     
    Kipp-, Dreh- und Zoomfunktion
    Die Kamera kann sowohl horizontal als auch vertikal geschwenkt werden und bietet somit ein Höchstmaß an Flexibilität.
     
    Flexibles 1,8 m langes Kabel
    Das lange, flexible Kabel gibt Ihnen genügend Bewegungsfreiheit.
     
    Videoeffekte
    Überraschen Sie Ihre Freunde mit coolen Videoeffekten, auf die Sie direkt aus dem Windows Live Messenger-Fenster zugreifen können.
     
    Bis zu 30 Bilder pro Sekunde
    Die Aufnahmen mit LifeCams erfolgen mit 30 Bildern pro Sekunde, wodurch die Videobilder flüssig und ohne Ruckeln angezeigt werden
     
     
     
     
     
    ";2;False;0;;;"Microsoft Wired LifeCam VX-3000 ";microsoft-wired-lifecam-vx-3000;True;True;P-2900;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;29.9000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;40889,480775463;27;3;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000237-microsoft-wired-lifecam-vx-3000.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000238-microsoft-wired-lifecam-vx-3000.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000239-microsoft-wired-lifecam-vx-3000.jpg;2;;False;;;;;False;False;False;;;;;False;;;;;; -5;0;True;SanDisk Secure Dügital Speicherkarte;"SanDisk Secure Digital (SD) Speicherkarte ";"
    SanDisk Secure Digital (SD) Speicherkarte 
    SecureDigital High Capacity Card (SDHC), entspricht neuem SD-2.0-Standard, Klasse 4
    nur geeignet für Endgeräte mit SDHC-Steckplatz (nicht rückwärtskompatibel zu Standard-SD-Cards)
    Schutz gegen unbeabsichtigtes Überschreiben der Daten
    beliebig oft beschreib- und löschbar
    original SanDisk Markenware, Erstausrüsterqualität
    ";2;False;0;;;SanDisk Secure Digital Speicherkarte;sandisk-secure-duegital-speicherkarte;True;True;P-2890;;;False;0;False;;False;False;0;False;0;1;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;1;9589;False;False;0;1;1;0;False;1;10000;;False;False;False;False;9.8000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;40889,4440046296;25;;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000125-sandisk-secure-dugital-speicherkarte.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000126-sandisk-secure-dugital-speicherkarte.jpg;;1;;False;ounce;;;;False;False;False;;;;;False;;;;;; -5;0;True;"Samsung SE-S084D externer DVD Brenner (DVD±RW (±R DL) weiß ";"Samsung SE-S084D externer DVD Brenner (DVD±RW (±R DL) weiß ";"
    Samsung SE-S084D – Exklusiver mobiler Brenner mit AV-Funktion.
    Der mobile Brenner SE-S084D überzeugt durch Innovation, Funktion und Design. Er setzt neue Maßstäbe und hebt sich in seiner Verarbeitung und den Einsatzmöglichkeiten deutlich von aktuellen Modellen ab.Das hochwertige Finish mit Soft-Touch-Taste und trendiger metallischer Linie machen den schlanken Brenner von Samsung optisch zu einem Highlight. Die Qualität des Produktes gewährt hohe Mobilität und vermittelt allein durch die robuste Haptik Zuverlässigkeit.
     
    Angeschlossen wird der Slim-Brenner SE-S084D via HiSpeed-USB. Ein zusätzliches Netzteil ist nicht notwendig, denn der Multiformatbrenner erreicht seine maximale Brenn- und Lesegeschwindigkeit über die Stromversorgung via USB BUS Power. Der 8fach Brenner ist kompatibel sowohl zu Windows als auch zu MAC Betriebssystemen; diese Kompatibilität wurde auch von beiden Partnern offiziell bestätigt. Somit ist seine grundsätzliche Funktion des Brennens und Lesen von Medien aller Art bestens sichergestellt.
     
    Durch die leichte und kompakte Bauweise mit nur 270 Gramm ist er die perfekte Begleitung für Netbook, Notebook oder All-In-One PC.
     
    Als zusätzliches Feature hat Samsung die AV-Funktion entwickelt. Unterstützt Ihr Fernseher die Wiedergabe via USB-Port. so lässt sich der SE-S084D an diese neue TV-Generation mit PVR Funktion anschließen und zum Abspielen JPEG, MP3 und AVI-Dateien nutzen. Der SE-S084D kann also auch als Player eingesetzt.
     
    Dieses neue Produktkonzept wurde auch mit dem IF Design Award 2010 honoriert.
    ";2;False;0;;;"Samsung SE-S084D externer DVD Brenner (DVD±RW (±R DL) weiß ";samsung-se-s084d-externer-dvd-brenner-dvdrw-r-dl-weiss;True;True;P-2870;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;69.9000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;40889,4407638889;24;19;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000287-samsung-se-s084d-externer-dvd-brenner-dvdrw-r-dl-weis.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000288-samsung-se-s084d-externer-dvd-brenner-dvdrw-r-dl-weis.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000289-samsung-se-s084d-externer-dvd-brenner-dvdrw-r-dl-weis.jpg;2;;False;;;;;False;False;False;;;;;False;;;;;; -5;0;True;"Slim USB DVD CD Blu Ray Laufwerk Gehäuse Case extern IDE / PATA Schwarz ";"Slim USB DVD CD Blu Ray Laufwerk Gehäuse Case extern IDE / PATA Schwarz ";"
    Externes USB-Gehäuse für optische Slim Blu-Ray, DVD und CD Laufwerke sowie Brenner
     
    verwandelt Ihr internes Laufwerk in ein externes
     
    - Hochwertiges Firstcom Gehäuse in Matt-Schwarz
    - Unterstützt USB 1.1, USB 2.0 sowie USB 3.0
    - Easy to Install / Sehr leichter Einbau
    - Automatische Erkennung / Plug & Play bei Windows Me / 2000 / XP / Vista / Windows 7
    Mac ab OS 8.6 oder höher (keine Treiber Installation notwendig)
    - Stromversorgung über USB (Bus-powered / kein extra Netzteil nötig)
    - Gummifüße verhindern ein Rutschen auf der Arbeitsfläche
    - Abmessungen: 137 x 135 x 18 (L x B x H mm)
    - für Slimline Laufwerke mit ca. 12,7 mm Höhe und IDE Anschluss geeignet
     
    Lieferumfang:
    1 x externes Slim Gehäuse
    1 x USB <-> IDE Board (Schnittstelle zum Laufwerk)
    1 x USB-Kabel für die Verbindung
    1 x USB-Kabel für die Stromzufuhr
    1 x Kurzanleitung
    und diverses Einbaumaterial
     
    Farbe: Schwarz
     
    Kann auch am PC, MAC, Notebook, Sub Notebook, Netbook etc. verwendet werden.
    Anmerkung: Ein Laufwerk ist nicht eingebaut und gehört nicht zum Lieferumfang.
    ";2;False;0;;;"Slim USB DVD CD Blu Ray Laufwerk Gehäuse Case extern IDE / PATA Schwarz ";slim-usb-dvd-cd-blu-ray-laufwerk-gehaeuse-case-extern-ide-pata-schwarz;True;True;P-2840;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;24.9000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;40889,4399305556;24;;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000223-slim-usb-dvd-cd-blu-ray-laufwerk-gehause-case-extern-ide-pata-schwarz.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000224-slim-usb-dvd-cd-blu-ray-laufwerk-gehause-case-extern-ide-pata-schwarz.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000225-slim-usb-dvd-cd-blu-ray-laufwerk-gehause-case-extern-ide-pata-schwarz.jpg;2;;False;;;;;False;False;False;;;;;False;;;;;; -5;0;True;Samsung SE-406AB/RSBD extern Slim BluRay Combo Laufwerk;"Samsung SE-406AB/RSBD extern Slim BluRay Combo Laufwerk (CyberLink TrueTheater, 3D Support, USB 2.0) ";"
    Erleben Sie HD-Kinospaß mit dem externen Slim Blu-ray Combo-Laufwerk SE-406AB für Ihr Notebook oder PC.
    Mit dem neuen Samsung Blu-ray Combo-Laufwerk verbinden Sie Arbeit und Vergnügen perfekt miteinander. Klassisch können Sie mit dem portablen Laufwerk, CDs und DVDs in hoher Qualität lesen und beschreiben. Aber ebenso können Sie mit dem SE-406AB HD-Inhalte am eigenen PC abspielen oder selbst erstellte Inhalte auf DVD oder BD auch an einem Fernseher mit Smart-TV-Funktion ansehen. Der Anschluss geschieht komfortabel über USB.
     
    Mit dem schlanken Design fällt das Laufwerk kaum ins Gewicht und lässt sich leicht transportieren. Dank Anschluss über USB benötigt es kein zusätzliches Netzteil und verbraucht nur wenig Energie. Das Samsung BD Combo ist extrem leise im Betrieb und zeichnet sich durch eine hohe Kompatibilität und überzeugende Brennergebnisse aus. Die unterstützte Buffer Under Run-Technologie verhindert Pufferunterlauffehler und ermöglicht das Beschreiben von Medien mit hoher Brenngeschwindigkeit.
     
    Mit der beiliegenden Software CyberLink BluRay Disc Suite 7 lässt sich das Combo-Laufwerk bequem bedienen. Sie können mit dem Laufwerk und einem 3D-fähigen Display Ihre 2D-DVD-Filmsammlung jetzt auch in 3D erleben. Denn die Software kann 2D-Filme in plastische 3D-Bilder umwandeln. Möglich wird dies mit der CyberLink TrueTheater 3D-Software. Voraussetzung dafür ist natürlich, dass der Nutzer ein 3D-fähiges Anzeigegerät samt 3D-Brille besitzt.
     
    Durch das Feature der AV-Konnektivität lässt sich das Gerät an Fernseher mit Smart TV-Funktion anschließen. Smart TV führt Online- und Offline-Inhalte auf dem Fernseher zu einem ganzheitlichen Erlebnis zusammen. So lassen sich gestreamte Medieninhalte in den Formaten JPEG, MP3 und AVI auf dem TV Gerät mit SMART Funktion wiedergeben. Das Laufwerk wird dazu einfach an die USB-Schnittstelle des Fernsehers angeschlossen und fungiert dabei wie ein USB-Stick. Dies ermöglicht das Auslesen der Inhalte auf dem Datenträger. Durch die Verbindung per USB-Anschluss ist der schnelle Zugriff auf Videos, Musik und Fotos gewährleistet.
     
    Ein Beispiel für die Multifunktionalität des schicken Laufwerks:
    Für Oma schnell eine Foto-DVD brennen, auf dem Notebook eine neue Software aufspielen und selbstgedrehte BD-Filme bearbeiten und anschließend auf dem Fernseher ansehen? Das Samsung Blu-ray Combo-Laufwerk SE-406AB erfüllt Ihnen all diese Wünsche.
    ";2;False;0;;;LSamsung SE-406AB/RSBD extern Slim BluRay Combo Laufwerk;samsung-se-406abrsbd-extern-slim-bluray-combo-laufwerk;True;True;P-2850;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;79.9000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;40889,4370833333;24;;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000226-samsung-se-406abrsbd-extern-slim-bluray-combo-laufwerk.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000227-samsung-se-406abrsbd-extern-slim-bluray-combo-laufwerk.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000228-samsung-se-406abrsbd-extern-slim-bluray-combo-laufwerk.jpg;2;;False;;;;;False;False;False;;;;;False;;;;;; -5;0;True;Canon Pixma MP 630 Multifunktionsgerät;"Canon Pixma MP 630 Multifunktionsgerät ";"
    Canon PIXMA MP620

    Hochwertiges Multifunktionssystem mit 9.600-dpi*-Drucksystem und nur 1 Picoliter feinen Tintentröpfchen für Fotos und Dokumente in überragender Druckqualität. Erweiterte Funktionen zum Druckmedien-Handling für die Digitalfotografie, kreative Arbeiten und anspruchsvolle Privatanwender. Features
    Drucken, Kopieren und Scannen
    Brillante Fotoprints mit 9.600 x 2.400 dpi und 1 Picoliter feinen Tintentröpfchen*
    Randlose Fotos im Format 10 x 15 cm in ca. 20 Sekunden*
    5-Tintensystem
    6,2 cm großes TFT-Farbdisplay mit Easy-Scroll-Bedienrad
    Scanner mit 4.800 dpi
    Direktscan auf Speicherkarte oder USB-Stick
    CD/DVD–Druck
    Automatische Duplexfunktion
     
    Foto- und Dokumentdruck
    Das hochwertige 9.600-dpi*-Drucksystem des PIXMA MP630 mit FINE-Druckkopf für bis zu 1 Picoliter feine Tintentröpfchen liefert beeindruckende Fotoprints. Der Druck eines randlosen Fotos im Format 10 x 15 cm erfolgt in ca. 20 Sekunden*.Die 1 Picoliter feinen Tintentröpfchen der neuen farbstoffbasierten Tinten – inkl. Fotoschwarz – erzeugen kontrastreiche Prints mit sanften Farbabstufungen und brillanten Details.
     
    ChromaLife100+** ist ein System aus dem FINE-Druckkopf des PIXMA MP630, Canon Originaltinten und ausgewähltem original Canon Fotopapier. Diese drei einzigartigen Komponenten erzeugen brillante Fotoprints mit hoher Farbstabilität. Textdokumente können in Schwarzweiß oder Farbe gedruckt werden, wobei eine schwarze Pigmenttinte für gestochen scharfen Text sorgt.
     
    Single-Ink-Technologie
    5 Tintentanks sorgen für Qualität und Effizienz – ist eine Tinte aufgebraucht, muss nur der betreffende Tank ausgetauscht werden.
     
    Bedienungsfreundlichkeit
    Mit dem hoch auflösenden 6,2 cm großen TFT-Farbdisplay können Sie Ihre Fotos auch ohne Computer bequem ansehen und mit dem Easy-Scroll-Bedienrad durchsuchen, auswählen, bearbeiten und den Druckvorgang starten. Ebenso ist es möglich, Aufnahmen direkt von kompatiblen Speicherkarten, PictBridge-kompatiblen Digitalkameras oder -Camcordern auszudrucken. Mit der Quick-Start-Funktion stehen alle Optionen in wenigen Sekunden zur Verfügung.
     
    Fortschrittliches Medien-Handling
    Gestalten Sie individuelle bedruckbare CDs und DVDs, indem Sie mit der Software CD-LabelPrint Layouts mit Ihren Texten und Bildern erstellen. Die integrierte Duplexeinheit ermöglicht den automatischen beidseitigen Druck auf Normalpapier, was Papier spart. Zwei Papierzuführungen ermöglichen das gleichzeitige Bestücken des Druckers z. B. mit Normalpapier und Fotopapier.
     
    Scannen
    Dank der optischen Auflösung von 4.800 dpi sind hervorragende Farbscans möglich, die Sie direkt an den PC oder als E-Mail senden bzw. als PDF erstellen können. Die intuitive Software MP Navigator EX gewährleistet eine einfache Bedienung. Der Auto-Scan-Modus beschleunigt den Scanvorgang, indem der Vorlagentyp erkannt und die entsprechenden Einstellungen automatisch gewählt werden. Mit der praktischen Option zum Direktscan auf Speicherkarte oder USB-Stick können die gescannten Daten einfach und flexibel gespeichert und transportiert werden.
     
    Betriebssysteme
    Kompatibel mit Windows und Mac OS X
    ";2;False;0;;;Canon Pixma MP 630 Multifunktionsgerät;canon-pixma-mp-630-multifunktionsgeraet;True;True;P-2180;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;2,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;169.0000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;40889,4313888889;"22;2095";25;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000133-canon-pixma-mp-630-multifunktionsgerat.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000134-canon-pixma-mp-630-multifunktionsgerat.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000135-canon-pixma-mp-630-multifunktionsgerat.jpg;2;;False;;;;;False;False;False;;;;;False;;;;;; -5;0;True;"Apple iPhone 4S schwarz ";"Apple iPhone 4S schwarz ";"
    Das neue iPhone 4S - jetzt mit Dual Core A5 Chip, neuer 8 MegaPixel-Kamera, iOS 5 und iCloud sowie dem neuen Siri.
     
    Dual-Core A5 Chip. Der leistungsstärkste iPhone Prozessor aller Zeiten.
    Mit zwei Prozessorkernen liefert der A5 Chip bis zu 2x mehr Leistung und bis zu 7x schnellere Grafik. Das wirst du merken. Und zwar schnell. Das iPhone 4S reagiert extrem schnell, was du sofort merkst, wenn du Apps öffnest, im Web surfst, beim Spielen und auch bei allem anderen. Und ganz egal was du machst, du kannst es richtig lange machen. Denn der A5 Chip ist so effizient, dass das iPhone 4S eine enorm lange Batterielaufzeit hat.
     
    Die Kaum-zu-glauben-dass-es-ein-Handy-ist Kamera.
    Wahrscheinlich die beste Kamera, die es je auf einem Telefon gab. Und dank fortschrittlichster Optik ist sie wahrscheinlich auch die einzige Kamera, die du brauchst. Schließlich hat sie eine Auflösung von 8 Megapixeln und eine spezielle Linse mit einer größeren f/2,4 Blende. Außerdem bietet sie einen optimierten rückwärtig belichteten Sensor, exzellenten Weißabgleich, verbesserte Farbgenauigkeit, Gesichtserkennung und reduzierte Bewegungsunschärfe. Es ist also ganz egal, wie viele Leute, wie viel Licht und wie viel Action du aufnimmst – alles sieht genau so aus, wie es aussehen soll. Und warte erst, bis du die Fotos siehst.
     
    Siri. Dein intelligenter, hilfsbereiter Assistent.Du musst ihn nur fragen.
    Jetzt kannst du dein iPhone einfach mit deiner Stimme benutzen. Sprich mit Siri so, wie du mit einer Person sprichst und sag ""Erinnere mich daran, Mama anzurufen, wenn ich zu Hause bin"" oder ""Brauche ich einen Schirm?"". Siri spricht Deutsch und versteht nicht nur, was du sagst, sondern auch was du meinst. Es erkennt, welche Apps für die richtige Antwort nötig sind. Und antwortet dir dann – wie dein persönlicher Assistent. Siri telefoniert, sendet Nachrichten, plant Meetings, legt Erinnerungen fest und mehr. Was noch? Frag einfach, und Siri sagt es dir selbst.
     
    Videoaufnahmen. In fantastischem 1080p HD.
    Nimm fantastische 1080p HD Videos auf, wo immer du bist. Durch die neue fortschrittliche Optik der Kamera ist das Licht immer genau richtig, die Farben immer leuchtend und alles sieht noch besser aus, als du es in Erinnerung hattest. Die Bildstabilisierung gleicht verwackelte Aufnahmen aus. Und du kannst Videos direkt auf dem iPhone bearbeiten und so schnell mit anderen teilen, wie du sie aufnimmst.
     
    iOS. Das fortschrittlichste mobile Betriebssystem der Welt. Und auch das einfachste.
    Jede neue iOS Version bietet Möglichkeiten, die alles noch einfacher machen. Deshalb ist iOS allen anderen um Jahre voraus. Und iOS 5 geht wieder einen großen Schritt weiter und bringt mehr als 200 neue Features auf das iPhone 4S. Hier sind nur einige unserer Favoriten.
     
    iCloud. Deine Inhalte. Auf all deinen Geräten.
    Mit iCloud kannst du deine Inhalte ganz einfach verwalten, denn iCloud erledigt alles für dich. iCloud speichert deine Musik, Fotos, Apps, Mails, Kontakte, Kalender, Dokumente und mehr und pusht alles drahtlos an all deine Geräte. Automatisch, nahtlos und einfach so.
     
    Retina Display.Das ist ganz klar.
    Auf dem iPhone 4S siehst du einfach alles gestochen scharf und lebendig. Das Retina Display ist das höchstauflösende Telefondisplay aller Zeiten. Die Pixeldichte ist so hoch, dass das menschliche Auge keine einzelnen Pixel erkennen kann. Was du aber ganz bestimmt siehst, sind gestochen scharfe Texte, Grafiken und Bilder. Alles sieht sogar noch besser aus als gedruckt.
     
    FaceTime. Wink doch mal hallo.
    Mit FaceTime hörst du nicht nur eine Stimme, sondern siehst auch das Gesicht dazu – von iPhone zu iPhone, iPad 2, iPod touch oder Mac über Wi-Fi. Es ist also ganz egal, wo die anderen sind und wo du bist – du bist immer da. FaceTime Anrufe sind so einfach wie ganz normale Anrufe. Und mit Siri sind sie sogar noch einfacher. Sag Siri einfach, dass du mit deiner Mutter facetimen willst, und schon seht ihr euch. Einfach so. Du verpasst nie wieder ein wichtiges Ereignis, Meeting oder einen guten Lacher. Und wer würde sich nicht darüber freuen, dich zu sehen?
     
    AirPlay. Live vom iPhone auf deinen Fernseher.
    Mit AirPlay kannst du Inhalte von deinem iPhone via Apple TV drahtlos an deinen HD Fernseher und Lautsprecher streamen.6 Und mit der AirPlay Synchronisierung erscheint alles, was du auf deinem iPhone siehst oder machst, gleichzeitig auf deinem HD Fernseher.
     
    AirPrint.Alles drahtlos drucken.
    Drucke deine Mails, Fotos, Webseiten und Dokumente einfach über Wi-Fi von deinem iPhone aus.7 Ganz ohne Software zu laden, Treiber zu installieren oder Kabel anzuschließen. Nur ein paar Fingertipps und schon hast du das, was eben noch auf dem iPhone war, als Ausdruck in der Hand.
     
    Besser. Schneller. Weltweiter.
    Das iPhone 4S ist das erste Telefon, das zum Übertragen und Empfangen intelligent zwischen zwei Antennen wechselt. So ist die Anrufqualität deutlich besser. Außerdem verdoppeln die Antennen die maximale HSDPA Datengeschwindigkeit auf 14,4 Mbit/s.8 Und das bedeutet schnellere Verbindungen, schnelleres Laden und Neuladen und schnellere Downloads. Das iPhone 4S ist ein Telefon für die ganze Welt. Du kannst es also fast überall verwenden. Ob GSM- oder CDMA-Standard spielt keine Rolle. Nutze es via Roaming in GSM-Netzen in 200 Ländern weltweit.
     
    Integrierte Apps. Machen alles, damit du alles machen kannst.
    Ganz Alltägliches erledigst du mit dem iPhone 4S auf ganz außergewöhnliche Weise. Mach fantastische Fotos und nimm HD Videos auf. Sieh Freunde und Familie mit FaceTime. Tauche auf dem Retina Display richtig ins Web ein. Check deine Mails. Sende Nachrichten. Lege Erinnerungen fest. Schau in deinen Kalender. Oder sag Siri einfach, wie es dir helfen soll. Siri findet dann selbst heraus, welche Apps es verwenden muss.
    Aufgrund der sehr umfangreichen Leistungsmerkmale können wir Ihnen hier nur einen Auszug präsentieren. Die vollständigen Funktionsbeschreibungen inkl. einer Vielzahl von Videos entnehmen Sie bitte der Herstellerwebseite.
    •Apple iPhone 4S
    •115,2 x 58,6 x 9,3 mm klein und 140 g leicht
    •Kapazität: 16 GB Flash-Laufwerk
    •Kamera, Fotos und Video:
    • 8.0 Megapixel Kamera
    • Videoaufnahme, HD (1080p) bis zu 30 fps mit Audio
    • Fotos und Videos in VGA-Qualität mit bis zu 30 fps mit der Kamera an der Vorderseite
    • Fokussieren per Fingertipp für Videos und Fotos LED-Blitz
    • Geotagging für Fotos und Videos
    •Display:
    • Retina Display
    • 3,5""-Multitouch-Display (8,89 cm Diagonale)
    • Auflösung von 960 x 640 Pixeln mit 326ppi
    • Typisches Kontrastverhältnis: 800:1
    • Fettabweisende Beschichtung an der Vorder- und Rückseite
    • Unterstützung für die Anzeige mehrerer Sprachen und Zeichen gleichzeitig
    •Stromversorgung und Batterie:
    • Sprechdauer: bis zu 8 Std. mit 3G, bis zu 14 Std. mit 2G
    • Standbydauer: bis zu 200 Std.
    • Internetnutzung: bis zu 6 Std. mit 3G, bis zu 9 Std. mit Wi-Fi
    • Videowiedergabe: bis zu 10 Std., Audiowiedergabe: bis zu 40 Std.
    •Betriebssystem: iOS 5
    •Mobilfunknetz und Wi-Fi:
    • UMTS/HSDPA/HSUPA (850, 900, 1900, 2100 MHz)
    • GSM/Edge (850, 900, 1800, 1900 MHz)
    • Funktechnologie: 802,11b/g/n Wi-Fi (802.11 nur mit 2,4 GHz), Bluetooth 4.0
    •GPS: Assisted GPS
    •Digitaler Kompass
    •Unterstützte Audioformate: AAC (8 bis 320 KBit/Sek.), Protected AAC (aus dem iTunes Store), HE-AAC, MP3 (8 bis 320 KBit/Sek.), MP3 VBR, Audible (Formate 2, 3, 4, Audible Enhanced Audio, AAX und AAX+), Apple Lossless, AIFF und WAV
    •TV und Video: AirPlay Mirroring to Apple TV support at 720p, Video mirroring and video out support: Up to 1080p with Apple Digital AV Adapter or Apple VGA Adapter (adapters sold separately), Video out support at 576p and 480p with Apple Component AV Cable; 576i and 480i with Apple Composite AV Cable (cables sold separately)
    •Unterstützte Videoformate: H.264 Video: bis zu 720p, 30 Bilder pro Sekunde, Main Level Profile Level 3.1 mit AAC-LC Audio bis zu 160 KBit/Sek., 48 kHz, Stereo-Audio in den Formaten .m4v, .mp4 und .mov; MPEG.4 Video: bis zu 2,5 MBit/Sek., 640 x 480 Pixel, 30 Bilder pro Sekunde, Simple Profile mit AAC-LC Audio bis zu 160 KBit/Sek., 48 kHz, Stereo-Audio in den Formaten .m4v, .mp4 und .mov; Motion JPEG (M-JPEG): bis zu 35 MBit/Sek., 1280 x 720 Pixel, 30 Bilder pro Sekunde, Audio im Format ulaw, PCM Stereo-Audio im Format .avi
    •Sensoren:
    • 3-Achsen-Gyrosensor
    • Beschleunigungssensor
    • Annäherungssensor
    • Umgebungslichtsensor
     
    Lieferumfang:
    iPhone 4S, Apple Earphones mit Fernbedienung und Mikrofon, Dock Connector-auf-USB-Kabel, Dokumentation
    ";2;False;0;;;"Apple iPhone 4S schwarz ";apple-iphone-4s-schwarz;True;True;PD-01081;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;639.0000;639.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;40885,5442708333;71;1;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000651-apple-iphone-4s-schwarz.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000652-apple-iphone-4s-schwarz.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000653-apple-iphone-4s-schwarz.jpg;1;;False;;;;;False;False;False;;;;;False;;;;;; -5;0;True;AVM FRITZ! Box WLAN 3270;AVM FRITZ! Box WLAN 3270 mit 300 Mbit/s und WLAN Eco-Mode;"
    FRITZ!Box WLAN 3270
    Einfach, sicher, kabellos surfen und vernetzen!
     
    FRITZ!Box WLAN 3270 verbindet alle Ihre Computer mit dem Internet - rasend schnell über ADSL oder ADSL2+ und kabellos mit dem neuen WLAN 802.11n.
     
    FRITZ!Box WLAN 3270 vereint ein DSL-Modem mit einem WLAN N-Router in einem Gerät. Mit modernem WLAN N bietet die FRITZ!Box übertragungsgeschwindigkeiten von bis zu 300 MBit/s beim kabellosen Surfen. Computer und netzwerkfähige Geräte lassen sich zudem über die vier Ethernet-Schnittstellen anschließen. Dank des USB-Anschlusses (USB 2.0) stehen Drucker und Speicher im ganzen Netzwerk zur Verfügung.
     
    Ein Hi-Speed-USB 2.0-Anschluss und die erweiterte NAS-Funktionalität mit Mediaserver und Onlinespeicher-Integration erschließen neue Anwendungsmöglichkeiten im Netzwerk.
     
    Damit sind Inhalte wie Filme, Musik und Bilder auch bei ausgeschaltetem Computer im gesamten Netzwerk verfügbar und können auf UPnP-AV-fähigen Geräten (z. B. HD-Fernseher oder Stereoanlage) wiedergegeben werden.
     
     FRITZ!Box WLAN 3270 verfügt über eine umfangreiche Softwareausstattung. Dazu gehören beispielsweise Firewall, Kindersicherung, VPN, WLAN-Nachtschaltung und WLAN-Autokanal.
     
    WLAN N
    FRITZ!Box WLAN 3270 ermöglicht WLAN-Verbindungen mit dem Funkstandard 802.11n im 2,4-GHz- oder im besonders störungsarmen 5-GHz-Band. Durch das Mehrantennenverfahren MIMO (Multiple Input Multiple Output) erhöhen sich Reichweite, Qualität und Datenrate der WLAN-Verbindung. FRITZ!Box WLAN 3270 ist bereits ab Werk sicher dank der voreingestellten, individuellen WPA-/WPA2-Verschlüsselung.
     
    Energie sparen mit FRITZ!
    Mit dem Eco-Mode passt FRITZ!Box WLAN 3270 die Funkleistung automatisch an den Datenverkehr an und sorgt für optimalen Stromverbrauch. Im Ruhezustand wird die Prozessorleistung minimiert und ungenutzte Schnittstellen werden abgeschaltet. Die Funkdauer kann dank der WLAN-Nachtschaltung beliebig eingestellt oder mit einem Schalter verändert werden.
     
    Mehr Möglichkeiten mit USB 2.0
    Ein Hi-Speed-USB 2.0-Anschluss ermöglicht neue Anwendungen im Netzwerk. Bilder, Musik und Videos von an der FRITZ!Box angeschlossenen Speichermedien können an UPnP-AV-kompatiblen Empfängern (HD-Fernseher, Stereoanlage) wiedergegeben werden. Zusätzlich kann ein USB-Drucker dem gesamten Netzwerk zur Verfügung gestellt werden.
     
    Egal ob Online- oder USB-Speicher - die integrierte FRITZ!NAS-Webseite (http://fritz.nas) bietet eine einfache und komfortable Möglichkeit, zentral auf alle Datenbestände an der FRITZ!Box zuzugreifen. Auf Wunsch auch über das Internet.
     
    Anschlüsse
    - DSL-Anschluss an ADSL2+ und ADSL.
     
    - Routerbetrieb auch mit Kabelmodem oder UMTS-Stick (UMTS/HSPA).
     
    - WLAN-Funknetze nach gängigen Standards (802.11n/g/b/a).
     
    - 4 x Ethernet (10/100 Base-T) für Anschluss und Vernetzung von Computern und Spielekonsolen.
     
    - USB 2.0-Anschluss für USB-Geräte wie Drucker und Speichermedien oder UMTS-Stick.
    ";2;False;0;;;AVM FRITZ! Box WLAN 3270 mit 300 Mbit/s und WLAN Eco-Mode;avm-fritz-box-wlan-3270;True;True;P-2690;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;169.0000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;40871,807349537;18;34;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000206-avm-fritz-box-wlan-3270.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000207-avm-fritz-box-wlan-3270.jpg;;2;;False;;;;;False;False;False;;;;;False;;;;;; -5;0;True;AVM FRITZ!Box Fon WLAN 7390;AVM FRITZ!Box Fon WLAN 7390;"
    FRITZ!Box Fon WLAN 7390
    Mehr Leistung für Internet, Telefon und digitale Medien.
     
    FRITZ!Box Fon WLAN 7390 verbindet alle Ihre Computer mit dem Internet - rasend schnell über VDSL (bis 100 MBit/s) oder ADSL2+/ADSL (bis 16 MBit/s). Der neue WLAN-Standard 802.11n (WLAN N) sorgt für ein Maximum an Geschwindigkeit und Reichweite beim kabellosen Surfen. Und dank integrierter DECT-Basisstation und HD-Telefonie wird das Telefonieren über das Internet zu einem komfortablen Erlebnis.
     
    FRITZ!Box Fon WLAN 7390 bietet eine bisher nicht erreichte Vielfalt an Anwendungen für den DSL-Anschluss. Der neue WLAN N-Funkstandard sorgt in Verbindung mit der MIMO- Mehrantennentechnik für eine optimale übertragung mit 2,4 und 5 GHz gleichzeitig (Dualband).
     
    Für die Internet- und Festnetztelefonie steht neben Anschlüssen für analoge und ISDN- Telefone auch eine integrierte DECT-Basis- station für bis zu 6 Schnurlostelefone zur Verfügung.
     
    FRITZ!Box Fon WLAN 7390 bietet dank leistungsstarkem Prozessor die Plattform für vernetzte Anwendungen wie IPTV, Video on Demand oder Mediastreaming.
     
     Zwei Hi-Speed-USB 2.0-Anschlüsse der FRITZ!Box Fon WLAN 7390 und die erweiterte NAS-Funktionalität mit Mediaserver und Onlinespeicher-Integration erschließen neue Anwendungsmöglichkeiten im Netzwerk. Damit sind Inhalte wie Filme, Musik und Bilder auch bei ausgeschaltetem Computer im gesamten Netzwerk verfügbar und können auf UPnP-AV-fähigen Geräten (z. B. HD-Fernseher oder Stereoanlage) wiedergegeben werden.
     
    FRITZ!Box Fon WLAN 7390 verfügt über eine umfangreiche Softwareausstattung. Dazu gehören beispielsweise Telefonbuch, Firewall, Kindersicherung, Faxempfang, VPN, WLAN-Nachtschaltung, WLAN-Autokanal oder ein integrierter Anrufbeantworter.
     
    Dual-WLAN N
    FRITZ!Box Fon WLAN 7390 ermöglicht WLAN-Verbindungen mit dem Funkstandard 802.11n im 2,4-GHz- und im besonders störungsarmen 5-GHz-Band gleichzeitig. Durch das Mehrantennenverfahren MIMO (Multiple Input Multiple Output) erhöhen sich Reichweite, Qualität und Datenrate der WLAN-Verbindung. FRITZ!Box Fon WLAN 7390 ist bereits ab Werk sicher dank der voreingestellten, individuellen WPA-/WPA2-Verschlüsselung.
     
    DECT-Basisstation
    Durch die integrierte DECT-Basisstation können Sie mit bis zu sechs Mobilteilen schnurlos telefonieren. Als ideale Ergänzung zur FRITZ!Box Fon WLAN 7390 bietet AVM die schnurlosen Telefone FRITZ!Fon MT-D und MT-F an, mit denen zahlreiche Komfortfunktionen sowie brillante HD-Telefonie genutzt werden können.
     
    Energie sparen mit FRITZ!
    Mit dem Eco-Mode passt FRITZ!Box Fon WLAN 7390 die Funkleistung automatisch an den Datenverkehr an und sorgt für optimalen Stromverbrauch. Im Ruhezustand wird die Prozessorleistung minimiert und ungenutzte Schnittstellen werden abgeschaltet. Die Funkdauer kann dank der WLAN-Nachtschaltung beliebig eingestellt oder mit einem Schalter verändert werden.
     
    Mehr Möglichkeiten mit USB 2.0
    Zwei Hi-Speed-USB 2.0-Anschlüsse ermöglichen neue Anwendungen im Netzwerk. Bilder, Musik und Videos von an der FRITZ!Box angeschlossenen Speichermedien können an UPnP-AV-kompatiblen Empfängern (HD-Fernseher, Stereoanlage) wiedergegeben werden. Zusätzlich kann ein USB-Drucker dem gesamten Netzwerk zur Verfügung gestellt werden.
     
    Egal ob interner, Online- oder USB-Speicher - die integrierte FRITZ!NAS-Webseite (http://fritz.nas) bietet eine einfache und komfortable Möglichkeit, zentral auf alle Datenbestände an der FRITZ!Box zuzugreifen. Auf Wunsch auch über das Internet.
     
    7390-3.jpg
    ";2;False;0;;;AVM FRITZ!Box Fon WLAN 7390;avm-fritzbox-fon-wlan-7390;True;True;P-2700;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;289.0000;289.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;40871,8066898148;18;34;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000103-avm-fritzbox-fon-wlan-7390.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000104-avm-fritzbox-fon-wlan-7390.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000105-avm-fritzbox-fon-wlan-7390.jpg;1;;False;;;;;False;False;False;;;;;False;;;;;; -5;0;True;"AVM FRITZ!Box Fon WLAN 7270 ";"AVM FRITZ!Box Fon WLAN 7270 ";"
    FRITZ!Box Fon WLAN 7270
    Kabellos mit DSL surfen und über das Internet telefonieren.
     
    FRITZ!Box Fon WLAN 7270 verbindet alle Ihre Computer mit dem Internet - rasend schnell über ADSL oder ADSL2+ und kabellos mit dem neuen WLAN 802.11n.
     
    FRITZ!Box Fon WLAN 7270 vereint DSL-Modem und WLAN-Router mit einer Telefonanlage für Internet- (VoIP-) und Festnetztelefonie und kann wahlweise an analogen oder ISDN-Anschlüssen eingesetzt werden. Sowohl analoge als auch ISDN- und DECT-Telefone werden durch FRITZ!Box Fon WLAN 7270 mit dem Internet und Festnetz verbunden. Das können bis zu zwei analoge Endgeräte wie Telefon und Fax sein, eine ISDN-TK-Anlage, aber auch bis zu sechs Schnurlostelefone, die sich einfach mit der in der FRITZ!Box Fon WLAN 7270 integrierten DECT-Basisstation verbinden lassen.
     
    Unabhängig von der Art des Anschlusses stehen alle wesentlichen Leistungsmerkmale wie Rufnummernanzeige, Dreierkonferenz, Rufumleitung und Makeln an den Telefonen zur Verfügung. Internettelefonie in HD-Qualität (High Definition) wird durch den Einsatz von Breitband-Sprachcodecs unterstützt.
     
     FRITZ!Box Fon WLAN 7270 bietet mit modernem WLAN N übertragungsgeschwindigkeiten von bis zu 300 MBit/s. Computer und netzwerkfähige Geräte lassen sich zudem über die vier LAN-Schnittstellen anschließen. Dank des USB-Anschlusses (USB 2.0) stehen Drucker und Speicher im ganzen Netzwerk zur Verfügung.
     
    FRITZ!Box Fon WLAN 7270 verfügt über eine umfangreiche Softwareausstattung. Dazu gehören beispielsweise Telefonbuch, integrierter Anrufbeantworter, Faxempfang, WLAN-Nachtschaltung, Kindersicherung und VPN.
     
    WLAN N
    FRITZ!Box Fon WLAN 7270 ermöglicht WLAN-Verbindungen mit dem Funkstandard 802.11n im 2,4-GHz- oder im besonders störungsarmen 5-GHz-Band. Durch das Mehrantennenverfahren MIMO (Multiple Input Multiple Output) erhöhen sich Reichweite, Qualität und Datenrate der WLAN-Verbindung. FRITZ!Box Fon WLAN 7270 ist bereits ab Werk sicher dank der voreingestellten, individuellen WPA-/WPA2-Verschlüsselung.
     
    DECT-Basisstation
    Durch die integrierte DECT-Basisstation können Sie mit bis zu sechs Mobilteilen schnurlos telefonieren, wenn diese den Standard CAT-iq oder GAP unterstützen. Als ideale Ergänzungen zur FRITZ!Box bietet AVM die schnurlosen Telefone FRITZ!Fon MT-F und FRITZ!Fon MT-D an, mit denen Sie zahlreiche Komfortfunktionen sowie Internettelefonie in HD-Qualität nutzen können.
     
    Energie sparen mit FRITZ!
    Mit dem Eco-Mode passt FRITZ!Box Fon WLAN 7270 die Funkleistung automatisch an den Datenverkehr an und sorgt für optimalen Stromverbrauch. Im Ruhezustand wird die Prozessorleistung minimiert und ungenutzte Schnittstellen werden abgeschaltet. Die Funkdauer kann dank der WLAN-Nachtschaltung beliebig eingestellt oder mit einem Schalter verändert werden.
     
    Mehr Möglichkeiten mit USB 2.0
    Ein Hi-Speed-USB 2.0-Anschluss ermöglicht neue Anwendungen im Netzwerk. Bilder, Musik und Videos von an der FRITZ!Box angeschlossenen Speichermedien können an UPnP-AV-kompatiblen Empfängern (HD-Fernseher, Stereoanlage) wiedergegeben werden. Zusätzlich kann ein USB-Drucker dem gesamten Netzwerk zur Verfügung gestellt werden.
     
    Egal ob Online- oder USB-Speicher - die integrierte FRITZ!NAS-Webseite (http://fritz.nas) bietet eine einfache und komfortable Möglichkeit, zentral auf alle Datenbestände an der FRITZ!Box zuzugreifen. Auf Wunsch auch über das Internet.
    ";2;False;0;;;AVM FRITZ!Box Fon WLAN 7270 N-Standard mit bis zu 300 MBit/Sek;avm-fritzbox-fon-wlan-7270;True;True;;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;249.0000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;40871,8016898148;18;34;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000200-avm-fritzbox-fon-wlan-7270.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000201-avm-fritzbox-fon-wlan-7270.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000202-avm-fritzbox-fon-wlan-7270.jpg;2;;False;;;;;False;False;False;;;;;False;;;;;; -5;0;True;"Samsung SyncMaster P2270 HD 22 Zoll TFT Monitor ";Samsung SyncMaster P2270 HD 22 Zoll TFT Monitor schwarz;"
    Samsung P2270HD
    Die SyncMaster 70er HD-Serie besticht mit edlem Design und technischen Raffinessen: So können die Modelle dieser Serie als LCD-Monitor, aber auch als vollwertiges LCD-TV-Gerät eingesetzt werden. Der integrierte TV Tuner macht es möglich. Vielseitige AV-Anschlussmöglichkeiten bieten zudem die Möglichkeit, weitere Peripheriegeräte anzuschließen. Das praktische 16:9-Format mit Full HD Auflösung und die Unterstützung von Dolby Digital Plus und SRS TruSurround HD runden die multimedialen Eigenschaften dieser Serie ab.
     
    TV Tuner
    Dieses SyncMaster-Modell ist mit einem TV Tuner ausgestattet und kann somit auch als vollwertiges LCD-TV-Gerät verwendet werden.
     
    16:9-Widescreen-Format
    Das praktische 16:9-Widescreen-Format ermöglicht ein noch angenehmeres Arbeiten bei gleichzeitiger Steigerung Ihrer Produktivität. Das Breitbildformat entspricht dem natürlichen Sichtfeld des Betrachters. Somit haben Sie immer alles im Blick, ohne auf wichtige Informationen verzichten zu müssen.
     
    Full HD
    Dieses SyncMaster Large Format Display verfügt über ein Full HD Panel mit einer nativen Auflösung von 1.920 x 1.080 Pixel. Somit können Bildinhalte im 1.080p-Format, der derzeit besten HD-Auflösung, wiedergegeben werden. 
     
    Dynamischer Kontrast
    Genießen Sie beste Bildqualität mit hoher Bildschärfe und Detailreichtum selbst in dunklen Szenen. Mit einem dynamischen Kontrast von bis zu 50.000:1 werden Sie jedes Detail auf dem Bildschirm erkennen können.
     
    HDMI
    HDMI steht für High Definition Multimedia Interface. Mit dieser Schnittstelle ist es möglich, HD Bild- und Tonmaterial in 100% verlustfreier, digitaler Qualität zu übertragen.
     
    MagicSpeed
    MagicSpeed garantiert Ihnen selbst bei schnell bewegten Bildschirminhalten, wie z. B. Filmen oder Computerspielen, eine schlierenfreie Darstellung für beste Bildqualität. 
      
    HDCP
    HDCP oder auch High Bandwidth Digital Content Protection schützt urheberrechtlich geschützte Formate (z. B. Videodaten) vor illegalen Kopien. HDCP muss dabei sowohl vom Quellgerät (z. B. DVD-Player) als auch vom Ausgabegerät (Monitor) unterstützt werden. Dieses SyncMaster-Modell ist HDCP-kompatibel.
     
    Energiesparfunktion
    Samsung Displays, die dieses Logo tragen, sind besonders energieeffizient und schonen somit die Umwelt.
     
    RoHS-Zertifikat
    Die Displays von Samsung wurden von Nemko mit dem RoHS-Logo zertifiziert, d. h. sie enthalten keine gefährlichen Substanzen gemäß den Richtlinien der Europäischen Union. Damit ist Samsung der erste Hersteller am Markt, der offiziell diese Zertifizierung erhalten hat. 
     
    ";2;False;0;;;Samsung SyncMaster P2270 HD 22 Zoll;samsung-syncmaster-p2270-hd-22-zoll-tft-monitor;True;True;P-2480;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;199.0000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;40871,5791087963;9;5;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000462-samsung-syncmaster-p2270-hd-22-zoll-tft-monitor.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000463-samsung-syncmaster-p2270-hd-22-zoll-tft-monitor.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000464-samsung-syncmaster-p2270-hd-22-zoll-tft-monitor.jpg;2;;False;;;;;False;False;False;;;;;False;;;;;; -5;0;True;Apple iPod Touch 8 GB schwarz;Apple iPod Touch 8 GB schwarz;"
    Apple iPod Touch 8 GB schwarz
     
    mit integrierter WiFi Funktion

     
    Ein großartiger iPod. Ein großartiger Taschencomputer. Großartiger mobiler Spielspaß. Und das Ganze in einem unglaublich schlanken, eleganten neuen Design aus Edelstahl. Filme, Videos und Fernsehsendungen auf einem 3,5"" Display ansehen!Im Web surfen, mailen! Multitouch-Oberfläche: Die revolutionäre Technologie des iPhone und die Software Version 3.1 stecken in diesem genialen iPod. Das brillante Breitformat-Display rückt Ihre Videos und Spiele ins beste Licht Surfen Sie mit Safari im Web und sehen Sie YouTube Videos auf dem iPod mit integrierter Wi-Fi Funktionalität an.
     
    Mit Ihrem iPod touch können Sie im iTunes Wi-Fi Music Store nach Songs suchen, Hörproben abspielen und Titel kaufen.  Lieferumfang: iPod touch, Ohrhörer, USB 2.0 Kabel, Dock-Adapter, Kurzanleitung
     
    Der iPod touch kann alles, was du am iPod toll findest. Und noch vielmehr.
    Du kannst Filme, Videos und Fernsehsendungen auf einem 3,5"" Display ansehen. Mit der revolutionären Multi-Touch-Technologie kannst du dein Musikarchiv mit Cover Flow durchblättern. Und wenn dir nach mehr ist, tipp einfach auf iTunes, um durch das Angebot zu stöbern und sofort einzukaufen. Hör dir Wiedergabelisten an, die automatisch für dich erstellt werden. Schau Filme auf dem brillanten 3,5"" Display. Und kauf mit einem Fingertipp bei iTunes ein - wann immer du willst. All das und noch viel mehr mit dem iPod touch, den es schon ab 189 € gibt. Wi-Fi ist schon integriert. So kannst du im Web surfen, mailen, deinen Facebook Status aktualisieren, mit AIM chatten und noch viel mehr - und das alles auf einem Gerät, das locker in jede Tasche passt. Hier hast du die Finger im Spiel. Und nicht nur die. Denn mit den Spielen auf dem iPod touch tauchst du richtig in die Action ein - einfach neigen, tippen, drehen. Und via Wi-Fi kannst du jederzeit im App Store neue Spiele kaufen. Die iPhone 3.1 Software ist auf dem iPod touch bereits installiert, sodass der Spaß gleich beginnen kann. Damit kannst du nützliche Funktionen wie Peer-to-Peer-Spiele und Cut, Copy & Paste direkt nach dem Auspacken nutzen.
    Next Level Fun: Der neue iPod touch
     
    Musik
    Stöber durch deine Alben. Hör dir einen einzigartigen Mix an, der nur für dich erstellt wurde. Oder schau das Video deines Lieblingssongs an. Mit dem iPod touch kannst du mehr als nur Musik hören.
     
    Cover Flow
    Auf dem iPod touch gibt's Musik nicht nur auf die Ohren. Mit Cover Flow ist Musik auch etwas für Augen und Finger. Dreh den iPod touch einfach auf die Seite und blätter durch deine Albumcover. Tipp auf ein Albumcover, um es umzudrehen und die Songliste zu sehen. Tipp noch einmal und Musik ab.
     
    Genius Mixe
    Die Genius Funktion wurde weiter verbessert. Jetzt gibt es Genius Mixe. Du brauchst den iPod touch nur mit iTunes zu synchronisieren. Genius durchsucht dann automatisch deine Mediathek nach Songs, die gut zusammenpassen und erstellt bis zu zwölf Mixe.
    Diese Mixe sind wie Radiosender, auf denen nur deine Musik läuft.
     
    Genius Wiedergabelisten
    Angenommen du hörst einen Song auf deinem iPod touch, der dir gut gefällt, und du möchtest weitere Titel hören, die dazu passen. Genius findet weitere Songs auf deinem iPod touch und erstellt eine Genius Wiedergabeliste für dich. Hör dir die Wiedergabeliste sofort an, speichere sie für später oder versuch's noch einmal und sieh, was dabei herauskommt. Verlass dich auf Genius, wenn du einen Mix willst, auf den du selbst nie gekommen wärst.
     
    Shake to Shuffle
    Die Dinge mal aufrütteln. Musikalisch natürlich. Wenn du das nächste Mal Musik hörst, aktiviere die Schüttelfunktion und wenn du den iPod touch dann kurz schüttelst, springt er nach dem Zufallsprinzip zu einem anderen Song aus deiner Sammlung.
     
    iTunes
    Pack Musik und Videos aus der iTunes Mediathek deines Computers auf den iPod touch. Oder kauf und lade neue Songs auf den iPod touch, wenn du über Wi-Fi auf iTunes zugreifst. Wenn du den iPod touch das nächste Mal mit dem Computer verbindest, werden alle Songs, die du auf dem iPod touch gekauft hast, auf den Mac oder PC übertragen.
     
    Bluetooth
    Schau mal, keine Kabel. Der iPod touch enthält die iPhone 3.1 Software, sodass du Bluetooth Stereokopfhörer anschließen kannst. Lass den iPod in deiner Tasche stecken oder auf dem Schreibtisch aufladen, während du weiter Musik hörst.
     
    Filme und Fernsehsendungen
    Ein Kinohit. Ein Video-Podcast. Deine Lieblingsserie. Jetzt laufen sie auch in einer U-Bahn oder einem Flugzeug in deiner Nähe.
    Widescreen-Display
    Du kannst Videos für viele Stunden überallhin mitnehmen und auf dem gestochen scharfen 3,5"" Widescreen-Farbdisplay ansehen. Kauf im iTunes Store und wähle unter tausenden vonFilmen, Fernsehsendungen und Video-Podcasts, die du auf den iPod touch laden kannst. Von Hollywood-Hits bis zu Indie-Streifen - es gibt etwas für jeden Geschmack. Mit wenigen Fingertipps kannst du Filme kaufen und laden. Du magst lieber Fernsehsendungen? Lade eine einzelne Folge oder die gesamte Staffel.
     
    On-Screen Steuerung
    Auch während du Video guckst, kannst du die Steuerung einblenden - ein Fingertipp auf das Display genügt. Du kannst die Wiedergabe starten oder unterbrechen, einzelne Kapitel anzeigen und die Lautstärke anpassen. Natürlich kannst du auch die Lautstärkeregler links am iPod touch verwenden. Du willst zwischen Widescreen und bildschirmfüllender Anzeige wechseln? Einfach aufs Display doppeltippen.
     
    iTunes
    Du brauchst Unterhaltung für deinen nächsten Flug oder die Autofahrt? Mit iTunes auf dem iPod touch und einer Wi-Fi-Verbindung kannst du auch unterwegsFilme und Fernsehsendungen kaufen. Du kannst Filme auch leihen, wenn du dir nicht sicher bist, ob du den Film behalten willst. Und natürlich kannst du Filme und Fernsehsendungen auf dem Mac oder PC kaufen und dann mit dem iPod touch synchronisieren.
     
    App Store
    Kaufe im App Store und entdecke über 65.000 Apps, mit denen du noch mehr auf dem iPod touch machen kannst. Stöbere in tausenden von Apps in verschiedenen Kategorien. Von Spielen über Lifestyle und Soziale Netzwerke bis zu Unterhaltung und mehr.
     
    Apps durchstöbern
    Du kannst auf verschiedene Arten im App Store shoppen. Tipp auf ""Neu"" und ""Topaktuell"", um eine Liste der aktuellen und angesagten Apps zu erhalten. Stöbere nach Kategorien. Schau dir die topaktuellen Apps an. Wenn du genau weißt, wonach du suchst, kannst du auch eine Schnellsuche durchführen.
     
    Genius Empfehlungen für Apps
    Es gibt tausende von Apps im App Store, und jeden Tag kommen mehr dazu. Mit dieser neuen Funktion des iPod touch findest du coole neue Apps noch einfacher. Genius für Apps. Funktioniert genau wie Genius für deine Musik. Tipp auf das Genius Symbol und du bekommst Empfehlungen für Apps anhand der Apps, die du und andere schon geladen haben.
     
    Apps laden
    Wenn du eine App findest, die dich interessiert, kannst du sie überall, wo eine Wi-Fi-Verbindung besteht, drahtlos kaufen, auf den iPod laden und dann sofort loslegen.
     
    Updates für Apps
    iPod touch sagt dir, wenn ein App Update verfügbar ist, damit du immer die neuesten Versionen deiner Lieblings-Apps hast.
     
    iTunes
    Entdecke und lade neue Musik, Filme, Fernsehsendungen, Podcasts und Hörbücher in iTunes auf dem iPod touch.
     
    Einkaufen, immer und überall
    Greif über die im iPod touch integrierte Wi-Fi-Funktion auf den iTunes Store zu. Durchsuche Millionen von iTunes Plus Songs in brillanter Audioqualitätund tausende von Filmen, Fernsehsendungen, Hörbüchern und kostenlosen Podcasts und Vorlesungen von iTunes U. Stöbere nach Neuerscheinungen, Top-Titeln und Genres. Oder finde mit der Schnellsuche genau das, wonach du suchst. Hör in einen Song oder sieh dir eine Videovorschau an. Wenn du dann etwas kaufen möchtest, brauchst du nur darauf zu tippen. Nicht sicher, ob es sich lohnt, den Film zu kaufen? Dann leih ihn einfach. Alles was du auf dem iPod touch kaufst, hat denselben Preis wie im iTunes Store auf deinem Computer.
     
    Synchronisieren mit iTunes
    Sobald du den iPod touch mit dem Computer verbindest, werden die Songs, Filme, Fernsehsendungen, Hörbücher und Podcasts, die du unterwegs geladen hast, mit deiner iTunes Mediathek auf deinem Mac oder PC synchronisiert. Wenn du etwas nur teilweise auf den iPod touch geladen hast, beendet der Computer den Download automatisch für dich.
     
    Sprachsteuerung
    Mit der Sprachsteuerung beim neuen 32 GB und 64 GB iPod touch kannst du deine Musik mit Sprachbefehlen steuern. Und der iPod hört aufs Wort. Auf ""Spiel"", ""Shuffle"" oder ""Wie heißt das Lied?"".
     
    Sagen und abspielen.
    Die Sprachsteuerung kennt die Musik auf deinem iPod touch. Wenn du etwas Bestimmtes hören willst, sag es einfach. Zum Beispiel ""Spiel Bob Dylan"" und der iPod touch hört aufs Wort. Frag ihn, welcher Song grad läuft, und der iPod touch sagt es dir. Sag ihm, dass er dein Lieblingsalbum, deinen Lieblingssänger oder deine Lieblingswiedergabeliste spielen soll. Verwende einfache Befehle wie ""shuffle"", ""nächster Song"" und ""anhalten"". Du kannst dem iPod touch sogar sagen, dass er mehr Songs wie den, der gerade läuft, abspielen soll.
     
    Sprich ins Mikro
    Der neue 32 GB und 64 GB iPod touch wird mit den Apple Earphones mit Fernbedienung und Mikro geliefert. So kannst du die Sprachsteuerung auch dann nutzen, wenn der iPod touch in der Tasche steckt. Zum Aktivieren der Sprachsteuerung über die Kopfhörer hältst du einfach die Mitteltaste der Fernbedienung gedrückt.
     
    Die Sprachsteuerung unterstützt die folgenden Sprachen:
    Chinesisch (China), Chinesisch (Kantonesisch), Chinesisch (Taiwan), Deutsch, Englisch (Großbritannien), Englisch (USA), Finnisch, Französisch (Frankreich), Französisch (Kanada), Italienisch, Japanisch, Koreanisch, Niederländisch, Norwegisch, Polnisch, Portugiesisch (Brasilien), Portugiesisch (Portugal), Russisch, Schwedisch, Spanisch (Mexiko), Spanisch (Spanien)
     
    Fotos
    Der iPod touch hat für bis zu 90.000 deiner Lieblingsfotos Platz. Durch Streichen kannst du sie durchschauen und all die Erinnerst-du-dich-noch-Momente mit anderen teilen.
     
    Fotos sichern
    Wenn dir tolle Bilder gemailt werden, kannst du sie einfach im Fotoarchiv auf dem iPod touch sichern und dann wie jedes andere Foto nutzen. Du kannst sie zum Beispiel als Hintergrundbilder verwenden, im Internet teilen oder weitergeben.
     
    Fotos teilen
    Du hast tausende Fotos immer zur Hand. Blätter durch Streichen auf dem Display durch Miniaturen. Mit einem Fingertipp siehst du Fotos bildschirmfüllend. Spiel Diashows mit Musik und Übergängen ab. Maile Fotos an Freunde oder teile sie in einer MobileMe Galerie.
     
    Fotos synchronisieren
    Fotos aus iPhoto auf einem Mac oder Adobe Photoshop Elements und Adobe Photoshop Album auf einem PC werden via iTunes mit dem iPod touch synchronisiert. Einfach nur die Fotos und Alben aussuchen, die mit dem iPod touch synchronisiert werden sollen. Dann kannst du sie überall ansehen und mit anderen teilen.
     
    Homescreen
    Angenommen du möchtest ""Karten"" als erste App in der zweiten Zeile haben. Oder Mail unten im Dock. Mit den anpassbaren Homescreens kannst du den iPod touch zu deinem iPod touch machen.
     
    Individuelles Anpassen
    Ordne die Symbole auf deinem Homescreen an wie du willst - direkt auf dem iPod touch oder auf deinem Computer in iTunes 9. Bewege eine App eine Zeile nach oben, zwei Apps nach rechts oder auf einen anderen Homescreen. Du kannst bis zu 11 Homescreens erstellen und hast so schnellen Zugriff auf Spiele und Apps, die du aus dem App Store lädst, und auf deine Safari Weblinks.
     
    Hometaste
    Was auch immer du gerade mit deinem iPod touch machst – die Hometaste bringt dich immer zurück zum ersten Homescreen. Wenn du auf die Hometaste drückst, kannst du von jedem Homescreen wieder zurück zum ersten springen.
     
    Apps und Weblinks hinzufügen
    Für jede App, die du aus dem App Store lädst, erscheint ein neues Symbol auf dem Homescreen. Von häufig besuchten Websites kannst du praktische Weblinks erstellen. Sie erscheinen auf dem Homescreen und du kannst per Fingertipp darauf zugreifen.
     
    Spotlight Suche
    Du suchst was? Von einem Ort aus kannst du die gesamten Inhalte des iPod touch durchsuchen. Streich auf dem ersten Homescreen einfach nach rechts, um Spotlight zu öffnen. Sobald du anfängst zu tippen, durchsucht Spotlight deine gesamten Songs, Videos, Kontakte, Mails, Kalender, Notizen und sogar deine Hörbücher und Podcasts.
     
    Safari
    Safari, der fortschrittlichste Webbrowser auf einem Mobilgerät, ist auch auf dem iPod touch integriert. Damit erlebst du das Internet in deiner Hand genauso wie auf dem Computer zuhause. Alles was du brauchst ist eine Wi-Fi-Verbindung.
     
    Überall ins Internet
    Der iPod touch ist der einzige iPod mit integriertem drahtlosen Internetzugriff. Bei bestehender Wi-Fi-Verbindung kannst du im Internet surfen und Nachrichten lesen, Sportergebnisse sehen, Rechnungen bezahlen und online einkaufen. Und beim 32 GB oder 64 GB iPod touch wirst du sehen, dass Webseiten jetzt noch schneller als vorher geladen werden.
     
    Im Web stöbern
    Der iPod touch synchronisiert deine Lesezeichen vom PC oder Mac, sodass du ruckzuck auf deine Lieblingsseiten zugreifen kannst. Außerdem ist die Google- und Yahoo!-Suche schon integriert, sodass du im Web schnell findest, was du suchst.
     
    Weblinks
    Wenn du eine Website öfter besuchst - etwa die einer Zeitung, eines Blogs oder eine Sport-Website - kannst du einfach ein Symbol, einen sogenannten Weblink, auf dem Homescreen erstellen. Wenn du mit Safari Weblinks erstellst, sind deine Lieblingsseiten nur einen Fingertipp entfernt.
     
    Zoom
    Wenn du eine Website öfter besuchst, brauchst du nur mit dem Finger auf das Multi-Touch-Display zu tippen oder die Anzeige aufzuziehen. Websites lassen sich im Hoch- oder Querformat anzeigen. Einfach den iPod touch um 90 Grad drehen, und schon wird auch die Darstellung der Webseite gedreht.
     
    Mail
    Mails auf dem iPod touch funktionieren genau wie auf deinem Computer und sehen auch genau so aus. Und sie funktionieren mit deinen vorhandenen Accounts.
     
    Nachrichten und Anhänge ansehen
    Der iPod touch unterstützt Rich-HTML-E-Mail, sodass Bilder und Fotos zusammen mit dem Text einer E-Mail angezeigt werden. Anhänge siehst du in ihrem Originalformat und nicht als abgespeckte Version. Du kannst in mehr als einem Dutzend standardmäßigen Datei- und Bildformaten drehen, zoomen und schwenken, darunter PDF, Microsoft Word, Excel, PowerPoint und iWork.
     
    Zugriff auf alle Accounts
    Mails von gängigen Anbietern wie MobileMe, Google Mail, Microsoft Exchange, Yahoo! und den meisten standardmäßigen IMAP- und POP-Systemen kannst du mit dem iPod touch ganz einfach abrufen.
     
    Schnellere Eingabe
    Der iPod touch erkennt E-Mail-Adressen in verschiedenen Programmen. Wenn du auf einer Webseite oder in einer Karte eine E-Mail-Adresse siehst, reicht ein Fingertipp auf dem iPod touch, um eine neue Mail zu öffnen, in der die Adresse bereits eingetragen ist.
     
    Intelligente Eingabe
    Die innovative iPod touch Tastatur mit integriertem Wörterbuch* schlägt während der Eingabe Wörter vor. So kannst du ganz schnell und einfach Mails schreiben. Dreh den iPod touch einfach. Dann wird die Tastatur vom Hochformat ins Querformat gedreht und du hast größere Tasten und mehr Platz zum Tippen.
     
    Postfach durchsuchen
    Du musst das Postfach jetzt nicht mehr Mail für Mail durchsuchen. Durch schnelles Abwärtsstreichen wird jetzt ein Suchfeld geöffnet, mit dem du deine Mails nach Absender, Empfänger, Betreff oder Titelzeilen durchsuchen kannst.
     
    Karten
    Finde deinen Weg und die nächste Pizzeria. Mit Karten und einer Wi-Fi-Verbindung kannst du Wegbeschreibungen abrufen, Firmen finden und Verkehrsinformationen prüfen.
     
    Finde dich selbst
    Der iPod touch zeigt dir mithilfe von bekannten Wi-Fi-Hot-Spots, wo du bist. Mit der Stichwortsuche kannst du auch interessante Orte finden. Wenn du z. B. ""Kaffee"" eingibst, werden dir alle Cafés in der Nähe angezeigt.
     
    Wo geht's lang?
    Gib einfach eine Adresse ein, um Wegbeschreibungen abzurufen - von jedem Ort aus. Wähle das Transportmittel wie Auto, öffentliches Verkehrsmittel oder zu Fuß. Die Route lässt sich dann Schritt für Schritt anzeigen. Du kannst dem markierten Weg auf der Karte folgen und selbst die Fahrtdauer wird angezeigt. Oder markiere zwei Orte und lass dir die beste Route zwischen diesen anzeigen.
     
    Verschiedene Kartendarstellungen
    Wie bei Google Karten auf deinem Computer kannst du mit dem Programm ""Karten"" auf dem iPod touch zwischen unterschiedlichen Darstellungen von Google-Karten, Satellitenbildern und einer Hybriddarstellung wechseln. Und mit Multi-Touch kannst du unterwegs zoomen, den Ausschnitt bewegen und die Darstellung ändern.
     
    Verkehrsinformationen
    Die Verkehrsinformationen geben dir anhand der grünen, roten und gelben Markierungen einen Überblick über die Verkehrssituation auf deiner Route.
     
    YouTube
    Skateboard Moves, die so nicht geplant waren. Witzige Werbespots aus anderen Ländern. Was auch immer du gern auf YouTube ansiehst - der iPod touch ist für dich da.
     
    Videogrüße von unterwegs.
    Maile Links deiner Lieblingsvideos an Freunde. Tippe auf der Detailseite des YouTube Videos auf ""Senden"", und schon erstellt der iPod touch eine Mail mit dem zugehörigen Videolink.
     
    Auf YouTube suchen.
    Stöber in Videokategorien wie ""Highlights"", ""Topvideos"", ""Neue Videos"" oder ""Bestwertung"". Du kannst auch per Schlagwort nach einem Video suchen. Etwas Passendes gefunden? Mit einem Lesezeichen kannst du das Video auch vormerken und später ansehen.
     
    Nike + iPod Kompatibilität
    Rock dein Training. Der iPod touch hat eine integrierte Unterstützung für Nike + iPod. Das ist Musik und Motivation in einem.
    Finetuning für dein Lauftraining.
     
    Nike + iPod Sensor
    Der iPod touch hat eine integrierte Unterstützung für Nike + iPod. Einfach den Nike + iPod Sensor (separat erhältlich) in die Nike+ Schuhe stecken und los geht's. Der Sensor überträgt deine Laufdaten drahtlos an den iPod touch und zeichnet Laufzeit, Laufstrecke und Kalorienverbrauch auf. Du erhältst sogar Feedback zum Trainingsfortschritt.
     
    Finetuning für dein Cardio Workout
    Diese Funktion kann auch zusammen mit neuen, in vielen Fitnessstudios vorhandenen Geräten für das Ausdauertraining gekoppelt werden. Such dir einfach ein mit Nike + iPod kompatibles Fitnessgerät wie beispielsweise Laufbänder, Ellipsentrainer, Stepper und Hometrainer.
     
    Synchronisieren mit nikeplus.com
    Später kannst du am Computer den iPod touch via iTunes synchronisieren und deine Trainingsdaten an nikeplus.com übertragen. Auf dieser Website kannst du dein Training verfolgen, dir Ziele setzen und deine Freunde herausfordern.
     
    Sprachmemos
    Du hast vielleicht ein ganz gutes Gedächtnis, aber manchmal ist es besser, kleine (und große) Infos einfach irgendwo festzuhalten. Mit ""Sprachmemos"" kein Problem.
     
    Memos (oder alles andere)aufnehmen
    Nimm eine Aufgabenliste, geniale Ideen oder eine Wette zwischen dir und deinem Freund auf. Mit dem Programm ""Sprachmemos"" kannst du über die Apple Earphones mit Fernbedienung und Mikro oder ein externes Mikrofon aufnehmen, was immer du willst. Sprachmemos kannst du selbst dann aufnehmen, wenn du den iPod touch gerade verwendest, um Mails zu checken oder im Web zu surfen.
     
    Memos bearbeiten
    Aufgenommene Memos kannst du direkt auf dem iPod touch trimmen. So behältst du nur das, was du wirklich brauchst.
     
    Memos sortieren
    Ordne deine Memos mithilfe von Etiketten aus einer vordefinierten Liste oder erstelle eigene Etiketten.
     
    Memos teilen
    Maile Memos an Freunde und Kollegen. Mit dem iPod touch aufgenommene Memos werden via iTunes mit deinem Mac oder PC synchronisiert, damit du sie später mit anderen teilen kannst.
     
    Weitere Funktionen
    Auf dem iPod touch ist die neueste Software schon installiert. Und außerdem gibt's praktische Apps wie Kontakte, Kalender, Notizen, Aktien und Wetter.
     
    iPod touch 3.1 Softwarefunktionen.
     
    Genius Mixe
    Diese neue Funktion ist wie ein privater DJ, der deine iTunes Mediathek durchsucht, um Songs zu finden, die gut zusammenpassen und aus diesen dann tolle Mixe erstellt. Alles ganz automatisch.
     
    Genius Empfehlungen für Apps
    Im App Store gibt's zehntausende Apps. Wie soll man da die richtig collen neuen finden? Mit Genius. Denn Genius sieht sich die Apps an, die du schon hast, und empfiehlt dir weitere.
     
    Peer-to-Peer-Spiele
    Die neusten Spiele kannst du ganz leicht mit Freunden spielen - egal, ob sie neben dir oder in einer anderen Ecke des Landes sitzen.
     
    Kauf Filme, Fernsehsendungen und Hörbücher via Wi-Fi
    Lade via Wi-Fi Filme, Fernsehsendungen, Musikvideos und Hörbücher aus dem iTunes Store auf deinen iPod touch.
     
    Tastatur im Querformat
    Du brauchst mehr Platz zum Tippen? Dreh den iPod touch ins Querformat, um in Mail, Notizen und Safari mit einer größeren Tastatur zu arbeiten.
     
    Cut, Copy & Paste
    Einfach Text und Fotos ausschneiden, kopieren und wieder einsetzen - selbst zwischen Programmen. Du kannst auch Inhalte aus dem Web kopieren.
     
    Spotlight Suche
    Gesucht, gefunden - von einem Ort aus. Spotlight durchsucht alle deine Kontakte, E-Mails, Kalender und Notizen und auch alle Songs und Videos.
     
    Stereo Bluetooth
    Hör Musik und andere Audioinhalte drahtlos. Verbinde den iPod touch mit kompatiblen Bluetooth Stereokopfhörern.
     
    Automatischer Wi-Fi-Login
    Wenn du dich einmal bei einem Wi-Fi-Hotspot anmeldest, loggt der iPod touch sich beim nächsten Mal automatisch ein.
     
    Shake to Shuffle
    Schüttel den iPod kurz, und schon springt er nach dem Zufallsprinzip zu einem anderen Song in deiner Sammlung. Lass dich einfach überraschen.
     
    Bedienungshilfen
    Der neue iPod touch hat standardmäßig Bedienungshilfen integriert, mit denen auch Menschen mit Beeinträchtigungen alles, was der iPod touch zu bieten hat, erleben können. Alle Bedienungshilfen des iPod touch ansehen
     
    Kindersicherung
    Du entscheidest, welche Musik, Videos und Apps auf dem iPod touch für deine Kinder geeignet sind.
    Der iPod touch hat auch die folgenden praktischen Apps:
     
    Kalender
    Das Programm ""Kalender"" funktioniert mit Yahoo!, Google, Microsoft Outlook, iCal, MobileMe und Microsoft Exchange ActiveSync für Unternehmen. Füge Termine hinzu, lass dich an Termine erinnern, und abonniere Kalender, damit du über Feiertage und Sportveranstaltungen auf dem Laufenden bleibst.
     
    Kontakte
    Namen, E-Mail-Adressen, Telefonnummern und mehr - immer zur Hand. Synchronisier Kontakte in iTunes auf dem Mac oder PC mit dem iPod touch. Neue Kontakte kannst du auch unterwegs mit einem einfachen Fingertipp hinzufügen.
     
    Notizen
    Schluss mit Papier und Bleistift. Mach dir mit ""Notizen"" auf dem iPod schnell eine Notiz, damit du wichtige Infos immer parat hast. Maile deine Gedanken mit der integrierten Mail-Funktion an dich oder andere.
     
    Aktien
    Die Aktien App auf dem iPod touch zeigt dir Börseninformationen für die Aktien, die dich interessieren. Wenn du nähere Details über eine Aktie brauchst, tipp auf ""Y!"", um im Handumdrehen Yahoo! Finance zu öffnen.
     
    Wetter
    Informier dich über das Wetter in der ganzen Welt oder zuhause. Füge die gewünschten Städte hinzu und zeige eine sechstägige Vorhersage für alle an. Tipp auf ""Y!"", um den Yahoo! Stadtführer zu öffnen, der dir zeigt, wo was los ist.
     
    Rechner
    Im Programm ""Rechner"" des iPod touch stecken gleich zwei Rechner. Im Hochformat kannst du ihn als einfachen Taschenrechner verwenden. Dreh den iPod touch ins Querformat, um aus ihm einen wissenschaftlichen Rechner zu machen.
     
    iPod touch Technologie
    Dank der revolutionären Hardwaretechnologie im iPod touch kannst du alle Funktionen mit Streichen, Tippen und Auf- oder Zuziehen steuern. Deswegen wirkt das Autorennen so echt. Deswegen kannst du das, was du eben im Café mitbekommen hast, sofort twittern. Und genau deswegen ist der iPod touch der beste iPod aller Zeiten.
     
    Multi-Touch
    Das Multi-Touch-Display besitzt einen Schutzfilm über der kapazitiven Sensorik, die Berührungen anhand elektrischer Felder erkennt. Diese Informationen werden an das darunterliegende LCD-Display übertragen. Dank der Software des iPod touch kannst du mit Cover Flow durch Alben stöbern, durch deine Fotos blättern, mit Auf- und Zuziehen Bildausschnitte von Websites zoomen und Spiele superpräzise steuern.
     
    Beschleunigungssensor
    Der iPod touch reagiert über einen integrierten Beschleunigungssensor auf Bewegungen. Dieser Sensor erkennt, wenn du deinen iPod touch ins Querformat drehst und verändert automatisch den Inhalt des Displays. Die Technologie des Beschleunigungssensors kommt besonders bei Spielen gut, denn damit bist du mitten im Spielgeschehen. Das ist perfekt für Autorennen, bei denen der ganze iPod zum Lenkrad wird, und Geschicklichkeitsspiele wie Rolando, bei denen du das Spiel mit deinen Bewegungen steuerst
     
    Drahtlos
    Der iPod touch hat eine integrierte Unterstützung für drahtlosen 802.11b/g Internetzugriff. Überall, wo es ein Wi-Fi-Netzwerk gibt, kommst du mit deinem iPod touch ins Internet. Im Café mailen. Am Flughafen im Web surfen. Spiele vom Sofa aus kaufen. Im iTunes Store stöbern und Musik kaufen und laden. Der iPod touch findet nahegelegene Wi-Fi-Hot-Spots, auch geschützte Netzwerke. Wenn du ein bestimmtes Netzwerk bisher noch nicht verwendet hast, Drahtlos Symbol musst du beim ersten Mal ein Kennwort eingeben, das sich der iPod touch dann merkt. Wenn du dann das nächste Mal in Reichweite dieses Netzwerks bist, loggt er sich automatisch ein.
     
    Bluetooth
    Bluetooth ist eine drahtlose Technologie, mit der du Geräte ohne lästige Kabel verwenden kannst. Was bedeutet das für den iPod touch? Du kannst jetzt mit dem iPod touch und Bluetooth Kopfhörern Musik hören, ganz egal, wo im Raum der iPod ist. Du kannst also auf dem Bett relaxen, während der iPod auf dem Schreibtisch aufgeladen wird. Bluetooth auf dem iPod touch eignet sich auch besonders für Peer-to-Peer-Spiele.
     
    Design
    Der iPod touch ist von außen genau so großartig wie von innen. Du brauchst nur einen in die Hand zu nehmen. Das Gehäuse des iPod touch ist gerade einmal 8,5 mm hoch. Das optische Glas auf der Vorderseite und die Rückseite aus poliertem Edelstahl geben ihm einen eleganten Touch und fühlen sich in der Hand einfach gut an. Schalte ihn ein und du wirst über das brillante 3,5"" Display einfach staunen. Der iPod touch ist die perfekte Kombination aus großartigem Design und revolutionärer Technologie - das perfekte Paket.
    ";2;False;0;;;Apple iPod Touch 8 GB schwarz mit integrierter WiFi Funktion;apple-ipod-touch-8-gb-schwarz-2;True;True;PD-01085;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;169.9000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;40871,5555092593;44;1;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000434-apple-ipod-touch-64-gb-schwarz.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000435-apple-ipod-touch-64-gb-schwarz.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000436-apple-ipod-touch-64-gb-schwarz.jpg;2;;False;;;;;False;False;False;;;;;False;;;;;; -5;0;True;Samsung Galaxy S II (i9100) DualCore Smartphone schwarz;"Samsung Galaxy S II (i9100) DualCore Smartphone (10.9 cm (4.3 Zoll) Super-Amoled Plus Display, Android 2.3, 8 MP Full-HD Kamera, 2 MP Frontkamera) schwarz ";"
    Samsung launcht mit dem Galaxy S II den Nachfolger des Bestsellers Galaxy S. Das Galaxy S II ist nicht nur das schlankste (8,49 mm), sondern dank des 1,2 GHz Dual-Core Prozessors auch das schnellste Smartphone seiner Klasse. Darüber hinaus besticht es durch ein 4,3"" Super Amoled Plus Touch-Display. Das Galaxy S II verwendet als Betriebssystem die aktuellste Android 2.3 Version – auch bekannt unter dem Namen Gingerbread. Die integrierte 8 Megapixel Kamera mit LED Blitz hält die schönsten Momente in erstklassiger Qualität fest – darüber hinaus ermöglicht die 2 Megapixel Frontkamera Video Telefonate in beeindruckender Qualität. Das Schreiben von E-Mails und SMS gelingt unkompliziert dank Swype®-Texteingabe. Zahlreiche aktuelle und nützliche Apps stehen im Android Market™ zum Download bereit. Die integrierte Google Maps Navigation™ führt ans gewünschte Ziel. AllShare, HD Video, Exchange ActiveSync und eine Vielzahl an weiteren Applikationen lassen keine Wünsche offen. Ein erstklassiges Zusammenspiel von Hardware und Funktionen leistet sein Übriges für ein ausgezeichnetes Nutzererlebnis auf höchstem Niveau!
     
    4,27-Zoll SUPER AMOLED Plus
    Bekennen Sie Farbe! Dieses brillante Display bietet den besten Farbumfang, ein hohes Kontrastverhältnis sowie ultimative Schärfe bei Bildern. Die bahnbrechende Verkürzung der Video-Reaktionszeit sorgt für ruckfreie Videowiedergabe. Die neue Technologie benötigt weniger Platz und Energie: Im Vergleich zum Vorgänger benötigt das Display 18% weniger Energie. Es ist damit eines der dünnsten, langlebigsten Smartphones am Markt.
     
    Brillante Performance
    Das Unmögliche ist möglich. Der Samsung Dual Core Application Prozessor ist die reaktionsschnelle Antwort im Bereich mobile Performance. Er bietet Multitasking in Hochgeschwindigkeit, schnelles Laden von Internetseiten, schnelle Reaktionszeiten, eine intuitive Benutzeroberfläche, blitzschnelle Bildbearbeitung und Spiele mit hoher Performance. Und mit der superschnellen Möglichkeit zum Encodieren und Decodieren, die alles im Bereich Videoaufzeichnung und -wiedergabe (1080p / 30fps) unterstützt, stellt er alle anderen Dual Core-Prozessoren in den Schatten. Problemloses Video- oder Musik-Streaming bekommt dank des schnellen Drahtlosstandards HSPA 21 Mbps einen großen Schub. Hervorragende Rechenleistung, herausstechende Performance.
     
    Schlankes Design
    Schlank, schlanker, GALAXY S II. Das Samsung GALAXY S II führt die Riege an – mit nur 8,49 mm und einem luxuriösen Design liegt es zudem gut in der Hand. Das GALAXY S II ist eines der schlanksten Smartphones und bietet außerdem HyperSkin für einen schönen Metall-Look mit einer fingerabdruckfreien und rutschfesten Akkuabdeckung.
     
    Readers Hub
    Lassen Sie Ihre Bücher zu Hause: Das Samsung GALAXY S II übernimmt diese Aufgabe. Stöbern Sie im Readers Hub in Ihrer Bücherei mit Klassikern oder suchen Sie in mehr als 2 Millionen Büchern die neusten Bestseller. Sie können auch 2.500 Magazine in 20 Sprachen und 1.600 Zeitungen in 47 Sprachen zur Lieferung einrichten. Mit klarem, deutlichem Text und der hohen Bedienerfreundlichkeit macht das Lesen Spaß: vergrößern, nur Text und Seitenansichten, Audiozugriff sowie schnelles Verteilen per E-Mail sind nur einige Funktionen. Glauben Sie an Bücher, beschränken Sie sich jedoch nicht nur auf Papier.
     
    8-Megapixel-Kamera mit LED-Blitz
    Immer gute Fotos. Der 8-Megapixel-Kamera mit Autofokus entgehen auch bei Action-Fotos keine Details. Machen Sie auch bei schlechten Lichtverhältnissen mit dem integrierten LED-Blitz wunderschöne und detaillierte Aufnahmen. Und dank der stark verbesserten Benutzeroberfläche von Android Gingerbread ist selbst schneller Szenenwechsel möglich. Wechseln Sie problemlos auf die 2-Megapixel-Kamera vorne, um Selbstporträts zu machen. Einfach immer gute Bilder.
     
    Aufzeichnung & Wiedergabe in Full-HD
    Werden Sie zum Star. Mit den Möglichkeiten zur Videoaufzeichnung des Samsung GALAXY S II können auch Sie zur Berühmtheit werden. Mit der 1080p Full-HD-Aufzeichnung ist jeder Moment ein potenzielles Meisterwerk in der Entstehung. Erfassen Sie die Action in hoher Auflösung und mit Dual Core-Geschwindigkeit und geben Sie Ihre HD-Aufzeichnungen mit bestechender Klarheit auf dem 4,3"" SUPER AMOLED Plus Display wieder.
     
    Spracherkennung & Sprachübersetzung
    Einfach Sprachbefehle nutzen. Tippen Sie nur doppelt auf die Home-Taste und steuern Sie das Samsung GALAXY S II mit ausgewählten Sprachbefehlen. Führen Sie wichtige Funktionen wie anrufen, Musik hören oder SMS schreiben mit einfachen Sprachbefehlen aus. Sie können auch Ihre Gedanken festhalten, sich selbst eine Notiz schreiben oder unterwegs sogar mit Google Voice Translation eine Übersetzung anfertigen. Galaxy S II kann Ihnen eingehende Nachrichten auch vorlesen.
     
    Game Hub
    Noch mehr Spielspaß. Über den Game Hub von Samsung GALAXY S II können Sie hochwertige Spiele herunterladen: 12 soziale Netzwerkspiele und 13 Prämiumspiele einschließlich Gameloft’s Let Golf 2 und Real Football 2011. Sie können nach Spielen und Informationen zu Neuerscheinungen suchen oder einfach nur spielen. Mit einem Beschleunigungsaufnehmer, einem magnetischen Sensor und Gyroskop-Sensor heben sich Spiele mit Hand- und Armbewegungen deutlich aus der Masse ab. Die kleinste Bewegung reicht bereits aus – das ist spannende Unterhaltung.
     
    Social Hub
    Mit dem Social Hub lassen sich Ihre Online-Kontakte besser organisieren und synchronisieren. Sammeln Sie Ihre Informationen aus E-Mails, SMS, IM und SNS in einem einheitlichen Posteingang – Interaktionen mit anderen sind so schneller und auf die von Ihnen gewünschte Art möglich.
     
    Music Hub
    Musik darf nicht fehlen. Der neue native Music-Player von Samsung bietet ein intuitives Wiedergabesystem zum Suchen, Entdecken, Anspielen, Kaufen und Herunterladen von Musikstücken für unterwegs. Die App bietet auch viele Informationen zum Kauf sowie Zugriff auf alle gewünschten Künstler, Liedtexte und Bewertungen. Sie können Empfehlungen für neue Songs abrufen und durch Bassverstärkung und 5.1 Kanal-Sound den Hörspaß noch mehr steigern.
     
    Microsoft Exchange ActiveSync
    Das Samsung GALAXY S II ist für sicheren Zugriff auf Unternehmensressourcen auf einem Microsoft Exchange Server optimiert, damit Sie in Bezug auf geschäftliche E-Mails, Terminplaner, Kontakte und Aufgabensynchronisation auf dem Laufenden sind. Das Handy bietet die umfangreichste mobile Implementierung von Exchange ActiveSync. Es bietet das sicherste Mobile Device Management unter den Smartphones und unterstützt die meisten Richtlinien und Einschränkungen unter den Android ActiveSync Clients und ermöglicht Kommunikation in Echtzeit mit Telefonen der Mitarbeiter, um Einstellungen per Fernzugriff zu konfigurieren, die Einhaltung der Richtlinien zu überwachen, die Sicherheit bei synchronisierten Daten zu gewährleisten und verwaltete Telefone zu sperren oder Daten zu löschen.
    ";2;False;0;;;Samsung Galaxy S II (i9100) DualCore Smartphone schwarz;samsung-galaxy-s-ii-i9100-dualcore-smartphone-schwarz;True;True;PD-01084;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;439.9000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;40871,5057638889;76;5;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000172-samsung-galaxy-s-ii-i9100-dualcore-smartphone-schwarz.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000173-samsung-galaxy-s-ii-i9100-dualcore-smartphone-schwarz.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000174-samsung-galaxy-s-ii-i9100-dualcore-smartphone-schwarz.jpg;2;;False;;;;;False;False;False;;;;;False;;;;;; -5;0;True;Nokia N9 Smartphone schwarz;"Nokia N9 Smartphone (9,9 cm (3,9 Zoll) Display, 16GB, Touchscreen, 8 Megapixel Kamera) schwarz ";"
    Nokia N9 Smartphone
    Formatfüllender Touchscreen
    Ein einzigartiges Smartphone mit formatfüllendem Touchscreen. Die gewölbte Oberfläche aus kratzfestem Glas geht nahtlos in das glatte, aus einem Block gefertigte Gehäuse über. Jedes Detail strahlt Innovation aus. Auf dem brillanten AMOLED-Touchscreen erscheint alles in lebendigen Farben und das gewölbte Glas macht den Wechsel zwischen Apps per Fingerbewegung zum Kinderspiel.
     
    Einfach nur eine Fingerbewegung - Überzeugend benutzerfreundlich
    Alles läuft auf eine einfache Fingerbewegung hinaus. Das macht die Nutzung dieses Smartphones so intuitiv wie nie zuvor. Es gibt keine Zurück- oder Menü-Taste mehr – nur fliessende Fingerbewegungen, während Sie von App zu App wechseln. Mit einer Fingerbewegung über eine beliebige Ecke des Touchscreens gelangen Sie zur Startansicht, mit einer weiteren Bewegung wechseln Sie zwischen den drei Startansichten.
     
    Eine Startansicht - Drei einfache Ansichten
    Drei Ansichten sind alles, was Sie brauchen. In der vertrauten App-Ansicht starten Sie Anwendungen, eine weitere Ansicht zeigt die offenen Apps und macht Multitasking zum Kinderspiel: Sie machen genau dort weiter, wo Sie aufgehört haben.- Die Ansicht ""Ereignisse"" bringt Sie jederzeit auf den neuesten Stand der Dinge. Live-Feeds von Facebook und Twitter, E-Mails in Echtzeit, RSS-Feeds und mehr – alles an einer Stelle.
     
    Karten und Navigation kostenlos
    Live-Feeds von Facebook und Twitter, E-Mails in Echtzeit, RSS-Feeds und mehr – alles an einer Stelle. Sie finden die besten Angebote in Ihrer Stadt wie Cafés, Geschäfte, Konzerte, Hotels und mehr. Für mehr als 80 Städte weltweit steht Ihnen eine Übersicht von Strecken und Haltestellen des öffentlichen Nahverkehrs zur Verfügung. Entsprechendes Kartenmaterial ist bereits vorinstalliert, sodass Sie sofort starten können. Die Anwendung ""Fahren"" ist dank einfacher Bedienung über Touchscreen für die Verwendung im Auto optimiert.
     
    Browser der nächsten Generation
    Zeit für mehr Tempo. Das Nokia N9 bietet einen schnellen mobilen Internet-Browser und Seiten werden in kürzester Zeit aufgebaut. Die Unterstützung für HTML5 bedeutet für Sie das Beste aus dem Web, inklusive interaktiver Apps und schneller Videowiedergabe. Der Browser reagiert schnell auf jede Berührung. Sie können mehrere Seiten gleichzeitig öffnen und schnell zwischen den Seiten wechseln.
     
     
     
    8-Megapixel-Kamera mit Optik von Carl Zeiss
    Die Gelegenheit für ein gutes Foto kommt schnell und ist ebenso schnell vorbei. Mit der integrierten 8-Megapixel-Kamera mit Optik von Carl Zeiss können Sie brillante Fotos oder Videos in herausragender HD-Qualität aufnehmen.
     
    Die besten Apps und Spiele
    Apps sind heutzutage allgegenwärtig. Das Wichtigste ist jedoch die Qualität und nicht, wie viele man besitzt. Auf dem Nokia N9 sind die besten Apps wie Skype, Facebook, Twitter, AccuWeather und AP Mobile bereits vorinstalliert. Auch die Vollversion von Angry Birds ist bereits vorinstalliert – für viele Stunden Spass. Und im Ovi Store gibt es viele weitere Apps und Spiele.
    ";2;False;0;;;Nokia N9 Smartphone schwarz;nokia-n9-smartphone-schwarz;True;True;PD-01083;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;539.0000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;40871,4967013889;74;17;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000164-nokia-n9-smartphone-schwarz.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000165-nokia-n9-smartphone-schwarz.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000166-nokia-n9-smartphone-schwarz.jpg;3;;False;;;;;False;False;False;;;;;False;;;;;; -5;0;True;Nokia N9 Smartphone magenta;Nokia N9 Smartphone (9,9 cm (3,9 Zoll) Display, 16GB, Touchscreen, 8 Megapixel Kamera) magenta;"
    Nokia N9 Smartphone
    Formatfüllender Touchscreen
    Ein einzigartiges Smartphone mit formatfüllendem Touchscreen. Die gewölbte Oberfläche aus kratzfestem Glas geht nahtlos in das glatte, aus einem Block gefertigte Gehäuse über. Jedes Detail strahlt Innovation aus. Auf dem brillanten AMOLED-Touchscreen erscheint alles in lebendigen Farben und das gewölbte Glas macht den Wechsel zwischen Apps per Fingerbewegung zum Kinderspiel.
     
    Einfach nur eine Fingerbewegung - Überzeugend benutzerfreundlich
    Alles läuft auf eine einfache Fingerbewegung hinaus. Das macht die Nutzung dieses Smartphones so intuitiv wie nie zuvor. Es gibt keine Zurück- oder Menü-Taste mehr – nur fliessende Fingerbewegungen, während Sie von App zu App wechseln. Mit einer Fingerbewegung über eine beliebige Ecke des Touchscreens gelangen Sie zur Startansicht, mit einer weiteren Bewegung wechseln Sie zwischen den drei Startansichten.
     
    Eine Startansicht - Drei einfache Ansichten
    Drei Ansichten sind alles, was Sie brauchen. In der vertrauten App-Ansicht starten Sie Anwendungen, eine weitere Ansicht zeigt die offenen Apps und macht Multitasking zum Kinderspiel: Sie machen genau dort weiter, wo Sie aufgehört haben.- Die Ansicht ""Ereignisse"" bringt Sie jederzeit auf den neuesten Stand der Dinge. Live-Feeds von Facebook und Twitter, E-Mails in Echtzeit, RSS-Feeds und mehr – alles an einer Stelle.
     
    Karten und Navigation kostenlos
    Live-Feeds von Facebook und Twitter, E-Mails in Echtzeit, RSS-Feeds und mehr – alles an einer Stelle. Sie finden die besten Angebote in Ihrer Stadt wie Cafés, Geschäfte, Konzerte, Hotels und mehr. Für mehr als 80 Städte weltweit steht Ihnen eine Übersicht von Strecken und Haltestellen des öffentlichen Nahverkehrs zur Verfügung. Entsprechendes Kartenmaterial ist bereits vorinstalliert, sodass Sie sofort starten können. Die Anwendung ""Fahren"" ist dank einfacher Bedienung über Touchscreen für die Verwendung im Auto optimiert.
     
    Browser der nächsten Generation
    Zeit für mehr Tempo. Das Nokia N9 bietet einen schnellen mobilen Internet-Browser und Seiten werden in kürzester Zeit aufgebaut. Die Unterstützung für HTML5 bedeutet für Sie das Beste aus dem Web, inklusive interaktiver Apps und schneller Videowiedergabe. Der Browser reagiert schnell auf jede Berührung. Sie können mehrere Seiten gleichzeitig öffnen und schnell zwischen den Seiten wechseln.
     
     
     
    8-Megapixel-Kamera mit Optik von Carl Zeiss
    Die Gelegenheit für ein gutes Foto kommt schnell und ist ebenso schnell vorbei. Mit der integrierten 8-Megapixel-Kamera mit Optik von Carl Zeiss können Sie brillante Fotos oder Videos in herausragender HD-Qualität aufnehmen.
     
    Die besten Apps und Spiele
    Apps sind heutzutage allgegenwärtig. Das Wichtigste ist jedoch die Qualität und nicht, wie viele man besitzt. Auf dem Nokia N9 sind die besten Apps wie Skype, Facebook, Twitter, AccuWeather und AP Mobile bereits vorinstalliert. Auch die Vollversion von Angry Birds ist bereits vorinstalliert – für viele Stunden Spass. Und im Ovi Store gibt es viele weitere Apps und Spiele.
    ";2;False;0;;;Nokia N9 Smartphone magenta;nokia-n9-smartphone-magenta;True;True;PD-01082;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;549.0000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;40871,4934027778;"74;2095";17;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000655-nokia-n9-smartphone-magenta.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000656-nokia-n9-smartphone-magenta.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000657-nokia-n9-smartphone-magenta.jpg;2;;False;;;;;False;False;False;;;;;False;;;;;; -5;0;True;"Apple iPhone 4S weiß ";Apple iPhone 4S weiß;"
    Das neue iPhone 4S - jetzt mit Dual Core A5 Chip, neuer 8 MegaPixel-Kamera, iOS 5 und iCloud sowie dem neuen Siri.
     
    Dual-Core A5 Chip. Der leistungsstärkste iPhone Prozessor aller Zeiten.
    Mit zwei Prozessorkernen liefert der A5 Chip bis zu 2x mehr Leistung und bis zu 7x schnellere Grafik. Das wirst du merken. Und zwar schnell. Das iPhone 4S reagiert extrem schnell, was du sofort merkst, wenn du Apps öffnest, im Web surfst, beim Spielen und auch bei allem anderen. Und ganz egal was du machst, du kannst es richtig lange machen. Denn der A5 Chip ist so effizient, dass das iPhone 4S eine enorm lange Batterielaufzeit hat.
     
    Die Kaum-zu-glauben-dass-es-ein-Handy-ist Kamera.
    Wahrscheinlich die beste Kamera, die es je auf einem Telefon gab. Und dank fortschrittlichster Optik ist sie wahrscheinlich auch die einzige Kamera, die du brauchst. Schließlich hat sie eine Auflösung von 8 Megapixeln und eine spezielle Linse mit einer größeren f/2,4 Blende. Außerdem bietet sie einen optimierten rückwärtig belichteten Sensor, exzellenten Weißabgleich, verbesserte Farbgenauigkeit, Gesichtserkennung und reduzierte Bewegungsunschärfe. Es ist also ganz egal, wie viele Leute, wie viel Licht und wie viel Action du aufnimmst – alles sieht genau so aus, wie es aussehen soll. Und warte erst, bis du die Fotos siehst.
     
    Siri. Dein intelligenter, hilfsbereiter Assistent.Du musst ihn nur fragen.
    Jetzt kannst du dein iPhone einfach mit deiner Stimme benutzen. Sprich mit Siri so, wie du mit einer Person sprichst und sag ""Erinnere mich daran, Mama anzurufen, wenn ich zu Hause bin"" oder ""Brauche ich einen Schirm?"". Siri spricht Deutsch und versteht nicht nur, was du sagst, sondern auch was du meinst. Es erkennt, welche Apps für die richtige Antwort nötig sind. Und antwortet dir dann – wie dein persönlicher Assistent. Siri telefoniert, sendet Nachrichten, plant Meetings, legt Erinnerungen fest und mehr. Was noch? Frag einfach, und Siri sagt es dir selbst.
     
    Videoaufnahmen. In fantastischem 1080p HD.
    Nimm fantastische 1080p HD Videos auf, wo immer du bist. Durch die neue fortschrittliche Optik der Kamera ist das Licht immer genau richtig, die Farben immer leuchtend und alles sieht noch besser aus, als du es in Erinnerung hattest. Die Bildstabilisierung gleicht verwackelte Aufnahmen aus. Und du kannst Videos direkt auf dem iPhone bearbeiten und so schnell mit anderen teilen, wie du sie aufnimmst.
     
    iOS. Das fortschrittlichste mobile Betriebssystem der Welt. Und auch das einfachste.
    Jede neue iOS Version bietet Möglichkeiten, die alles noch einfacher machen. Deshalb ist iOS allen anderen um Jahre voraus. Und iOS 5 geht wieder einen großen Schritt weiter und bringt mehr als 200 neue Features auf das iPhone 4S. Hier sind nur einige unserer Favoriten.
     
    iCloud. Deine Inhalte. Auf all deinen Geräten.
    Mit iCloud kannst du deine Inhalte ganz einfach verwalten, denn iCloud erledigt alles für dich. iCloud speichert deine Musik, Fotos, Apps, Mails, Kontakte, Kalender, Dokumente und mehr und pusht alles drahtlos an all deine Geräte. Automatisch, nahtlos und einfach so.
     
    Retina Display.Das ist ganz klar.
    Auf dem iPhone 4S siehst du einfach alles gestochen scharf und lebendig. Das Retina Display ist das höchstauflösende Telefondisplay aller Zeiten. Die Pixeldichte ist so hoch, dass das menschliche Auge keine einzelnen Pixel erkennen kann. Was du aber ganz bestimmt siehst, sind gestochen scharfe Texte, Grafiken und Bilder. Alles sieht sogar noch besser aus als gedruckt.
     
    FaceTime. Wink doch mal hallo.
    Mit FaceTime hörst du nicht nur eine Stimme, sondern siehst auch das Gesicht dazu – von iPhone zu iPhone, iPad 2, iPod touch oder Mac über Wi-Fi. Es ist also ganz egal, wo die anderen sind und wo du bist – du bist immer da. FaceTime Anrufe sind so einfach wie ganz normale Anrufe. Und mit Siri sind sie sogar noch einfacher. Sag Siri einfach, dass du mit deiner Mutter facetimen willst, und schon seht ihr euch. Einfach so. Du verpasst nie wieder ein wichtiges Ereignis, Meeting oder einen guten Lacher. Und wer würde sich nicht darüber freuen, dich zu sehen?
     
    AirPlay. Live vom iPhone auf deinen Fernseher.
    Mit AirPlay kannst du Inhalte von deinem iPhone via Apple TV drahtlos an deinen HD Fernseher und Lautsprecher streamen.6 Und mit der AirPlay Synchronisierung erscheint alles, was du auf deinem iPhone siehst oder machst, gleichzeitig auf deinem HD Fernseher.
     
    AirPrint.Alles drahtlos drucken.
    Drucke deine Mails, Fotos, Webseiten und Dokumente einfach über Wi-Fi von deinem iPhone aus.7 Ganz ohne Software zu laden, Treiber zu installieren oder Kabel anzuschließen. Nur ein paar Fingertipps und schon hast du das, was eben noch auf dem iPhone war, als Ausdruck in der Hand.
     
    Besser. Schneller. Weltweiter.
    Das iPhone 4S ist das erste Telefon, das zum Übertragen und Empfangen intelligent zwischen zwei Antennen wechselt. So ist die Anrufqualität deutlich besser. Außerdem verdoppeln die Antennen die maximale HSDPA Datengeschwindigkeit auf 14,4 Mbit/s.8 Und das bedeutet schnellere Verbindungen, schnelleres Laden und Neuladen und schnellere Downloads. Das iPhone 4S ist ein Telefon für die ganze Welt. Du kannst es also fast überall verwenden. Ob GSM- oder CDMA-Standard spielt keine Rolle. Nutze es via Roaming in GSM-Netzen in 200 Ländern weltweit.
     
    Integrierte Apps. Machen alles, damit du alles machen kannst.
    Ganz Alltägliches erledigst du mit dem iPhone 4S auf ganz außergewöhnliche Weise. Mach fantastische Fotos und nimm HD Videos auf. Sieh Freunde und Familie mit FaceTime. Tauche auf dem Retina Display richtig ins Web ein. Check deine Mails. Sende Nachrichten. Lege Erinnerungen fest. Schau in deinen Kalender. Oder sag Siri einfach, wie es dir helfen soll. Siri findet dann selbst heraus, welche Apps es verwenden muss.
     
    Aufgrund der sehr umfangreichen Leistungsmerkmale können wir Ihnen hier nur einen Auszug präsentieren. Die vollständigen Funktionsbeschreibungen inkl. einer Vielzahl von Videos entnehmen Sie bitte der Herstellerwebseite.
    •Apple iPhone 4S
    •115,2 x 58,6 x 9,3 mm klein und 140 g leicht
    •Kapazität: 16 GB Flash-Laufwerk
    •Kamera, Fotos und Video:
    • 8.0 Megapixel Kamera
    • Videoaufnahme, HD (1080p) bis zu 30 fps mit Audio
    • Fotos und Videos in VGA-Qualität mit bis zu 30 fps mit der Kamera an der Vorderseite
    • Fokussieren per Fingertipp für Videos und Fotos LED-Blitz
    • Geotagging für Fotos und Videos
    •Display:
    • Retina Display
    • 3,5""-Multitouch-Display (8,89 cm Diagonale)
    • Auflösung von 960 x 640 Pixeln mit 326ppi
    • Typisches Kontrastverhältnis: 800:1
    • Fettabweisende Beschichtung an der Vorder- und Rückseite
    • Unterstützung für die Anzeige mehrerer Sprachen und Zeichen gleichzeitig
    •Stromversorgung und Batterie:
    • Sprechdauer: bis zu 8 Std. mit 3G, bis zu 14 Std. mit 2G
    • Standbydauer: bis zu 200 Std.
    • Internetnutzung: bis zu 6 Std. mit 3G, bis zu 9 Std. mit Wi-Fi
    • Videowiedergabe: bis zu 10 Std., Audiowiedergabe: bis zu 40 Std.
    •Betriebssystem: iOS 5
    •Mobilfunknetz und Wi-Fi:
    • UMTS/HSDPA/HSUPA (850, 900, 1900, 2100 MHz)
    • GSM/Edge (850, 900, 1800, 1900 MHz)
    • Funktechnologie: 802,11b/g/n Wi-Fi (802.11 nur mit 2,4 GHz), Bluetooth 4.0
    •GPS: Assisted GPS
    •Digitaler Kompass
    •Unterstützte Audioformate: AAC (8 bis 320 KBit/Sek.), Protected AAC (aus dem iTunes Store), HE-AAC, MP3 (8 bis 320 KBit/Sek.), MP3 VBR, Audible (Formate 2, 3, 4, Audible Enhanced Audio, AAX und AAX+), Apple Lossless, AIFF und WAV
    •TV und Video: AirPlay Mirroring to Apple TV support at 720p, Video mirroring and video out support: Up to 1080p with Apple Digital AV Adapter or Apple VGA Adapter (adapters sold separately), Video out support at 576p and 480p with Apple Component AV Cable; 576i and 480i with Apple Composite AV Cable (cables sold separately)
    •Unterstützte Videoformate: H.264 Video: bis zu 720p, 30 Bilder pro Sekunde, Main Level Profile Level 3.1 mit AAC-LC Audio bis zu 160 KBit/Sek., 48 kHz, Stereo-Audio in den Formaten .m4v, .mp4 und .mov; MPEG.4 Video: bis zu 2,5 MBit/Sek., 640 x 480 Pixel, 30 Bilder pro Sekunde, Simple Profile mit AAC-LC Audio bis zu 160 KBit/Sek., 48 kHz, Stereo-Audio in den Formaten .m4v, .mp4 und .mov; Motion JPEG (M-JPEG): bis zu 35 MBit/Sek., 1280 x 720 Pixel, 30 Bilder pro Sekunde, Audio im Format ulaw, PCM Stereo-Audio im Format .avi
    •Sensoren:
    • 3-Achsen-Gyrosensor
    • Beschleunigungssensor
    • Annäherungssensor
    • Umgebungslichtsensor
     
    Lieferumfang:
    iPhone 4S, Apple Earphones mit Fernbedienung und Mikrofon, Dock Connector-auf-USB-Kabel, Dokumentation
    ";2;False;0;;;Apple iPhone 4S weiß;apple-iphone-4s-weiss;True;True;PD-01080;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;2,5000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;779.0000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;40870,6516782407;71;1;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000646-apple-iphone-4s-weis.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000647-apple-iphone-4s-weis.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000648-apple-iphone-4s-weis.jpg;2;;False;;;;;False;False;False;;;;;False;;;;;; -5;0;True;"AVM FRITZ!Fon MT-F VoIP Dect-Telefon ";"AVM FRITZ!Fon MT-F Innovatives DECT-Telefon ";"
    FRITZ!Fon MT-F: HD-Telefonie und komfortable Internetdienste mit DECT.
    Telefonieren Sie mit dem Schnurlostelefon FRITZ!Fon MT-F in bestechender Qualität über das Internet und nutzen Sie komfortable Webdienste. Als intelligentes Telefon der neuesten DECT-Generation vereint das FRITZ!Fon den Komfort der schnurlosen Telefonie mit den Qualitäts- und Leistungsmerkmalen der Internettelefonie (VoIP) in einem Gerät.
     
    Bei der Internettelefonie mit einem FRITZ!Fon wird durch HD-Telefonie (High Definition) ein brillantes, natürliches Klanggefühl erreicht. Sprache lässt sich mit dem FRITZ!Fon in ihrem gesamten Frequenzspektrum wiedergeben, was die Klangqualität von Festnetzverbindungen deutlich übertrifft.
     
    FRITZ!Fon unterstützt die übertragung großer Bandbreiten. Dies ermöglicht neben HD-Telefonie auch die Nutzung komfortabler Internetdienste wie den Empfang von E-Mails, Podcasts, RSS-Feeds und Internetradio.
     
    Die Steuerung von FRITZ!Box-Anwendungen am Handgerät bietet viel zusätzlichen Komfort. Und durch DECT-Eco wird Funkabstrahlung bei Nichtnutzung der Telefone verhindert.
     
    Die FRITZ!Box-Modelle FRITZ!Box Fon WLAN 7390, 7320, 7270, 7240 sowie FRITZ!Box 6360 Cable stellen mit der integrierten DECT-Basisstation, mehreren Anrufbeantwortern und Telefonbüchern für bis zu 300 Einträge den idealen Partner für das FRITZ!Fon dar. Mit der umfangreichen Prozessor- und Speicherausstattung ist auch der Grundstein für neue Anwendungen gelegt. Denn das FRITZ!Fon ist lernfähig:
     
    Als eines der ersten intelligenten Schnurlostelefone wird es auch künftig per Firmware-Updates aktualisiert und um neue Funktionen erweitert werden können.
     
    Umfangreicher Komfort
    Das FRITZ!Fon MT-F ist mit zahlreichen Komfortfunktionen ausgestattet. Dazu zählen Lauthören und Freisprechen in HD-Qualität sowie ISDN-Leistungsmerkmale wie Namensanzeige bei bekannten Rufnummern, Halten, Makeln, Anklopfen, Rufumleitung oder Dreierkonferenz. Die Internettelefonie in HD-Qualität lässt sich so in ihrem vollen Umfang und Komfort nutzen, ohne dass der Computer eingeschaltet sein muss.
     
    FRITZ!Fon informiert zudem aktiv über unbeantwortete Anrufe, Nachrichten auf dem Anrufbeantworter und zeigt eingegangene E-Mails an. An der DECT-Basisstation der FRITZ!Box Fon WLAN 7390, 7320, 7270, 7240 oder FRITZ!Box 6360 Cable lassen sich bis zu 6 FRITZ!Fon-Handgeräte oder andere DECT-Telefone anmelden. Die Erstinstallation und individuelle Einstellungen erfolgen dabei bequem über einfache Assistenten.
     
    FRITZ!Box als idealer Partner
    Das FRITZ!Fon MT-F kann als Mobilteil an jeder DECT-Basisstation eingesetzt werden. Im Zusammenspiel mit der FRITZ!Box Fon WLAN 7390, 7320, 7270, 7240 oder FRITZ!Box 6360 Cable kann jedoch das volle Spektrum der Möglichkeiten beim Telefonieren und Surfen über das Internet ausgenutzt werden.
     
    Die FRITZ!Box Fon WLAN 7390 zum Beispiel vereint eine bisher nicht erreichte Vielfalt in einem Gerät: VDSL- und ADSL-Unterstützung, DECT-Basisstation fürs schnurlose Telefonieren sowie WLAN N für die optimale Datenübertragung. über den Mediaserver sind gespeicherte Filme, Musik und Bilder auch bei ausgeschaltetem Computer im gesamten Netzwerk verfügbar. Darüber hinaus kann der Online-Speicher wie eine lokale Festplatte genutzt werden. So wird die FRITZ!Box Fon WLAN 7390 zur idealen Plattform für vernetzte Anwendungen wie IPTV, Video on Demand oder Mediastreaming.
     
    Bedienung
    - Einfach einschalten und Suchtaste auf FRITZ!Box drücken.
     
    - Einfache Bedienung über intuitives Menü.
     
    - Telefonbuch komfortabel über FRITZ!Box-Oberfläche einrichten und anzeigen.
     
    - In FRITZ!Box integrierte Anrufbeantworter einfach am FRITZ!Fon MT-F einrichten und abhören.
     
    - Blinkende Leuchtdiode signalisiert eingegangene Anrufe, neue Nachrichten auf dem Anrufbeantworter und neue E-Mails.
    ";2;False;0;;;AVM FRITZ!Fon MT-F;avm-fritzfon-mt-f-voip-dect-telefon;True;True;PD-01079;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;79.0000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;40653,4526388889;20;34;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000643-avm-fritzfon-mt-f-voip-dect-telefon.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000644-avm-fritzfon-mt-f-voip-dect-telefon.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000645-avm-fritzfon-mt-f-voip-dect-telefon.jpg;3;;False;;;;;False;False;False;;;;;False;;;;;; -5;0;True;Apple iPhone 4 weiß;Apple iPhone 4 weiß;"
    Produktbeschreibungen
    - Retina Display, 3,5"" Multi-Touch-Widescreen-Display (8,89 cm Diagonale)
    - 960 x 640 Pixel bei 326 ppi
    - Kontrastverhältnis: 800:1
    - Fettabweisende Beschichtung an der Vorder- und Rückseite
    - Unterstützung für die Anzeige mehrerer Sprachen und Zeichen gleichzeitig
    - UMTS/HSDPA/HSUPA
    - GSM/EDGE
    - 802.11b/g/n WLAN
    - Bluetooth 2.1 + EDR
    - Li-Ionen-Akku, Sprechdauer bis zu 14Std. (2G), Internet bis zu 10Std. (WLAN)
     
    ";2;False;0;;;Apple iPhone 4 weiß;apple-iphone-4-weiss;True;True;PD-01078;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;779.0000;779.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.5000;0.0000;0.0000;0.0000;40653,4446064815;71;1;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000641-apple-iphone-4-weis.png;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000642-apple-iphone-4-weis.png;;2;;False;;;;;False;False;False;;;;;False;;;;;; -5;0;True;"Apple iPhone 4 schwarz ";"Apple iPhone 4 schwarz ";"
    Produktbeschreibungen
    - Retina Display, 3,5" Multi-Touch-Widescreen-Display (8,89 cm Diagonale)
    - 960 x 640 Pixel bei 326 ppi
    - Kontrastverhältnis: 800:1
    - Fettabweisende Beschichtung an der Vorder- und Rückseite
    - Unterstützung für die Anzeige mehrerer Sprachen und Zeichen gleichzeitig
    - UMTS/HSDPA/HSUPA
    - GSM/EDGE
    - 802.11b/g/n WLAN
    - Bluetooth 2.1 + EDR
    - Li-Ionen-Akku, Sprechdauer bis zu 14Std. (2G), Internet bis zu 10Std. (WLAN)
    ";2;False;0;;;"Apple iPhone 4 schwarz ";apple-iphone-4-schwarz;True;True;PD-01077;;;False;0;False;;False;False;0;False;0;1;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;2;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;639.0000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;40653,4410763889;71;1;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000639-apple-iphone-4-schwarz.png;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000640-apple-iphone-4-schwarz.png;;1;;False;ounce;;;;False;False;False;;;;;False;;;;;; -5;0;True;Apple iPad 2 schwarz;Apple iPad 2. Generation schwarz;"
    Kapazität
    16-GB-Flash-Laufwerk
    32-GB-Flash-Laufwerk
    64-GB-Flash-Laufwerk

    Abmessungen und Gewicht

    •Höhe: 241,2 mm
    •Breite: 185,7 mm
    •Tiefe: 8,8 mm
    •Gewicht: 601 g

    •Höhe: 241,2 mm
    •Breite: 185,7 mm
    •Tiefe: 8,8 mm
    •Gewicht: 613 g


    Drahtlose Technologie und Funknetz

    •Wi-Fi (802.11a/b/g/n)
    •Bluetooth 2.1 + EDR Technologie
    •Wi-Fi + 3G Modell: UMTS/HSDPA/HSUPA (850, 900, 1900, 2100 MHz); GSM/EDGE (850, 900, 1800, 1900 MHz)
    •Nur Datentransfer
    •Wi-Fi (802.11a/b/g/n)
    •Bluetooth 2.1 + EDR Technologie
    Weitere Infos zu Wi-Fi + 3G

    Display

    •9,7"" Multi-Touch Hochglanz-Widescreendisplay mit LED-Hintergrundbeleuchtung und IPS-Technologie (24,63 cm Diagonale)
    •Auflösung von 1024 x 768 Pixeln bei 132 ppi
    •Fettabweisende Beschichtung
    •Unterstützung für die Anzeige mehrerer Sprachen und Zeichen gleichzeitig
     
    Chip
    Speziell entwickelter, hochleistungsfähiger 1 GHz Dual-Core Apple A5 SOC (System-on-a-Chip) mit niedrigem Stromverbrauch
     
    Kamera, Fotos, Videoaufnahme

    •Rückkamera: Videoaufnahme, HD (720p) bis zu 30 fps mit Audio, Fotokamera mit 5-fach Digitalzoom
    •Frontkamera: Videoaufnahme, VGA mit bis zu 30 fps mit Audio, Fotokamera in VGA-Qualität
    •Fokussieren per Fingertipp für Videos und Fotos
    •Geotagging für Fotos und Videos via Wi-Fi
     
    Stromversorgung und Batterie

    •Integrierte wiederaufladbare Lithium-Polymer-Batterie mit 25 Wattstunden
    •Bis zu 10 Stunden Surfen im Web mit Wi-Fi, Video- oder Musikwiedergabe
    •Aufladen über das Netzteil oder einen USB Anschluss am Computer

    •Integrierte wiederaufladbare Lithium-Polymer-Batterie mit 25 Wattstunden
    •Bis zu 10 Stunden Surfen im Web mit Wi-Fi, Video- oder Musikwiedergabe
    •Bis zu 9 Stunden Batterielaufzeit beim Surfen im Internet über das 3G Datennetzwerk
    •Aufladen über das Netzteil oder einen USB Anschluss am Computer
     
    Ein- und Ausgabe

    •30-poliger Dock-Anschluss
    •3,5 mm Stereo-/Kopfhöreranschluss (Minianschluss)
    •Integrierter Lautsprecher
    •Mikrofon

    •30-poliger Dock-Anschluss
    •3,5 mm Stereo-/Kopfhöreranschluss (Minianschluss)
    •Integrierter Lautsprecher
    •Mikrofon
    •Fach für Micro-SIM-Karte (nur beim Wi-Fi + 3G Modell)
     
    Sensoren

    •3-Achsen-Gyrosensor
    •Beschleunigungssensor
    •Umgebungslichtsensor

    •3-Achsen-Gyrosensor
    •Beschleunigungssensor
    •Umgebungslichtsensor
     
    Ortungsfunktion

    •Wi-Fi
    •Digitaler Kompass

    •Wi-Fi
    •Digitaler Kompass
    •Assisted GPS
    •Mobilfunknetz
     
    Audiowiedergabe

    •Frequenzbereich: 20 Hz bis 20.000 Hz
    •Unterstützte Audioformate: HE-AAC (V1 und V2), AAC (8 bis 320 Kbit/s), Protected AAC (aus dem iTunes Store), MP3 (8 bis 320 Kbit/s), MP3 VBR, Audible (Formate 2, 3, 4, Audible Enhanced Audio, AAX und AAX+), Apple Lossless, AIFF und WAV
    •Maximale Lautstärke vom Benutzer festlegbar
    •Dolby Digital 5.1 Surround Sound Durchschleifen mit Apple Digital AV Adapter (separat erhältlich)
     
    TV und Video

    •Unterstützung für Bildschirmsynchronisation und Videoausgabe: bis zu 1080p mit dem Apple Digital AV Adapter oder dem Apple VGA-Adapter (Kabel separat erhältlich)
    •Unterstützung für die Videoausgabe mit 576p und 480p mit dem Apple AV-Kabel (Komponentenvideo), mit 576i und 480i mit dem Apple AV-Kabel (Composite-Video)
    •Unterstützte Videoformate: H.264 Video: bis zu 720p, 30 Bilder pro Sekunde, Main Profile Level 3.1 mit AAC-LC Audio mit bis zu 160 Kbit/s, 48 kHz, Stereo-Audio in den Formaten .m4v, .mp4 und .mov; MPEG-4 Video: bis zu 2,5 Mbit/s, 640 x 480 Pixel, 30 Bilder pro Sekunde, Simple Profile mit AAC-LC Audio mit bis zu 160 Kbit/s, 48 kHz, Stereo-Audio in den Formaten .m4v, .mp4 und .mov; Motion JPEG (M-JPEG): bis zu 35 Mbit/s, 1280 x 720 Pixel, 30 Bilder pro Sekunde, Audio im Format .ulaw, PCM Stereo-Audio im Format .avi
     
    Unterstützte
    E-Mail Anhänge

    Anzeigbare Dokumenttypen: .jpg, .tiff, .gif (Bilder); .doc und .docx (Microsoft Word); .htm und .html (Webseiten); .key (Keynote); .numbers (Numbers); .pages (Pages); .pdf (Vorschau und Adobe Acrobat); .ppt und .pptx (Microsoft PowerPoint); .txt (Text); .rtf (Rich Text Format); .vcf (Kontaktdaten); .xls und .xlsx (Microsoft Excel)

    Sprachen

    •Sprachunterstützung für Englisch (USA), Englisch (Großbritannien), Französisch (Frankreich), Deutsch, traditionelles Chinesisch, vereinfachtes Chinesisch, Niederländisch, Italienisch, Spanisch, Portugiesisch (Brasilien), Portugiesisch (Portugal), Dänisch, Schwedisch, Finnisch, Norwegisch, Koreanisch, Japanisch, Russisch, Polnisch, Türkisch, Ukrainisch, Ungarisch, Arabisch, Thailändisch, Tschechisch, Griechisch, Hebräisch, Indonesisch, Malaiisch, Rumänisch, Slowakisch, Kroatisch, Katalanisch und Vietnamesisch

    •Tastaturunterstützung für Englisch (USA), Englisch (Großbritannien), Französisch (Frankreich), Französisch (Kanada), Französisch (Schweiz), Deutsch, traditionelles Chinesisch (Handschrift, Pinyin, Zhuyin, Cangjie, Wubihua), vereinfachtes Chinesisch (Handschrift, Pinyin, Wubihua), Niederländisch, Italienisch, Spanisch, Portugiesisch (Brasilien), Portugiesisch (Portugal), Dänisch, Schwedisch, Finnisch, Norwegisch, Koreanisch, Japanisch (Romaji, 10 Tasten), Japanisch (Kana), Russisch, Polnisch, Türkisch, Ukrainisch, Estnisch, Ungarisch, Isländisch, Litauisch, Lettisch, Flämisch, Arabisch, Thailändisch, Tschechisch, Griechisch, Hebräisch, Indonesisch, Malaiisch, Rumänisch, Slowakisch, Kroatisch, Bulgarisch, Serbisch (Kyrillisch/Lateinisch), Katalanisch, Vietnamesisch, Tibetisch, Mazedonisch und Cherokee
     
    •Wörterbuchunterstützung (aktiviert Textvorhersage und automatische Korrektur) für Englisch (USA), Englisch (Großbritannien), Französisch, Deutsch, traditionelles Chinesisch, vereinfachtes Chinesisch, Niederländisch, Italienisch, Spanisch, Portugiesisch (Brasilien), Portugiesisch (Portugal), Dänisch, Schwedisch, Finnisch, Norwegisch, Koreanisch, Japanisch (Romaji), Japanisch (Kana), Russisch, Polnisch, Türkisch, Ukrainisch, Ungarisch, Litauisch, Flämisch, Arabisch, Thailändisch, Tschechisch, Griechisch, Hebräisch, Indonesisch, Malaiisch, Rumänisch, Slowakisch, Kroatisch, Katalanisch, Vietnamesisch und Cherokee

    Bedienungshilfen

    •Unterstützung für die Wiedergabe von Inhalten mit erweiterten Untertiteln
    •VoiceOver Bildschirmlesetechnologie
    •Bildschirmfüllender Zoom
    •Anzeigeoption ""Weiß-auf-Schwarz""
    •Mono-Audioausgabe
     
    Umgebungsbedingungen

    •Betriebstemperatur: 0 °C bis 35 °C
    •Lagertemperatur: -20 °C bis 45 °C
    •Relative Luftfeuchtigkeit: 5 % bis 95 %, nicht kondensierend
    •Maximale Betriebshöhe: ca. 3.000 m über NN, ohne Druckausgleich
     
    Voraussetzungen für Mac

    •Mac mit USB 2.0 Anschluss
    •Mac OS X 10.5.8 (oder neuer)
    •iTunes 10.2 oder neuer empfohlen
    (kostenlos ladbar unter www.itunes.com/de/download)
    •iTunes Store Account
    •Internetzugang
     
    Voraussetzungen für Windows

    •PC mit USB 2.0 Anschluss
    •Windows 7, Windows Vista oder Windows XP Home oder Professional mit Service Pack 3 (oder neuer)
    •iTunes 10.2 oder neuer empfohlen
    (kostenlos ladbar unter www.itunes.com/de/download)
    •iTunes Store Account
    •Internetzugang
     
    Lieferumfang

    •iPad
    •Dock Connector auf USB Kabel
    •10W USB Power Adapter (Netzteil)
    •Dokumentation
     
    Umweltverträglichkeit

     
    Das iPad steht exemplarisch für das Engagement von Apple in Sachen Umweltschutz. Die folgenden Merkmale des iPad tragen zu seiner geringeren Umweltbelastung bei:

    •Arsenfreies Displayglas
    •Frei von bromhaltigen Flammschutzmitteln
    •Quecksilberfreies Display mit LED-Hintergrundbeleuchtung
    •Ohne PVC
    •Recycelbares Gehäuse aus Aluminium und Glas
    ";2;False;0;;;Apple iPad 2 schwarz;apple-ipad-2-schwarz;True;True;PD-01076;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;9300;False;False;0;1;1;0;False;1;10000;;False;False;False;False;479.0000;479.0000;499.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;40653,4073263889;54;1;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000633-apple-ipad-2-schwarz.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000634-apple-ipad-2-schwarz.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000635-apple-ipad-2-schwarz.jpg;1;;False;;;;;False;False;False;;;;;False;;;;;; -5;0;True;Apple iPad 2 weiß;Apple iPad 2. Generation weiß;"
    Kapazität
     
    16-GB-Flash-Laufwerk
    32-GB-Flash-Laufwerk
    64-GB-Flash-Laufwerk

    Abmessungen und Gewicht
     
    •Höhe: 241,2 mm
    •Breite: 185,7 mm
    •Tiefe: 8,8 mm
    •Gewicht: 601 g
     
    •Höhe: 241,2 mm
    •Breite: 185,7 mm
    •Tiefe: 8,8 mm
    •Gewicht: 613 g
     
     
    Drahtlose Technologie und Funknetz

    •Wi-Fi (802.11a/b/g/n)
    •Bluetooth 2.1 + EDR Technologie
    •Wi-Fi + 3G Modell: UMTS/HSDPA/HSUPA (850, 900, 1900, 2100 MHz); GSM/EDGE (850, 900, 1800, 1900 MHz)
    •Nur Datentransfer
    •Wi-Fi (802.11a/b/g/n)
    •Bluetooth 2.1 + EDR Technologie
    Weitere Infos zu Wi-Fi + 3G
     

    Display

     
    •9,7"" Multi-Touch Hochglanz-Widescreendisplay mit LED-Hintergrundbeleuchtung und IPS-Technologie (24,63 cm Diagonale)
    •Auflösung von 1024 x 768 Pixeln bei 132 ppi
    •Fettabweisende Beschichtung
    •Unterstützung für die Anzeige mehrerer Sprachen und Zeichen gleichzeitig
     
     
    Chip
    Speziell entwickelter, hochleistungsfähiger 1 GHz Dual-Core Apple A5 SOC (System-on-a-Chip) mit niedrigem Stromverbrauch
     
     
    Kamera, Fotos, Videoaufnahme
     
    •Rückkamera: Videoaufnahme, HD (720p) bis zu 30 fps mit Audio, Fotokamera mit 5-fach Digitalzoom
    •Frontkamera: Videoaufnahme, VGA mit bis zu 30 fps mit Audio, Fotokamera in VGA-Qualität
    •Fokussieren per Fingertipp für Videos und Fotos
    •Geotagging für Fotos und Videos via Wi-Fi
     
     
    Stromversorgung und Batterie
     
    •Integrierte wiederaufladbare Lithium-Polymer-Batterie mit 25 Wattstunden
    •Bis zu 10 Stunden Surfen im Web mit Wi-Fi, Video- oder Musikwiedergabe
    •Aufladen über das Netzteil oder einen USB Anschluss am Computer
     
    •Integrierte wiederaufladbare Lithium-Polymer-Batterie mit 25 Wattstunden
    •Bis zu 10 Stunden Surfen im Web mit Wi-Fi, Video- oder Musikwiedergabe
    •Bis zu 9 Stunden Batterielaufzeit beim Surfen im Internet über das 3G Datennetzwerk
    •Aufladen über das Netzteil oder einen USB Anschluss am Computer
     
     
    Ein- und Ausgabe
     
    •30-poliger Dock-Anschluss
    •3,5 mm Stereo-/Kopfhöreranschluss (Minianschluss)
    •Integrierter Lautsprecher
    •Mikrofon
     
    •30-poliger Dock-Anschluss
    •3,5 mm Stereo-/Kopfhöreranschluss (Minianschluss)
    •Integrierter Lautsprecher
    •Mikrofon
    •Fach für Micro-SIM-Karte (nur beim Wi-Fi + 3G Modell)
     
     
    Sensoren
     
    •3-Achsen-Gyrosensor
    •Beschleunigungssensor
    •Umgebungslichtsensor
     
    •3-Achsen-Gyrosensor
    •Beschleunigungssensor
    •Umgebungslichtsensor
     
     
    Ortungsfunktion
     
    •Wi-Fi
    •Digitaler Kompass
     
    •Wi-Fi
    •Digitaler Kompass
    •Assisted GPS
    •Mobilfunknetz
     
     
    Audiowiedergabe
     
    •Frequenzbereich: 20 Hz bis 20.000 Hz
    •Unterstützte Audioformate: HE-AAC (V1 und V2), AAC (8 bis 320 Kbit/s), Protected AAC (aus dem iTunes Store), MP3 (8 bis 320 Kbit/s), MP3 VBR, Audible (Formate 2, 3, 4, Audible Enhanced Audio, AAX und AAX+), Apple Lossless, AIFF und WAV
    •Maximale Lautstärke vom Benutzer festlegbar
    •Dolby Digital 5.1 Surround Sound Durchschleifen mit Apple Digital AV Adapter (separat erhältlich)
     
     
    TV und Video
     
    •Unterstützung für Bildschirmsynchronisation und Videoausgabe: bis zu 1080p mit dem Apple Digital AV Adapter oder dem Apple VGA-Adapter (Kabel separat erhältlich)
    •Unterstützung für die Videoausgabe mit 576p und 480p mit dem Apple AV-Kabel (Komponentenvideo), mit 576i und 480i mit dem Apple AV-Kabel (Composite-Video)
    •Unterstützte Videoformate: H.264 Video: bis zu 720p, 30 Bilder pro Sekunde, Main Profile Level 3.1 mit AAC-LC Audio mit bis zu 160 Kbit/s, 48 kHz, Stereo-Audio in den Formaten .m4v, .mp4 und .mov; MPEG-4 Video: bis zu 2,5 Mbit/s, 640 x 480 Pixel, 30 Bilder pro Sekunde, Simple Profile mit AAC-LC Audio mit bis zu 160 Kbit/s, 48 kHz, Stereo-Audio in den Formaten .m4v, .mp4 und .mov; Motion JPEG (M-JPEG): bis zu 35 Mbit/s, 1280 x 720 Pixel, 30 Bilder pro Sekunde, Audio im Format .ulaw, PCM Stereo-Audio im Format .avi
     
     
    Unterstützte
    E-Mail Anhänge
     
    Anzeigbare Dokumenttypen: .jpg, .tiff, .gif (Bilder); .doc und .docx (Microsoft Word); .htm und .html (Webseiten); .key (Keynote); .numbers (Numbers); .pages (Pages); .pdf (Vorschau und Adobe Acrobat); .ppt und .pptx (Microsoft PowerPoint); .txt (Text); .rtf (Rich Text Format); .vcf (Kontaktdaten); .xls und .xlsx (Microsoft Excel)
     
    Sprachen
     
    •Sprachunterstützung für Englisch (USA), Englisch (Großbritannien), Französisch (Frankreich), Deutsch, traditionelles Chinesisch, vereinfachtes Chinesisch, Niederländisch, Italienisch, Spanisch, Portugiesisch (Brasilien), Portugiesisch (Portugal), Dänisch, Schwedisch, Finnisch, Norwegisch, Koreanisch, Japanisch, Russisch, Polnisch, Türkisch, Ukrainisch, Ungarisch, Arabisch, Thailändisch, Tschechisch, Griechisch, Hebräisch, Indonesisch, Malaiisch, Rumänisch, Slowakisch, Kroatisch, Katalanisch und Vietnamesisch
     
    •Tastaturunterstützung für Englisch (USA), Englisch (Großbritannien), Französisch (Frankreich), Französisch (Kanada), Französisch (Schweiz), Deutsch, traditionelles Chinesisch (Handschrift, Pinyin, Zhuyin, Cangjie, Wubihua), vereinfachtes Chinesisch (Handschrift, Pinyin, Wubihua), Niederländisch, Italienisch, Spanisch, Portugiesisch (Brasilien), Portugiesisch (Portugal), Dänisch, Schwedisch, Finnisch, Norwegisch, Koreanisch, Japanisch (Romaji, 10 Tasten), Japanisch (Kana), Russisch, Polnisch, Türkisch, Ukrainisch, Estnisch, Ungarisch, Isländisch, Litauisch, Lettisch, Flämisch, Arabisch, Thailändisch, Tschechisch, Griechisch, Hebräisch, Indonesisch, Malaiisch, Rumänisch, Slowakisch, Kroatisch, Bulgarisch, Serbisch (Kyrillisch/Lateinisch), Katalanisch, Vietnamesisch, Tibetisch, Mazedonisch und Cherokee
     
    •Wörterbuchunterstützung (aktiviert Textvorhersage und automatische Korrektur) für Englisch (USA), Englisch (Großbritannien), Französisch, Deutsch, traditionelles Chinesisch, vereinfachtes Chinesisch, Niederländisch, Italienisch, Spanisch, Portugiesisch (Brasilien), Portugiesisch (Portugal), Dänisch, Schwedisch, Finnisch, Norwegisch, Koreanisch, Japanisch (Romaji), Japanisch (Kana), Russisch, Polnisch, Türkisch, Ukrainisch, Ungarisch, Litauisch, Flämisch, Arabisch, Thailändisch, Tschechisch, Griechisch, Hebräisch, Indonesisch, Malaiisch, Rumänisch, Slowakisch, Kroatisch, Katalanisch, Vietnamesisch und Cherokee
     
    Bedienungshilfen
     
    •Unterstützung für die Wiedergabe von Inhalten mit erweiterten Untertiteln
    •VoiceOver Bildschirmlesetechnologie
    •Bildschirmfüllender Zoom
    •Anzeigeoption ""Weiß-auf-Schwarz""
    •Mono-Audioausgabe
     
     
    Umgebungsbedingungen 

    •Betriebstemperatur: 0 °C bis 35 °C
    •Lagertemperatur: -20 °C bis 45 °C
    •Relative Luftfeuchtigkeit: 5 % bis 95 %, nicht kondensierend
    •Maximale Betriebshöhe: ca. 3.000 m über NN, ohne Druckausgleich
     
     
    Voraussetzungen für Mac
     
    •Mac mit USB 2.0 Anschluss
    •Mac OS X 10.5.8 (oder neuer)
    •iTunes 10.2 oder neuer empfohlen
    (kostenlos ladbar unter www.itunes.com/de/download)
    •iTunes Store Account
    •Internetzugang
     
     
    Voraussetzungen für Windows
     
    •PC mit USB 2.0 Anschluss
    •Windows 7, Windows Vista oder Windows XP Home oder Professional mit Service Pack 3 (oder neuer)
    •iTunes 10.2 oder neuer empfohlen
    (kostenlos ladbar unter www.itunes.com/de/download)
    •iTunes Store Account
    •Internetzugang
     
     
    Lieferumfang
     
    •iPad
    •Dock Connector auf USB Kabel
    •10W USB Power Adapter (Netzteil)
    •Dokumentation
     
     
    Umweltverträglichkeit
     
     
    Das iPad steht exemplarisch für das Engagement von Apple in Sachen Umweltschutz. Die folgenden Merkmale des iPad tragen zu seiner geringeren Umweltbelastung bei:
    •Arsenfreies Displayglas
    •Frei von bromhaltigen Flammschutzmitteln
    •Quecksilberfreies Display mit LED-Hintergrundbeleuchtung
    •Ohne PVC
    •Recycelbares Gehäuse aus Aluminium und Glas
    ";2;False;0;;;Apple iPad 2 weiß;apple-ipad-2-weiss;True;True;PD-01075;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;479.0000;0.0000;499.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;40653,4018865741;54;1;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000627-apple-ipad-2-weis.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000628-apple-ipad-2-weis.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000629-apple-ipad-2-weis.jpg;1;;False;;;;;False;False;False;;;;;False;;;;;; -5;0;True;Apple MacBook Pro MC721D/A 15,4 Zoll Notebook;"Apple MacBook Pro MC721D/A 39.1 cm (15,4 Zoll) Notebook (Intel Core i7 2635QM, 2 GHz, 4GB RAM, 500GB HDD, AMD 6490M, DVD, Mac OS) ";"
    Apple MacBook Pro MC721D/A
    Intel Core i7 2635QM, 2 GHz

    Unibody-Gehäuse. Am Anfang jedes MacBook Pro steht ein Werkstück aus Aluminium.Stark, leicht und schön in einem.
    Das MacBook Pro ist aus einem einzigen Aluminiumblock gefertigt - eine technische Meisterleistung, bei der viele Bauteile durch ein einziges ersetzt werden. Das Ganze nennt sich Unibody. Gleich beim ersten Mal, wenn Sie ein MacBook Pro in der Hand haben, werden Sie den Unterschied spüren. Das Gehäuse ist dünner und leichter als andere Notebooks. Es sieht elegant aus. Und es fühlt sich stabil und robust an: perfekt für die Aktentasche, den Rucksack und natürlich auch für draußen.
     
    Ein Display voll brillanter Ideen.
    Alles, was Apple Designer und Ingenieure tun, ist von A bis Z durchdacht. Sie entschieden sich beim MacBook Pro für die LED-Hintergrundbeleuchtung, weil das Display damit sofort seine volle Helligkeit erreicht und trotzdem unglaublich dünn ist. Sie verwendeten eine durchgehende Oberfläche aus Glas, nicht nur weil es schön aussieht, sondern weil es dem ganzen Display Struktur verleiht. Und über dem Bildschirm haben sie die neue, integrierte FaceTime HD Kamera versteckt. So siehst du Freunde und Familie im Großformat - und dabei so gut wie nichts von der Kamera.
     
    Magnetverschluss
    Da der magnetische Verschluss keine beweglichen Teile hat, die abbrechen können oder an denen man hängen bleibt, ist das Öffnen und Schließen so einfach wie alles beim MacBook Pro.
     
    Einfach auf alle Anschlüsse zugreifen.
    Alle Anschlüsse am MacBook Pro - der MagSafe Netzanschluss, der Gigabit Ethernetanschluss, der Thunderbolt Anschluss, der USB Anschluss, der Karten-Steckplatz und der Audioeingang und -ausgang - sind ganz auf einer Seite des Notebooks integriert. So bleiben die Kabel schön geordnet und Geräte lassen sich schnell und einfach anschließen und auch wieder trennen.
     
    Hinterlässt Eindruck. Aber nicht auf die Umwelt.
    Weil Apple die vollständige Kontrolle über Design, Fertigung und Verpackung des MacBook Pro hat, hat Apple einen Vorsprung beim Umweltschutz. Die Technologie zur Hintergrundbeleuchtung des Displays spart Energie. Glas und Aluminium sind besonders recyclingfähig. Das MacBook Pro kommt fast ohne Giftstoffe aus. Und die Verpackung des 39,11 cm / 15,4"" Modells ist im Vergleich zum Vorgängermodell 34 Prozent kleiner. Das bedeutet nicht nur, dass für die Verpackungen weniger Bäume gefällt werden, es werden für den Transport auch weniger Flugzeugen, Güterzügen und LKWs benötigt.
     
    Thunderbolt AnschlussDie Grafikleistung, die Sie brauchen, wenn Sie sie brauchen.
    Alle MacBook Pro Modelle haben jetzt einen integrierten Intel HD Graphics 3000 Prozessor für die täglichen Aufgaben. Er codiert Videos schnell, ermöglicht HD Videotelefonate mit FaceTime und vieles mehr. Und auch Decodieren erledigt er effizienter, was bedeutet, dass Sie richtig lange DVDs und iTunes Filme schauen können. Bei anspruchsvollen Grafikprogrammen wechseln die 39,11 cm / 15,4"" MacBook Pro Modelle automatisch den Grafikprozessor und arbeiten mit den neuen leistungsstarken AMD Radeon Grafikprozessoren. Diese bieten verglichen mit den Vorgängermodellen die bis zu 3-fache Leistung. So sehen Sie bei 3D Spielen mehr Bilder pro Sekunde oder können schneller als je zuvor an HD Videoprojekten arbeiten.
     
    Das neue Thunderbolt. Die schnellste, vielseitigste I/O Technologie in einem Notebook.
    Stellen Sie sich vor, Sie könnten auf deinem Notebook auf mehrere unkomprimierte HD Videostreams zugreifen - und zwar so schnell, dass Sie einen HD Spielfilm in Echtzeit schneiden können. Thunderbolt macht genau das möglich. Mit Thunderbolt lassen sich superschnelle Peripheriegeräte der nächsten Generation an die Computer der nächsten Generation anschließen - angefangen beim MacBook Pro. Die Thunderbolt Pipeline ist ultraschnell und ultraflexibel. Sie ist über 12 Mal schneller als FireWire 800 und bis zu 20 Mal schneller als USB 2.0. Und sie bietet beispiellose Erweiterungsmöglichkeiten. Kurzum: Sie verändert alles, was Sie auf Ihrem Notebook machen können. Der Thunderbolt Anschluss gibt Ihnen Plug&Play Anschluss für eine völlig neue Welt von Thunderbolt Peripheriegeräten sowie für das Apple LED Cinema Display und andere Mini DisplayPort Peripheriegeräte. Sie können bis zu sechs Thunderbolt Geräte in Reihenschaltung anschließen, darunter auch Ihr Display. Außerdem unterstützt Thunderbolt Video und Achtkanal-Audio, sodass es auch möglich ist, HDMI-kompatible Geräte wie Fernseher oder Stereoanlagen über einen HDMI-Adapter anzuschließen. Auch aktuelle VGA-, DVI- und DisplayPort Adapter werden unterstützt.
     
    Die neue FaceTime HD Kamera. Der Unterschied ist ganz klar.
    Sehen Sie mehr von Ihren Freunden mit dem HD Widescreenformat - und zwar gestochen scharf. Die neue FaceTime HD Kamera bietet die dreifache Auflösung der vorherigen Kamera, was perfekt für das brillante Display mit LED-Hintergrundbeleuchtung ist. Außerdem arbeitet sie jetzt bei schwachem Licht noch besser. Sie können mit Ihren Freunden HD Telefonate in 720p von einem neuen MacBook Pro zu einem anderen führen. Außerdem sind auch Videotelefonate zu anderen Macs mit Intel Prozessor, zum iPhone 4 oder zum neuen iPod touch möglich.
     
    Multi-Touch Trackpad - Jede Menge Platz für GestenMulti-Touch Trackpad. Fürs tägliche Handwerk.
    Mit dem Multi-Touch Trackpad interagieren Sie auf ganz natürliche Art mit den Inhalten auf deinem Display. Und die glatte Glasoberfläche bietet jede Menge Platz für Gesten. Durch Auf- und Zuziehen können Sie ein- und auszoomen, durch Streichen in deinen Fotos blättern, durch Drehen ein Bild anpassen und vieles mehr. Das Trackpad kommt ohne Taste aus, sodass Sie überall klicken können. Wenn Sie aus der Welt des rechten Mausklicks kommen, können Sie diesen entweder mit zwei Fingern auslösen, oder Sie konfigurieren einen physischen Rechtsklick-Bereich auf dem Trackpad. Je mehr Sie mit dem Multi-Touch Trackpad vertraut sind, desto mehr werden Sie sich fragen, wie Sie jemals ohne ausgekommen sind.
     
    Lange Laufzeit. Weniger aufladen. Mehr machen.
    Das neue MacBook Pro bietet eine fantastische Batterielaufzeit und das mit leistungsstärkeren Prozessoren und schnelleren Grafikprozessoren. Die energieeffiziente Prozessorarchitektur mit integriertem Video-Encoder sowie das automatische Umschalten zwischen den Grafikprozessoren bei den 39,11 cm / 15,4"" Modellen helfen, die Batterielaufzeit weiter zu verbessern. So können Sie pro Ladung bis zu 7 Stunden ohne Kabel im Web surfen oder es für Liveauftritte oder auf ein Shooting mitnehmen. Die fortschrittlichen chemischen Eigenschaften und die Adaptive Charging Technologie sorgen dafür, dass die Batterie bis zu 1000 Ladezyklen durchlaufen kann. Und da die Batterie des MacBook Pro bis zu fünf Jahre hält, kommt das MacBook Pro in einem Zeitraum, in dem ein herkömmliches Notebook drei Batterien verbraucht, mit nur einer aus. Das ist für die Benutzer genauso gut, wie für die Umwelt. Apple verwendet eine neue, strengere Testmethode, um zu messen, welche Ergebnisse Sie unter realen Bedingungen erzielen, z. B. beim Surfen in einem Cafe oder wenn Sie die neuesten Webvideos ansehen. Und wie schneidet dieses MacBook Pro dabei verglichen mit der Vorgängergeneration ab? Es liefert die gleiche fantastische Leistung.
     
    Hat beste Verbindungen.
    Unterwegs haben Sie mit der 802.11n Technologie im MacBook Pro immer Verbindung. Das MacBook Pro findet automatisch verfügbare Netzwerke und Sie können sich mit einem Klick verbinden. Auch die drahtlose Bluetooth Technologie ist integriert, sodass Sie drahtloses Zubehör sofort nach dem Auspacken verwenden können.
     
    DVDs superschnell brennen.
    Homevideos, die Sie mit iMovie und iDVD gemacht haben, können Sie mit dem 8-fach SuperDrive Laufwerk des MacBook Pro superschnell auf eine DVD brennen. Das SuperDrive kann auch Double-Layer-DVDs (also DVDs mit fast 9 GB Speicherplatz) beschreiben, sodass es auch hervorragend für Datensicherungen geeignet ist.
     
    Neue Intel Core i7 Prozessoren.
    Neue Quad-Core Intel Core i7 Prozessoren sind Standard beim 39,11 cm / 15,4"" MacBook Pro. Alle Modelle verwenden die kürzlich optimierten Chipsets von Intel. Was heißt das für die neuen MacBook Pro Modelle? Kurz gesagt: Sie sind bis zu zwei Mal schneller als die Vorgängergeneration und erledigen auch anspruchsvolle Aufgaben wie HD Videoschnitt, Audiokompilierung oder Rendering mehrschichtiger Bilddateien unglaublich schnell. Und da Mac OS X Snow Leopard darauf ausgelegt ist, jeden Prozessorkern zu nutzen, holt das Betriebssystem wirklich alles an Leistung aus dem Prozessor heraus.
     
    Schnellere Einzelchip-Mikroarchitektur.
    Ob Sie einen Film ansehen, Ihren Blog auf den neuesten Stand bringen oder Fotos bearbeiten - die Daten müssen von A nach B gelangen, um verarbeitet werden zu können. Die neueste Intel Core Architektur bringt den Prozessor, den Cache, den Speichercontroller und den Grafikprozessor auf einem einzigen Chip unter. Deswegen müssen die Daten keine weiten Wege zurücklegen, was für Sie schnellere Performance und höhere Effizienz bedeutet.
     
    Turbo Boost 2.0.
    Angenommen, Sie arbeiten mit einem prozessorintensiven Programm wie Aperture 3 oder Final Cut Pro, das von einem Leistungsschub profitiert würde. Turbo Boost ist eine dynamische Technologie, die automatisch die Geschwindigkeit der aktiven Prozessorkerne auf 3,4 GHz erhöht. Turbo Boost 2.0 ist noch dynamischer und effizienter. Es wechselt die Kernfrequenz in kleineren Schritten als bisher, sodass der Prozessor die Leistung ohne Effizienzeinbußen verwalten kann. All das passiert im Hintergrund. Sie arbeiten einfach nur schneller.
     
    Hyper-Threading.
    Hyper-Threading ist jetzt Standard auf jedem MacBook Pro. Mit dieser Technologie können auf jedem Kern zwei Threads gleichzeitig laufen, Mac OS X erkennt also bei einem Quad-Core Prozessor acht und bei einem Dual-Core Prozessor vier virtuelle Kerne. Wenn Sie mehrere Programme gleichzeitig verwenden, verteilt der Prozessor die Aufgaben gleichmäßiger über eine größere Anzahl Kerne.
     
    Integrierter Speichercontroller.
    Mit schnellerem Speicherzugriff legt jeder Kern direkt mit der Verarbeitung der Daten los, statt auf ihr Eintreffen zu warten. Genau deshalb nutzt die neue Intel Core Architektur einen integrierten Speichercontroller, der den schnellen 1333 MHz Speicher direkt mit dem Prozessor verbindet und Ihre Programme immer die maximale Prozessorleistung zur Verfügung haben.
     
    Energieeffiziente Grafik.
    Dank der neuen Mikroarchitektur ist der Grafikprozessor auf dem gleichen Chip wie der Zentralprozessor und hat direkten Zugriff auf den L3-Cache. Kurze Wege bedeuten mehr Leistung. Der Grafikprozessor erhöht auch automatisch die Taktrate für noch höhere Auslastung. Ein integrierter Video-Encoder ermöglicht jetzt HD Videotelefonate mit FaceTime, und der effiziente Decoder sorgt für lange Batterielaufzeit, wenn Sie sich DVDs oder iTunes Filme ansiehen.
     
    Mac OS X. Das fortschrittlichste Betriebssystem der Welt.
    Mac OS X ist das Herz jedes MacBook Pro und Mac. Dieses Betriebssystem ist genau auf die integrierten Intel Multicore-Prozessoren und fortschrittlichen Grafikprozessoren zugeschnitten. Die neueste Version, Mac OS X Snow Leopard, basiert komplett auf einer 64-Bit-Architektur, genau wie alle anderen Programme, die mit dem Mac kommen. Das bedeutet: Alles, was Sie auf Ihrem MacBook Pro machen, passiert superschnell und mit einer unglaublichen Gesamtleistung.
     
    Hat eine ganze Menge draufProgramme, ebenso leistungsstark wie benutzerfreundlich.
    Weil Apple sowohl das MacBook Pro, wie auch die integrierte Software entwickelt, arbeitet alles perfekt zusammen. Und mit den Apple Programmen sind Sie ganz schnell vertraut, weil alle ähnlich funktionieren. Das heißt, wenn Sie ein Programm kennen, sind Sie auch schnell mit allen anderen vertraut. Außerdem weiß Apple genau, was mobile Produktivität bedeutet. Darum haben wir Funktionen wie Expose und Spaces hinzugefügt. Damit können Sie ganz einfach auf alles auf Ihrem MacBook Pro zugreifen. Expose zeigt sämtliche geöffneten Fenster nebeneinander, verkleinert sie und ordnet sie so, dass Sie den Inhalt jedes Fensters sehen können - ein Tastendruck oder eine Geste genügt. Und mit Spaces können Sie Fenster zusammen auf ihrem eigenen Schreibtisch oder Bereich gruppieren und ganz einfach zwischen diesen wechseln. Legen Sie einen Bereich zum Arbeiten fest, einen zum Spielen und einen für was auch immer. Mit Expose und Spaces haben Sie beim Multitasking auf einem Notebookdisplay einen riesigen Vorteil.
     
    Darauf verzichten Sie beim Mac: PC-Viren.
    Trojaner, Würmer, E-Mail Viren. Die digitale Welt kann ganz schön beängstigend sein. Zum Glück ist der Mac immun gegen die tausenden von Viren, die Windows Computer plagen. Denn Mac OS X kommt mit integrierten Sicherheitsmechanismen, die Sie schützen - ohne dass Sie etwas machen müssen. Und sollten doch mal potenzielle Sicherheitsrisiken auftreten, reagiert Apple sofort und stellt neue Softwareaktualisierungen und Sicherheitsverbesserungen bereit, die Sie automatisch laden und mit einem Klick installieren können.
     
    Das automatische Backup rettet Ihren Tag. Und die Woche, den Monat ...
    Backups müssen sein. Trotzdem vergissen Sie sie bestimmt hin und wieder. Deshalb kümmert sich jetzt das MacBook Pro um die Datensicherung. Time Machine, ein Programm, das auf jedem Mac dabei ist, sichert automatisch Ihr ganzes System auf einer externen Festplatte oder Time Capsule. Time Machine speichert eine Kopie von jeder Datei. Und es merkt sich, wie Ihr System an einem bestimmten Tag ausgesehen hat. So können Sie, wenn Sie wollen, die Zeit zurückdrehen und Ihren Mac wie in der Vergangenheit sehen.
     
    Mit iMovie können Sie aus Ihren Videos großartige Filme machenAuch die täglichen Sachen machen mehr Spaß.
    Anders als viele PC-Notebooks kommt das MacBook Pro mit allem, was Sie brauchen, um E-Mails zu senden, Kalender zu verwalten, Kontakte zu organisieren und mehr. Und Sie können schon wenige Minuten nach dem Auspacken damit loslegen. Denn jeder Mac kommt mit Mail, um E-Mails zu senden und empfangen, iCal zum Organisieren von Terminen und wichtigen Ereignissen, dem Adressbuch zum Verwalten von Kontakten, iTunes für alles, was mit Unterhaltung zu tun hat, und weiteren tollen und nützlichen Programmen, die Sie jeden Tag verwenden werden.
     
    Der Mac App Store. Tausend weitere Gründe, den Mac zu lieben.
    Über tausend Mac Apps sind nur einen Klick entfernt - im Mac App Store. Suchen Sie einfach Apps, die Ihnen gefallen, und klicken Sie einfach, um sie zu laden und zu installieren. Ohne Verpackung. Ohne CDs oder DVDs. Und ohne Probleme. Sie können die Apps nach Kategorien durchstöbern oder direkt etwas Bestimmtes suchen. Und Sie können einfach dafür sorgen, dass Ihre Apps up-to-date sind, denn Ihr Mac zeigt Ihnen an, wann Updates verfügbar sind.
     
    iPhoto. Fotos ganz einfach verwalten, bearbeiten und teilen.
    iPhoto ist ein benutzerfreundliches Programm für Fotos, mit dem Sie Ihre Bilder schnell organisieren, wiederfinden und verbessern können - sodass sie immer perfekt aussehen. Mit den iPhoto Funktionen ""Gesichter"", ""Orte"" und ""Ereignisse"" behalten Sie den Überblick über Ihre Fotos. Sie sagen Ihnen, wen Sie fotografiert haben, wo und wann. Und all das in den neuen Vollbildmodi.
     
    iMovie. Und aus Homevideos werden Home-Blockbuster.
    Homevideos müssen nicht langweilig sein. Mit iMovie können Sie aus Ihren Videos großartige Filme machen. Zum Beispiel Trailer im Hollywoodstil, mit denen Sie Ihr Publikum begeistern.
     
    GarageBand. Großartige Musik machen, ganz einfachissimo.
    Egal, ob Sie Musiktalent haben oder einfach nur neugierig sind - GarageBand ist genau das richtige Programm für Sie. Schließ einfach eine elektrische Gitarre oder ein USB Keyboard an. Und schon können Sie mit virtuellen Nachbildungen der bekanntesten Amps und Stompboxes der Welt sowie mit 100 Software-Instrumenten spielen.
    ";2;False;0;;;Apple MacBook Pro MC721D/A 15,4 Zoll Notebook;apple-macbook-pro-mc721da-154-zoll-notebook;True;True;P-0760;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;2,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;1483.9000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;40652,8677546296;3;1;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000545-apple-macbook-pro-mc721da-154-zoll-notebook.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000546-apple-macbook-pro-mc721da-154-zoll-notebook.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000547-apple-macbook-pro-mc721da-154-zoll-notebook.jpg;2;;False;;;;;False;False;False;;;;;False;;;;;; -5;0;True;Apple MacBook Pro MD313D/A 13,3 Zoll Notebook;"Apple MacBook Pro MD313D/A 33,78cm (13,3"")";"
    Apple MacBook Pro MD313D/A 13,3 Zoll Notebook
    Intel Core i5  2x 2,40 GHz
     
    Bis zu 2x schnellere Prozessoren. Bis zu 3x schnellere Grafik.
    Quad-Core und Dual-Core Intel Prozessoren der nächsten Generation.
    Das 13"" MacBook Pro gibt es jetzt mit einem 2,4 GHz Intel Core i5 Prozessor oder dem schnellsten Dual-Core Prozessor, den es gibt: dem 2,8 GHz Intel Core i7. Diese Prozessoren bieten Turbo Boost Geschwindigkeiten und machen das 13"" MacBook Pro bis zu doppelt so schnell wie die Vorgängergeneration.
     
    Aber nur schnell ist uns nicht genug. Deshalb bieten die neuen 15"" und 17"" Modelle Quad-Core Leistung für praktisch alles, was du machen willst. Auch ein 2,4 GHz Quad-Core Intel Core i7 Prozessor mit Turbo Boost Geschwindigkeiten und bis zu 8 MB gemeinsam genutztem L3-Cache ist verfügbar. Auf MacBook Pro Modellen mit diesem Prozessor laufen Programme bis zu doppelt so schnell wie auf der besten Vorgängerkonfiguration.
     
    Die Grafikleistung, die du brauchst, wenn du sie brauchst.
    Alle MacBook Pro Modelle haben jetzt einen integrierten Intel HD Graphics 3000 Prozessor für die täglichen Aufgaben. Er codiert Videos schnell, ermöglicht HD Videotelefonate mit FaceTime und vieles mehr. Und auch Decodieren erledigt er effizienter, was bedeutet, dass du richtig lange DVDs und iTunes Filme schauen kannst.
     
    Bei anspruchsvollen Grafikprogrammen wechseln die 15"" und 17"" MacBook Pro Modelle automatisch den Grafikprozessor und arbeiten mit den neuen leistungsstarken AMD Radeon Grafikprozessoren. Diese bieten verglichen mit den Vorgängermodellen die bis zu 3-fache Leistung.3 So siehst du bei 3D Spielen mehr Bilder pro Sekunde oder kannst schneller als je zuvor an HD Videoprojekten arbeiten.
     
    Das neue Thunderbolt. Die schnellste, vielseitigste I/O Technologie in einem Notebook.
    Stell dir vor, du könntest auf deinem Notebook auf mehrere unkomprimierte HD Videostreams zugreifen - und zwar so schnell, dass du einen HD Spielfilm in Echtzeit schneiden kannst. Thunderbolt macht genau das möglich. Mit Thunderbolt lassen sich superschnelle Peripheriegeräte der nächsten Generation an die Computer der nächsten Generation anschließen - angefangen beim MacBook Pro. Die Thunderbolt Pipeline ist ultraschnell und ultraflexibel. Sie ist über 12 Mal schneller als FireWire 800 und bis zu 20 Mal schneller als USB 2.0. Und sie bietet beispiellose Erweiterungsmöglichkeiten. Kurzum: Sie verändert alles, was du auf deinem Notebook machen kannst.
     
    Der Thunderbolt Anschluss gibt dir Plug&Play Anschluss für eine völlig neue Welt von Thunderbolt Peripheriegeräten sowie für das Apple LED Cinema Display und andere Mini DisplayPort Peripheriegeräte. Du kannst bis zu sechs Thunderbolt Geräte in Reihenschaltung anschließen, darunter auch dein Display. Außerdem unterstützt Thunderbolt Video und Achtkanal-Audio, sodass es auch möglich ist, HDMI-kompatible Geräte wie Fernseher oder Stereoanlagen über einen HDMI-Adapter anzuschließen. Auch aktuelle VGA-, DVI- und DisplayPort Adapter werden unterstützt.
     
    Die neue FaceTime HD Kamera. Der Unterschied ist ganz klar.
    Sieh mehr von deinen Freunden mit dem HD Widescreenformat - und zwar gestochen scharf. Die neue FaceTime HD Kamera bietet die dreifache Auflösung der vorherigen Kamera, was perfekt für das brillante Display mit LED-Hintergrundbeleuchtung ist. Außerdem arbeitet sie jetzt bei schwachem Licht noch besser. Du kannst mit deinen Freunden HD Telefonate in 720p von einem neuen MacBook Pro zu einem anderen führen. Außerdem sind auch Videotelefonate zu anderen Macs mit Intel Prozessor5, zum iPhone 4 oder zum neuen iPod touch möglich.
     
    Multi-Touch Trackpad. Fürs tägliche Handwerk.
    Mit dem Multi-Touch Trackpad interagierst du auf ganz natürliche Art mit den Inhalten auf deinem Display. Und die glatte Glasoberfläche bietet jede Menge Platz für Gesten. Durch Auf- und Zuziehen kannst du ein- und auszoomen, durch Streichen in deinen Fotos blättern, durch Drehen ein Bild anpassen und vieles mehr. Das Trackpad kommt ohne Taste aus, sodass du überall klicken kannst. Wenn du aus der Welt des rechten Mausklicks kommst, kannst du diesen entweder mit zwei Fingern auslösen, oder du konfigurierst einen physischen Rechtsklick-Bereich auf dem Trackpad. Je mehr du mit dem Multi-Touch Trackpad vertraut bist, desto mehr wirst du dich fragen, wie du jemals ohne ausgekommen bist.
     
    Lange Laufzeit. Weniger aufladen. Mehr machen.
    Das neue MacBook Pro bietet eine fantastische Batterielaufzeit und das mit leistungsstärkeren Prozessoren und schnelleren Grafikprozessoren. Die energieeffiziente Prozessorarchitektur mit integriertem Video-Encoder sowie das automatische Umschalten zwischen den Grafikprozessoren bei den 15"" und 17"" Modellen helfen, die Batterielaufzeit weiter zu verbessern. So kannst du pro Ladung bis zu 7 Stunden ohne Kabel im Web surfen6 oder es für Liveauftritte oder auf ein Shooting mitnehmen. Die fortschrittlichen chemischen Eigenschaften und die Adaptive Charging Technologie sorgen dafür, dass die Batterie bis zu 1000 Ladezyklen durchlaufen kann.7 Und da die Batterie des MacBook Pro bis zu fünf Jahre hält, kommt das MacBook Pro in einem Zeitraum, in dem ein herkömmliches Notebook drei Batterien verbraucht, mit nur einer aus. Das ist für die Benutzer genauso gut, wie für die Umwelt.
     
    Apple verwendet eine neue, strengere Testmethode, um zu messen, welche Ergebnisse du unter realen Bedingungen erzielst, z. B. beim Surfen in einem Café oder wenn du die neuesten Webvideos ansiehst. Und wie schneidet dieses MacBook Pro dabei verglichen mit der Vorgängergeneration ab? Es liefert die gleiche fantastische Leistung.
     
    Hat beste Verbindungen.
    Unterwegs hast du mit der 802.11n Technologie im MacBook Pro immer Verbindung.8 Das MacBook Pro findet automatisch verfügbare Netzwerke und du kannst dich mit einem Klick verbinden. Auch die drahtlose Bluetooth Technologie ist integriert, sodass du drahtloses Zubehör sofort nach dem Auspacken verwenden kannst.
     
    Immer Anschluss finden.
    Mit dem neuen Thunderbolt Anschluss kannst du bis zu sechs Geräte in Reihenschaltung anschließen, darunter auch dein Display. So bekommst du eine vollwertige Workstation. Für die Anbindung von iPad, iPod, iPhone, Digitalkameras und externen Festplatten gibt es zwei USB 2.0 Anschlüsse (drei beim 17"" MacBook Pro) und einen FireWire 800 Anschluss.
     
    Der neue SDXC Kartensteckplatz der 13"" und 15"" MacBook Pro Modelle unterstützt bis zu 64 GB Karten und macht es leicht, alle deine Fotos auf und von deinem MacBook Pro zu übertragen, damit du sie sofort bearbeiten und teilen kannst. Und der ExpressCard/34 Steckplatz am 17"" MacBook Pro ist perfekt für einen eSATA Adapter geeignet oder sogar für eine 3G Karte für die drahtlose Kommunikation, wenn kein Wi-Fi Netzwerk vorhanden ist.
     
    DVDs superschnell brennen.
    Homevideos, die du mit iMovie und iDVD gemacht hast, kannst du mit dem 8-fach SuperDrive Laufwerk des MacBook Pro superschnell auf eine DVD brennen. Das SuperDrive kann auch Double-Layer-DVDs (also DVDs mit fast 9 GB Speicherplatz) beschreiben, sodass es auch hervorragend für Datensicherungen geeignet ist.
    ";2;False;0;;;Apple MacBook Pro MD313D/A 13,3 Zoll Notebook;apple-macbook-pro-md313da-133-zoll-notebook;True;True;P-0740;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;1099.9000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;40652,639537037;3;1;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000456-apple-macbook-pro-md313da-133-zoll-notebook.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000457-apple-macbook-pro-md313da-133-zoll-notebook.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000458-apple-macbook-pro-md313da-133-zoll-notebook.jpg;2;;False;;;;;False;False;False;;;;;False;;;;;; -5;0;True;Apple MacBook Pro MC725D/A 17 Zoll Notebook;"Apple MacBook Pro MC725D/A 43.2 cm (17 Zoll) Notebook (Intel Core i7 2720QM, 2,2 GHz, 4GB RAM, 750GB HDD, AMD 6750M, DVD, Mac OS) ";"
    Apple MacBook Pro MC725D/A
    Intel Core i7 2720QM, 2,2 GHz
     
    Stark, leicht und schön in einem.
    Das MacBook Pro ist aus einem einzigen Aluminiumblock gefertigt - eine technische Meisterleistung, bei der viele Bauteile durch ein einziges ersetzt werden. Das Ganze nennt sich Unibody. Gleich beim ersten Mal, wenn Sie ein MacBook Pro in der Hand haben, werden Sie den Unterschied spüren. Das Gehäuse ist dünner und leichter als andere Notebooks. Es sieht elegant aus. Und es fühlt sich stabil und robust an: perfekt für die Aktentasche, den Rucksack und natürlich auch für draußen.
     
    Ein Display voll brillanter Ideen.
    Alles, was Apple Designer und Ingenieure tun, ist von A bis Z durchdacht. Sie entschieden sich beim MacBook Pro für die LED-Hintergrundbeleuchtung, weil das Display damit sofort seine volle Helligkeit erreicht und trotzdem unglaublich dünn ist. Sie verwendeten eine durchgehende Oberfläche aus Glas, nicht nur weil es schön aussieht, sondern weil es dem ganzen Display Struktur verleiht. Und über dem Bildschirm haben sie die neue, integrierte FaceTime HD Kamera versteckt. So siehst du Freunde und Familie im Großformat - und dabei so gut wie nichts von der Kamera.
     
    Magnetverschluss
    Da der magnetische Verschluss keine beweglichen Teile hat, die abbrechen können oder an denen man hängen bleibt, ist das Öffnen und Schließen so einfach wie alles beim MacBook Pro.
     
    Einfach auf alle Anschlüsse zugreifen.
    Alle Anschlüsse am MacBook Pro - der MagSafe Netzanschluss, der Gigabit Ethernetanschluss, der Thunderbolt Anschluss, der USB Anschluss, der Karten-Steckplatz und der Audioeingang und -ausgang - sind ganz auf einer Seite des Notebooks integriert. So bleiben die Kabel schön geordnet und Geräte lassen sich schnell und einfach anschließen und auch wieder trennen.
     
    Hinterlässt Eindruck. Aber nicht auf die Umwelt.
    Weil Apple die vollständige Kontrolle über Design, Fertigung und Verpackung des MacBook Pro hat, hat Apple einen Vorsprung beim Umweltschutz. Die Technologie zur Hintergrundbeleuchtung des Displays spart Energie. Glas und Aluminium sind besonders recyclingfähig. Das MacBook Pro kommt fast ohne Giftstoffe aus. Und die Verpackung des 43,18 cm / 17"" Modells ist im Vergleich zum Vorgängermodell 34 Prozent kleiner. Das bedeutet nicht nur, dass für die Verpackungen weniger Bäume gefällt werden, es werden für den Transport auch weniger Flugzeugen, Güterzügen und LKWs benötigt.
     
    Thunderbolt AnschlussDie Grafikleistung, die Sie brauchen, wenn Sie sie brauchen.
    Alle MacBook Pro Modelle haben jetzt einen integrierten Intel HD Graphics 3000 Prozessor für die täglichen Aufgaben. Er codiert Videos schnell, ermöglicht HD Videotelefonate mit FaceTime und vieles mehr. Und auch Decodieren erledigt er effizienter, was bedeutet, dass Sie richtig lange DVDs und iTunes Filme schauen können. Bei anspruchsvollen Grafikprogrammen wechseln die 43,18 cm / 17"" MacBook Pro Modelle automatisch den Grafikprozessor und arbeiten mit den neuen leistungsstarken AMD Radeon Grafikprozessoren. Diese bieten verglichen mit den Vorgängermodellen die bis zu 3-fache Leistung. So sehen Sie bei 3D Spielen mehr Bilder pro Sekunde oder können schneller als je zuvor an HD Videoprojekten arbeiten.
     
    Das neue Thunderbolt. Die schnellste, vielseitigste I/O Technologie in einem Notebook.
    Stellen Sie sich vor, Sie könnten auf deinem Notebook auf mehrere unkomprimierte HD Videostreams zugreifen - und zwar so schnell, dass Sie einen HD Spielfilm in Echtzeit schneiden können. Thunderbolt macht genau das möglich. Mit Thunderbolt lassen sich superschnelle Peripheriegeräte der nächsten Generation an die Computer der nächsten Generation anschließen - angefangen beim MacBook Pro. Die Thunderbolt Pipeline ist ultraschnell und ultraflexibel. Sie ist über 12 Mal schneller als FireWire 800 und bis zu 20 Mal schneller als USB 2.0. Und sie bietet beispiellose Erweiterungsmöglichkeiten. Kurzum: Sie verändert alles, was Sie auf Ihrem Notebook machen können. Der Thunderbolt Anschluss gibt Ihnen Plug&Play Anschluss für eine völlig neue Welt von Thunderbolt Peripheriegeräten sowie für das Apple LED Cinema Display und andere Mini DisplayPort Peripheriegeräte. Sie können bis zu sechs Thunderbolt Geräte in Reihenschaltung anschließen, darunter auch Ihr Display. Außerdem unterstützt Thunderbolt Video und Achtkanal-Audio, sodass es auch möglich ist, HDMI-kompatible Geräte wie Fernseher oder Stereoanlagen über einen HDMI-Adapter anzuschließen. Auch aktuelle VGA-, DVI- und DisplayPort Adapter werden unterstützt.
     
    Die neue FaceTime HD Kamera. Der Unterschied ist ganz klar.
    Sehen Sie mehr von Ihren Freunden mit dem HD Widescreenformat - und zwar gestochen scharf. Die neue FaceTime HD Kamera bietet die dreifache Auflösung der vorherigen Kamera, was perfekt für das brillante Display mit LED-Hintergrundbeleuchtung ist. Außerdem arbeitet sie jetzt bei schwachem Licht noch besser. Sie können mit Ihren Freunden HD Telefonate in 720p von einem neuen MacBook Pro zu einem anderen führen. Außerdem sind auch Videotelefonate zu anderen Macs mit Intel Prozessor, zum iPhone 4 oder zum neuen iPod touch möglich.
     
    Multi-Touch Trackpad - Jede Menge Platz für GestenMulti-Touch Trackpad. Fürs tägliche Handwerk.
    Mit dem Multi-Touch Trackpad interagieren Sie auf ganz natürliche Art mit den Inhalten auf deinem Display. Und die glatte Glasoberfläche bietet jede Menge Platz für Gesten. Durch Auf- und Zuziehen können Sie ein- und auszoomen, durch Streichen in deinen Fotos blättern, durch Drehen ein Bild anpassen und vieles mehr. Das Trackpad kommt ohne Taste aus, sodass Sie überall klicken können. Wenn Sie aus der Welt des rechten Mausklicks kommen, können Sie diesen entweder mit zwei Fingern auslösen, oder Sie konfigurieren einen physischen Rechtsklick-Bereich auf dem Trackpad. Je mehr Sie mit dem Multi-Touch Trackpad vertraut sind, desto mehr werden Sie sich fragen, wie Sie jemals ohne ausgekommen sind.
     
    Lange Laufzeit. Weniger aufladen. Mehr machen.
    Das neue MacBook Pro bietet eine fantastische Batterielaufzeit und das mit leistungsstärkeren Prozessoren und schnelleren Grafikprozessoren. Die energieeffiziente Prozessorarchitektur mit integriertem Video-Encoder sowie das automatische Umschalten zwischen den Grafikprozessoren bei den 43,18 cm / 17"" Modellen helfen, die Batterielaufzeit weiter zu verbessern. So können Sie pro Ladung bis zu 7 Stunden ohne Kabel im Web surfen oder es für Liveauftritte oder auf ein Shooting mitnehmen. Die fortschrittlichen chemischen Eigenschaften und die Adaptive Charging Technologie sorgen dafür, dass die Batterie bis zu 1000 Ladezyklen durchlaufen kann. Und da die Batterie des MacBook Pro bis zu fünf Jahre hält, kommt das MacBook Pro in einem Zeitraum, in dem ein herkömmliches Notebook drei Batterien verbraucht, mit nur einer aus. Das ist für die Benutzer genauso gut, wie für die Umwelt. Apple verwendet eine neue, strengere Testmethode, um zu messen, welche Ergebnisse Sie unter realen Bedingungen erzielen, z. B. beim Surfen in einem Cafe oder wenn Sie die neuesten Webvideos ansehen. Und wie schneidet dieses MacBook Pro dabei verglichen mit der Vorgängergeneration ab? Es liefert die gleiche fantastische Leistung.
     
    Hat beste Verbindungen.
    Unterwegs haben Sie mit der 802.11n Technologie im MacBook Pro immer Verbindung. Das MacBook Pro findet automatisch verfügbare Netzwerke und Sie können sich mit einem Klick verbinden. Auch die drahtlose Bluetooth Technologie ist integriert, sodass Sie drahtloses Zubehör sofort nach dem Auspacken verwenden können.
     
    DVDs superschnell brennen.
    Homevideos, die Sie mit iMovie und iDVD gemacht haben, können Sie mit dem 8-fach SuperDrive Laufwerk des MacBook Pro superschnell auf eine DVD brennen. Das SuperDrive kann auch Double-Layer-DVDs (also DVDs mit fast 9 GB Speicherplatz) beschreiben, sodass es auch hervorragend für Datensicherungen geeignet ist.
     
    Neue Intel Core i7 Prozessoren.
    Neue Quad-Core Intel Core i7 Prozessoren sind Standard beim 43,18 cm / 17"" MacBook Pro. Alle Modelle verwenden die kürzlich optimierten Chipsets von Intel. Was heißt das für die neuen MacBook Pro Modelle? Kurz gesagt: Sie sind bis zu zwei Mal schneller als die Vorgängergeneration und erledigen auch anspruchsvolle Aufgaben wie HD Videoschnitt, Audiokompilierung oder Rendering mehrschichtiger Bilddateien unglaublich schnell. Und da Mac OS X Snow Leopard darauf ausgelegt ist, jeden Prozessorkern zu nutzen, holt das Betriebssystem wirklich alles an Leistung aus dem Prozessor heraus.
     
    Schnellere Einzelchip-Mikroarchitektur.
    Ob Sie einen Film ansehen, Ihren Blog auf den neuesten Stand bringen oder Fotos bearbeiten - die Daten müssen von A nach B gelangen, um verarbeitet werden zu können. Die neueste Intel Core Architektur bringt den Prozessor, den Cache, den Speichercontroller und den Grafikprozessor auf einem einzigen Chip unter. Deswegen müssen die Daten keine weiten Wege zurücklegen, was für Sie schnellere Performance und höhere Effizienz bedeutet.
     
    Turbo Boost 2.0.
    Angenommen, Sie arbeiten mit einem prozessorintensiven Programm wie Aperture 3 oder Final Cut Pro, das von einem Leistungsschub profitiert würde. Turbo Boost ist eine dynamische Technologie, die automatisch die Geschwindigkeit der aktiven Prozessorkerne auf 3,4 GHz erhöht. Turbo Boost 2.0 ist noch dynamischer und effizienter. Es wechselt die Kernfrequenz in kleineren Schritten als bisher, sodass der Prozessor die Leistung ohne Effizienzeinbußen verwalten kann. All das passiert im Hintergrund. Sie arbeiten einfach nur schneller.
     
    Hyper-Threading.
    Hyper-Threading ist jetzt Standard auf jedem MacBook Pro. Mit dieser Technologie können auf jedem Kern zwei Threads gleichzeitig laufen, Mac OS X erkennt also bei einem Quad-Core Prozessor acht und bei einem Dual-Core Prozessor vier virtuelle Kerne. Wenn Sie mehrere Programme gleichzeitig verwenden, verteilt der Prozessor die Aufgaben gleichmäßiger über eine größere Anzahl Kerne.
     
    Integrierter Speichercontroller.
    Mit schnellerem Speicherzugriff legt jeder Kern direkt mit der Verarbeitung der Daten los, statt auf ihr Eintreffen zu warten. Genau deshalb nutzt die neue Intel Core Architektur einen integrierten Speichercontroller, der den schnellen 1333 MHz Speicher direkt mit dem Prozessor verbindet und Ihre Programme immer die maximale Prozessorleistung zur Verfügung haben.
     
    Energieeffiziente Grafik.
    Dank der neuen Mikroarchitektur ist der Grafikprozessor auf dem gleichen Chip wie der Zentralprozessor und hat direkten Zugriff auf den L3-Cache. Kurze Wege bedeuten mehr Leistung. Der Grafikprozessor erhöht auch automatisch die Taktrate für noch höhere Auslastung. Ein integrierter Video-Encoder ermöglicht jetzt HD Videotelefonate mit FaceTime, und der effiziente Decoder sorgt für lange Batterielaufzeit, wenn Sie sich DVDs oder iTunes Filme ansiehen.
     
    Mac OS X. Das fortschrittlichste Betriebssystem der Welt.
    Mac OS X ist das Herz jedes MacBook Pro und Mac. Dieses Betriebssystem ist genau auf die integrierten Intel Multicore-Prozessoren und fortschrittlichen Grafikprozessoren zugeschnitten. Die neueste Version, Mac OS X Snow Leopard, basiert komplett auf einer 64-Bit-Architektur, genau wie alle anderen Programme, die mit dem Mac kommen. Das bedeutet: Alles, was Sie auf Ihrem MacBook Pro machen, passiert superschnell und mit einer unglaublichen Gesamtleistung.
     
    Hat eine ganze Menge draufProgramme, ebenso leistungsstark wie benutzerfreundlich.
    Weil Apple sowohl das MacBook Pro, wie auch die integrierte Software entwickelt, arbeitet alles perfekt zusammen. Und mit den Apple Programmen sind Sie ganz schnell vertraut, weil alle ähnlich funktionieren. Das heißt, wenn Sie ein Programm kennen, sind Sie auch schnell mit allen anderen vertraut. Außerdem weiß Apple genau, was mobile Produktivität bedeutet. Darum haben wir Funktionen wie Expose und Spaces hinzugefügt. Damit können Sie ganz einfach auf alles auf Ihrem MacBook Pro zugreifen. Expose zeigt sämtliche geöffneten Fenster nebeneinander, verkleinert sie und ordnet sie so, dass Sie den Inhalt jedes Fensters sehen können - ein Tastendruck oder eine Geste genügt. Und mit Spaces können Sie Fenster zusammen auf ihrem eigenen Schreibtisch oder Bereich gruppieren und ganz einfach zwischen diesen wechseln. Legen Sie einen Bereich zum Arbeiten fest, einen zum Spielen und einen für was auch immer. Mit Expose und Spaces haben Sie beim Multitasking auf einem Notebookdisplay einen riesigen Vorteil.
     
    Darauf verzichten Sie beim Mac: PC-Viren.
    Trojaner, Würmer, E-Mail Viren. Die digitale Welt kann ganz schön beängstigend sein. Zum Glück ist der Mac immun gegen die tausenden von Viren, die Windows Computer plagen. Denn Mac OS X kommt mit integrierten Sicherheitsmechanismen, die Sie schützen - ohne dass Sie etwas machen müssen. Und sollten doch mal potenzielle Sicherheitsrisiken auftreten, reagiert Apple sofort und stellt neue Softwareaktualisierungen und Sicherheitsverbesserungen bereit, die Sie automatisch laden und mit einem Klick installieren können.
     
    Das automatische Backup rettet Ihren Tag. Und die Woche, den Monat ...
    Backups müssen sein. Trotzdem vergissen Sie sie bestimmt hin und wieder. Deshalb kümmert sich jetzt das MacBook Pro um die Datensicherung. Time Machine, ein Programm, das auf jedem Mac dabei ist, sichert automatisch Ihr ganzes System auf einer externen Festplatte oder Time Capsule. Time Machine speichert eine Kopie von jeder Datei. Und es merkt sich, wie Ihr System an einem bestimmten Tag ausgesehen hat. So können Sie, wenn Sie wollen, die Zeit zurückdrehen und Ihren Mac wie in der Vergangenheit sehen.
     
    Mit iMovie können Sie aus Ihren Videos großartige Filme machenAuch die täglichen Sachen machen mehr Spaß.
    Anders als viele PC-Notebooks kommt das MacBook Pro mit allem, was Sie brauchen, um E-Mails zu senden, Kalender zu verwalten, Kontakte zu organisieren und mehr. Und Sie können schon wenige Minuten nach dem Auspacken damit loslegen. Denn jeder Mac kommt mit Mail, um E-Mails zu senden und empfangen, iCal zum Organisieren von Terminen und wichtigen Ereignissen, dem Adressbuch zum Verwalten von Kontakten, iTunes für alles, was mit Unterhaltung zu tun hat, und weiteren tollen und nützlichen Programmen, die Sie jeden Tag verwenden werden.
     
    Der Mac App Store. Tausend weitere Gründe, den Mac zu lieben.
    Über tausend Mac Apps sind nur einen Klick entfernt - im Mac App Store. Suchen Sie einfach Apps, die Ihnen gefallen, und klicken Sie einfach, um sie zu laden und zu installieren. Ohne Verpackung. Ohne CDs oder DVDs. Und ohne Probleme. Sie können die Apps nach Kategorien durchstöbern oder direkt etwas Bestimmtes suchen. Und Sie können einfach dafür sorgen, dass Ihre Apps up-to-date sind, denn Ihr Mac zeigt Ihnen an, wann Updates verfügbar sind.
     
    iPhoto. Fotos ganz einfach verwalten, bearbeiten und teilen.
    iPhoto ist ein benutzerfreundliches Programm für Fotos, mit dem Sie Ihre Bilder schnell organisieren, wiederfinden und verbessern können - sodass sie immer perfekt aussehen. Mit den iPhoto Funktionen ""Gesichter"", ""Orte"" und ""Ereignisse"" behalten Sie den Überblick über Ihre Fotos. Sie sagen Ihnen, wen Sie fotografiert haben, wo und wann. Und all das in den neuen Vollbildmodi.
     
    iMovie. Und aus Homevideos werden Home-Blockbuster.
    Homevideos müssen nicht langweilig sein. Mit iMovie können Sie aus Ihren Videos großartige Filme machen. Zum Beispiel Trailer im Hollywoodstil, mit denen Sie Ihr Publikum begeistern.
     
    GarageBand. Großartige Musik machen, ganz einfachissimo.
    Egal, ob Sie Musiktalent haben oder einfach nur neugierig sind - GarageBand ist genau das richtige Programm für Sie. Schließ einfach eine elektrische Gitarre oder ein USB Keyboard an. Und schon können Sie mit virtuellen Nachbildungen der bekanntesten Amps und Stompboxes der Welt sowie mit 100 Software-Instrumenten spielen.  
    ";2;False;0;;;Apple MacBook Pro MC725D/A 17 Zoll Notebook;apple-macbook-pro-mc725da-17-zoll-notebook;True;True;P-0700;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;2,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;2299.9000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;40652,5987037037;3;1;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000312-apple-macbook-pro-mc725da-17-zoll-notebook.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000313-apple-macbook-pro-mc725da-17-zoll-notebook.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000314-apple-macbook-pro-mc725da-17-zoll-notebook.jpg;2;;False;;;;;False;False;False;;;;;False;;;;;; -5;0;True;Apple iPod Nano 8 GB 6. Gen. verschiedene Farben;Apple iPod Nano 8 GB 6. Generation verschiedene Farben;"
    Der Remix für Ihre Finger
    Der iPod nano mit Multi-Touch ist einfach, intuitiv und macht jede Menge Spaß - wie Ihre Musik. Und er ist jetzt noch kleiner, damit Musik bei allem, was Sie machen, eine größere Rolle spielen kann.
     
    Musik. Fühlen Sie den Beat
    Ihre Greatest Hits. Zum Anfassen
    Die besten Dinge im Leben kommen mit Soundtrack. Und genau da glänzt der iPod nano. Mit dem Multi-Touch Display können Sie Ihre Musik ganz neu erleben. Ein Tipp genügt und er spielt, was Sie hören wollen. Stöbern Sie in Ihrer Musik nach Songs, Alben, Interpreten, Wiedergabelisten, Genres oder Komponisten - streichen Sie dazu über den Homescreen. Sie können sogar die Symbole auf dem Homescreen neu ordnen, damit alles so ist, wie Sie es wollen.
     
    Das ist ein echter Musikclip
    Mit dem neuen integrierten Clip können Sie mit Ihren Lieblingssongs am Ärmel (oder in der Tasche, Jacke oder Hose) wandern, laufen, Rad fahren und abrocken. Und das Cover zum Song, der gerade läuft, passt perfekt auf das Display.
     
    Rock around the clock
    Die integrierte aufladbare Lithium-Ionen-Batterie sorgt für 24 Stunden Musik nonstop. Wenn Sie sich den 8 GB oder 16 GB iPod nano anklippen, haben Sie genug Songs für den Weg zur Arbeit, fürs Training und mehr.
     
    Songs aus dem Finger schütteln
    Überlassen Sie alles dem Zufall. Einfach den iPod nano kurz schütteln und er springt zu einem anderen Song aus Ihrer Sammlung. Schütteln ist perfekt, wenn Ihnen gerade nicht nach einer bestimmten Musik ist. Lassen Sie sich einfach überraschen.
     
    Genius. Ihr Mixmaster
     
    Eingebauter Clip

     
    Ihr persönlicher DJ
    Angenommen, Sie hören einen Song, der Ihnen gut gefällt, und möchten ähnliche hören. Ein Tipp auf Genius genügt. Genius findet weitere Songs auf Ihrem iPod nano, die gut dazu passen und erstellt eine Genius Wiedergabeliste für Sie. Wenn Sie einen Mix wollen, auf den Sie selbst nie gekommen wären, erstellen Sie einen Genius Mix in iTunes und synchronisieren ihn mit Ihrem iPod nano. Tippen Sie auf das Symbol für Genius Mixe und entdecken Sie Songs, die Sie lange nicht mehr gehört haben, oder Musik, von der Sie gar nicht mehr wussten, dass Sie sie haben.
     
    FM Radio. Und Sie haben alles auf dem Sender
    Radio nano
    Mit dem iPod nano können Sie auf der Radiowelle surfen. Der FM Tuner zeigt Ihnen den Interpreten, Song oder Sender, der gerade läuft. Ein Tipp genügt und Sie sehen die Radiosteuerungen. Streichen Sie über den Tuner, um den Sender zu wechseln, und stellen Sie dann Ihre Lieblingssender per Fingertipp ein.
     
    Live-Pause
    Wenn Sie Ihre Lieblingssendung im Radio einmal kurz unterbrechen müssen, verpassen Sie dank Live-Pause trotzdem keinen einzigen Beat. Einfach Tippen und Sendung oder Song werden angehalten. Noch mal Tippen und es geht da weiter, wo Sie aufgehört haben. Sie können sogar bis zu 15 Minuten zurückspulen und dann vorspulen, um wieder live dabei zu sein.
     
    Fitness. Treffen Sie Ihren neuen Trainer
     
    Anklippen und los geht´s
    Das neue Design des iPod nano hilft Ihnen fit zu bleiben. Weil er so klein und tragbar ist, ist er auch beim Joggen, Wandern und im Fitnessstudio immer dabei. Klippen Sie ihn an und steuern Sie Ihre Musik mit nur einem Tippen oder Streichen, sodass Sie sich voll auf Ihr Workout konzentrieren können. Ob Laufen, Walken oder der Weg zum Fitnessstudio - für den kleinen iPod nano ist kein Weg zu weit.
     
    Schritte zum Fitbleiben
    Sie können den iPod nano auch als Schrittzähler verwenden. Er zählt Ihre Schritte und hilft Ihnen beim Erreichen Ihrer Fitnessziele. Einfach anklippen und los geht´s. Sie können eine tägliche Schrittvorgabe festlegen und Ihre Fortschritte sehen, wenn Sie Ihre Daten auf die Nike+ Website laden.
     
    Rocken Sie Ihr Training
    Ob beim Joggen oder im Fitnessstudio, mit dem Nike + iPod Sport Kit (separat erhältlich) motiviert Sie der iPod nano vom Warm Up bis zum Cool Down. Ziehen Sie Ihre Nike+ Joggingschuhe an und klippen Sie sich den iPod nano an. Sehen Sie wie Sie Kilometer für Kilometer zurücklegen und hören Sie das Sprachfeedback in Echtzeit, während Ihre Songs laufen. Schließen Sie den iPod nano im Fitnessstudio an ein Gerät an, das mit Nike + iPod kompatibel ist. So zeichnet er Ihre Geschwindigkeit, die Dauer und die Laufstrecke auf, während Sie Ihr Training rocken.
     
    iTunes. Damit der iPod was zu spielen hat
    Alles für gute Unterhaltung
    iTunes ist der beste Weg, Ihren iPod nano mit den neuesten Hits, Podcasts, Hörbüchern und vielem mehr zu füllen. Und auch die beste Art, Ihre immer weiter wachsende Sammlung digitaler Medien zu durchstöbern und auf dem Mac oder PC zu organisieren. Alle im iTunes Store gekauften Inhalte und alle von CDs importierten Songs werden in Ihrer Mediathek in iTunes angezeigt. Sie können Ihre eigenen oder Genius Wiedergabelisten erstellen, Genius Mixe auswählen und alles mit Ihrem iPod nano synchronisieren. Und iTunes ist als kostenloser Download verfügbar.
     
    Der beste Music Store der Welt
    Laden Sie Ihre Lieblingssongs auf Ihren iPod nano. Oder stöbern Sie in über 13 Millionen Songs und finden Sie weitere Hits. Sie können nach dem Namen eines Interpreten, Songs oder Albums suchen und so genau die richtigen Songs finden. Sie suchen neue Musik und brauchen Hilfe? Die Genius Seitenleiste empfiehlt Ihnen neue Musik, die auf Ihren Lieblingssongs basiert. Sie können in jeden Song kostenlos 30 Sekunden reinhören. Und mit einem Klick können Sie einen Song kaufen. Er wird dann sofort geladen. Schneller und einfacher können Sie Ihre digitale Musiksammlung für den iPod nicht zusammenstellen.
     
    Bedienungshilfen
    Integrierte Bedienungshilfen.
    iPod nano kommt mit Bedienungshilfen, die Menschen mit Handicaps helfen Musik, Hörbücher und mehr zu erleben.
     
    VoiceOver
    Der iPod touch bietet VoiceOver, die weltweit erste Bildschirmlesefunktion, die auf Gesten basiert. Tippen Sie auf das Display und Sie hören eine Beschreibung des Objekts, das Sie gerade berühren. Steuern Sie den iPod nano durch Doppeltippen, Bewegen oder Streichen. Mit den optionalen Apple Earphones mit Fernbedienung und Mikrofon können Sie Ihre Musik steuern, ohne auf das Display zu sehen. VoiceOver nennt Ihnen den Song und Interpreten und spricht auch noch 29 Sprachen.
     
    Weiß auf Schwarz
    Wenn Sie stärkeren Kontrast möchten, stellen Sie das Display des iPod nano so ein, dass Weiß auf Schwarz angezeigt wird. Sie können diese Funktion in jeder App und auch auf dem Homescreen verwenden.
     
    Mono Audio
    Wenn Sie nur auf einem Ohr gut hören können, können Sie ""Mono-Audio"" aktivieren, damit die Audioausgabe auf beide Ohrhörer geleitet wird und Sie beide Kanäle mit dem gesunden Ohr hören können.

    Produktbeschreibungen
     
    Highlights
    - Multi-Touch Display
    - Genius - dein Mixmaster
    - FM Radio
    - iTunes
    - Integrierte Bedienungshilfen (VoiceOver und Weiß auf Schwarz)
     
    Akku
    - Akkutyp: Li-Ion
    - Akkulaufzeit bis zu 24 Stunden
     
    Display
    - Farbdisplay
    - Bilddiagonale: 3,91 cm
    - 1,54- Display
    - Auflösung Breite: 240 Pixel
    - Auflösung Höhe: 240 Pixel
     
    Speicher
    - Interner Speicher 8.000 MB
     
    Stromversorgung
    - USB-Lader
     
    Wiedergabeformate Audio
    - AAC
    - MP3
    - WAV
     
    Grundeigenschaften
    - Breite: 40,9 mm
    - Höhe: 37,5 mm
    - Tiefe: 8,78 mm
    - Gewicht: 21,1 g
    - Gewicht: 21,1 g
    - Farbe: Dunkelgrau
     
    Lieferumfang
    - iPod nano
    - Apple Earphones
    -Dock Connector auf USB Kabel
    - Dokumentation und wichtige Produktinformationen
    ";2;False;0;;;Apple iPod Nano 8 GB 6. Gen. verschiedene Farben;apple-ipod-nano-8-gb-6-gen-verschiedene-farben;True;True;PD-01073;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;149.9000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;40652,5607638889;49;1;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000266-apple-ipod-nano-16-gb-6-gen-verschiedene-farben.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000267-apple-ipod-nano-16-gb-6-gen-verschiedene-farben.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000268-apple-ipod-nano-16-gb-6-gen-verschiedene-farben.jpg;3;;False;;;;;False;False;False;;;;;False;;;;;; -5;0;True;Apple MacBook Air MC966D/A-i7 13,3 Zoll Notebook;"Apple MacBook Air 33,78cm (13,3"") 1,8GHz i7 4GB 256GB SSD";"
    Eindrücke:
    Bei der Entwicklung des neuen MacBook Air gab’s nur ein Ziel: ein unglaublich dünnes und leichtes Notebook, genauso leistungsstark und vielseitig wie doppelt so große Geräte. Und mit Flash-Speicher,
     
    stabilem Unibody-Gehäuse, Multi-Touch und einer ausdauernden
     
    Batterie erreicht das MacBook Air nicht nur das Ziel, es ist der neue Standard, wie ein Notebook sein sollte. Perfekt bis ins letzte Detail.
     
    Design:
    Gerade mal 1,7 cm flach. Aber damit legt das neue MacBook Air die Messlatte sehr hoch - und es macht den Flash-Speicher zum Maßstab. Da Flash-Chips so klein sind, ist das MacBook Air so unglaublich dünn und leicht. Diese Flash-Chips sind Solid-State-Komponenten, sie arbeiten ohne bewegliche Teile. Das macht sie zuverlässig, robust und sehr leise beim Arbeiten. Und da wir sie direkt auf der Hauptplatine platzieren, brauchen sie viel weniger Platz – etwa 90 % weniger, um genau zu sein. Es bleibt mehr Platz für andere wichtige Dinge. Zum Beispiel eine größere Batterie. Damit ist ein Notebook entstanden, das fast nichts wiegt und mit einer Batterieladung stundenlang durchhält. So entsteht echte Mobilität.
     
    Umweltverträglichkeit:
    Die folgenden Merkmale des MacBook Air tragen zu seiner geringeren Umweltbelastung bei:
     
    Frei von bromhaltigen Flammschutzmitteln
    Ohne PVC
    PVC-freie Netzkabel sind in Australien, Japan, Neuseeland, Nord- und Südamerika, der Schweiz, Taiwan, Thailand und Großbritannien verfügbar.
    Hochgradig recyclebares Aluminiumgehäuse
    ENERGY STAR 5.2 konform
    EPEAT-Bewertung ""Gold""
    Das MacBook Air hat in den USA und Kanada von der EPEAT die Bewertung ""Gold"" erhalten.
     
    Mitgelieferte Software:
     
    OS X Lion
    Enthält Mail, Adressbuch, iCal, Mac App Store, iTunes, Safari, Time Machine, FaceTime, Photo Booth, Mission Control, Launchpad, AirDrop, Resume-Funktion, automatisches Sichern, Versionen, Übersicht, Spotlight, QuickTime und mehr.
     
    iLife '11
    Enthält iPhoto, iMovie und GarageBand.
     
    Display:
     
    Hochauflösendes 13,3"" Hochglanz-Widescreendisplay mit LED-Hintergrundbeleuchtung (33,78 cm Diagonale), Unterstützung für Millionen Farben
     
    Unterstützte Auflösungen:
     
    1440 x 900 (nativ), 1280 x 800, 1152 x 720 und 1024 x 640 Pixel bei einem Seitenverhältnis von 16:10, 1024 x 768 und 800 x 600 Pixel bei einem Seitenverhältnis von 4:3
    ";2;False;0;;;Apple MacBook Air MC966D/A-i7 13,3 Zoll Notebook;apple-macbook-air-mc966da-i7-133-zoll-notebook;True;True;P-0720;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;2,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;1599.9000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;40652,0359953704;4;1;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000465-apple-macbook-air-mc966da-i7-133-zoll-notebook.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000466-apple-macbook-air-mc966da-i7-133-zoll-notebook.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000467-apple-macbook-air-mc966da-i7-133-zoll-notebook.jpg;2;;False;;;;;False;False;False;;;;;False;;;;;; -5;0;True;Samsung Galaxy S II (i9100) DualCore Smartphone weiß;Samsung Galaxy S II (i9100) DualCore Smartphone (10.9 cm (4.3 Zoll) Super-Amoled Plus Display, Android 2.3, 8 MP Full-HD Kamera, 2 MP Frontkamera) weiß;"
    Samsung launcht mit dem Galaxy S II den Nachfolger des Bestsellers Galaxy S. Das Galaxy S II ist nicht nur das schlankste (8,49 mm), sondern dank des 1,2 GHz Dual-Core Prozessors auch das schnellste Smartphone seiner Klasse. Darüber hinaus besticht es durch ein 4,3"" Super Amoled Plus Touch-Display. Das Galaxy S II verwendet als Betriebssystem die aktuellste Android 2.3 Version – auch bekannt unter dem Namen Gingerbread. Die integrierte 8 Megapixel Kamera mit LED Blitz hält die schönsten Momente in erstklassiger Qualität fest – darüber hinaus ermöglicht die 2 Megapixel Frontkamera Video Telefonate in beeindruckender Qualität. Das Schreiben von E-Mails und SMS gelingt unkompliziert dank Swype®-Texteingabe. Zahlreiche aktuelle und nützliche Apps stehen im Android Market™ zum Download bereit. Die integrierte Google Maps Navigation™ führt ans gewünschte Ziel. AllShare, HD Video, Exchange ActiveSync und eine Vielzahl an weiteren Applikationen lassen keine Wünsche offen. Ein erstklassiges Zusammenspiel von Hardware und Funktionen leistet sein Übriges für ein ausgezeichnetes Nutzererlebnis auf höchstem Niveau!
     
    4,27-Zoll SUPER AMOLED Plus
    Bekennen Sie Farbe! Dieses brillante Display bietet den besten Farbumfang, ein hohes Kontrastverhältnis sowie ultimative Schärfe bei Bildern. Die bahnbrechende Verkürzung der Video-Reaktionszeit sorgt für ruckfreie Videowiedergabe. Die neue Technologie benötigt weniger Platz und Energie: Im Vergleich zum Vorgänger benötigt das Display 18% weniger Energie. Es ist damit eines der dünnsten, langlebigsten Smartphones am Markt.
     
    Brillante Performance
    Das Unmögliche ist möglich. Der Samsung Dual Core Application Prozessor ist die reaktionsschnelle Antwort im Bereich mobile Performance. Er bietet Multitasking in Hochgeschwindigkeit, schnelles Laden von Internetseiten, schnelle Reaktionszeiten, eine intuitive Benutzeroberfläche, blitzschnelle Bildbearbeitung und Spiele mit hoher Performance. Und mit der superschnellen Möglichkeit zum Encodieren und Decodieren, die alles im Bereich Videoaufzeichnung und -wiedergabe (1080p / 30fps) unterstützt, stellt er alle anderen Dual Core-Prozessoren in den Schatten. Problemloses Video- oder Musik-Streaming bekommt dank des schnellen Drahtlosstandards HSPA 21 Mbps einen großen Schub. Hervorragende Rechenleistung, herausstechende Performance.
     
    Schlankes Design
    Schlank, schlanker, GALAXY S II. Das Samsung GALAXY S II führt die Riege an – mit nur 8,49 mm und einem luxuriösen Design liegt es zudem gut in der Hand. Das GALAXY S II ist eines der schlanksten Smartphones und bietet außerdem HyperSkin für einen schönen Metall-Look mit einer fingerabdruckfreien und rutschfesten Akkuabdeckung.
     
    Readers Hub
    Lassen Sie Ihre Bücher zu Hause: Das Samsung GALAXY S II übernimmt diese Aufgabe. Stöbern Sie im Readers Hub in Ihrer Bücherei mit Klassikern oder suchen Sie in mehr als 2 Millionen Büchern die neusten Bestseller. Sie können auch 2.500 Magazine in 20 Sprachen und 1.600 Zeitungen in 47 Sprachen zur Lieferung einrichten. Mit klarem, deutlichem Text und der hohen Bedienerfreundlichkeit macht das Lesen Spaß: vergrößern, nur Text und Seitenansichten, Audiozugriff sowie schnelles Verteilen per E-Mail sind nur einige Funktionen. Glauben Sie an Bücher, beschränken Sie sich jedoch nicht nur auf Papier.
     
    8-Megapixel-Kamera mit LED-Blitz
    Immer gute Fotos. Der 8-Megapixel-Kamera mit Autofokus entgehen auch bei Action-Fotos keine Details. Machen Sie auch bei schlechten Lichtverhältnissen mit dem integrierten LED-Blitz wunderschöne und detaillierte Aufnahmen. Und dank der stark verbesserten Benutzeroberfläche von Android Gingerbread ist selbst schneller Szenenwechsel möglich. Wechseln Sie problemlos auf die 2-Megapixel-Kamera vorne, um Selbstporträts zu machen. Einfach immer gute Bilder.
     
    Aufzeichnung & Wiedergabe in Full-HD
    Werden Sie zum Star. Mit den Möglichkeiten zur Videoaufzeichnung des Samsung GALAXY S II können auch Sie zur Berühmtheit werden. Mit der 1080p Full-HD-Aufzeichnung ist jeder Moment ein potenzielles Meisterwerk in der Entstehung. Erfassen Sie die Action in hoher Auflösung und mit Dual Core-Geschwindigkeit und geben Sie Ihre HD-Aufzeichnungen mit bestechender Klarheit auf dem 4,3"" SUPER AMOLED Plus Display wieder.
     
    Spracherkennung & Sprachübersetzung
    Einfach Sprachbefehle nutzen. Tippen Sie nur doppelt auf die Home-Taste und steuern Sie das Samsung GALAXY S II mit ausgewählten Sprachbefehlen. Führen Sie wichtige Funktionen wie anrufen, Musik hören oder SMS schreiben mit einfachen Sprachbefehlen aus. Sie können auch Ihre Gedanken festhalten, sich selbst eine Notiz schreiben oder unterwegs sogar mit Google Voice Translation eine Übersetzung anfertigen. Galaxy S II kann Ihnen eingehende Nachrichten auch vorlesen.
     
    Game Hub
    Noch mehr Spielspaß. Über den Game Hub von Samsung GALAXY S II können Sie hochwertige Spiele herunterladen: 12 soziale Netzwerkspiele und 13 Prämiumspiele einschließlich Gameloft’s Let Golf 2 und Real Football 2011. Sie können nach Spielen und Informationen zu Neuerscheinungen suchen oder einfach nur spielen. Mit einem Beschleunigungsaufnehmer, einem magnetischen Sensor und Gyroskop-Sensor heben sich Spiele mit Hand- und Armbewegungen deutlich aus der Masse ab. Die kleinste Bewegung reicht bereits aus – das ist spannende Unterhaltung.
     
    Social Hub
    Mit dem Social Hub lassen sich Ihre Online-Kontakte besser organisieren und synchronisieren. Sammeln Sie Ihre Informationen aus E-Mails, SMS, IM und SNS in einem einheitlichen Posteingang – Interaktionen mit anderen sind so schneller und auf die von Ihnen gewünschte Art möglich.
     
    Music Hub
    Musik darf nicht fehlen. Der neue native Music-Player von Samsung bietet ein intuitives Wiedergabesystem zum Suchen, Entdecken, Anspielen, Kaufen und Herunterladen von Musikstücken für unterwegs. Die App bietet auch viele Informationen zum Kauf sowie Zugriff auf alle gewünschten Künstler, Liedtexte und Bewertungen. Sie können Empfehlungen für neue Songs abrufen und durch Bassverstärkung und 5.1 Kanal-Sound den Hörspaß noch mehr steigern.
     
    Microsoft Exchange ActiveSync
    Das Samsung GALAXY S II ist für sicheren Zugriff auf Unternehmensressourcen auf einem Microsoft Exchange Server optimiert, damit Sie in Bezug auf geschäftliche E-Mails, Terminplaner, Kontakte und Aufgabensynchronisation auf dem Laufenden sind. Das Handy bietet die umfangreichste mobile Implementierung von Exchange ActiveSync. Es bietet das sicherste Mobile Device Management unter den Smartphones und unterstützt die meisten Richtlinien und Einschränkungen unter den Android ActiveSync Clients und ermöglicht Kommunikation in Echtzeit mit Telefonen der Mitarbeiter, um Einstellungen per Fernzugriff zu konfigurieren, die Einhaltung der Richtlinien zu überwachen, die Sicherheit bei synchronisierten Daten zu gewährleisten und verwaltete Telefone zu sperren oder Daten zu löschen.
    ";2;False;0;;;Samsung Galaxy S II (i9100) DualCore Smartphone weiß;samsung-galaxy-s-ii-i9100-dualcore-smartphone-weiss;True;False;P-0020;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;439.9000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;40651,9089699074;76;5;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000473-samsung-galaxy-s-ii-i9100-dualcore-smartphone-weis.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000474-samsung-galaxy-s-ii-i9100-dualcore-smartphone-weis.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000475-samsung-galaxy-s-ii-i9100-dualcore-smartphone-weis.jpg;2;;False;;;;;False;False;False;;;;;False;;;;;; -5;0;True;HTC Hero;"HTC Hero ";"
    HTC Hero Smartphone ohne Vertrag, ohne Branding, kein Simlock
    Probiere etwas Neues. Sei Du selbst.
     
    Der HTC Hero bietet Dir das ultimative HTC-Erlebnis. Du kannst dieses Smartphone wie kein anderes an Deine individuellen Bedürfnisse anpassen und machst es dadurch zu einem Mobiltelefon, das wie für Dich geschaffen ist. Es verbindet Dich leichter denn je mit den Menschen, die für Dich wichtig sind. - Denn alle Kommunikationen werden nach Personen anstatt nach Anwendungen organisiert. Der HTC Hero wird Dir - egal wo Du gerade bist und was Du gerade machst - das Leben durch seine einfache und intuitive Bedienung erleichtern. So, wie Du es Dir von Deinem Handy immer gewünscht hast!
     
    Make it your Hero
    Der HTC Hero ermöglicht Dir einen Level der Personalisierung, den kein anderes Smartphone bislang geboten hat. Anstatt wichtige Anwendungen hinter zahlreichen Menüstrukturen zu verstecken, kannst Du sie nun dort positionieren, wo Du direkten Zugriff hast: nämlich direkt auf einem der 7-teiligen Homescreens! Und weil HTC an die absolute Personalisierung glaubt, kannst Du auch viele Widgets mit vielfältigen Designs und in verschiedener Größe anpassen, ganz nach Deinem Geschmack. Das interaktive Erlebnis geht weiter, wenn Du z.B. einen Aktien-Ticker auf den Homescreen legst oder Dir die aktuelle Wettervorhersage für heute oder auch gleich für die nächsten fünf Tage auf einen Blick anzeigen lässt.
     
    Stay close with friends
    Die vernetzte Welt bietet uns zwar die Möglichkeit, mit mehr Menschen als jemals zuvor in Kontakt zu bleiben, aber den Überblick über alle Kontakte zu behalten, wird immer schwieriger. Statt umständlich eine Anwendung nach der anderen zu öffnen, um Deine Freunde zu kontaktieren, funktioniert das mit dem HTC Hero einfacher: Wenn Du Deine Kontakte aufrufst, siehst Du auf einen Blick die verschiedenen Möglichkeiten der Kontaktaufnahme und alle bisherigen Interaktionen - einschließlich der E-Mails, die Du an Deine privaten und beruflichen E-Mail-Adressen erhalten hast. Außerdem kannst Du direkt Status-Updates in Deinen Social Communities verfolgen und Dir die neuesten Fotos ansehen, die Deine Freunde gerade hochgeladen haben.
     
    Discover the Unexpected
    Selbst grundlegende Dinge wie die Anruf-Funktion werden Dich beim HTC Hero angenehm überraschen. Denn Du findest eine Person, indem Du ihre Telefonnummer wählst oder einfach nur die ersten Buchstaben ihres Namens eingibst. Und während Du in der Kontakt-Ansicht bist, kannst Du auch gleich einmal nachsehen, ob Dein Kontakt bald Geburtstag hat oder neue Infos oder Bilder auf Facebook oder Flickr eingestellt hat.
     
    Mit dem HTC Hero kannst Du Deine Inhalte immer aus der Perspektive betrachten, die Dir gerade am besten passt. Deine Inbox ist zum Beispiel nicht nur eine Liste mit E-Mails, sondern vielmehr ein Konversations-Chat. Mails mit Anhängen kannst Du in einer separaten Dokumenten-Bibliothek ansehen. Die Fotos in Deinem Fotoalbum sind nicht nur auf Deinem Handy abgespeichert, sondern Du kannst sie via Upload auf Facebook oder Flickr auch mit Deinen Freunden teilen.
     
    Suche und finde einfach alles, überall – mit Deinem HTC Hero. Anhand des Such-Buttons durchsuchst Du Tweets in Twitter, findest Personen in Deiner Kontaktliste, suchst nach E-Mails in Deinem Posteingang oder Terminen in Deinem Kalender… und selbst die sprichwörtliche Suche nach der Nadel im Heuhaufen ist so von Erfolg gekrönt.
     
     
    ";2;False;0;;;HTC Hero weiß;htc-hero;True;True;P-0015;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;449.0000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;40651,7809027778;"73;2095";36;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000344-htc-hero.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000345-htc-hero.jpg;;2;;False;;;;;False;False;False;;;;;False;;;;;; -5;0;True;LG KM 900 Arena;LG KM 900 Arena;"LG KM 900 Arena
     
    FM Transmitter, GPS, 5MP,WLAN 
     

    brilliantes, hochauflösendes 3Zoll Touchscreen
    benutzerfreundliches S-Class User Interface durch taktiles Feedback bei Tastendruck & Widgets
    Dolby Mobile Surround Sound und FM Transmitter für ein einzigartiges Musikerlebnis
    FM-Radio mit Senderspeicher und FMTransmitter
    Lieferumfang: Gerät, Akku, Ladegerät, stereo Kabel, Headset, Bedienungsanleitung, USB Datenkabel, PC-Software ";2;False;0;;;LG KM900 Arena;lg-km-900-arena;True;True;P-0026;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;219.0000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;40651,7531597222;"72;2095";19;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000233-lg-km-900-arena.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000234-lg-km-900-arena.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000235-lg-km-900-arena.jpg;2;;False;;;;;False;False;False;;;;;False;;;;;; -5;0;True;HTC Touch Diamond 2;HTC Touch Diamond 2;"
    HTC Touch Diamond II
     
    Brillantes Design und intuitive Bedienung sorgen schon beim ersten Ausprobieren für ein faszinierendes Erlebnis.
    Der HTC Touch Diamond2 liefert ein komplett neues Erlebnis mobiler Kommunikation, das die Interaktionsfähigkeit mit anderen Menschen spürbar vereinfacht.
     
    In Kombination mit der neuen TouchFLO™ 3D-Oberfläche ist der HTC Touch Diamond2 das aktuell attraktivste Smartphone für Konsumenten, die auf Design und Funktion setzen.
     
    Erstmals präsentiert HTC einen personenzentrischen Kommunikationsansatz: Zu jeder Kontaktperson steht die gesamte Konversationshistorie auf einen Fingerstreich zur Verfügung, unabhängig von der Art der Kommunikation wie Sprache, Text oder E-Mail.
     
    Features
     
    5-Megapixel-Kamera mit Autofokus
    Erweitertes TouchFLO 3D für eine bessere intuitive Nutzung
    3,2” WVGA LCD Touchscreen mit 480x800 Pixeln
    Zoom-Leiste für präzises Hinein- und Heraus- Zoomen in Bildern, Webseiten oder Google Maps™
    microSD™ (SD 2.0-kompatibel) Erweiterungs-Slot 
     
    Mehr als ein Telefongespräch
    In der heutigen Zeit gibt es viele verschiedene Arten der Kommunikation, doch sie haben alle etwas gemeinsam: Am anderen Ende befindet sich immer eine Person. Aus diesem Grund ermöglicht Ihnen der HTC Touch Diamond2, Ihre Kommunikation nach Personen zu organisieren – nicht nur nach der Art wie Sie kommunizieren.
     
    In Ihren Kontakten befindet sich Ihre gesamte Kommunikations-Historie – egal ob E-Mail, SMS oder Telefongespräch. Es spielt keine Rolle, ob Sie während eines Gesprächs nach einer E-Mail gefragt werden oder Sie in einem Café sitzend einen Text abrufen möchten – alle Interaktionen sind nach Personen geordnet in einem Kommunikationsbaum abgelegt.
     
    Erweitern Sie Ihr Blickfeld
    Eine unbestrittene Tatsache bei Smartphones – ein großer Bildschirm bei einem kleinen Gerät, das ist gut. Genau darum haben wir das Display des Touch Diamond2 so groß wie möglich designt, bei gleichbleibend kompaktem Gehäuse. Genießen Sie Videos, Webseiten, Fotos und andere Abbildungen auf dem ultra-scharfen Widescreen-Display – es lässt auch das kleinste Detail erkennen. 
    Schön und leistungsfähig zugleich
    Das Mobiltelefon ist eines der wenigen Gegenstände, die wir heutzutage immer an unserer Seite haben. Es hilft uns nicht nur mit unseren Freunden, Geschäftspartnern und dem weltweiten Geschehen verbunden zu sein – es ergänzt uns. Der Touch Diamond2 ist Ihr perfekter Begleiter: Er hält Sie auf dem Laufenden und ist stilvolles Accessoire zugleich.
    Mit seinem klaren und doch elegantem Design ist das HTC Touch Diamond 2 ein Smartphone mit Stil und Eleganz. Seine einfache Handhabung über den TouchFlo-3D- Bildschirm überzeugt. Feinste Sensoren garantieren eine empfindliche, daher schnelle Bedienbarkeit. Ein neues Erlebnis von mobiler Kommunikation ob im privaten oder im business-Bereich.
     
    Die zahlreichen Funktionen sind komfortabel zu bedienen, die ausgeprägte Technik im HTC Touch Diamond 2 vereint zahlreiche Funktionen mit wenig Aufwand. Als Navigationsgerät ein zuverlässiger Wegweiser ist das HTC Touch Diamond 2 ein edler Begleiter, nicht zuletzt durch die zahlreichen Onlinefunktionen für Unterwegs der ideale Communicator.
     
    ";2;False;0;;;HTC Touch Diamond 2 Smartphone;htc-touch-diamond-2;True;True;P-0012;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;399.0000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;40651,7106365741;73;36;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000198-htc-touch-diamond-2.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000199-htc-touch-diamond-2.jpg;;2;;False;;;;;False;False;False;;;;;False;;;;;; -5;0;True;HTC Touch HD;HTC Touch HD;"
    HTC Touch HD (Blackstone) (UMTS, HSDPA, 5MP, Touch Screen, 3.8 Zoll Display) Smartphone ohne Branding
     
    HTC – Smarte Geräte für smarte Leute / Perfekt für Sie geeignet
    Bei der Entwicklung von HTC-Produkten berücksichtigen wir immer die Bedürfnisse individueller Anwender. Wenn Sie gerne Text eintippen, gibt es für Sie Geräte mit praktischen aufschiebbaren QWERTZ-Tastaturen. Mit einem unserer vielen Touch-Geräte können Sie entweder mit Ihren Fingern oder einem Stift Anwendungen bedienen und im Internet browsen. Wenn Sie sich eine hohe Leistungsfähigkeit wünschen, geben Ihnen unsere 3,5G-Geräte die Geschwindigkeit, die Sie für das Herunterladen und Streaming von Medieninhalt aus dem Internet benötigen. Wenn Sie nach einem Telefon suchen, das einfach alles kann, finden Sie in unserem Produktsortiment leistungsfähige PDA-Telefone, die Ihnen alle möglichen Funktionen für unterwegs bieten. Die Liste kann unaufhörlich fortgesetzt werden.
     
    HTC glaubt nicht, dass es lediglich eine große Lösung für alle Probleme gibt. Warum sollten Sie Ihre Lebensweise auf die Funktionen eines einzelnen Produktes abstimmen? Egal welche Bedürfnisse Sie haben, mit unserer jahrelangen Erfahrung in Innovation, unserem Fachwissen und unserem Vorstellungsvermögen kann HTC Ihnen mit Sicherheit Produkte bieten, die perfekt auf Sie und Ihren Lebensstil zugeschnitten sind.
     
    Führende Technologie
    HTC ist ein Vorreiter in der Technologie für mobile Geräte. Wir entwickeln nicht nur Produkte mit Funktionen, die Sie haben sollten, wir entwickeln Produkte mit Funktionen, die Sie wirklich benötigen, und die Sie sich wirklich wünschen. Wir wissen, dass Sie sich ein schickes und smartes Gerät wünschen, mit dem Sie Ihre Arbeiten erledigen können, mit denen Sie jederzeit erreichbar sind und mit denen Sie auch mal etwas Spaß haben können. Dies ist der Grund dafür, warum HTC immer wieder neue Maßstäbe bei der Herstellung von Produkten setzt, die Kunden das bestmögliche mobile Erlebnis bieten können.
     
    HTC hört Ihnen zu
    HTC produziert Produkte, die Ihnen, unserem geschätzten Kunden, gefallen. Um dies auch wirklich zu erreichen, legen wir sehr viel Wert darauf, Ihnen zuzuhören und herauszufinden, wie Sie Ihr Leben gestalten und welche Wünsche Sie haben. Wir verfolgen nicht nur die Trends auf dem Markt sondern auch die Entwicklungen im kulturellen Umfeld. Wir nehmen uns die Bedürfnisse unserer Kunden zu Herzen und entwickeln auf effiziente Weise neue Produkte, um Ihre Wünsche in kürzester Zeit zu erfüllen.
     
    Das HTC Touch HD im Detail
    Genießen Sie Musikvideos, Filme und Streams, wie Sie es sich nie auf einem Mobilgerät erträumt hätten. Das Surfen im Internet wird zu einer berauschenden Erfahrung ... so als hätten Sie Ihren Laptop dabei. Und das alles auf einem hochauflösenden 3,8""-WVGA-Display, das sich nahtlos mit der berührungsempfindlichen TouchFLOTM 3D-Oberfläche vereint.
     
    Dank der blitzschnellen 3.5G-Technologie erreicht Ihre Internetverbindung echte Breitbandgeschwindigkeit. In HSDPA-Netzen liefert das Touch HDTM eine Downloadgeschwindigkeit von bis zu 7,2 Mbit/s – so können Sie ohne Einschränkungen arbeiten und spielen.
     
    Das neue Register „Stock“ (Aktien) informiert über aktuelle Aktienkurse, während in der Startanzeige E-Mails, Nachrichten und der Kalender nur einen Fingerzeig entfernt sind.
     
    Die Routenführung bringt Sie sicher ans Ziel, Satellitenkarten weisen Ihnen den Weg und mit GoogleTM Maps wissen Sie jederzeit, wo Sie gerade sind. Auf dem breiten Display sind die Karten jetzt noch größer und schärfer. Die Anzeigesteuerung bietet eine Zoomfunktion und eine Detailansicht. So wird Navigation völlig neu definiert.
     
    Zu den Highlights des Gerätes gehören:
    - Kinoerlebnis für unterwegs mit 3,8 Zoll breitem WVGA-Display (480 X 800 Pixel)
    - Fortschrittliche TouchFLOTM 3D -Oberfläche, die beim Navigieren durch Kontakte und Webseiten sowie Anzeigen von 
      Medieninhalten perfekt auf Fingerbewegungen reagiert
    - HSDPA-Internetverbindung ermöglicht Surfen und Datentransfer mit Breitbandgeschwindigkeit.
    - Google MapsTM im Breitbildformat
    - 5-Megapixel-Kamera für höchste Foto- und Videoqualität
    - Durch den 3,5-mm-Audioanschluss ist das Touch HDTM mit umfangreichen Audiozubehör kompatibel.
     
    ";2;False;0;;;HTC Touch HD Smartphone;htc-touch-hd;True;True;P-0009;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;449.0000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;40651,6773263889;73;36;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000188-htc-touch-hd.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000189-htc-touch-hd.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000190-htc-touch-hd.jpg;1;;False;;;;;False;False;False;;;;;False;;;;;; -5;0;True;Sony Ericsson Xperia PLAY Smartphone;Sony Ericsson Xperia PLAY Smartphone (10,1 cm (4 Zoll) Touchscreen, 5 MP Kamera, Android OS 2.3, inkl. 7 vorinstallierten Spielen);"
    Sony Ericsson Xperia PLAY
    Effizientes Arbeiten und hochklassiges Spielevergnügen
    Sie brauchen ein hocheffizientes, voll ausgestattetes Smartphone? Und was wäre, wenn es noch richtige Spielsteuerungselemente bieten würde? Hier ist es: Das Xperia™ PLAY. Ein PlayStation™ certified Android™ Smartphone, das Sie in die Spiele Ihrer Wahl eintauchen lassen.
     
    Vorinstallierte Spiele
    Auf dem Xperia™ PLAY haben Sie viele Spiele vorinstalliert, mit denen Sie Ihr Können unter Beweis stellen können. Und das ist nur der Anfang. Wählen Sie aus einem riesigen Angebot, das ständig wächst und bereits Tausende von Spielen der weltbesten Anbieter umfasst, unter anderem auch PlayStation®-Spiele. Besuchen Sie den Android Market™ und schauen SIe nach, welche Anbieter bereits Spiele bereitgestellt haben. (Vorinstalliert sind folgende Spiele: Star Battalion, Bruce Lee: Dragon Warrior, Crash Bandicoot, FIFA10, SIMS 3, Tetris)
     
    Das Xperia PLAY™ ist in aller Munde. Das erste PlayStation®-zertifizierte Smartphone löst wahre Begeisterungsstürme bei den Spieleanbietern aus.
     
    So, das ist nun das PSP Handy?
    Einst ein Traum. Heute Realität. Das erste PlayStation certified Android™-Smartphone bietet eine unglaubliche Grafik, eine großartige Tonqualität und richtige Spielsteuerungselemente. Das Handy wird dennoch nicht ""das PSP Handy"" genannt. Wir nennen es Xperia™ PLAY.
     
    Das Smartphone als Controller
    Spielbegeisterte erkennen sofort die Konsolentasten. Sie wurden von demselben Team entwickelt und getestet, das auch den PS3-Controller entwickelt hat.
     
    Das erste PlayStation®-zertifizierte Smartphone mit speziellen Spieletasten, L/R-Schultertasten und vier Symboltasten
    4-Zoll-Multitouch-Bildschirm mit 16 Millionen Farben
    Spielvergnügen wie bei einer Spielekonsole mit überragendem Stereo-Sound
    Mit Snapdragon 1-GHz-CPU und dem leistungsstarken Grafikprozessor Adreno 205, der optimales Spielvergnügen garantiert
    Micro SD mit 8 GB (im Lieferumfang enthalten), erweiterbar auf 32 GB
     
    Multimedia-Smartphone mit Android™
    Nie wieder verlaufen. Entdecken Sie Städte und Sehenswürdigkeiten mit 3D-Karten. Verwenden Sie Google Voice Search™, um Anrufe zu tätigen, Nachrichten zu schreiben usw. Mit Ihrem Xperia™ PLAY Android™ Handy brauchen Sie nicht mehr zu tippen. Geben Sie die Anweisungen einfach per Sprache ein. Darf's etwas mehr sein? Holen Sie sich alle Apps, die Sie brauchen, aus dem Android Market™.
     
    Greife direkt auf die mobilen Dienste von Google™
    Surfe per Sprachbefehl mit Google Voice Search™ im Internet
    Mach aus deinem Smartphone im Handumdrehen eine Spielekonsole
    ";2;False;0;;;Sony Ericsson Xperia PLAY Smartphone;sony-ericsson-xperia-play-smartphone;True;True;P-0028;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;269.9000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;40651,6637268519;77;35;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000573-sony-ericsson-xperia-play-smartphone.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000574-sony-ericsson-xperia-play-smartphone.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000575-sony-ericsson-xperia-play-smartphone.jpg;2;;False;;;;;False;False;False;;;;;False;;;;;; -5;0;True;LG P970 Optimus Black Smartphone;"LG P970 Optimus Black Smartphone (10.2cm (4 Zoll) NOVA-Touchscreen, 5 MP Kamera, 9.2mm dünn, Android 2.2, 3.5mm Buchse, Wifi, GPS) schwarz ";"
    Die Superlative - LG P970 Optimus Black mit NOVA Display Technologie
    Neue Technologie für helles und gleichzeitig energiesparendes Display
    10.2 cm (4 Zoll) Touchscreen Smartphone mit Android 2.2 Betriebssystem, 2 Megapixel Frontkamera, WiFi (b/g/n standards).
     
    Superflach, superhell und super energiesparend: Das neue Android-Modell LG P970 OPTIMUS BLACK steht für eine neue Form der Superlative bei Smartphones. Das NOVA-Display mit einer Bildschirmdiagonale von 10,2 Zentimetern garantiert die hellste, klarste und deutlichste Anzeige auf einem Mobiltelefon-Display — selbst bei direkter Sonneneinstrahlung. Einen Superlativ bringt LG auch mit dem Design des neuen Android-Modells: Mit nur 9,2 Millimetern ist das LG P970 OPTIMUS BLACK eines der dünnsten Smartphones auf dem Markt.
     
    LG’s NOVA-Technologie — ein Display-Novum in Sachen Helligkeit…
    „Unser LG P970 OPTIMUS BLACK ist der Inbegriff des innovativen Smartphones. Die Kombination aus anspruchsvoller Technologie sowohl beim Display als auch beim Design machen unser neues Android-Modell zu einem absoluten Must-Have“, so Gunter Thiel, Head of Mobile Marketing bei der LG Electronics Deutschland GmbH.
    Mit einer Leuchtdichte von 700cd/m² (Candela pro Quadratmeter) setzt das NOVA-Display neue Standards: Sehr gute Smartphones-Displays kommen aktuell auf bis zu 480 cd/m². Dank seiner größeren Helligkeit und reinen Weißtönen, die eine kontrastreiche Schwarz-Weiß-Darstellung ermöglichen, bietet das neue Smartphone den Anwendern mehr Komfort beim Surfen im Internet, Lesen von E-Mails und Verfassen von Dokumenten.
     
    … und im Stromverbrauch
    Das NOVA-Display zeigt auch seine „grüne“ Seite: Es verfügt nicht nur über eine höhere Leuchtkraft, sondern sorgt darüber hinaus für eine deutliche Reduzierung des Energieverbrauchs. Im Vergleich zu einer herkömmlichen LCD-Anzeige benötigt das Display 50 Prozent weniger Strom. Auch AMOLEDs verbrauchen doppelt so viel Energie wie ein NOVA-Display für die Darstellung eines hauptsächlich weißen Bildschirms, also des Farbschemas, das am häufigsten beim Browsen im Web genutzt wird. In Verbindung mit dem 1500-mAh-Akku des LG P970 OPTIMUS BLACK steht den Nutzern genügend Energie für ihre täglichen Anforderungen selbst bei maximaler Helligkeitseinstellung zur Verfügung.
     
    Superlative auch in Sachen Style …
    Dank seinem ultraflachen 9,2 Millimetern Design setzt das LG P970 OPTIMUS BLACK mehr als nur stylishe Akzente: Mit einem Gewicht von gerade mal 109 Gramm, einer eleganten Linienführung und abgerundeten Kanten wird das neue Smartphone zu einem wahren Handschmeichler. Mit der raffinierten Rückseite des Geräts, die nach Außen flach zuläuft, wirkt das Profil von 6,0 Millimetern noch einmal schlanker. Ein unverwechselbares Kennzeichen des LG P970 OPTIMUS BLACK ist das minimalistische Design — selbst der Lautsprecher ist nahezu unsichtbar im Rahmen des Telefons integriert.
     
    … und Funktionen: Wi-Fi Direct, Apps und vieles mehr
    Als weltweit erste Gerät unterstützt das LG P970 OPTIMUS BLACK Wi-Fi Direct1 für die schnelle Übertragung von Daten zu anderen Geräten. Zudem bietet das neue Android-Smartphone eine Reihe von intelligenten Funktionen für den einfachen und schnelleren Zugriff auf relevante Apps und Inhalte. Das OPTIMUS User Interface (UI) 2.0 ermöglicht den Anwendern den direkten Zugriff auf Nachrichten, E-Mails und verpasste Anrufe mit nur einer Fingerberührung auf dem gesperrten Display. Die Gestensteuerung unterstützt auch intuitive Kommandos wie Hochheben, Schütteln und Antippen, um Anrufe entgegenzunehmen, in den Kameramodus zu schalten oder Musik zu genießen. Ebenfalls ein Novum ist die Ausstattung mit einer Frontkamera mit 2 Megapixeln Auflösung.
    (1Für die Aktivierung von Wi-Fi Direct™ auf dem Smartphone ist eine Anwendung erforderlich, die in der erste Hälfte des Jahres 2011 im Android Market zum Download zur Verfügung gestellt wird.)
     
    Alle Features des LG P970 OPTIMUS BLACK sind auf der Android 2.2 Froyo Plattform mit der Möglichkeit zum zukünftigen Upgrade auf Android 2.3 Gingerbread verfügbar. Nach einem Upgrade auf Android Gingerbread können die Nutzer Videogespräche mit höherer Qualität über die 2- Megapixel-Frontkamera des LG P970 OPTIMUS BLACK führen.
     
    Beschreibung der Features
     
    2 MP Front-Kamera
    Warum auf Bildqualität für sich selbst verzichten? Mit der 2 MP Front-Kamera haben Sie jetzt eine noch höhere Auflösung für die Front-Kamera zur Verfügung. Für Selbstporträts und Videotelefonie in noch höherer Qualität.
     
    Volle Flash-Unterstützung und Android Market
    Dank des Android Betriebssystems haben Sie uneingeschränkten mobilen Zugriff auf das Internet. Ihr Smartphone unterstützt sämtliche Flash-Formate und setzt dem Online-Spaß keine Grenzen. Ausserdem haben Sie die Möglichkeit, auf Apps zuzugreifen und können Sich beispielsweise den Google Navigator kostenlos herunterladen. So haben Sie ein Navigationsgerät in Ihrem Handy.
     
    Im gigantischen Online Store Android Market stöbern Sie vom Handy aus durch über 200.000 Apps für Social Networks, Games, Lifestyle, Shopping und mehr. Oder Sie finden genau die App, die Sie schon lange gesucht haben. So individualisieren Sie Ihr Smartphone genau nach Ihren Wünschen und machen Ihren neuen Begleiter zu einem Spezialisten auf jedem Gebiet.
     
    G-Key
    Mit dem G-Key bedienen Sie Ihr Smartphone noch intuitiver. Bei aktiviertem G-Key nehmen Sie eingehende Anrufe mit einer einfachen Bewegung ihres LG an, scrollen zwischen Fotos oder wechseln Anwendungen wörtlich im Handumdrehen.
     
    NOVA Display
    Mit einem NOVA-Display müssen Sie nie wieder nach einem schattigen Platz suchen, um etwas erkennen zu können. Ob in völliger Dunkelheit oder direkter Sonneneinstrahlung, das NOVA Display bietet Ihnen jederzeit perfekte Klarheit und eine ungekannte Farbechtheit. Es ist dabei bis zu 50% energieeffizienter als vergleichbare LCD-Displays.
     
    Wi-Fi Direct
    Mit der Wi-Fi Direct Technik übertragen Sie Daten zwischen Wi-Fi-Geräten ganz simpel und schnell, ohne einen externen Acces Point zu benötigen. Wi-Fi Direct zeichnet sich dabei nicht nur durch die einfache Bedienung sondern darüber hinaus auch durch die extrem hohe Übertragungsrate aus: 20 mal schneller als über eine herkömmliche Bluetooth-Verbindung.
    ";2;False;0;;;LG P970 Optimus Black Smartphone;lg-p970-optimus-black-smartphone;True;True;P-0023;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;189.0000;189.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;40651,6470023148;"72;2095";19;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000259-lg-p970-optimus-black-smartphone.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000260-lg-p970-optimus-black-smartphone.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000261-lg-p970-optimus-black-smartphone.jpg;2;;False;;;;;False;False;False;;;;;False;;;;;; -5;0;True;Motorola Milestone 2 Smartphone;Motorola Milestone 2 Smartphone (9,4 cm (3,7 Zoll) Touch-Display, 5 Megapixel Kamera, 1Ghz, 16GB, Android 2.2);"
    Motorola Milestone 2 - Slider Smartphone mit QWERTZ Tastatur (9,4 cm (3,7 Zoll) Touch-Display, 5 Megapixel Kamera, 1Ghz, 16GB, Android 2.2)
     
    Motorola Milestone 2 - Ansichten
    MILESTONE™ 2 mit MOTOBLUR™
    Das ultraflache Slider - Smartphone mit Android™ 2.2 und ausklappbarer QWERTZ-Tastatur bietet im Vergleich zu seinem Vorgänger noch mehr Geschwindigkeit, noch mehr Verbindungsmöglichkeiten, noch mehr Messaging, noch mehr Speicher, noch mehr Web-Erlebnisse, noch mehr Multimedia, den Adobe® Flash®-Player 10.1 und ein Plus an Personalisierung.
     
    Das Hochleistungs-Smartphone besitzt einen 1 GHz-Prozessor, der alle Eingaben blitzschnell umsetzt, selbst wenn viele Anwendungen parallel laufen oder eine Vielzahl von Webseiten geöffnet sind. E-Mails oder Nachrichten lassen sich dank verbesserter QWERTZ-Tastatur mit noch größeren Tasten und sehr gutem Tastendruck schneller eingeben. MILESTONE 2 ist bestens auf die Anbindung an das firmeneigene IT-Netz eingestellt. Zusätzliche Kontrollmöglichkeiten erhöhen die Sicherheit in Firmennetzwerken. Das Smartphone lässt sich außerdem als persönlicher WLAN-Hotspot einsetzen, über den sich bis zu fünf Nutzer mit ihren Geräten im Internet einloggen können.
     
    MOTOBLUR synchronisiert DatenMOTOBLUR™ erleben
     
    Das MILESTONE 2 ist mit der neuesten MOTOBLUR-Version, Motorolas mobilem Dienst für soziale Netzwerke, ausgestattet.
    MOTOBLUR fasst alle verfolgten Threads, Freunde und freigegebene Posts, Links oder Fotos in einem einzigen Datenstrom zusammen.
    MOTOBLUR synchronisiert Daten von Gmail, Arbeits-E-Mails, Facebook, Myspace und Twitter. Dabei werden Ihre Daten sogar gesichert, d. h. Sie können auch bei einem Verlust des Telefons die Informationen auf einem neuen Telefon von Motorola mit MOTOBLUR wiederherstellen, wenn Sie Ihren Benutzernamen und ein Kennwort eingeben.
     
     
    Fotos und VideosBilder und Videosequenzen in großartiger Qualität

    Die 5-MP-Kamera mit Zoom, Autofokus, Blitzlicht und Bildstabilisation ist ideal für die Aufnahme von Bildern und Videosequenzen in großartiger Qualität. Content posten, runterladen oder synchronsieren mit Motorola Media Link. Das Motorola MILESTONE 2 nimmt HD-Videos mit 720p-Signal auf und gibt diese auch in HD wieder. Und das Beste: Da das MILESTONE 2 nach dem DLNA-Standard (Digital Living Network Alliance) arbeitet, können die Videos oder andere Multimedia-Inhalte anschließend mit DLNA-kompatiblen Geräten ausgetauscht werden.
     
    Multimedia-Inhalte
    Internet - Nachrichten - Multimedia und Online-Communitys
    Dank Adobe Flash Player 10.1 kann man außerdem Angebote Tausender Webseiten so sehen, wie sie sein sollen. Ein weiteres Highlight ist der vernetzte Mediaplayer, der neben der Musik die Songtexte sowie zusätzliche Informationen zum Künstler zugänglich macht und Applikationen bietet, um Empfehlungen zu geben und auszutauschen.
     
    Mit einem internen Speicher von 8 GB bietet MILESTONE 2 jede Menge Speicherplatz für Multimedia-Inhalte. Dieser lässt sich über die mitgelieferte 8 GB microSD-Karte erweitern. Wem das nicht genügt, kann microSD-Karten von bis zu 32 GB verwenden.
     
    Eine Reihe von Google™-Applikationen wie Google Search™, Google Maps™, Google Mail™ und YouTube™ runden die Geräteausstattung ab. Außerdem bietet der Android Market™ Zugang zu Tausenden Apps.
     
    Smartes Zubehör
    Das MILESTONE 2 wird mit einer 8 GB-microSD-Karte und einem Headset ausgeliefert. Nutzer können die Motorola Media Link Software kostenlos herunterladen, um Musik oder andere Multimedia-Inhalte ganz einfach zwischen dem Smartphone und dem PC auszutauschen
     
     
    Zubehör: Multimedia-StationMit weiterem optionalem Zubehör läuft das MILESTONE 2 zuhause, im Auto oder im Büro zur Höchstform auf:
    Die optionale Autohalterung ist startklar für die Straße. Sobald das Handy in der Autohalterung steckt, stellt es auf den Automodus um. Mit einer Berührung sind alle Funktionen zugänglich, egal, ob Kontaktauswahl über die Freisprecheinrichtung, Musik, Internetradio, Podcasts, Google Maps™ mit Navigation™ oder vieles mehr. Das Handy lässt sich einfach über das Ladekabel aufladen, das an die Autohalterung angeschlossen werden kann. Mit integriertem GPS und der MOTONAV Schritt-für-Schritt-Navigation gelangt man immer ans Ziel
     

    MILESTONE 2 verwandelt sich in der komfortablen Multimedia-Station in eine Schaltzentrale für Filme, Musik, Bilder oder in einen Digitalwecker. Im Desktop-Modus kann das Gerät mit den Wunsch-Apps individualisiert werden. Und das alles, während das Milestone 2 automatisch auflädt. Die Multimedia-Station ist auch mit dem ersten MILESTONE kompatibel.
    ";2;False;0;;;Motorola Milestone 2 Smartphone;motorola-milestone-2-smartphone;True;True;P-0036;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;499.0000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;40651,6393981481;"75;2095";16;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000424-motorola-milestone-2-smartphone.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000425-motorola-milestone-2-smartphone.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000426-motorola-milestone-2-smartphone.jpg;2;;False;;;;;False;False;False;;;;;False;;;;;; -5;0;True;BlackBerry Curve 8520;BlackBerry Curve 8520 schwarz;"
    BlackBerry Curve 8520
      
     
    QWERTZ-Tastatur


    Das BlackBerry Curve 8520 Smartphone passt genau in Ihre Hand, in Ihre Tasche - und in Ihr Leben.
    Mit dem schlanken und leichten Design liegt es gut in der Hand und bietet hohen Bedienkomfort.
    Nachrichten können mit dem BlackBerry Curve 8520 Smartphone mit der vollständigen QWERTZ-Tastatur
    einfach und schnell versendet werden. Jeder Buchstabe ist einer eigenen Taste zugewiesen.
    Dies erleichtert die Eingabe und fühlt sich ganz natürlich an.
    Das helle Display sorgt mit mehr als 65.000 Farben für eine brillante Anzeige, ganz egal, ob Sie sich E-Mails,
    Textnachrichten, Videos oder Bilder ansehen.
     
    Das BlackBerry Curve 8520 Smartphone ist unmittelbar mit Apple-Computern kompatibel.
    Synchronisieren Sie Ihre Kontaktlisten, Kalender, Termine und Notizen mit den Anwendungen,
    die Sie am häufigsten nutzen. Wenn Sie die BlackBerry Desktop Software auf Ihrem BlackBerry
    Curve 8520 Smartphone verwenden, ist das BlackBerry Smartphone ganz ähnlich zu bedienen
    wie Ihr Apple-Computer.
    Schlankes vereinfachtes Design
    Spezielle Medientasten
    Verbindung mit BlackBerry App World
    Videokamerafunktionen (2.0 Megapixel-Digitalkamera)
    Unterstützung von Apple-Computern
    ";2;False;0;;;BlackBerry Curve 8520 Smartphone ohne Vertrag;blackberry-curve-8520;True;True;P-0033;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;269.0000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;40651,6285069444;"70;2095";43;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000488-blackberry-curve-8520.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000489-blackberry-curve-8520.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000490-blackberry-curve-8520.jpg;2;;False;;;;;False;False;False;;;;;False;;;;;; -5;0;True;LG KP500 Cookie;"LG KP500 Cookie schwarz ";"
    LG KP500 Cookie
     
    LG KP500 Cookie Smartphone
    Touchscreenhandy mit iPhone-Feeling für Einsteiger!
    Das Full-Touchscreen-Telefon LG KP500 überzeugt durch innovative Technologien und Features, wie sie bislang nur High-End-Telefonen mit kompletter Touchscreen-Bedienung vorbehalten waren.
     
    Touchscreen für alle
    Die Optimierung der Benutzeroberfläche stand bei der Entwicklung des LG KP500 im Mittelpunkt. Die Onscreen-QWERTZ-Tastatur wird eingeblendet, sobald der Benutzer das LG KP500 quer hält, und das Auto- Rotating-Display zeigt Bilder oder Dokumente immer in der passenden Ausrichtung an, egal wie man das Handy hält.
     
    Spielspaß
    Darüber hinaus bietet das LG KP500 auch noch Bewegungssensor-Spiele, die für ein aktiveres und spannenderes Spielerlebnis sorgen, indem der Benutzer das Mobiltelefon in die gewünschte Richtung dreht oder neigt.
     
    Intuitive Bedienung
    Dank seiner intuitiven Benutzeroberfläche kann das LG KP500 mit den klaren Symbolen auf dem 3-Zoll-Display sofort von jedermann verwendet werden. So ist es auch ganz einfach, den Kontakt zu Freunden zu halten.
     
    Kurzwahlfunktionen über Icons
    Über die innovative Bedienoberfläche kann der Benutzer das Foto von Freunden der entsprechenden Kurzwahl zuordnen und muss dann lediglich zu dem Bild des gewünschten Gesprächspartners blättern und es berühren, um ihn anzurufen.
     
    3,0-Megapixel-Digitalkamera
    Das großzügige 3""-Display bietet darüber hinaus nicht nur genügend Platz für eine komfortable Bedienung, sondern auch die Möglichkeit Videoclips, eigene Filmchen (max.320 x 240 Pixel, bis zu 24fps) oder Fotos zu betrachten. Diese können mit der 3,0-Megapixel-Digitalkamera (2-faches Digital-Zoom) geschossen und auch per Internet versendet werden.
     
    Unterhaltung an Bord
    Radio und MP3-Player befinden sich ebenfalls an Bord. Für einfachen Datentransfer besitzt das LG KP500 sowohl einen USB-Anschluss, als auch eine Bluetooth-Anbindung.
     
    Reichhaltiger Lieferumfang
    Geliefert wird das LG KP500 in schwarzer Farbausführung inklusive Akku, Ladegerät, Stereo-Kabel-Headset, Bedienungsanleitung, USB-Datenkabel, PC-Software und Styluspen.
    ";2;False;0;;;LG KP500 Cookie;lg-kp500-cookie;True;True;P-0022;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;139.0000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;40651,569375;"72;2095";19;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000247-lg-kp500-cookie.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000248-lg-kp500-cookie.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000249-lg-kp500-cookie.jpg;1;;False;;;;;False;False;False;;;;;False;;;;;; -5;0;True;Sony Ericsson Satio;Sony Ericsson Satio;"
    Sony Ericsson Satio
     
    Satio - Erlebe Entertainment in nicht für möglich gehaltenen Farbdimensionen.
    Das Satio bringt Technik und Ästhetik auf völlig neue Weise zusammen und ist mit einer 12,1 Megapixel Kamera ausgestattet.
    Lass Bilder sprechen Mit den einzigartigen Touch Panels tippst du dich direkt in deine beste Musik und deine Lieblingsvideos.
    Die leistungsfähige Touchscreen-Kamera liefert dir gestochen scharfe Bilder. Jede Aufnahme ein Meisterstück.
    Zum Scharfstellen tippen

    Die 12,1 Megapixel Kamera mit Xenon-Blitzlicht und intuitivem manuellen Fokus liefert hochaufgelöste Aufnahmen, die auch auf einem großen Bildschirm beeindrucken.
    The Magic Touch
    Auf dem Sony Ericsson Satio holst du deine Lieblingsinhalte mit nur einer Berührung auf den Bildschirm.
    Ob TV-Serien, Handyvideos, Podcasts oder Musik: Mit dem genialen Fulltouch-Medienmenü dieses beeindruckenden Entertainment-Handys tauchst du direkt ein.
    Widescreenwunder
    Die 16 Millionen Farben auf dem Sony Ericsson Satio machen Videos und Fotos zum Augenschmaus.
    Auf dem gestochen klaren 3,5-Zoll-Bildschirm im 16:9-Format siehst du sie genau so, wie sie gedacht sind.
    Symbian OS
    Ein offenes Betriebssystem für Mobilgeräte, das Ihnen den Download neuer Anwendungen auf Ihr Handy ermöglicht
    TFT-Touchscreen mit 360x640 Pixel und 16,777,216 Farben
    unterstützte Netze: GSM/GPRS/EDGE 850/900/1800/1900 UMTS/HSPA 900/2100
    12.1 Megapixel mit Autofokus und Bildstabilisator
    Betriebssystem: Symbian OS
    Lieferumfang:
    Sony Ericsson Satio, Verpackung, Akku, Ladegerät, Bedienungsanleitung, Headset, Datenkabel, Handytasche, TV Kabel, Bedienstift
    ";2;False;0;;;Sony Ericsson Satio;sony-ericsson-satio;True;True;P-0029;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;299.0000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;40651,4580324074;77;35;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000415-sony-ericsson-satio.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000416-sony-ericsson-satio.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000417-sony-ericsson-satio.jpg;2;;False;;;;;False;False;False;;;;;False;;;;;; -5;0;True;Blackberry Bold 9700 QWERTZ;"Blackberry Bold 9700 QWERTZ ";"
    Blackberry Bold 9700 QWERTZ
     
    Schlank, smart und beeindruckend: Das Flagschiff Blackberry Bold 9700!
     
     
    Das Blackberry Bold 9700 ist ein Blackberry Smartphone mit vollständiger QWERTZ-Tastatur in edlem Schwarz!
    Es kombiniert praktische Funktionen wie eine 3,2-Megapixel-Autofokuskamera samt Bildstabilisator und Blitz mit
    dem Bedienkomfort eines sensitiven Trackpads, das eine mühelose Steuerung aller wichtigen Funktionen per
    Fingertip ermöglicht. Im Gegensatz zu seinen Vorgängern wurden behutsame Modifikationen bei der Gestaltung
    des User-Interface, der Anordnung von Bedienelementen und technischer Auslegung von Media-Player und
    Stereo-Lautsprechern vorgenommen. Ansonsten wartet dieses Smartphone mit bewährten Attributen auf,
    darunter geschwungenes und harmonisches Design, sowie ein großes helles Display, das mit seinen brillanten
    Farben Webseiten, Fotos, Spiele und Videoclips optimal darstellt.
    Smartphone mit hochauflösendem 2,44¿-Farbdisplay mit 480 x 360 Pixeln und mehr als 65.000 Farben
    Bedienfreundliches Touchpad und vollständige, beleuchtete QWERTZ-Tastatur
    3,2 Megapixel-Digitalkamera mit Autofokus, Bildstabilisierung und 2-fach Digitalzoom
    Integrierter A-GPS-Empfänger
    Lieferumfang:
    Akku, Ladegerät, Stereo-Kabel-Headset, Bedienungsanleitung, USB Datenkabel und PC-Software
    ";2;False;0;;;"Blackberry Bold 9700 QWERTZ ";blackberry-bold-9700-qwertz;True;True;P-0032;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;499.0000;499.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;40651,4502777778;"70;2095";43;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000403-blackberry-bold-9700-qwertz.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000404-blackberry-bold-9700-qwertz.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000405-blackberry-bold-9700-qwertz.jpg;2;;False;;;;;False;False;False;;;;;False;;;;;; -5;0;True;Samsung Galaxy S Super Clear LCD (i9003) Smartphone;"Samsung Galaxy S Super Clear LCD (i9003) Smartphone (10,1 cm (4 Zoll) Display, Touchscreen, 5 Megapixel Kamera) schwarz ";"
    Überirdisch leistungsstark.
    Eine Leistungsklasse für sich, das ist das Samsung Galaxy S Super Clear LCD (i9003). Highlight des eleganten Android™-Smartphones ist der extragroße Super Clear LCD-Touchscreen. Hier wird das Betrachten von Videos zum mobilen Kinoerlebnis. Auch das Surfen im Internet geht dank großem Display und Multitouch-Zoom leicht von der Hand. Das Schreiben von E-Mails und SMS gelingt unkompliziert dank Swype®-Texteingabe. Zahlreiche aktuelle und nützliche Apps stehen im Android Market™ zum Download bereit. Die integrierte Google Maps Navigation™ führt ans gewünschte Ziel. Ein erstklassiges Zusammenspiel von Hardware und Funktionen leistet sein Übriges für ein ausgezeichnetes Nutzererlebnis auf höchstem Niveau! Das Samsung Galaxy S Super Clear LCD - überirdisch leistungsstark und galaktisch gut.
     
    Unvergessliche Bildqualität
    Das Super Clear LC-Display beeindruckt durch seine ausgeprägte Farbtreue und ist deutlich heller und weniger anfällig für reflektierendes Licht als konventionelle LC-Displays. Eine Luftpolsterschicht zwischen Bildschirm und berührungsempfindlicher Schicht des Touchscreens besteht nicht, da die Berührungssensoren direkt auf dem Display angebracht sind. Dies sorgt nicht nur für die sichtbar bessere Farbdarstellung, sondern auch für höhere Schärfe und erlaubt dünnere Displaybauweisen.
     
    In bester Kommunikation
    Wollen Sie selbstgedrehte Videos oder Bilder mit anderen teilen, gelangen diese auf direktem Wege über das Mobilfunknetz in Social Communities wie zum Beispiel Facebook®, Twitter ™oder MySpace™ – ein Antippen des Touchscreens genügt. Das interaktive Telefonbuch hält Sie übersichtlich darüber auf dem Laufenden, was Ihre Freunde in den Sozialen Netzwerken posten. Ohne, dass Sie deren Profile einzeln aufrufen müssten. Ein Blick genügt.
     
    Schnelle Texteingabe
    Von den Erfindern der automatischen Textvervollständigung T9 kommt mit Swype® die Revolution der Texteingabe über Touchscreens. Texte werden nicht Buchstabe für Buchstabe eingegeben, sondern einzelne Worte werden ohne abzusetzen mit dem Finger über die virtuelle Tastatur nachgefahren. Texte lassen sich so bis zu 1,5-mal schneller verfassen. Bei mehrdeutigen Eingaben bietet Swype® eine Übersicht in Frage kommender Begriffe. Typische Rechtschreibfehler werden dabei automatisch korrigiert.
     
    Kabelloser Datenaustausch
    Multimediainhalte bringen Sie spielend leicht auf DLNA™-kompatible Geräte wie Fernseher, PCs und Notebooks. Dank DLNA™-Standard AllShare™ komplett kabellos und ohne lange Einrichtung. Sollte Ihr Fernseher nicht DLNA™-tauglich sein, erweitert das optional erhältliche Multimedia Gateway WMG160 diesen mit der entsprechenden Funktionalität.
     
    Mobil arbeiten
    ThinkFree® bietet auch unterwegs Zugriff auf lokal oder online gespeicherte Office-Dokumente. Diese stehen zur Ansicht und zur Bearbeitung zur Verfügung.
    ";2;False;0;;;Samsung Galaxy S Super Clear LCD (i9003) Smartphone;samsung-galaxy-s-super-clear-lcd-i9003-smartphone;True;True;PD-01071;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;469.0000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;40651,4194212963;76;5;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000623-samsung-galaxy-s-super-clear-lcd-i9003-smartphone.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000624-samsung-galaxy-s-super-clear-lcd-i9003-smartphone.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000625-samsung-galaxy-s-super-clear-lcd-i9003-smartphone.jpg;2;;False;;;;;False;False;False;;;;;False;;;;;; -5;0;True;HTC Desire HD;"HTC Desire HD Smartphone (10,9 cm (4.3 Zoll) Touchscreen, 8MP Kamera, Android OS 2.2, HSPA) Maduro Brown ";"
    Innovation, die macht was Sie wollen
    Das HTC Desire HD ermöglichtmit der neuesten Technologie, einem 10,9 cm Touchscreen und dem bislang schnellsten Prozessor ein besonderes Interneterlebnis. Es ist mit Android™ 2.2 und der neuesten Version von HTC Sense™ ausgestattet.
     
    Ein 10,9 cm WVGA Touchscreen
    Der große Touchscreen eigent sich perfektzum Anschauen von Videos, Filmen und Fotos sowie zum Surfen im Internet. Videos können mit einer Auflösung von 720p aufgenommen und in HD-Qualität auf Ihrem TV wiedergegeben werden. Musik wird ganz einfach auf den internen Speicher oder eine SD-Karte übertragen.
     
    Das ultimative Interneterlebnis
    Die Kombination aus dem 10,9 cm Touchscreenund dem 1 GHz-Prozessor sorgt für das ultimative Interneterlebnis. Sie können mehrere Websites gleichzeitig öffnen und diese parallel nutzen, genau so, wie Sie es von Ihrem PC gewöhnt sind. Die Textanpassung sorgt dafür, dass sich der Text beim Hineinzoomen in eine Website automatisch an das Display anpasst, so dass Sie nicht mehr scrollen müssen. Dank Flash 10.1-Unterstützung werden alle Websites so angezeigt, wie sie aussehen sollen.
     
    Mit nur einem Fingertipp...
    ...Ihre Freunde erreichen
    Mit dem Favoriten-Widget können Sie direkt auf Ihrem Homescreen verschiedene Kontaktgruppen mit Freunden oder Kollegen anlegen. Ein Anruf, eine SMS oder eine E-Mail sind dann nur noch einen Fingertipp entfernt.
     
    ...alle Anwendungen oder Apps bedienen
    Sie können jede beliebige Anwendung oder App auf dem 7-teiligen Homescreen platzieren und nach Belieben anordnen, indem Sie sie einfach per Drag & Drop dort hinziehen. So ist alles, was Ihnen wichtig ist, immer nur einen Fingertipp entfernt.
     
    Auf Facebook, Twitter und Flickr gleichzeitig zugreifen
    Mit Friend Stream sehen Sie alle neuen Facebook-Updates, Tweets und Flickr-Fotos Ihrer Freunde in einer Ansicht, die sich automatisch aktualisiert. Und wenn Sie Ihre eigenen Profile in diesen Sozialen Netzwerken aktualisieren wollen, können Sie das in nur einem Schritt erledigen. 
     
    Schöne Momente Festhalten
    Mit der 8 Megapixel Kamera erzielen Sie erstaunliche Aufnahmen. Eine hohe Auflösung, großartige Farben und eine Vielzahl an Einstellungsmöglichkeiten bringen ein hohes Maß an Professionalität in Ihre Aufnahmen. Im dunkler Umgebung helfen Ihnen 2 LED-Blitze, immer alles im Bild zu haben. Und auch Videos erscheinen nun in HD-Auflösung. Erfassen Sie Ihre nächste Geburtstagsparty, die Firmenfeier oder Ihre Freunde in 720p Qualität.
    Sehen Sie alles auf einem großen Display
    Vorbei sind die Zeiten, in denen Sie Texte auf winzigen Displays entziffern mussten und die entscheidenden Informationen übersehen haben. Auf dem 10,9 cm großen Display des HTC Desire HD genießen Sie ein wahrhaft großartiges Interneterlebnis. Mit Features wie der gestochen scharfen Textdarstellung und der brillanten Wiedergabe von Fotos und Videos ist das HTC Desire HD wie dafür geschaffen, Ihre Lieblingswebsites, YouTube-Clips und Facebook-Fotos optimal wiederzugeben.
     
    Ein Handy, das Sie nicht verlieren können
    Mit HTC Sense™ können Sie Ihr Handy aus derFerne über ein sicheres Web-Portal steuern. Sie können es anweisen zu klingeln, selbst wenn es stumm geschaltet ist, um es wiederzufinden, oder Sie sperren es und löschen alle Inhalte, falls es gestohlen wurde. Sie können eine Nachricht an Ihr Handy senden, in der Sie den Finder um die Rückgabe bitten. Kontakte, SMS und MMS können gesichert werden, sodass sie einfach wieder hergestellt werden können.
    ";2;False;0;;;HTC Desire HD Smartphone;htc-desire-hd;True;True;;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;3,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;299.0000;299.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;40651,414375;"73;2095";36;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000621-htc-desire-hd.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000622-htc-desire-hd.jpg;;1;;False;;;;;False;False;False;;;;;False;;;;;; -5;0;True;HTC HD7;"HTC HD7 Smartphone (10,9 cm (4,3 Zoll) Touchscreen, Windows Phone 7, 5MP Kamera, GPS, Dolby Mobile, 8 GB interner Speicher, ohne Branding) schwarz ";"
    Mobiles Entertainment in High Definition
    Das HTC HD7 ist das ultimative Handy für die Wiedergabe von Filmen. Denn durch das Widescreen-Display, den hochwertigen Klang und den großen Speicher erleben Sie auch unterwegs perfektes Kino.
     
    Großes Display und toller Klang
    Genießen Sie Ihre Filme auf dem riesigen 10,9 cm Widescreen-Display. Dabei müssen Sie Ihr Handy nicht die ganze Zeit in der Hand halten – klappen Sie einfach den Ständer aus und lehnen Sie sich bequem zurück. Durch die Dolby Mobile-Technologie erleben Sie auch unterwegs einen bislang unerreichten Klang in Kinoqualität. Mit Zune® haben Sie ein perfektes Mediencenter, denn damit können Sie auch unterwegs Inhalte herunterladen und diese mit Ihrem PC synchronisieren. 8-16 GB integrierter Speicher sorgen für genug Platz, um all Ihre Filme, Musik und Spiele überallhin mitzunehmen.
     
    Neue Features mit Windows Phone 7
    Freuen Sie sich darauf, mit weniger Bedienschritten mehr zu erledigen. Nutzen Sie den Windows® Phone Marketplace für den schnellen, bequemen Einkauf und besuchen Sie den HTC Hub für weitere Windows® Apps, die für HTC-Nutzer kostenlos sind. Langeweile ist dank Xbox Live® Gaming auf Ihrem Handy kein Thema mehr.
     
    Der Mensch an erster Stelle
    Auf dem HTC HD7 finden Sie die gesamte Kommunikation mit Ihren Kontakten an einem Ort. So haben Sie direkt Zugriff auf Facebook®- und Windows® Live-Updates und Fotos, SMS und MMS, E-Mails und Anrufe. Die Personen, die Sie zuletzt kontaktiert haben, werden Ihnen auch zuerst angezeigt oder Sie gehen alternativ Ihre ganze Kontaktliste durch.
     
    Momente festhalten und teilen
    Mit der integrierten 5 Megapixel Kamera halten Sie jeden Augenblick fest. Ob Firmenveranstaltungen, Geburtstagsfeiern, Trips durch die Natur - Ihr HTC HD7 lässt Sie nie im Stich. Der eingebaute Blitz hilft Ihnen, selbst an dunklen Orten ein scharfes Bild zu erhalten. Direkt nach der Aufnahme, können Sie dieses auf einer der unzähligen Social Network Seiten veröffentlichen und so mit Ihren Freunden und Bekannten teilen.Mit der Videofunktion zeichnen Sie verblüffende HD-Videos mit 720p auf
    ";2;False;0;;;HTC HD7 Smartphone;htc-hd7;True;True;PD-01069;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;3,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;299.0000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;40651,4104166667;73;36;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000619-htc-hd7.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000620-htc-hd7.jpg;;1;;False;;;;;False;False;False;;;;;False;;;;;; -5;0;True;Blackberry Bold 9000;Blackberry Bold 9000 black;"
    Blackberry Bold 9000  
     
     
    WLAN, GPS, QWERTZ-Tastatur, Kamera mit 2 MP, MP3-Player

     
    Das BlackBerry Bold Smartphone ist Innovation pur
    Mobile Komplettlösung mit hinterleuchteter QWERTZ (Tastatur), beweglichem Trackwheel und 480 x 320 Pixel Display
     
    Verfügbare Funktionen:
    Mobile E-Mail, Organizer, Mobiles Internet, Telefon, Kamera, Videoaufnahme, Media Player, Zugriff auf Unternehmensdaten, SMS, MMS, GPS & Blackberry Maps
    Erweiterbarer Speicherplatz - unterstützt microSD-Karten, 1 GB integrierter + 128 MB Flash-Speicher
    Unterstützt Tri-Band-HSDPA, Quad-Band-GSM/EDGE 3G und WLAN 4 und kann als Hochgeschwindigkeits-Modem mit 3,6 MB/s eingesetzt werden
    ";2;False;0;;;Blackberry Bold 9000;blackberry-bold-9000;True;True;P-0031;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;459.0000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;40651,1651736111;"70;2095";43;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000370-blackberry-bold-9000.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000371-blackberry-bold-9000.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000372-blackberry-bold-9000.jpg;2;;False;;;;;False;False;False;;;;;False;;;;;; -5;0;True;Blackberry Curve 8900;Blackberry Curve 8900;"
    Blackberry Curve 8900 
     
     
    WLAN, GPS, QWERTZ-Tastatur, BlackBerry Maps, Organizer, Kamera mit 3,2 MP, MP3-Player
     
     
    Deutsche Tastatur im QWERTZ-Layout mit beweglichem Trackball, ESC- und Menütaste zur intuitiven Menüsteuerung, hochauflösendes 2,44 Zoll-Farbdisplay mit 480x360 Pixel
     
    Verfügbare Funktionen:
    WLAN-kompatibel IEEE 802.11b/g, Integrierter GPS-Empfänger, Media Player für Audio und Video, Videoaufzeichnung, BlackBerry Maps, Mobile E-Mail, Organizer, Browser, Mobiltelefon, Zugriff auf
    Unternehmens-EDV, SMS/MMS
     
    3,2 Megapixel-Kamera mit Autofokus, automatischem Blitz und Bildstabilisierung, Videofunktion
    Netzkompatibilität: GSM 900/1800/GPRS (Europa, Asien, Australien, Südamerika (teilw.)), CDMA 850/1900/GPRS (Nordamerika), EDGE
    ";2;False;0;;;Blackberry Curve 8900;blackberry-curve-8900;True;True;P-0035;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;359.0000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;40651,1558101852;70;43;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000365-blackberry-curve-8900.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000366-blackberry-curve-8900.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000367-blackberry-curve-8900.jpg;1;;False;;;;;False;False;False;;;;;False;;;;;; -5;0;True;HTC Touch 2;HTC Touch 2;"
    HTC Touch 2 
     
    Das HTC Touch2 macht es Ihnen leicht
     
      
    Bleiben Sie in Kontakt mit Ihren Freunden, finden Sie heraus, was es bei Facebook Neues gibt, rufen Sie Ihre Mails ab oder surfen Sie im Web.
    All diese Möglichkeiten stehen Ihnen auf Fingerdruck zur Verfügung – mit einem kompakten Telefon, das perfekt in der Hand liegt.
    Sie möchten noch mehr mit dem Touch2 erleben? Dann laden Sie doch einfach Spiele und Anwendungen aus dem Windows Marketplace auf Ihr Handy, um es noch besser an Ihre Wünsche anzupassen.
    Und damit Ihre Daten jederzeit sicher sind, können Sie direkt auf dem Microsoft MyPhone-Server ein Backup anlegen – ohne einen PC dafür zu benötigen.
    Der HTC Touch2 bietet zahlreiche Verbesserungen bezüglich des TouchFLO, des User Interface (Wetterbericht, Shortcuts zu den beliebtesten Anwendungen...) und die Einführung von Google Maps für Mobiltelefone, YouTube und vieles mehr.
    Touch2 - Technische Details :
    Displaytaktiles 2.8"" TFT-LCD Display mit QVGA Auflösung Windows Mobile® 6.5
    Professionaltaktile Front Panel Buttons für einfache Bedienbarkeit NetworkSchnelles Surfen und hohe Download-Geschwindigkeiten dank HSDPA
    GPSintegrierte GPS Antenne
    Fotoapparat3.2 Megapixel mit der Möglichkeit, Videos aufzunehmen
    AnschlüsseWi-Fi (IEEE 802.11 b/g), Bluetooth 2.0, 3.5 mm Audioanschluss
    Betriebssystem: HTC TouchFLO mit Windows Mobile 6.5 Professional
    Verbindungsoptionen: GSM/Edge (850/900/1800/1900 MHz), WCDMA/HSDPA (900/2100 MHz), HSDPA (7,2 Mbps)
    Gesprächszeiten: WCDMA bis zu 370 Minuten, GSM bis zu 440 Minuten
    Standby-Zeiten: WCDMA bis zu 500 Stunden, GSM bis zu 370 Stunden
    ";2;False;0;;;HTC Touch 2;htc-touch-2;True;True;P-0016;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;299.0000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;40650,9831712963;73;36;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000577-htc-touch-2.jpg;;;2;;False;;;;;False;False;False;;;;;False;;;;;; -5;0;True;"HTC HD2 ";"HTC HD2 in edlem schwarzen Design ";"
    HTC HD2 in edlem schwarzen Design
      
    Windows Mobile 6.5; 4,3 Zoll WVGA Touchscreen Display, 5 Megapixel-Kamera mit Auto-Fokus und LED Blitzlicht
     
    Mit dem HTC HD2 präsentiert die HTC Corporation, weltweiter Marktführer bei Telefonen auf Basis von Windows Mobile und Android, das neue Flaggschiff seiner Windows Phone-Familie.
     
    Der HTC HD2 ist das weltweit erste Windows Phone mit HTC Sense, einem mobilen Erlebnis, das den Anwender und seine natürlichen Handlungsstränge in den Mittelpunkt stellt.
    Mächtige Leistungsreserven verspricht der mit 1 GHz getaktete Snapdragon-Prozessor von Qualcomm, der den HTC HD2 zur ultimativen Surf-, Multimedia- und Gaming-Maschine macht.
    Erstes Windows Phone mit HTC Sense
    HTC Sense basiert auf drei fundamentalen Prinzipien, die durch Zuhören und Beobachten, wie Menschen leben und kommunizieren, ermittelt wurden: Make it Mine, Stay Close und Discover the Unexpected.
    Make it Mine
    Der HD2 lässt sich maßgeschneidert an individuelle Anforderungen anpassen. Und dabei spielt das brillante Display seine gesamte Größe aus.
     
    Animierte Hintergründe oder Wetterapplikationen (bei Regen fallen Regentropfen, bei bewölktem Himmel ziehen Wolkenschwaden über den Bildschirm etc.) vermitteln ein einzigartiges Erlebnis,
    ohne dabei andere wichtige Anwendungen oder Inhalte zu stören.
    Eine Vielzahl an Unterhaltungs- und Zusatzapplikationen aus dem Windows Marketplace for Mobile lädt zudem ein, den HD2 komplett an die eigenen Vorlieben anzupassen.
    Stay Close
    Egal über welche Art von Kommunikationskanal (Sprache, SMS, Email, Facebook etc.) die Verbindung mit Freunden, Verwandten oder Geschäftspartnern aufrecht gehalten werden soll,
    der Personen-bezogene Kommunikationsansatz von HTC stellt zu jeder Kontaktperson die gesamte Konversationshistorie auf einen Fingerstreich zur Verfügung.

    Discover the Unexpected
    Auf Basis des mobilen Erlebnisses HTC Sense hält der HTC HD2 eine Vielzahl an Erweiterungen bereit, die den Umgang mit dem Smartphone-Giganten spürbar vereinfachen.
     
    Der HD2 verfügt über diverse Sensoren, unter anderem einen Näherungssensor, der Fehleingaben während eines Telefonats verhindert.

    Lieferumfang:
    HTC Touch HD2, Akku, Ladekabel, USB-Kabel, kabelgebundenes Headset
    ";2;False;0;;;HTC HD2 Smartphone;htc-hd2;True;True;P-0011;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;3,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;599.0000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;40650,9376967593;"73;2095";36;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000386-htc-hd2.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000387-htc-hd2.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000388-htc-hd2.jpg;1;;False;;;;;False;False;False;;;;;False;;;;;; -5;0;True;Sony Ericsson XPERIA X10 Mini Pro Smartphone;Sony Ericsson XPERIA X10 Mini Pro Smartphone (6,6 cm (2,6 Zoll) Display, QWERTZ-Tastatur, Android, WLAN, GPS, 5 Megapixel Kamera;"
    Leistungsmerkmale des Sony Ericsson X10 Mini Pro Smartphone
    Cleveres Zubehör
    Rufen Sie Ihre Freunde an und lassen Sie Sich anrufen. Hören Sie Musik, halten Sie die Musik an und überspringen Sie einen Titel. Ganz ohne Ihr Handy. Sind Sie auf der Suche nach portablen Stereo-Lautsprechern? Die Sony Ericsson MS450 Lautsprecher (Optional) oder einem Hi-Fi-Headset mit Fernbedienung (z.B. Sony Ericsson MH810 - Optional)? Lassen Sie Ihr Handy in der Tasche und verwenden Sie Ihr Zubehör als Fernbedienung.
     
    Timescape™ - Freunde treffen
    Sony Ericsson Timescape™ ermöglicht die Anzeige der gesamten Kommunikation an einem Ort. Facebook™, Twitter™, SMS, Anrufe in Abwesenheit - alles in einer Anwendung zusammgefasst. Jede Menge geöffnete Anwendungen, um zu sehen, was gerade los ist? Die Zeiten sind endlich vorbei.
     
    Mit der Kraft von QWERTZ
    Sie tippen lieber auf einer Tastatur? Mit der kompletten QWERTZ-Tastatur können Sie Nachrichten noch einfacher schreiben.
     
    Alles von überall
    Die gesamte Kommunikation mit Ihren Freunden über das Telefonbuch. Alle Informationen zu Interpreten über den Music-Player. Einfach die Infinity-Taste berühren und schon werden alle Informationen angezeigt. Sofort.
     
    Individuelle Freiheit
    Ihre unverzichtbare Navigationsanwendung? Ihre Musik? Eine News-Site? Sie entscheiden, was wichtig für Sie ist. Wählen Sie die Symbole für die vier Ecken auf dem Startbildschirm selbst aus. Sie können die Anordnung jederzeit wieder ändern. In der Mitte des Bildschirms können Sie ein Widget einfügen. Gestalten Sie Ihren Bildschirm frei nach Ihren individuellen Bedürfnissen.
     
    Android - Google - Apps
    Das Xperia™ X10 Mini basiert auf der Android™-Plattform. Sie haben die Möglichkeit alle Google™-Anwendungen im vollen Umfang genießen zu können – Google Search™, Google Voice Search™, Google Talk™, Gmail™, YouTube™, Google™ Maps und dem Android Market™.
     
    Selbst aussuchen - Android Market™
    In Ausgehstimmung? In Aufbruchlaune? Oder im Ausruhmodus? Downloaden Sie jede beliebige Anwendung vom Android Market™ und passen Sie Ihr Xperia™ X10 Mini nach Ihren individuellen Vorlieben an.
     
    HSPA – rasante Geschwindigkeit
    Turbo-UMTS ermöglicht Ihnen breitbandähnliche Geschwindigkeiten auf dem Handy. Laden Sie große Dateien und E-Mail-Anhänge in wenigen Augenblicken herunter. Holen Sie sich Websites und Newsfeeds in Sekunden auf den Bildschirm.
     
    Finden Sie Ihr Ziel - mit aGPS
    Nie wieder verlaufen. Ihr Telefon verfügt über integriertes aGPS. Ortsgebundene Dienste helfen Ihnen, den Weg an Ihr Ziel zu finden. Oder fügen Sie Ihren Bildern mit der Geo-Tagging-Funktion Ortsangaben hinzu.
     
    UKW-Radio
    Musik liegt in der Luft - einfach einstellen und genießen. Ihr Handy verfügt über ein integriertes UKW-Radio.
     
    Wi-Fi-Verbindung
    Schnell und einfach in Verbindung bleiben. Unterwegs. In Cafés. Am Flughafen. Ihr Xperia™ X10 Mini unterstützt Wi-Fi.
    ";2;False;0;;;Sony Ericsson XPERIA X10 Mini Pro Smartphone;sony-ericsson-xperia-x10-mini-pro-smartphone;True;True;P-0027;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;159.9000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;40650,9259606482;77;35;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000476-sony-ericsson-xperia-x10-mini-pro-smartphone.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000477-sony-ericsson-xperia-x10-mini-pro-smartphone.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000478-sony-ericsson-xperia-x10-mini-pro-smartphone.jpg;2;;False;;;;;False;False;False;;;;;False;;;;;; -5;0;True;"Apple iPod touch 4G 64 GB ";"Der neue iPod touch. Jetzt mit FaceTime, Retina Display, HD-Video und Game Center. ";"
    Der neue iPod touch. Jetzt mit FaceTime, Retina Display, HD-Video und Game Center.
     
    Spaß, hoch entwickelt. Der neue iPod touch.
    Tonnen von innovativen Funktionen gibt es jetzt auch auf dem iPod touch. Einfach damit er noch mehr Spaß macht. Teilen Sie schöne Momente mit Freunden via FaceTime. Nehmen Sie Videos in HD auf. Oder erleben Sie Spiele auf dem höchstauflösenden iPod Display, das es je gab. Der iPod touch hat so viel Technologie, dass Sie glatt vergessen, dass es ein iPod ist.
     
    Sieht unglaublich aus. Ist aber wahr.

    Mit seinem neuen Design ist der iPod touch der dünnste, leichteste und fantastischste iPod touch, den es je gab. Um das zu spüren, müssen Sie ihn nur in die Hand nehmen. Er ist gerade mal 7,2 mm dünn. Mit seiner Vorderseite aus Hightech-Glas und der Rückseite aus Edelstahl fühlt er sich einfach fantastisch an. Wenn Sie ihn einschalten, sind Sie sofort vom brillanten Retina Display fasziniert. Der iPod touch kombiniert großartiges Design und revolutionäre Technologie - von außen wie von innen.
     
    Retina Display. Die Zukunft sieht gut aus.
    Es gibt viele Gründe, den iPod touch immer wieder anzusehen. Beispielsweise das LCD-Display mit 960 x 640 Pixeln und Hintergrundbeleuchtung. Es hat eine Pixeldichte von 326 ppi und ist damit das höchstauflösende iPod Display, das es je gab. Die Apple Ingenieure haben dafür superkleine, kaum 78 Mikrometer breite Pixel entwickelt, die das menschliche Auge nicht mehr als einzelne Pixel wahrnehmen kann. Und obwohl Sie sie nicht sehen können, werden Sie den Unterschied bemerken. Der Text ist gestochen scharf und alles sieht leuchtend und lebendig aus.
     
    Apple A4 Prozessor. Mehr Power für Sie.
    Hinter - oder besser gesagt unter - dem ganzen Spaß, den Sie mit dem iPod touch haben, steckt der Apple A4 Chip. Die Apple Ingenieure haben den A4 Chip als leistungsstarken und energieeffizienten Mobilprozessor entworfen. Damit bewältigt der iPod touch komplexe Aufgaben wie Multitasking, Videoschnitt und FaceTime Anrufe. All das bei noch mehr Batterielaufzeit. Und mehr Spaß.
     
    Gyrosensor + Beschleunigungssensor. Wirklich bewegend.
    Der iPod touch hat jetzt ein paar neue Tricks drauf. Er hat einen integrierten 3-Achsen-Gyrosensor, der zusammen mit dem Beschleunigungssensor dafür sorgt, dass der iPod touch Aktionen wie Beschleunigung, 3D Bewegung und Drehrate erkennt. Im Klartext: Mehr Bewegungen, mehr Gesten und größere Präzision für noch mehr Spielspaß.
     
    Zwei Kameras. Doppelt so viel Spaß.
    Für Videoaufnahmen hat der iPod touch zwei integrierte Kameras. Mit der Rückkamera nimmt er fantastische HD 720p Videos auf. Und der hoch entwickelte rückwärtig belichtete Sensor sorgt selbst bei schwacher Beleuchtung für tolle Aufnahmen. Das integrierte Mikrofon nimmt dabei gleichzeitig Gespräche, Musik oder alles andere auf. Die Frontkamera des iPod touch ist perfekt für FaceTime Anrufe1 und um sich selbst aufzunehmen. Schon erstaunlich, wie viel Spaß in etwas so Kleines passt.
    Multi-Touch. Alles unter Kontrolle Ihrer.
    Wie macht der iPod touch eigentlich genau das, was Sie wollen, wenn Sie mit Ihren Fingern über das Display streichen? Genau genommen ist es eine Kettenreaktion. Das Multi-Touch Display hat einen Schutzfilm über der kapazitiven Sensorik, die Berührungen anhand elektrischer Felder erkennt. Diese Informationen werden an das Retina Display darunter übermittelt. So könen Sie alles mit den Fingern steuern, mit Cover Flow in Ihren Alben blättern, Fotos sehen und vergrößern, in eine Website zoomen und Spiele steuern.
     
    FaceTime auf dem iPod touch. Sagen Sie nicht einfach Hallo. Sagen Sie es mit einem Lächeln.
    Ein Lächeln sagt mehr als tausend SMS.
    Bringen Sie LOL auf die nächste Stufe und sehen Sie Ihre Freunde wirklich lachen. Oder lassen Sie XOXO lebendig werden und schicken Sie einen Kuss um die halbe Welt. FaceTime auf dem iPod touch macht's möglich. FaceTime funktioniert sofort nach dem Auspacken - Sie geben einfach Ihre Apple ID und E-Mail Adresse ein. Oder erstellen einen neuen E-Mail Account extra für FaceTime. FaceTime ist supereinfach. Stellen Sie sich vor, Sie wollen über Wi-Fi mit Ihrer besten Freundin videotelefonieren. Dann tippen Sie auf die FaceTime App, finden sie dort und starten den Anruf. Auf ihrem iPod touch oder iPhone 4 erscheint dann eine Einladung, die sie annehmen kann. Sobald sie annimmt, wird FaceTime gestartet. Das alles funktioniert ganz nahtlos und sowohl im Hoch- als auch im Querformat. Sie werden im wahrsten Sinne des Wortes sehen, wie viel Spaß Sie haben können.
     
    Videotelefonieren Sie mit Freunden per FaceTime oder spielen Sie gegen Freunde oder Fremde mit Game Center.
     
    Zwei Kameras für Spaß von jeder Seite.
    Der iPod touch hat zwei Kameras - eine vorne über dem Display und eine auf der Rückseite. Die Frontkamera ist für FaceTime optimiert. Sie hat genau das richtige Sichtfeld und die richtige Brennweite, um auf die Entfernung einer Armlänge das Gesicht zu fokussieren. So zeigt sie Sie immer im besten Licht. Was besonders praktisch ist, wenn Sie mit jemandem sprechen, der mehr als nur ein Freund ist.
    Die Rückkamera. Teilen Sie Ihre Ansicht.
    Wenn Ihre Mitbewohnerin es doch nicht mehr zum Konzert schafft, lassen Sie sie mit FaceTime doch wenigstens die Zugabe sehen. Wenn die Band auf die Bühne kommt und ihren Lieblingshit spielt, tippen Sie einfach auf die Taste. Und noch bevor der Sänger die erste Zeile singt, wechselt der iPod touch zur Rückkamera und überträgt einen mit Sicherheit legendären Auftritt. Tippen Sie noch einmal und der iPod touch wechselt zurück auf die Frontkamera und zu Ihnen. Einfach und schnell - macht einfach Spaß!
     
    HD Videoaufnahme auf dem iPod touch. Nehmen Sie jeden Spaß mit. Und auf.
     
    Integrierter Schnittplatz.
    Sie müssen mit dem Bearbeiten Ihrer Videos nicht warten, bis Sie wieder am Computer sitzen. Einfache Schnittfunktionen sind direkt im iPod touch integriert, sodass Sie gleich damit loslegen können. Ziehen Sie einfach, um Start- und Endpunkt des Films festzulegen. Behalten Sie nur die Teile des Videos, die Ihnen besonders gefallen, und machen Sie daraus einen Film, den Sie und Ihre Freunde immer und immer wieder anschauen wollen.
     
    Mit iMovie auf dem iPod touch erstellen Sie Minikinofilmhits mit ein paar Fingertipps.
    Stellen Sie sich vor, Sie sind unterwegs und wollen eine Videopostkarte erstellen, mit allem, was Sie erlebt und gesehen haben. Machen Sie das einfach mit der iMovie App - Sie bekommen sie im App Store. Mit iMovie für den iPod touch können Sie Videoclips zusammenfügen und bearbeiten, ihnen mit dynamischen Themen und Übergängen noch eine Extraportion Wow geben, Musik und Fotos hinzufügen und den fertigen Film mit allen teilen.
     
    Drehen Sie einen Film. Mit Ihnen in der Hauptrolle.
    Wenn Sie das nächste Mal eine aufregende Wanderung gemacht haben, erzählen Sie Ihren Freunden nicht nur davon - zeigen Sie es ihnen. Neben der HD Kamera auf der Rückseite besitzt der iPod touch eine Frontkamera mit VGA-Qualität über dem Display. So sehen Sie sich selbst, während Sie Videos aufnehmen. Das ist perfekt, um sich selbst zu filmen, denn Sie brauchen nicht mehr zu hoffen, dass Sie im Bild sind, sondern sehen es gleich. Also machen Sie sich bereit für die Aufnahme.
     
    Teilen Sie mit Freunden den Rest Ihres Lebens.
    Haben Sie auch schon mal eine Mail geschrieben und dabei etwas Unbeschreibliches gesehen? Dann nehmen Sie die Kamera und nehmen Sie es auf. Anschließend können Sie Ihren HD Film direkt auf YouTube laden. Oder wählen Sie ein Video aus den Aufnahmen und verschicken es mit einer Mail. Sie können es auch mit einem Fingertipp auf Ihre Facebook Seite oder in Ihren Blog posten. Und alle mit dem iPod touch aufgenommenen Videos ganz leicht mit Ihrem Mac oder PC synchronisieren.
    So haben alle ein gutes Bild von Ihnen.

    Eine unglaubliche Aussicht. Ein toller Kuchen. Ihr Hund, wie er soooooo süß schaut. Wenn Sie einen Schnappschuss für Facebook machen wollen, können Sie eine der beiden Kameras des iPod touch verwenden. Tippen Sie einfach auf das Display, um die Belichtung anzupassen. Dann posten Sie das Bild auf Facebook und warten auf die Kommentare.
     
    Game Center. Spielen Sie gegen Ihre besten Feinde
    Game Center. Mögen die Spiele beginnen.
    Mit der neuen Game Center App auf dem iPod touch können Sie Ihr Spiele-Netzwerk erweitern. Exponentiell. Zum Spielen brauchen Sie nur einen iPod touch oder ein iPhone mit iOS 4.1. Bei iOS 4.1 wird eine Game Center App auf dem Homescreen angezeigt. Tippen Sie einfach darauf, meldes sich mit Ihrer Apple ID an und schon kann´s losgehen. Sie können einen Spielernamen erstellen, der für Ihre Freunde und die Spieler-Community sichtbar ist. Fügen Sie mehrere E-Mail Adressen zur Game Center App hinzu, damit Freunde Sie einfacher finden können. Sie können die Spiele über die Links im Game Center laden und auch direkt aus der Game Center App starten. Und das Beste: Sobald Sie sich bei Game Center anmelden, bleiben Sie verbunden. Bis Sie dich wieder abmelden.
     
    Beste Freunde. Bald beste Gegner.
    Treten Sie gegen Ihre Freunde in einem Rennen an. Oder einem Match. Oder in einem Kampf. Wenn Sie bei der Game Center App angemeldet sind, können Sie jemanden mit einer Freundschaftsanfrage einladen und dafür den Spielernamen oder die E-Mail Adresse der Person verwenden. Ihre Freunde erscheinen in einer separaten Freundeliste in der Game Center App. Tippen Sie auf die Namen von Freunden und Sie sehen, welche Spiele sie gespielt haben. Sie können auch neue Freundschaftsanfragen ansehen und eigene hinzufügen.
    Leaderbords und Erfolge. Damit jeder sieht, wo Sie stehen.
    Sehen Sie sich auf den Ranglisten für jedes Spiel Ihre Platzierung unter Ihren Freunden und anderen Spielern an. Sie können auch Ihre Erfolge mit denen Ihrer Freunde vergleichen. Sehen Sie sich die Leaderboards und Erfolge in der Game Center App und jedem einzelnen Spiel an. Und dann lassen Sie es krachen.
     
    Trefen Sie Ihre Gegner. Und treffen Sie sie hart.
    Sie möchten eine Runde mit mehreren Freunden spielen? Mit Auto-Match werden Ihnen zuerst Ihre Freunde als Gegner vorgeschlagen, wenn diese auch nach einem Auto-Match suchen. Wenn nicht, wird Ihnen ein Freund in spe irgendwo auf dem Globus als Gegner vorgeschlagen. Oder laden Sie Ihre Freunde ein und lassen Sie Auto-Match alle für ein Spiel benötigten Spieler finden.
    Musik. Lassen Sie Ihre Finger tanzen.
    Cover Flow. Musik sieht so gut aus.
    Auf dem iPod touch gibt's Musik nicht nur auf die Ohren. Mit Cover Flow ist sie auch was für Augen und Finger. Drehen Sie den iPod touch auf die Seite und blättern Sie durch Ihre Albumcover. Tippen Sie auf ein Cover, um es umzudrehen und die Songliste zu sehen. Noch ein Tipp und die Musik läuft.
     
    Genius Wiedergabelisten. In jedem guten Song steckt eine noch bessere Wiedergabeliste.
    Angenommen Sie hören einen Song auf einem iPod touch, der Ihnen gut gefällt, und möchten weitere Titel hören, die gut dazu passen. Genius findet weitere Songs auf Ihrem iPod touch und erstellt eine Genius Wiedergabeliste. Hören Sie sich die Liste sofort an, speichern Sie sie für später oder versuchen's noch einmal und sehen, was dabei herauskommt. Verlassen Sie sich auf Genius, wenn Sie einen Mix wollen, auf den Sie selbst nie gekommen wären. 
     
    Genius Mixe. Nehmen Sie den DJ mit nach Hause.
    Genius ist Ihr persönlicher DJ. Synchronisieren Sie Ihren iPod touch mit iTunes und Genius durchsucht Ihre Mediathek automatisch nach Songs, die gut zusammenpassen. Dann erstellt Genius mehrere Mixe. Diese Mixe sind wie Radiosender, auf denen nur Ihre Lieblingshits laufen. So finden Sie Songs wieder, die Sie lange nicht mehr gehört haben oder von denen Sie gar nicht mehr wussten, dass Sie sie haben.
     
    Lassen Sie Ihre Finger tanzen. 
     
    Shake to shuffle. So ein Zufall.
    Die Dinge mal aufrütteln. Musikalisch natürlich. Wenn Sie das nächste Mal Musik hören, aktivieren Sie einfach die Schüttelfunktion. Wenn Sie den iPod touch dann kurz schütteln, springt er nach dem Zufallsprinzip zu einem anderen Song in Ihrer Sammlung. So entdecken Sie Ihre Musik immer wieder neu.
     
    iTunes. Das ist Entertainment.
    Packen Sie Songs und Musikvideos aus Ihrer iTunes Mediathek auf dem Computer auf den iPod touch. Oder kaufen und laden Sie neue Songs auf den iPod touch, wenn Sie sich über Wi-Fi mit iTunes verbinden. Wenn Sie dann den iPod touch das nächste Mal mit dem Computer verbinden, werden alle Songs, die Sie auf dem iPod touch gekauft haben, auf den Mac oder PC übertragen. Und mit iTunes Ping können Sie jetzt sehen, welche Musik Ihre Freunde hören, kaufen und empfehlen. Oder informieren Sie sich dort über Ihre Lieblingskünstler und was sie so hören.
     
    Bluetooth. Entfesseln Sie Ihre Musik.
    Die Unterstützung für das drahtlose Bluetooth ist im iPod touch schon drin. Das heißt, Sie können drahtlose Stereokopfhörer verwenden. Lassen Sie den iPod in Ihrer Tasche stecken oder auf dem Schreibtisch aufladen, während Sie weiter Musik hören.
     
    Filme und Fernsehsendungen. So haben Sie überall eine Sehenswürdigkeit.
    Ganz großes Kino. Auf einem kleinen Display.
    Mit dem iPod touch ist jeden Tag und überall Kinotag. Nehmen Sie Videos für viele Stunden Unterhaltung mit und sehen Sie sie auf dem fantastischen 3,5 Zoll Retina Display an. Kaufen Sie im iTunes Store und wählen Sie aus tausenden Filmen, Fernsehsendungen und Video-Podcasts für Ihren iPod touch. Da ist für jeden etwas dabei - von Hollywood Blockbustern bis zu Independent Filmen. Ein paar Fingertipps und Sie haben Filme geladen und können sie ansehen. Sie mögen lieber Fernsehsendungen? Die gibt's auch. Sie können einzelne Folgen oder gleich eine ganze Staffel kaufen. Mit dem iPod touch haben Sie Ihre Videos immer dabei.
    Sie haben alles unter Kontrolle.
    Wenn Sie ein Video schauen, tippen Sie einfach auf das Display und schon haben Sie die Steuerung. Damit können Sie die Wiedergabe starten oder unterbrechen, zu einzelnen Kapiteln springen und die Lautstärke anpassen. Oder verwenden Sie die Lautstärketasten links am iPod touch. Wenn Sie zwischen Widescreen- und Vollbildanzeige wechseln wollen, reicht ein Doppeltipp auf das Display. Das ist wie die Fernbedienung des Fernsehers. Nur, dass Sie nicht darum kämpfen müssen.
     
    iTunes. Für beste Unterhaltung.
    Sie brauchen für den nächsten Flug oder die nächste Fahrt etwas Unterhaltung? Mit iTunes auf dem iPod touch und einer Wi-Fi Verbindung können Sie sofort Filme und Fernsehsendungen kaufen. Oder Sie kaufen sie auf Ihrem Mac oder PC und synchronisieren sie mit dem iPod touch. Nur das Popcorn ist nicht dabei.
     
     
    Besuchen Sie Ihre Lieblingswebsites. Alles, was Sie dazu brauchen, ist ein iPod touch und Wi-Fi. 
     
    Laden Sie die iBooks App kostenlos und Sie haben nicht nur einen großartigen E-Book-Reader, sondern auch einen tollen Ort, um Bücher zu kaufen. 
     
    Und vieles mehr...
     
    App Store
    Laden Sie Apps direkt auf den iPod touch
     
    iTunes
    Erstellen Sie einen iTunes Store Account und kaufen Sie jederzeit via Wi-Fi ein.
     
    iBooks
    Laden Sie die iBooks App kostenlos und Sie haben nicht nur einen großartigen E-Book-Reader, sondern auch einen tollen Ort, um Bücher zu kaufen.
     
    iMovie
    Bearbeiten Sie Videos, fügen Sie Themen und Musik hinzu und teilen Sie Ihre Filme mit Anderen
     
    Mail
    Senden Sie Mails und sehen Sie sich Anhänge von Ihrem Google Mail, MobileMe oder einem anderen E-Mail Account an.
     
    Safari Webbrowser
    Besuchen Sie Ihre Lieblingswebsites. Alles, was Sie dazu brauchen, ist ein iPod touch und Wi-Fi.
     
    Fotos
    Nehmen Sie Ihre Fotos mit. Teilen Sie sie per E-Mail. Wählen Sie Ihr Lieblingsfoto als Hintergrundbild.
     
    Homescreen
    Ordnen Sie in iTunes Ihre Apps auf mehreren Homescreens an.
     
     
    Sprachsteuerung
    Steuern Sie die Musik auf dem iPod touch mit Sprachbefehlen
     
    Karten
    Finden Sie Restaurants, Konzerte und mehr und lassen Sie sich mit Karten zeigen, wie Sie hinkommen.
     
    YouTube
    Sehen Sie sich die neuesten Videohits und Ihre Lieblingsvideos an.
     
    Nike + iPod
    Erreichen Sie Ihre Trainingsziele mit integrierter Unterstützung für Nike + iPod
     
    Sprachmemos
    Nehmen Sie Notizen, Gedanken oder alles andere auf.
     
    Bedienungshilfen
    Der iPod touch kommt mit Bildschirmlesefunktion und weiteren Bedienungshilfen
     
    Lieferumfang
    iPod touch, Ohrhörer, USB 2.0 Kabel, Dock Adapter, Kurzanleitung
    ";2;False;0;;;"Apple iPod touch 4G 64 GB ";apple-ipod-touch-4g-64-gb;True;True;PD-01068;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;359.9900;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;40637,4565162037;45;1;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000615-apple-ipod-touch-4g-32-gb.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000616-apple-ipod-touch-4g-32-gb.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000617-apple-ipod-touch-4g-32-gb.jpg;1;;False;;;;;False;False;False;;;;;False;;;;;; -5;0;True;"Apple iPod touch 4G 8 GB ";"Der neue iPod touch. Jetzt mit FaceTime, Retina Display, HD-Video und Game Center. ";"
    Der neue iPod touch. Jetzt mit FaceTime, Retina Display, HD-Video und Game Center.
     
    Spaß, hoch entwickelt. Der neue iPod touch.
    Tonnen von innovativen Funktionen gibt es jetzt auch auf dem iPod touch. Einfach damit er noch mehr Spaß macht. Teilen Sie schöne Momente mit Freunden via FaceTime. Nehmen Sie Videos in HD auf. Oder erleben Sie Spiele auf dem höchstauflösenden iPod Display, das es je gab. Der iPod touch hat so viel Technologie, dass Sie glatt vergessen, dass es ein iPod ist.
     
    Sieht unglaublich aus. Ist aber wahr.

    Mit seinem neuen Design ist der iPod touch der dünnste, leichteste und fantastischste iPod touch, den es je gab. Um das zu spüren, müssen Sie ihn nur in die Hand nehmen. Er ist gerade mal 7,2 mm dünn. Mit seiner Vorderseite aus Hightech-Glas und der Rückseite aus Edelstahl fühlt er sich einfach fantastisch an. Wenn Sie ihn einschalten, sind Sie sofort vom brillanten Retina Display fasziniert. Der iPod touch kombiniert großartiges Design und revolutionäre Technologie - von außen wie von innen.
     
    Retina Display. Die Zukunft sieht gut aus.
    Es gibt viele Gründe, den iPod touch immer wieder anzusehen. Beispielsweise das LCD-Display mit 960 x 640 Pixeln und Hintergrundbeleuchtung. Es hat eine Pixeldichte von 326 ppi und ist damit das höchstauflösende iPod Display, das es je gab. Die Apple Ingenieure haben dafür superkleine, kaum 78 Mikrometer breite Pixel entwickelt, die das menschliche Auge nicht mehr als einzelne Pixel wahrnehmen kann. Und obwohl Sie sie nicht sehen können, werden Sie den Unterschied bemerken. Der Text ist gestochen scharf und alles sieht leuchtend und lebendig aus.
     
    Apple A4 Prozessor. Mehr Power für Sie.
    Hinter - oder besser gesagt unter - dem ganzen Spaß, den Sie mit dem iPod touch haben, steckt der Apple A4 Chip. Die Apple Ingenieure haben den A4 Chip als leistungsstarken und energieeffizienten Mobilprozessor entworfen. Damit bewältigt der iPod touch komplexe Aufgaben wie Multitasking, Videoschnitt und FaceTime Anrufe. All das bei noch mehr Batterielaufzeit. Und mehr Spaß.
     
    Gyrosensor + Beschleunigungssensor. Wirklich bewegend.
    Der iPod touch hat jetzt ein paar neue Tricks drauf. Er hat einen integrierten 3-Achsen-Gyrosensor, der zusammen mit dem Beschleunigungssensor dafür sorgt, dass der iPod touch Aktionen wie Beschleunigung, 3D Bewegung und Drehrate erkennt. Im Klartext: Mehr Bewegungen, mehr Gesten und größere Präzision für noch mehr Spielspaß.
     
    Zwei Kameras. Doppelt so viel Spaß.
    Für Videoaufnahmen hat der iPod touch zwei integrierte Kameras. Mit der Rückkamera nimmt er fantastische HD 720p Videos auf. Und der hoch entwickelte rückwärtig belichtete Sensor sorgt selbst bei schwacher Beleuchtung für tolle Aufnahmen. Das integrierte Mikrofon nimmt dabei gleichzeitig Gespräche, Musik oder alles andere auf. Die Frontkamera des iPod touch ist perfekt für FaceTime Anrufe1 und um sich selbst aufzunehmen. Schon erstaunlich, wie viel Spaß in etwas so Kleines passt.
    Multi-Touch. Alles unter Kontrolle Ihrer.
    Wie macht der iPod touch eigentlich genau das, was Sie wollen, wenn Sie mit Ihren Fingern über das Display streichen? Genau genommen ist es eine Kettenreaktion. Das Multi-Touch Display hat einen Schutzfilm über der kapazitiven Sensorik, die Berührungen anhand elektrischer Felder erkennt. Diese Informationen werden an das Retina Display darunter übermittelt. So könen Sie alles mit den Fingern steuern, mit Cover Flow in Ihren Alben blättern, Fotos sehen und vergrößern, in eine Website zoomen und Spiele steuern.
     
    FaceTime auf dem iPod touch. Sagen Sie nicht einfach Hallo. Sagen Sie es mit einem Lächeln.
    Ein Lächeln sagt mehr als tausend SMS.
    Bringen Sie LOL auf die nächste Stufe und sehen Sie Ihre Freunde wirklich lachen. Oder lassen Sie XOXO lebendig werden und schicken Sie einen Kuss um die halbe Welt. FaceTime auf dem iPod touch macht's möglich. FaceTime funktioniert sofort nach dem Auspacken - Sie geben einfach Ihre Apple ID und E-Mail Adresse ein. Oder erstellen einen neuen E-Mail Account extra für FaceTime. FaceTime ist supereinfach. Stellen Sie sich vor, Sie wollen über Wi-Fi mit Ihrer besten Freundin videotelefonieren. Dann tippen Sie auf die FaceTime App, finden sie dort und starten den Anruf. Auf ihrem iPod touch oder iPhone 4 erscheint dann eine Einladung, die sie annehmen kann. Sobald sie annimmt, wird FaceTime gestartet. Das alles funktioniert ganz nahtlos und sowohl im Hoch- als auch im Querformat. Sie werden im wahrsten Sinne des Wortes sehen, wie viel Spaß Sie haben können.
     
    Videotelefonieren Sie mit Freunden per FaceTime oder spielen Sie gegen Freunde oder Fremde mit Game Center.
     
    Zwei Kameras für Spaß von jeder Seite.
    Der iPod touch hat zwei Kameras - eine vorne über dem Display und eine auf der Rückseite. Die Frontkamera ist für FaceTime optimiert. Sie hat genau das richtige Sichtfeld und die richtige Brennweite, um auf die Entfernung einer Armlänge das Gesicht zu fokussieren. So zeigt sie Sie immer im besten Licht. Was besonders praktisch ist, wenn Sie mit jemandem sprechen, der mehr als nur ein Freund ist.
    Die Rückkamera. Teilen Sie Ihre Ansicht.
    Wenn Ihre Mitbewohnerin es doch nicht mehr zum Konzert schafft, lassen Sie sie mit FaceTime doch wenigstens die Zugabe sehen. Wenn die Band auf die Bühne kommt und ihren Lieblingshit spielt, tippen Sie einfach auf die Taste. Und noch bevor der Sänger die erste Zeile singt, wechselt der iPod touch zur Rückkamera und überträgt einen mit Sicherheit legendären Auftritt. Tippen Sie noch einmal und der iPod touch wechselt zurück auf die Frontkamera und zu Ihnen. Einfach und schnell - macht einfach Spaß!
     
    HD Videoaufnahme auf dem iPod touch. Nehmen Sie jeden Spaß mit. Und auf.
     
    Integrierter Schnittplatz.
    Sie müssen mit dem Bearbeiten Ihrer Videos nicht warten, bis Sie wieder am Computer sitzen. Einfache Schnittfunktionen sind direkt im iPod touch integriert, sodass Sie gleich damit loslegen können. Ziehen Sie einfach, um Start- und Endpunkt des Films festzulegen. Behalten Sie nur die Teile des Videos, die Ihnen besonders gefallen, und machen Sie daraus einen Film, den Sie und Ihre Freunde immer und immer wieder anschauen wollen.
     
    Mit iMovie auf dem iPod touch erstellen Sie Minikinofilmhits mit ein paar Fingertipps.
    Stellen Sie sich vor, Sie sind unterwegs und wollen eine Videopostkarte erstellen, mit allem, was Sie erlebt und gesehen haben. Machen Sie das einfach mit der iMovie App - Sie bekommen sie im App Store. Mit iMovie für den iPod touch können Sie Videoclips zusammenfügen und bearbeiten, ihnen mit dynamischen Themen und Übergängen noch eine Extraportion Wow geben, Musik und Fotos hinzufügen und den fertigen Film mit allen teilen.
     
    Drehen Sie einen Film. Mit Ihnen in der Hauptrolle.
    Wenn Sie das nächste Mal eine aufregende Wanderung gemacht haben, erzählen Sie Ihren Freunden nicht nur davon - zeigen Sie es ihnen. Neben der HD Kamera auf der Rückseite besitzt der iPod touch eine Frontkamera mit VGA-Qualität über dem Display. So sehen Sie sich selbst, während Sie Videos aufnehmen. Das ist perfekt, um sich selbst zu filmen, denn Sie brauchen nicht mehr zu hoffen, dass Sie im Bild sind, sondern sehen es gleich. Also machen Sie sich bereit für die Aufnahme.
     
    Teilen Sie mit Freunden den Rest Ihres Lebens.
    Haben Sie auch schon mal eine Mail geschrieben und dabei etwas Unbeschreibliches gesehen? Dann nehmen Sie die Kamera und nehmen Sie es auf. Anschließend können Sie Ihren HD Film direkt auf YouTube laden. Oder wählen Sie ein Video aus den Aufnahmen und verschicken es mit einer Mail. Sie können es auch mit einem Fingertipp auf Ihre Facebook Seite oder in Ihren Blog posten. Und alle mit dem iPod touch aufgenommenen Videos ganz leicht mit Ihrem Mac oder PC synchronisieren.
    So haben alle ein gutes Bild von Ihnen.

    Eine unglaubliche Aussicht. Ein toller Kuchen. Ihr Hund, wie er soooooo süß schaut. Wenn Sie einen Schnappschuss für Facebook machen wollen, können Sie eine der beiden Kameras des iPod touch verwenden. Tippen Sie einfach auf das Display, um die Belichtung anzupassen. Dann posten Sie das Bild auf Facebook und warten auf die Kommentare.
     
    Game Center. Spielen Sie gegen Ihre besten Feinde
    Game Center. Mögen die Spiele beginnen.
    Mit der neuen Game Center App auf dem iPod touch können Sie Ihr Spiele-Netzwerk erweitern. Exponentiell. Zum Spielen brauchen Sie nur einen iPod touch oder ein iPhone mit iOS 4.1. Bei iOS 4.1 wird eine Game Center App auf dem Homescreen angezeigt. Tippen Sie einfach darauf, meldes sich mit Ihrer Apple ID an und schon kann´s losgehen. Sie können einen Spielernamen erstellen, der für Ihre Freunde und die Spieler-Community sichtbar ist. Fügen Sie mehrere E-Mail Adressen zur Game Center App hinzu, damit Freunde Sie einfacher finden können. Sie können die Spiele über die Links im Game Center laden und auch direkt aus der Game Center App starten. Und das Beste: Sobald Sie sich bei Game Center anmelden, bleiben Sie verbunden. Bis Sie dich wieder abmelden.
     
    Beste Freunde. Bald beste Gegner.
    Treten Sie gegen Ihre Freunde in einem Rennen an. Oder einem Match. Oder in einem Kampf. Wenn Sie bei der Game Center App angemeldet sind, können Sie jemanden mit einer Freundschaftsanfrage einladen und dafür den Spielernamen oder die E-Mail Adresse der Person verwenden. Ihre Freunde erscheinen in einer separaten Freundeliste in der Game Center App. Tippen Sie auf die Namen von Freunden und Sie sehen, welche Spiele sie gespielt haben. Sie können auch neue Freundschaftsanfragen ansehen und eigene hinzufügen.
    Leaderbords und Erfolge. Damit jeder sieht, wo Sie stehen.
    Sehen Sie sich auf den Ranglisten für jedes Spiel Ihre Platzierung unter Ihren Freunden und anderen Spielern an. Sie können auch Ihre Erfolge mit denen Ihrer Freunde vergleichen. Sehen Sie sich die Leaderboards und Erfolge in der Game Center App und jedem einzelnen Spiel an. Und dann lassen Sie es krachen.
     
    Trefen Sie Ihre Gegner. Und treffen Sie sie hart.
    Sie möchten eine Runde mit mehreren Freunden spielen? Mit Auto-Match werden Ihnen zuerst Ihre Freunde als Gegner vorgeschlagen, wenn diese auch nach einem Auto-Match suchen. Wenn nicht, wird Ihnen ein Freund in spe irgendwo auf dem Globus als Gegner vorgeschlagen. Oder laden Sie Ihre Freunde ein und lassen Sie Auto-Match alle für ein Spiel benötigten Spieler finden.
    Musik. Lassen Sie Ihre Finger tanzen.
    Cover Flow. Musik sieht so gut aus.
    Auf dem iPod touch gibt's Musik nicht nur auf die Ohren. Mit Cover Flow ist sie auch was für Augen und Finger. Drehen Sie den iPod touch auf die Seite und blättern Sie durch Ihre Albumcover. Tippen Sie auf ein Cover, um es umzudrehen und die Songliste zu sehen. Noch ein Tipp und die Musik läuft.
     
    Genius Wiedergabelisten. In jedem guten Song steckt eine noch bessere Wiedergabeliste.
    Angenommen Sie hören einen Song auf einem iPod touch, der Ihnen gut gefällt, und möchten weitere Titel hören, die gut dazu passen. Genius findet weitere Songs auf Ihrem iPod touch und erstellt eine Genius Wiedergabeliste. Hören Sie sich die Liste sofort an, speichern Sie sie für später oder versuchen's noch einmal und sehen, was dabei herauskommt. Verlassen Sie sich auf Genius, wenn Sie einen Mix wollen, auf den Sie selbst nie gekommen wären. 
     
    Genius Mixe. Nehmen Sie den DJ mit nach Hause.
    Genius ist Ihr persönlicher DJ. Synchronisieren Sie Ihren iPod touch mit iTunes und Genius durchsucht Ihre Mediathek automatisch nach Songs, die gut zusammenpassen. Dann erstellt Genius mehrere Mixe. Diese Mixe sind wie Radiosender, auf denen nur Ihre Lieblingshits laufen. So finden Sie Songs wieder, die Sie lange nicht mehr gehört haben oder von denen Sie gar nicht mehr wussten, dass Sie sie haben.
     
    Lassen Sie Ihre Finger tanzen. 
     
    Shake to shuffle. So ein Zufall.
    Die Dinge mal aufrütteln. Musikalisch natürlich. Wenn Sie das nächste Mal Musik hören, aktivieren Sie einfach die Schüttelfunktion. Wenn Sie den iPod touch dann kurz schütteln, springt er nach dem Zufallsprinzip zu einem anderen Song in Ihrer Sammlung. So entdecken Sie Ihre Musik immer wieder neu.
     
    iTunes. Das ist Entertainment.
    Packen Sie Songs und Musikvideos aus Ihrer iTunes Mediathek auf dem Computer auf den iPod touch. Oder kaufen und laden Sie neue Songs auf den iPod touch, wenn Sie sich über Wi-Fi mit iTunes verbinden. Wenn Sie dann den iPod touch das nächste Mal mit dem Computer verbinden, werden alle Songs, die Sie auf dem iPod touch gekauft haben, auf den Mac oder PC übertragen. Und mit iTunes Ping können Sie jetzt sehen, welche Musik Ihre Freunde hören, kaufen und empfehlen. Oder informieren Sie sich dort über Ihre Lieblingskünstler und was sie so hören.
     
    Bluetooth. Entfesseln Sie Ihre Musik.
    Die Unterstützung für das drahtlose Bluetooth ist im iPod touch schon drin. Das heißt, Sie können drahtlose Stereokopfhörer verwenden. Lassen Sie den iPod in Ihrer Tasche stecken oder auf dem Schreibtisch aufladen, während Sie weiter Musik hören.
     
    Filme und Fernsehsendungen. So haben Sie überall eine Sehenswürdigkeit.
    Ganz großes Kino. Auf einem kleinen Display.
    Mit dem iPod touch ist jeden Tag und überall Kinotag. Nehmen Sie Videos für viele Stunden Unterhaltung mit und sehen Sie sie auf dem fantastischen 3,5 Zoll Retina Display an. Kaufen Sie im iTunes Store und wählen Sie aus tausenden Filmen, Fernsehsendungen und Video-Podcasts für Ihren iPod touch. Da ist für jeden etwas dabei - von Hollywood Blockbustern bis zu Independent Filmen. Ein paar Fingertipps und Sie haben Filme geladen und können sie ansehen. Sie mögen lieber Fernsehsendungen? Die gibt's auch. Sie können einzelne Folgen oder gleich eine ganze Staffel kaufen. Mit dem iPod touch haben Sie Ihre Videos immer dabei.
    Sie haben alles unter Kontrolle.
    Wenn Sie ein Video schauen, tippen Sie einfach auf das Display und schon haben Sie die Steuerung. Damit können Sie die Wiedergabe starten oder unterbrechen, zu einzelnen Kapiteln springen und die Lautstärke anpassen. Oder verwenden Sie die Lautstärketasten links am iPod touch. Wenn Sie zwischen Widescreen- und Vollbildanzeige wechseln wollen, reicht ein Doppeltipp auf das Display. Das ist wie die Fernbedienung des Fernsehers. Nur, dass Sie nicht darum kämpfen müssen.
     
    iTunes. Für beste Unterhaltung.
    Sie brauchen für den nächsten Flug oder die nächste Fahrt etwas Unterhaltung? Mit iTunes auf dem iPod touch und einer Wi-Fi Verbindung können Sie sofort Filme und Fernsehsendungen kaufen. Oder Sie kaufen sie auf Ihrem Mac oder PC und synchronisieren sie mit dem iPod touch. Nur das Popcorn ist nicht dabei.
     
     
    Besuchen Sie Ihre Lieblingswebsites. Alles, was Sie dazu brauchen, ist ein iPod touch und Wi-Fi. 
     
    Laden Sie die iBooks App kostenlos und Sie haben nicht nur einen großartigen E-Book-Reader, sondern auch einen tollen Ort, um Bücher zu kaufen. 
     
    Und vieles mehr...
     
    App Store
    Laden Sie Apps direkt auf den iPod touch
     
    iTunes
    Erstellen Sie einen iTunes Store Account und kaufen Sie jederzeit via Wi-Fi ein.
     
    iBooks
    Laden Sie die iBooks App kostenlos und Sie haben nicht nur einen großartigen E-Book-Reader, sondern auch einen tollen Ort, um Bücher zu kaufen.
     
    iMovie
    Bearbeiten Sie Videos, fügen Sie Themen und Musik hinzu und teilen Sie Ihre Filme mit Anderen
     
    Mail
    Senden Sie Mails und sehen Sie sich Anhänge von Ihrem Google Mail, MobileMe oder einem anderen E-Mail Account an.
     
    Safari Webbrowser
    Besuchen Sie Ihre Lieblingswebsites. Alles, was Sie dazu brauchen, ist ein iPod touch und Wi-Fi.
     
    Fotos
    Nehmen Sie Ihre Fotos mit. Teilen Sie sie per E-Mail. Wählen Sie Ihr Lieblingsfoto als Hintergrundbild.
     
    Homescreen
    Ordnen Sie in iTunes Ihre Apps auf mehreren Homescreens an.
     
     
    Sprachsteuerung
    Steuern Sie die Musik auf dem iPod touch mit Sprachbefehlen
     
    Karten
    Finden Sie Restaurants, Konzerte und mehr und lassen Sie sich mit Karten zeigen, wie Sie hinkommen.
     
    YouTube
    Sehen Sie sich die neuesten Videohits und Ihre Lieblingsvideos an.
     
    Nike + iPod
    Erreichen Sie Ihre Trainingsziele mit integrierter Unterstützung für Nike + iPod
     
    Sprachmemos
    Nehmen Sie Notizen, Gedanken oder alles andere auf.
     
    Bedienungshilfen
    Der iPod touch kommt mit Bildschirmlesefunktion und weiteren Bedienungshilfen
     
    Lieferumfang
    iPod touch, Ohrhörer, USB 2.0 Kabel, Dock Adapter, Kurzanleitung
    ";2;False;0;;;"Apple iPod touch 4G 8 GB ";apple-ipod-touch-4g-8-gb;True;True;PD-01067;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;209.9900;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;40637,4560300926;45;1;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000615-apple-ipod-touch-4g-32-gb.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000616-apple-ipod-touch-4g-32-gb.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000617-apple-ipod-touch-4g-32-gb.jpg;1;;False;;;;;False;False;False;;;;;False;;;;;; -5;0;True;"Apple iPod touch 4G 32 GB ";"Der neue iPod touch. Jetzt mit FaceTime, Retina Display, HD-Video und Game Center. ";"
    Der neue iPod touch. Jetzt mit FaceTime, Retina Display, HD-Video und Game Center.
     
    Spaß, hoch entwickelt. Der neue iPod touch.
    Tonnen von innovativen Funktionen gibt es jetzt auch auf dem iPod touch. Einfach damit er noch mehr Spaß macht. Teilen Sie schöne Momente mit Freunden via FaceTime. Nehmen Sie Videos in HD auf. Oder erleben Sie Spiele auf dem höchstauflösenden iPod Display, das es je gab. Der iPod touch hat so viel Technologie, dass Sie glatt vergessen, dass es ein iPod ist.
     
    Sieht unglaublich aus. Ist aber wahr.

    Mit seinem neuen Design ist der iPod touch der dünnste, leichteste und fantastischste iPod touch, den es je gab. Um das zu spüren, müssen Sie ihn nur in die Hand nehmen. Er ist gerade mal 7,2 mm dünn. Mit seiner Vorderseite aus Hightech-Glas und der Rückseite aus Edelstahl fühlt er sich einfach fantastisch an. Wenn Sie ihn einschalten, sind Sie sofort vom brillanten Retina Display fasziniert. Der iPod touch kombiniert großartiges Design und revolutionäre Technologie - von außen wie von innen.
     
    Retina Display. Die Zukunft sieht gut aus.
    Es gibt viele Gründe, den iPod touch immer wieder anzusehen. Beispielsweise das LCD-Display mit 960 x 640 Pixeln und Hintergrundbeleuchtung. Es hat eine Pixeldichte von 326 ppi und ist damit das höchstauflösende iPod Display, das es je gab. Die Apple Ingenieure haben dafür superkleine, kaum 78 Mikrometer breite Pixel entwickelt, die das menschliche Auge nicht mehr als einzelne Pixel wahrnehmen kann. Und obwohl Sie sie nicht sehen können, werden Sie den Unterschied bemerken. Der Text ist gestochen scharf und alles sieht leuchtend und lebendig aus.
     
    Apple A4 Prozessor. Mehr Power für Sie.
    Hinter - oder besser gesagt unter - dem ganzen Spaß, den Sie mit dem iPod touch haben, steckt der Apple A4 Chip. Die Apple Ingenieure haben den A4 Chip als leistungsstarken und energieeffizienten Mobilprozessor entworfen. Damit bewältigt der iPod touch komplexe Aufgaben wie Multitasking, Videoschnitt und FaceTime Anrufe. All das bei noch mehr Batterielaufzeit. Und mehr Spaß.
     
    Gyrosensor + Beschleunigungssensor. Wirklich bewegend.
    Der iPod touch hat jetzt ein paar neue Tricks drauf. Er hat einen integrierten 3-Achsen-Gyrosensor, der zusammen mit dem Beschleunigungssensor dafür sorgt, dass der iPod touch Aktionen wie Beschleunigung, 3D Bewegung und Drehrate erkennt. Im Klartext: Mehr Bewegungen, mehr Gesten und größere Präzision für noch mehr Spielspaß.
     
    Zwei Kameras. Doppelt so viel Spaß.
    Für Videoaufnahmen hat der iPod touch zwei integrierte Kameras. Mit der Rückkamera nimmt er fantastische HD 720p Videos auf. Und der hoch entwickelte rückwärtig belichtete Sensor sorgt selbst bei schwacher Beleuchtung für tolle Aufnahmen. Das integrierte Mikrofon nimmt dabei gleichzeitig Gespräche, Musik oder alles andere auf. Die Frontkamera des iPod touch ist perfekt für FaceTime Anrufe1 und um sich selbst aufzunehmen. Schon erstaunlich, wie viel Spaß in etwas so Kleines passt.
    Multi-Touch. Alles unter Kontrolle Ihrer.
    Wie macht der iPod touch eigentlich genau das, was Sie wollen, wenn Sie mit Ihren Fingern über das Display streichen? Genau genommen ist es eine Kettenreaktion. Das Multi-Touch Display hat einen Schutzfilm über der kapazitiven Sensorik, die Berührungen anhand elektrischer Felder erkennt. Diese Informationen werden an das Retina Display darunter übermittelt. So könen Sie alles mit den Fingern steuern, mit Cover Flow in Ihren Alben blättern, Fotos sehen und vergrößern, in eine Website zoomen und Spiele steuern.
     
    FaceTime auf dem iPod touch. Sagen Sie nicht einfach Hallo. Sagen Sie es mit einem Lächeln.
    Ein Lächeln sagt mehr als tausend SMS.
    Bringen Sie LOL auf die nächste Stufe und sehen Sie Ihre Freunde wirklich lachen. Oder lassen Sie XOXO lebendig werden und schicken Sie einen Kuss um die halbe Welt. FaceTime auf dem iPod touch macht's möglich. FaceTime funktioniert sofort nach dem Auspacken - Sie geben einfach Ihre Apple ID und E-Mail Adresse ein. Oder erstellen einen neuen E-Mail Account extra für FaceTime. FaceTime ist supereinfach. Stellen Sie sich vor, Sie wollen über Wi-Fi mit Ihrer besten Freundin videotelefonieren. Dann tippen Sie auf die FaceTime App, finden sie dort und starten den Anruf. Auf ihrem iPod touch oder iPhone 4 erscheint dann eine Einladung, die sie annehmen kann. Sobald sie annimmt, wird FaceTime gestartet. Das alles funktioniert ganz nahtlos und sowohl im Hoch- als auch im Querformat. Sie werden im wahrsten Sinne des Wortes sehen, wie viel Spaß Sie haben können.
     
    Videotelefonieren Sie mit Freunden per FaceTime oder spielen Sie gegen Freunde oder Fremde mit Game Center.
     
    Zwei Kameras für Spaß von jeder Seite.
    Der iPod touch hat zwei Kameras - eine vorne über dem Display und eine auf der Rückseite. Die Frontkamera ist für FaceTime optimiert. Sie hat genau das richtige Sichtfeld und die richtige Brennweite, um auf die Entfernung einer Armlänge das Gesicht zu fokussieren. So zeigt sie Sie immer im besten Licht. Was besonders praktisch ist, wenn Sie mit jemandem sprechen, der mehr als nur ein Freund ist.
    Die Rückkamera. Teilen Sie Ihre Ansicht.
    Wenn Ihre Mitbewohnerin es doch nicht mehr zum Konzert schafft, lassen Sie sie mit FaceTime doch wenigstens die Zugabe sehen. Wenn die Band auf die Bühne kommt und ihren Lieblingshit spielt, tippen Sie einfach auf die Taste. Und noch bevor der Sänger die erste Zeile singt, wechselt der iPod touch zur Rückkamera und überträgt einen mit Sicherheit legendären Auftritt. Tippen Sie noch einmal und der iPod touch wechselt zurück auf die Frontkamera und zu Ihnen. Einfach und schnell - macht einfach Spaß!
     
    HD Videoaufnahme auf dem iPod touch. Nehmen Sie jeden Spaß mit. Und auf.
     
    Integrierter Schnittplatz.
    Sie müssen mit dem Bearbeiten Ihrer Videos nicht warten, bis Sie wieder am Computer sitzen. Einfache Schnittfunktionen sind direkt im iPod touch integriert, sodass Sie gleich damit loslegen können. Ziehen Sie einfach, um Start- und Endpunkt des Films festzulegen. Behalten Sie nur die Teile des Videos, die Ihnen besonders gefallen, und machen Sie daraus einen Film, den Sie und Ihre Freunde immer und immer wieder anschauen wollen.
     
    Mit iMovie auf dem iPod touch erstellen Sie Minikinofilmhits mit ein paar Fingertipps.
    Stellen Sie sich vor, Sie sind unterwegs und wollen eine Videopostkarte erstellen, mit allem, was Sie erlebt und gesehen haben. Machen Sie das einfach mit der iMovie App - Sie bekommen sie im App Store. Mit iMovie für den iPod touch können Sie Videoclips zusammenfügen und bearbeiten, ihnen mit dynamischen Themen und Übergängen noch eine Extraportion Wow geben, Musik und Fotos hinzufügen und den fertigen Film mit allen teilen.
     
    Drehen Sie einen Film. Mit Ihnen in der Hauptrolle.
    Wenn Sie das nächste Mal eine aufregende Wanderung gemacht haben, erzählen Sie Ihren Freunden nicht nur davon - zeigen Sie es ihnen. Neben der HD Kamera auf der Rückseite besitzt der iPod touch eine Frontkamera mit VGA-Qualität über dem Display. So sehen Sie sich selbst, während Sie Videos aufnehmen. Das ist perfekt, um sich selbst zu filmen, denn Sie brauchen nicht mehr zu hoffen, dass Sie im Bild sind, sondern sehen es gleich. Also machen Sie sich bereit für die Aufnahme.
     
    Teilen Sie mit Freunden den Rest Ihres Lebens.
    Haben Sie auch schon mal eine Mail geschrieben und dabei etwas Unbeschreibliches gesehen? Dann nehmen Sie die Kamera und nehmen Sie es auf. Anschließend können Sie Ihren HD Film direkt auf YouTube laden. Oder wählen Sie ein Video aus den Aufnahmen und verschicken es mit einer Mail. Sie können es auch mit einem Fingertipp auf Ihre Facebook Seite oder in Ihren Blog posten. Und alle mit dem iPod touch aufgenommenen Videos ganz leicht mit Ihrem Mac oder PC synchronisieren.
    So haben alle ein gutes Bild von Ihnen.

    Eine unglaubliche Aussicht. Ein toller Kuchen. Ihr Hund, wie er soooooo süß schaut. Wenn Sie einen Schnappschuss für Facebook machen wollen, können Sie eine der beiden Kameras des iPod touch verwenden. Tippen Sie einfach auf das Display, um die Belichtung anzupassen. Dann posten Sie das Bild auf Facebook und warten auf die Kommentare.
     
    Game Center. Spielen Sie gegen Ihre besten Feinde
    Game Center. Mögen die Spiele beginnen.
    Mit der neuen Game Center App auf dem iPod touch können Sie Ihr Spiele-Netzwerk erweitern. Exponentiell. Zum Spielen brauchen Sie nur einen iPod touch oder ein iPhone mit iOS 4.1. Bei iOS 4.1 wird eine Game Center App auf dem Homescreen angezeigt. Tippen Sie einfach darauf, meldes sich mit Ihrer Apple ID an und schon kann´s losgehen. Sie können einen Spielernamen erstellen, der für Ihre Freunde und die Spieler-Community sichtbar ist. Fügen Sie mehrere E-Mail Adressen zur Game Center App hinzu, damit Freunde Sie einfacher finden können. Sie können die Spiele über die Links im Game Center laden und auch direkt aus der Game Center App starten. Und das Beste: Sobald Sie sich bei Game Center anmelden, bleiben Sie verbunden. Bis Sie dich wieder abmelden.
     
    Beste Freunde. Bald beste Gegner.
    Treten Sie gegen Ihre Freunde in einem Rennen an. Oder einem Match. Oder in einem Kampf. Wenn Sie bei der Game Center App angemeldet sind, können Sie jemanden mit einer Freundschaftsanfrage einladen und dafür den Spielernamen oder die E-Mail Adresse der Person verwenden. Ihre Freunde erscheinen in einer separaten Freundeliste in der Game Center App. Tippen Sie auf die Namen von Freunden und Sie sehen, welche Spiele sie gespielt haben. Sie können auch neue Freundschaftsanfragen ansehen und eigene hinzufügen.
    Leaderbords und Erfolge. Damit jeder sieht, wo Sie stehen.
    Sehen Sie sich auf den Ranglisten für jedes Spiel Ihre Platzierung unter Ihren Freunden und anderen Spielern an. Sie können auch Ihre Erfolge mit denen Ihrer Freunde vergleichen. Sehen Sie sich die Leaderboards und Erfolge in der Game Center App und jedem einzelnen Spiel an. Und dann lassen Sie es krachen.
     
    Trefen Sie Ihre Gegner. Und treffen Sie sie hart.
    Sie möchten eine Runde mit mehreren Freunden spielen? Mit Auto-Match werden Ihnen zuerst Ihre Freunde als Gegner vorgeschlagen, wenn diese auch nach einem Auto-Match suchen. Wenn nicht, wird Ihnen ein Freund in spe irgendwo auf dem Globus als Gegner vorgeschlagen. Oder laden Sie Ihre Freunde ein und lassen Sie Auto-Match alle für ein Spiel benötigten Spieler finden.
    Musik. Lassen Sie Ihre Finger tanzen.
    Cover Flow. Musik sieht so gut aus.
    Auf dem iPod touch gibt's Musik nicht nur auf die Ohren. Mit Cover Flow ist sie auch was für Augen und Finger. Drehen Sie den iPod touch auf die Seite und blättern Sie durch Ihre Albumcover. Tippen Sie auf ein Cover, um es umzudrehen und die Songliste zu sehen. Noch ein Tipp und die Musik läuft.
     
    Genius Wiedergabelisten. In jedem guten Song steckt eine noch bessere Wiedergabeliste.
    Angenommen Sie hören einen Song auf einem iPod touch, der Ihnen gut gefällt, und möchten weitere Titel hören, die gut dazu passen. Genius findet weitere Songs auf Ihrem iPod touch und erstellt eine Genius Wiedergabeliste. Hören Sie sich die Liste sofort an, speichern Sie sie für später oder versuchen's noch einmal und sehen, was dabei herauskommt. Verlassen Sie sich auf Genius, wenn Sie einen Mix wollen, auf den Sie selbst nie gekommen wären. 
     
    Genius Mixe. Nehmen Sie den DJ mit nach Hause.
    Genius ist Ihr persönlicher DJ. Synchronisieren Sie Ihren iPod touch mit iTunes und Genius durchsucht Ihre Mediathek automatisch nach Songs, die gut zusammenpassen. Dann erstellt Genius mehrere Mixe. Diese Mixe sind wie Radiosender, auf denen nur Ihre Lieblingshits laufen. So finden Sie Songs wieder, die Sie lange nicht mehr gehört haben oder von denen Sie gar nicht mehr wussten, dass Sie sie haben.
     
    Lassen Sie Ihre Finger tanzen. 
     
    Shake to shuffle. So ein Zufall.
    Die Dinge mal aufrütteln. Musikalisch natürlich. Wenn Sie das nächste Mal Musik hören, aktivieren Sie einfach die Schüttelfunktion. Wenn Sie den iPod touch dann kurz schütteln, springt er nach dem Zufallsprinzip zu einem anderen Song in Ihrer Sammlung. So entdecken Sie Ihre Musik immer wieder neu.
     
    iTunes. Das ist Entertainment.
    Packen Sie Songs und Musikvideos aus Ihrer iTunes Mediathek auf dem Computer auf den iPod touch. Oder kaufen und laden Sie neue Songs auf den iPod touch, wenn Sie sich über Wi-Fi mit iTunes verbinden. Wenn Sie dann den iPod touch das nächste Mal mit dem Computer verbinden, werden alle Songs, die Sie auf dem iPod touch gekauft haben, auf den Mac oder PC übertragen. Und mit iTunes Ping können Sie jetzt sehen, welche Musik Ihre Freunde hören, kaufen und empfehlen. Oder informieren Sie sich dort über Ihre Lieblingskünstler und was sie so hören.
     
    Bluetooth. Entfesseln Sie Ihre Musik.
    Die Unterstützung für das drahtlose Bluetooth ist im iPod touch schon drin. Das heißt, Sie können drahtlose Stereokopfhörer verwenden. Lassen Sie den iPod in Ihrer Tasche stecken oder auf dem Schreibtisch aufladen, während Sie weiter Musik hören.
     
    Filme und Fernsehsendungen. So haben Sie überall eine Sehenswürdigkeit.
    Ganz großes Kino. Auf einem kleinen Display.
    Mit dem iPod touch ist jeden Tag und überall Kinotag. Nehmen Sie Videos für viele Stunden Unterhaltung mit und sehen Sie sie auf dem fantastischen 3,5 Zoll Retina Display an. Kaufen Sie im iTunes Store und wählen Sie aus tausenden Filmen, Fernsehsendungen und Video-Podcasts für Ihren iPod touch. Da ist für jeden etwas dabei - von Hollywood Blockbustern bis zu Independent Filmen. Ein paar Fingertipps und Sie haben Filme geladen und können sie ansehen. Sie mögen lieber Fernsehsendungen? Die gibt's auch. Sie können einzelne Folgen oder gleich eine ganze Staffel kaufen. Mit dem iPod touch haben Sie Ihre Videos immer dabei.
    Sie haben alles unter Kontrolle.
    Wenn Sie ein Video schauen, tippen Sie einfach auf das Display und schon haben Sie die Steuerung. Damit können Sie die Wiedergabe starten oder unterbrechen, zu einzelnen Kapiteln springen und die Lautstärke anpassen. Oder verwenden Sie die Lautstärketasten links am iPod touch. Wenn Sie zwischen Widescreen- und Vollbildanzeige wechseln wollen, reicht ein Doppeltipp auf das Display. Das ist wie die Fernbedienung des Fernsehers. Nur, dass Sie nicht darum kämpfen müssen.
     
    iTunes. Für beste Unterhaltung.
    Sie brauchen für den nächsten Flug oder die nächste Fahrt etwas Unterhaltung? Mit iTunes auf dem iPod touch und einer Wi-Fi Verbindung können Sie sofort Filme und Fernsehsendungen kaufen. Oder Sie kaufen sie auf Ihrem Mac oder PC und synchronisieren sie mit dem iPod touch. Nur das Popcorn ist nicht dabei.
     
     
    Besuchen Sie Ihre Lieblingswebsites. Alles, was Sie dazu brauchen, ist ein iPod touch und Wi-Fi. 
     
    Laden Sie die iBooks App kostenlos und Sie haben nicht nur einen großartigen E-Book-Reader, sondern auch einen tollen Ort, um Bücher zu kaufen. 
     
    Und vieles mehr...
     
    App Store
    Laden Sie Apps direkt auf den iPod touch
     
    iTunes
    Erstellen Sie einen iTunes Store Account und kaufen Sie jederzeit via Wi-Fi ein.
     
    iBooks
    Laden Sie die iBooks App kostenlos und Sie haben nicht nur einen großartigen E-Book-Reader, sondern auch einen tollen Ort, um Bücher zu kaufen.
     
    iMovie
    Bearbeiten Sie Videos, fügen Sie Themen und Musik hinzu und teilen Sie Ihre Filme mit Anderen
     
    Mail
    Senden Sie Mails und sehen Sie sich Anhänge von Ihrem Google Mail, MobileMe oder einem anderen E-Mail Account an.
     
    Safari Webbrowser
    Besuchen Sie Ihre Lieblingswebsites. Alles, was Sie dazu brauchen, ist ein iPod touch und Wi-Fi.
     
    Fotos
    Nehmen Sie Ihre Fotos mit. Teilen Sie sie per E-Mail. Wählen Sie Ihr Lieblingsfoto als Hintergrundbild.
     
    Homescreen
    Ordnen Sie in iTunes Ihre Apps auf mehreren Homescreens an.
     
     
    Sprachsteuerung
    Steuern Sie die Musik auf dem iPod touch mit Sprachbefehlen
     
    Karten
    Finden Sie Restaurants, Konzerte und mehr und lassen Sie sich mit Karten zeigen, wie Sie hinkommen.
     
    YouTube
    Sehen Sie sich die neuesten Videohits und Ihre Lieblingsvideos an.
     
    Nike + iPod
    Erreichen Sie Ihre Trainingsziele mit integrierter Unterstützung für Nike + iPod
     
    Sprachmemos
    Nehmen Sie Notizen, Gedanken oder alles andere auf.
     
    Bedienungshilfen
    Der iPod touch kommt mit Bildschirmlesefunktion und weiteren Bedienungshilfen
     
    Lieferumfang
    iPod touch, Ohrhörer, USB 2.0 Kabel, Dock Adapter, Kurzanleitung
    ";2;False;0;;;"Apple iPod touch 4G 32 GB ";apple-ipod-touch-4g-32-gb;True;True;PD-01066;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;279.9900;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;40637,445775463;45;1;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000615-apple-ipod-touch-4g-32-gb.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000616-apple-ipod-touch-4g-32-gb.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000617-apple-ipod-touch-4g-32-gb.jpg;1;;False;;;;;False;False;False;;;;;False;;;;;; -5;0;True;Apple iPod shuffle 2 GB 4G;"Der neue, bunte, tragbare iPod shuffle. Mit Tasten, VoiceOver und Wiedergabelisten - der beste iPod shuffle, den es je gab. ";"Der neue, bunte, tragbare iPod shuffle.
    Mit Tasten, VoiceOver und Wiedergabelisten - der beste iPod shuffle, den es je gab.
     
    Eingebauter Clip.

    Sie ist wieder da - die große Klickbedienung vorn auf dem iPod shuffle.
     
    Erhältlich in Silber, Blau, Grün, Orange und Pink.
     
    Design. Ganz schön ansteckend.
    Elegantes, poliertes Aluminium. Fünf leuchtende Farben.
    Das Gehäuse des iPod shuffle ist aus einem Stück Aluminium. Und weil es außerdem poliert ist, können Sie mit dem neuen, eleganten und robusten iPod shuffle richtig glänzen. Seine brillanten Farben machen ihn dabei zum perfekten Accessoire. Wählen Sie zwischen Silber, Blau, Grün, Orange und Pink.
     
    Hunderte Songs für unterwegs.
    Nehmen Sie Ihre Lieblingssongs überallhin mit. Neben 15 Stunden Batterielaufzeit1 kommt der iPod shuffle mit 2 GB Speicher - das heißt Platz für hunderte von Songs. Genug für alle Songs für Ihr Fitness-Training oder den Weg zur Arbeit. Und auch für mehrere Wiedergabelisten, Genius Mixe, Podcasts und Hörbücher.
     
    Geht immer. Und überall.
    Der iPod shuffle ist nicht nur tragbar. Er ist auch ansteckbar. Klippen Sie ihn an Hemd, Jacke, Jogginghose, Rucksack oder Tasche und er ist überall mit dabei - egal, ob Sie zum Supermarkt laufen oder zu Ihrer persönlichen Bestzeit.
     
    Bedienung. Musik auf Knopfdruck.

    Steuern Sie Ihre Musik mit nur einem Klick.
    Sie ist wieder da - die große Klickbedienung vorn auf dem iPod shuffle. Sie ist 18 Prozent größer als bei den Vorgängermodellen. So können Sie sie sie noch leichter sehen und bedienen. Drücken Sie auf die Mitteltaste, um die Wiedergabe zu starten oder zu stoppen. Drücken Sie auf die äußeren Tasten, um vor- und zurückzuspringen oder die Lautstärke anzupassen. Klick, klick, klick. Das ist Musik für Ihre Finger.
     
    Spielt nach Ihren Regeln.
    Sie sind eher ein spontaner Typ? Oder haben Sie vielleicht lieber Ihre Ordnung? Stellen Sie den Schalter für die Zufallswiedergabe so ein, wie Sie wollen. Links wird Ihre Musik zufällig durcheinander gewürfelt. In der Mitte werden Ihre Songs in der normalen Reihenfolge gespielt. Und rechts schalten Sie den iPod shuffle aus.
     
    Geben Sie Ihren Songs eine Stimme.
    Angenommen Sie hören einen Song und wollen den Titel oder den Interpreten wissen. Drücken Sie einfach oben auf deinem iPod shuffle auf die neue VoiceOver Taste und VoiceOver nennt Ihnen beides. VoiceOver nennt Ihnen auch die Namen Ihrer Wiedergabelisten und wechselt zwischen diesen. Und wenn die Batterie aufgeladen werden muss, sagt VoiceOver das auch.
     
    Spricht Ihre Sprache.
    Französische Chansons. Spanische Flamencos. Italienische Arien. Ihr Musikarchiv enthält Songs aus allen Ländern der Erde. Deshalb spricht VoiceOver 25 verschiedene Sprachen. Und kann Ihnen Songtitel und Interpreten in deren jeweiliger Landessprache oder einer anderen Sprache nennen.
     
    Wiedergabelisten. Der perfekte Mix für jede Stimmung.
    Ganz einfach synchronisieren.
    Mit iTunes auf dem Mac oder PC können Sie Ihre Sachen ganz einfach auf den iPod shuffle laden. Wählen Sie einfach die Hörbücher, Wiedergabelisten, Podcasts und andere Audiodateien, die Sie wollen, und synchronisieren Sie sie.
     
    Wenn eine Wiedergabeliste nicht reicht.

    Wahrscheinlich haben Sie in iTunes auf Ihrem Computer mehrere Wiedergabelisten. Eine für unterwegs. Eine fürs Fitnessstudio. Eine zum Chillen. Jetzt können Sie diese Wiedergabelisten mit dem iPod shuffle synchronisieren und haben immer genau den richtigen Mix - egal, in welcher Stimmung Sie gerade sind. VoiceOver nennt Ihnen den Namen jeder Wiedergabeliste. So können Sie ganz leicht zwischen ihnen wechseln und genau die auswählen, nach der Ihnen gerade ist.
     
    Genius auf dem iPod shuffle.

    Und es gibt noch einen anderen Weg einen guten Mix auf den iPod shuffle zu bekommen: Verlassen Sie sich auf Genius. Aktivieren Sie Genius in iTunes auf dem Computer und er findet automatisch Songs, die gut zusammenpassen. Dann werden Genius Mixe erstellt, die Sie ganz einfach mit Ihrem iPod shuffle synchronisieren können. Das ist perfekt, um Songs zu entdecken, die Sie schon seit Jahrhunderten nicht mehr gehört haben.
     
    Lieferumfang
    iPod shuffle, Ohrhörer, iPod shuffle USB Kabel (4,5 cm), Dokumentation";2;False;0;;;Apple iPod shuffle 2 GB 4G;apple-ipod-shuffle-2-gb-4g;True;True;PD-01065;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;54.9000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;40637,4367824074;41;1;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000600-apple-ipod-shuffle-2-gb-4g.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000601-apple-ipod-shuffle-2-gb-4g.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000602-apple-ipod-shuffle-2-gb-4g.jpg;1;;False;;;;;False;False;False;;;;;False;;;;;; -5;0;True;Nokia Lumia 800 Smartphone;Nokia Lumia 800 Smartphone (9,4 cm (3.7 Zoll) AMOLED Clear Black-Touchscreen, Micro-SIM only, Windows Phone Mango OS, 8 MP Kamera) schwarz;"
    Einfacher ist besser.
    Das Nokia Lumia 800 mit Windows Phone. Alle Aktivitäten Ihrer Kontakte auf einen Blick.
     
    Startseite
    Legen Sie Gruppen oder Kontakte auf der Startseite ab, um noch schneller auf sie zuzugreifen. Sie können beliebige Elemente auf der Startseite ablegen. Halten Sie einfach den Finger auf die gewünschten Apps oder Tools, bis das Menü „Auf Startseite“ angezeigt wird.
     
    Gruppen
    Die Gruppe „Familie“ ist im Kontakte-Hub vorkonfiguriert, damit Sie sofort loslegen können. Sie schlägt Ihnen Kontakte mit übereinstimmenden Namen als Gruppenmitglieder vor. Doch Sie können auch beliebige andere Gruppen als Kachel auf der Startseite ablegen. In diesen Kacheln werden Profilfotos, entgangene Anrufe und Status-Updates aller Kontakte dieser Gruppe anzeigt. Sofort nach einer Status-Änderung beginnt diese Kachel, sich in sich selbst zu drehen, damit Sie keine Nachricht mehr verpassen. Wenn Sie Ihre Kontakte leichter voneinander unterscheiden möchten, können Sie ihnen individuell oder als Gruppe eigene Klingeltöne zuweisen. Tippen Sie einfach auf das gewünschte Profil und dann auf das Stift-Symbol, um einen Klingelton zu bearbeiten und hinzuzufügen.
     
    Immer tolle Fotos
    Fotografieren war noch nie so einfach – betätigen Sie einfach den Auslöser. Sie müssen das Smartphone noch nicht einmal entsperren, um richtig tolle Fotos zu machen. Danach können Sie die Fotos ebenso schnell auf Facebook oder anderen sozialen Netzwerken veröffentlichen. Und die 5-Megapixel-Kamera mit Autofokus sorgt für brillante, detailreiche Fotos, die garantiert Eindruck machen.
     
    Sprachgesteuerte Aktivierung
    Halten Sie einfach die Windows-Taste gedrückt, um die Spracherkennung zu aktivieren. Sie können mithilfe von Sprachbefehlen Anrufe tätigen, Ihren Kalender aufrufen, Texte diktieren und sogar Internetrecherchen durchführen.
     
    Multitasking
    Halten Sie den Zurück-Pfeil gedrückt, um zu sehen, welche Anwendungen gleichzeitig ausgeführt werden. Profil
    Nokia Lumia Smartphones sind automatisch mit Facebook verknüpft und verwenden Ihr Standard-Profilbild. Doch auch das können Sie im Handumdrehen ändern – tippen Sie einfach auf „Profil“, um ein neues Foto auszuwählen.
     
    Nokia Lumia Smartphones und Bing
    Starten Sie die Anwendung im Handumdrehen über das Symbol „Suchen“, um Internetrecherchen durchführen zu können, ohne den Browser zu öffnen. Geben Sie einfach Ihren Suchbegriff ein und wählen Sie das beste Ergebnis. Einfach. Intuitiv. Schnell.
     
    Apps
    Mit Wi-Fi laden Sie Apps mit größerem Dateiumfang, mobile Spiele und Medien noch schneller herunter. So können Sie das von Ihrem Provider ggf. im Rahmen eines Vertrags zur Verfügung gestellte Dateivolumen genau dann nutzen, wenn Sie es wirklich benötigen.
     
    Xbox Live Avatar
    In Xbox Live erstellen Sie ganz leicht einen Avatar für die Xbox Community. Öffnen Sie einfach Xbox Live und klicken Sie auf „Avatar“. Dort können Sie Ihrer Figur je nach Wunsch Frisur, Gesichtszüge und Kleider geben - auch als Abbild Ihrer selbst. Eben einfach die vielen kleinen Dinge, die Sie unverwechselbar machen. Lassen Sie Ihrer Kreativität freien Lauf und freuen Sie sich auf rasantes Gaming.
     
    Musik kaufen
    Mit Millionen von Songs zur Auswahl bietet Ihnen Nokia Musik jederzeit Zugriff auf die neuesten Hits und Ihre Lieblings-Klassiker. Nutzen Sie einfach die Suchfunktion oder stöbern Sie in den neuesten Veröffentlichungen. Wenn Sie sich entschieden haben, genügt eine Berührung, um den Song zu kaufen und in Ihre Bibliothek herunterzuladen.
     
    Schnelle Steuerung
    Wahrscheinlich möchten Sie noch mehr tun, als nur Musik zu hören. Deshalb ist es gut, dass Sie nicht jedes Mal Nokia Musik öffnen müssen, um zu einem anderen Song zu wechseln. Tippen Sie einfach auf die Lautstärkeregelung und unterbrechen oder überspringen Sie Songs über den Schnellzugriff. Das funktioniert auch, wenn das Smartphone gesperrt ist.
     
    Aktuelle Wiedergabe
    Über die Wiedergabeliste können Sie Musik aus Ihrer Bibliothek jederzeit individuell steuern - beispielsweise als zufällige Wiedergabe oder als Dauerschleife.
     
    Sprachgestützte Navigation
    Die Nokia Navigation mit gesprochenen Richtungsanweisungen ist auf Ihrem Nokia Lumia Smartphone vorinstalliert. Ihnen gefällt die Stimme nicht? Dann ändern Sie einfach die Ansagestimme der Navigation oder laden Sie eine neue herunter. Öffnen Sie dazu die Einstellungen und wählen Sie die Stimme, die Ihnen am angenehmsten ist.
     
    Tag und Nacht
    Sie werden bei Nachtfahrten nie wieder durch Ihr Navigationssystem geblendet. Mit der Nokia Navigation können Sie die Helligkeit des Displays anpassen, ohne dadurch die Deutlichkeit der Anzeige zu beeinträchtigen.
     
    2D und 3D
    Die Nokia Navigation bietet sowohl 2D- als auch 3D-Kartenansichten. Wenn Sie also eine genauere Ansicht Ihrer Route benötigen oder nach einprägsamen Orientierungspunkten Ausschau halten möchten, können Sie die Ansicht einfach über die Einstellungen ändern.
     
    Nokia Karten herunterladen
    Nokia Karten ist nach wenigen Handgriffen auf Ihrem Smartphone einsatzbereit. Diese App beinhaltet kostenlose Reiseführer, Veranstaltungstipps, interessante Ziele in Ihrer Nähe, Wetterinfos und vieles mehr. Öffnen Sie die Karten-Kachel, rufen Sie Marketplace auf und starten Sie den Download – die Anwendung ist kostenlos. Nach der Installation können Sie Nokia Karten über 3G- oder WLAN-Verbindungen nutzen.
    ";2;False;0;;;Nokia Lumia 800 Smartphone;nokia-lumia-800-smartphone;True;True;P-0006;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;499.0000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;40603,5677546296;"74;2095";17;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000534-nokia-lumia-800-smartphone.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000535-nokia-lumia-800-smartphone.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000536-nokia-lumia-800-smartphone.jpg;1;;False;;;;;False;False;False;;;;;False;;;;;; -5;0;True;Nokia N9 Smartphone blau;Nokia N9 Smartphone (9,9 cm (3,9 Zoll) Display, 16GB, Touchscreen, 8 Megapixel Kamera) blau;"
    Nokia N9 Smartphone
    Formatfüllender Touchscreen
    Ein einzigartiges Smartphone mit formatfüllendem Touchscreen. Die gewölbte Oberfläche aus kratzfestem Glas geht nahtlos in das glatte, aus einem Block gefertigte Gehäuse über. Jedes Detail strahlt Innovation aus. Auf dem brillanten AMOLED-Touchscreen erscheint alles in lebendigen Farben und das gewölbte Glas macht den Wechsel zwischen Apps per Fingerbewegung zum Kinderspiel.
     
    Einfach nur eine Fingerbewegung - Überzeugend benutzerfreundlich
    Alles läuft auf eine einfache Fingerbewegung hinaus. Das macht die Nutzung dieses Smartphones so intuitiv wie nie zuvor. Es gibt keine Zurück- oder Menü-Taste mehr – nur fliessende Fingerbewegungen, während Sie von App zu App wechseln. Mit einer Fingerbewegung über eine beliebige Ecke des Touchscreens gelangen Sie zur Startansicht, mit einer weiteren Bewegung wechseln Sie zwischen den drei Startansichten.
     
    Eine Startansicht - Drei einfache Ansichten
    Drei Ansichten sind alles, was Sie brauchen. In der vertrauten App-Ansicht starten Sie Anwendungen, eine weitere Ansicht zeigt die offenen Apps und macht Multitasking zum Kinderspiel: Sie machen genau dort weiter, wo Sie aufgehört haben.- Die Ansicht ""Ereignisse"" bringt Sie jederzeit auf den neuesten Stand der Dinge. Live-Feeds von Facebook und Twitter, E-Mails in Echtzeit, RSS-Feeds und mehr – alles an einer Stelle.
     
    Karten und Navigation kostenlos
    Live-Feeds von Facebook und Twitter, E-Mails in Echtzeit, RSS-Feeds und mehr – alles an einer Stelle. Sie finden die besten Angebote in Ihrer Stadt wie Cafés, Geschäfte, Konzerte, Hotels und mehr. Für mehr als 80 Städte weltweit steht Ihnen eine Übersicht von Strecken und Haltestellen des öffentlichen Nahverkehrs zur Verfügung. Entsprechendes Kartenmaterial ist bereits vorinstalliert, sodass Sie sofort starten können. Die Anwendung ""Fahren"" ist dank einfacher Bedienung über Touchscreen für die Verwendung im Auto optimiert.
     
    Browser der nächsten Generation
    Zeit für mehr Tempo. Das Nokia N9 bietet einen schnellen mobilen Internet-Browser und Seiten werden in kürzester Zeit aufgebaut. Die Unterstützung für HTML5 bedeutet für Sie das Beste aus dem Web, inklusive interaktiver Apps und schneller Videowiedergabe. Der Browser reagiert schnell auf jede Berührung. Sie können mehrere Seiten gleichzeitig öffnen und schnell zwischen den Seiten wechseln.
     
     
     
    8-Megapixel-Kamera mit Optik von Carl Zeiss
    Die Gelegenheit für ein gutes Foto kommt schnell und ist ebenso schnell vorbei. Mit der integrierten 8-Megapixel-Kamera mit Optik von Carl Zeiss können Sie brillante Fotos oder Videos in herausragender HD-Qualität aufnehmen.
     
    Die besten Apps und Spiele
    Apps sind heutzutage allgegenwärtig. Das Wichtigste ist jedoch die Qualität und nicht, wie viele man besitzt. Auf dem Nokia N9 sind die besten Apps wie Skype, Facebook, Twitter, AccuWeather und AP Mobile bereits vorinstalliert. Auch die Vollversion von Angry Birds ist bereits vorinstalliert – für viele Stunden Spass. Und im Ovi Store gibt es viele weitere Apps und Spiele.
    ";2;False;0;;;Nokia N9 Smartphone blau;nokia-n9-smartphone-blau;True;True;P-0008;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;569.0000;569.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;40602,8930439815;74;17;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000280-nokia-n9-smartphone-blau.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000281-nokia-n9-smartphone-blau.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000282-nokia-n9-smartphone-blau.jpg;1;;False;;;;;False;False;False;;;;;False;;;;;; -5;0;True;Apple iPod Nano 8 GB verschiedene Farben;Apple iPod Nano 8 GB;"
    Apple iPod Nano 8 GB
     
     
    Neues gebogenes Design, der dünnste iPod, den es je gab mit neuen Farben zu Auswahl
    Die Bedieung optimiert: ein einziges Handschütteln und ein anderes Lied wird gespielt
    Die neue Funktion ""Genius"" findet die Songs in Ihrer Mediathek, die besonders gut zusammenpassen, und erstellt daraus eine Genius Wiedergabeliste.
    Viele Abspielformate: z.B. MP3, AAC, Apple Lossless, AIFF, WAV, H.264, MPEG-4
    Lieferumfang: iPod Nano, Ohrhörer, USB 2.0 Kabel, Dock-Adapter, Dokumentation
     
    Neues gebogenes Design, der dünnste iPod, den es je gab mit neuen Farben zu Auswahl
    Die Bedieung optimiert: ein einziges Handschütteln und ein anderes Lied wird gespielt
    Die neue Funktion ""Genius"" findet die Songs in Ihrer Mediathek, die besonders gut zusammenpassen, und erstellt daraus eine Genius Wiedergabeliste.
    Viele Abspielformate: z.B. MP3, AAC, Apple Lossless, AIFF, WAV, H.264, MPEG-4
    Lieferumfang: iPod Nano, Ohrhörer, USB 2.0 Kabel, Dock-Adapter, Dokumentation
     
    Ein musikalisches Genie
    Stell Dir vor, Du hörst einen Song. Toll wären jetzt andere Titel, die gut dazu passen. Was machst du? Ganz einfach: Du verwendest die neue Funktion ""Genius"". Diese findet die Songs in Deiner Mediathek, die gut zusammenpassen. Du erhältst eine Genius Wiedergabeliste, zusammengestellt von Deinem persönlichen, superintelligenten DJ.  
    Musik schneller finden
    Auch einen Song, den Du hören willst, findest Du jetzt viel einfacher. Du kannst Deine Alben mit Cover Flow anzeigen oder hältst einfach die mittlere Taste gedrückt und blätterst in Deinen Alben oder Interpreten. Den gewünschten Song gefunden? Einmal auf die mittlere Taste gedrückt, und schon hast Du ihn zur aktuellen Wiedergabeliste hinzugefügt. 
     
    Aufdrehen und rumdrehen
    Neige Deinen iPod nano in die Waagerechte, und schon kannst Du hören, sehen oder spielen wie nie zuvor. Deine Alben kannst Du mit Cover Flow durchblättern und siehst so viel mehr Alben oder Interpreten gleichzeitig auf dem Display.
     
    Shake it, Baby!
    Manchmal hat man einfach Lust auf eine kleine Überraschung. Darum kannst Du jetzt komplett dem Zufall überlassen, welches Lied Du als Nächstes hörst. Einfach den iPod nano kurz schütteln – und er springt zu irgendeinem anderen Song aus Deiner Musik-Bibliothek. Lass dich überraschen, was er Dir als Nächstes präsentiert.   
    Spiel ab!
    Jetzt kannst Du Dir mit Spielen die Zeit vertreiben, die ganz speziell auf den iPod nano und den Beschleunigungssensor zugeschnitten sind. Sie reagieren auf Deine Bewegungen und wirken dadurch so überzeugend, dass sie fast schon süchtig machen können. In jedem Fall wirst Du begeistert sein. Bereits vorinstalliert ist Maze, wo Du Dich durch Neigen, Kippen und allerlei andere Bewegungen durch riesige Labyrinthe manövrieren musst. Im iTunes Store stehen natürlich noch viele weitere Spiele zur Auswahl.
     
    Sogar Deine Fotos rocken
    Jetzt kannst Du gleich hunderte von Fotos aus der Tasche zaubern und überall vorführen. Senkrecht gehalten zeigt der iPod nano Deine Fotos im Hochformat an, wenn Du ihn um 90 Grad drehst, wechseln auch die Fotos ins Querformat. Die Fotos wirken in ihrem richtigen Größen- und Seitenverhältnis auf dem brillanten Display mit 320 x 240 Pixeln einfach hervorragend. 
    Der größte kleine Bildschirm der Welt
    Filme, Fernsehsendungen und Videos auf dem iPod nano anzusehen, ist das pure Vergnügen. Die hochauflösende Anzeige wirkt auf dem kristallklaren 2"" Breitbild-Display besonders brillant und lebendig. So hast Du mit dem iPod nano Dein eigenes Kino im Taschenformat immer dabei.  
     
    Produktbeschreibungen
    Flach, flacher, am flachsten mit nur 6,2mm bringt der iPod nano, in leuchtenden Farben, neuen Schwung ins Leben.
    Mit brilianterem Display, höherer Speicherkapazität und noch längerer Batterielaufzeit schütteln Sie sich einfach durch Ihre Mediathek.
    Leistungsmerkmale
    - Verschieden Menüs: Musik, Fernsehsendungen, Videos, Hörbücher, Podcasts, Diashows, Spiele
    - Geschwungenen Aluminium-Design mit gewölbtem Glas
    - HxBxT: 90,7 x 38,7 x 6,2 mm
    - Gewicht: 36,8 g
    Lieferumfang
    - iPod nano
    - Ohrhörer
    - USB 2.0-Kabel
    - Dock-Adapter
    - Dokumentation
    Display
    - 2- Farb-LCD mit LED-Hintergrundbeleuchtung
    - 320 x 240 Pixel
    Kapazität
    - 8 GB Flash-Laufwerk1 für bis zu 2.000 Songs, 7.000 Fotos, 8 Std. Videomaterial
    Batterie
    - Integrierte, wiederaufladbare Lithium-Ionen-Batterie
    - Musikwiedergabe: bis zu 24 Stunden bei voller Ladung
    - Videowiedergabe: bis zu 4 Stunden bei voller Ladung
    Audio
    - Unterbrechungsfreie Wiedergabe
    - Frequenzbereich: 20 Hz bis 20.000 Hz
    - Unterstützte Audioformate: AAC, Protected AAC, MP3, MP3 VBR, Audible, Apple Lossless, AIFF und WAV
    Systemvoraussetzungen
    - USB 2.0-Anschluss
    - mind. Mac OS X 10.4.11 bzw. mind. Windows Vista oder Windows XP Home oder Professional
    - mind. iTunes 8  

     
     
     
    ";2;False;0;;;Apple iPod Nano 8 GB;apple-ipod-nano-8-gb-verschiedene-farben;True;True;P-1371;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;139.0000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;40218,6740856481;47;1;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000075-apple-ipod-nano-8-gb-verschiedene-farben.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000076-apple-ipod-nano-8-gb-verschiedene-farben.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000077-apple-ipod-nano-8-gb-verschiedene-farben.jpg;1;;False;;;;;False;False;False;;;;;False;;;;;; -5;210;True;_SmartStore.biz 6;Das Shopping System;"
    SHOP
    Mit neuesten Technologien topmoderne Ergebnisse erzielen
    Durch konsequente Verwendung von HTML5, CSS3, jQuery und jQuery UI erzeugt SmartStore.biz 6 schnelle und übersichtliche Seiten. Erst kürzlich hat auch YouTube sein Portal mit diesen Technologien neu aufgestellt. Das jQuery Framework bietet komfortable Funktionen zur Manipulation von Webseiten. jQuery UI ist eine Erweiterung von jQuery und bietet Lösungen zur Gestaltung und Funktionalität der Benutzeroberfläche an.
    Zusammen mit HTML5 und CSS können mit diesen Technologien komplexe Seiten hochperformant erstellt werden. Komponenten aus der jQuery UI-Bibliothek passen sich automatisch SmartStore-Theme Designs an. So können Sie selbst Komponenten und Effekte aus jQuery UI einbinden.
    Facebook, Google & Co
    Soziale Interaktion und Zusammenarbeit belebt den Shop und bindet Besucher. SmartStore.biz 6 bietet Möglichkeiten für die Verwendung von allen wichtigen Plattformen.
    Kunden können mit Google+ und Facebook Like Ihren Shop weiterempfehlen oder über Facebook Kommentare ein Kommentar zu einem Ihrer Angebote verfassen, welcher dann auch auf der Facebook-Seite des Kunden erscheint.
    Megamenü Navigation
    Mehrspaltige Menüs werden immer beliebter. Die Megamenü Navigation bietet gegenüber der einfachen Dropdown Navigation größere Navigationsflächen und die Darstellung von mehreren Navigationsebenen auf einer Ebene.
    Shrinkmenü
    Klein aber fein. Navigationsleisten mit sehr vielen Einträgen werden oft unzureichend gut dargestellt. Meist werden Einträge abgeschnitten oder alle Einträge werden angezeigt und das Layout passt nicht mehr.
    Die Funktion „Shrinkmenu“ passt die Navigation so an, dass der Platz für die Navigation optimal genutzt wird.
    Produktliste
    Eine Produkliste führt sämtliche Produkte eines Shops auf. Die neue Produktliste in SmartStore.biz 6 stellt Produkte wahlweise in einer mehrspaltigen Galerieansicht und in einer Listenansicht dar.
    Produktdetail
    Das neue Produktdetail-Modul zeigt jetzt alle zum Produkt zugehörigen Bilder in einer Galerie dar. Eine Zoom-Ansicht, in der die Bilder-Galerie in Vollbild angezeigt wird und eine Vollbild-Ansicht, in der jeweils ein Bild in einer LightBox angezeigt, erlauben Ihnen eine detaillierte und schöne Produktpräsentation. In der Vollbild-Ansicht kann zudem, ohne diese Ansicht zu verlassen zu anderen Bildern navigiert werden.
    Durch die Verwendung des Tab-Moduls können Daten wie Produktbeschreibung aber auch andere Module übersichtlich dargestellt werden.
    Docked Minibasket
    Der neue interaktive Mini-Warenkorb dockt sich stets griffbereit in die Fußzeile des Shops an. Der Shop-Kunde kann nicht nur per Knopfdruck, sondern auch per Drag & Drop seine Waren in den Warenkorb legen.
    Die detaillierte Ansicht des Warenkorbs verschafft dem Käufer stets einen klaren Überblick über seine Einkaufsliste. Derartige Design Highlights  erzeugen beim Käufer Sympathiepunkte, die sich in den meisten Fällen verkaufsfördernd auswirken.
    Tabs
    Das neue Tab-Modul stellt beliebige Module in Tabs dar und ermöglicht somit eine übersichtliche Darstellung von vielen Inhalten. Inhalte können so platzsparend und übersichtlich bei minimalem Platzverbrauch angezeigt werden. Überlange Seiten und langes scrollen gehören damit zur Vergangenheit.
      
    Splitter
    Der neue Splitter ermöglicht es, beliebig viele Module horizontal anzuordnen. Inhalten werden so platzsparend und ansprechend dargestellt.
    Content-Slider
    Der Content-Slider macht aus beliebigem Inhalt auf der Seite eine Dia-Show.
    Stellen Sie Top-Produkte, Sonderangebote und News eindrucksvoll mit einem Conten-Slider dar. Viele hübsche und effektvolle Übergangseffekte, Auto-Slide-Modus und die Paginierung machen den Content-Slider zu einem Hingucker in Ihrem Shop. 
    THEMING & DESIGN
    Neue Themes
    Smartstore.biz 6 enthält zwei von Grund auf neu entwickelte Themes. Ein modernes und ansprechendes Shop-Design ist somit "out-of-the-box" garantiert!
    60 neue Banner-Grafiken
    60 neue Banner-Grafiken aus unterschiedlichen Themenbereichen bilden die Grundlage für schicke und harmonische Banner. Mit den neuen Editierfunktionen lassen sich so hervorragende Banner mühelos mit ein paar Klicks erstellen.
    Seiten-Layout
    Das neue Seitenlayout basiert auf dem 960 Grid System.
    Per Knopfdruck kann das Layout eines Themes verändert werden. Layout-Typen wie Feste Breite, Hybrid und Dynamisch können sofort auf jedes Theme angewendet werden.
    Darüber hinaus können Außen- und Innenabstände, die Ausrichtung und die Breite der Seite einfach eingestellt werden.
    HTML Container
    HTML Container sind „Behälter“ für andere HTML-Elemente und dienen zur optischen Ausgestaltung. Container schaffen Übersicht und setzen Akzente.
    SmartStore.biz 6 enthält eine Container-Bibliothek mit mehr als 60 modern gestalteten Containern, die sich beliebig mit jedem Theme kombinieren lassen.
    Banner-Editor
    Der neue Banner-Editor bietet jetzt Ausblendeffekte für Ihren Banner nach allen Seiten und intelligente Spiegelungsfunktionen. Banner können nach allen Seiten mit eleganten Ausblendeffekten versehen werden und erzielen. Mit den neuen Editierfunktionen lassen sich so hervorragende Banner mühelos mit ein paar Klicks erstellen.
    WEITERE HIGHLIGHTS
    User Interface
    Innerhalb von SmartStore.biz 6 wurden die Funktionen in vielen Bereichen verbessert.
    Die Benutzeroberfläche wurde auf den neusten Stand gebracht.
    Alle wichtigen Menü-Einträge und Funktionen sind nun über ein anpassbares, Office 2010 ähnliches Ribbon erreichbar.
    Page-Designer
    Der Page-Designer wurde grundlegend Überarbeitet. Zur Übersichtlichkeit lassen sich nun Module auf- und zuklappen. Die Bedienung per Drag & Drop wurde intuitiver gestaltet.
    Multipanel Module
    Multipanel Module erzeugen aus anderen Modulen neue Darstellungen. So können z.B. aus vielen Bildern Galerien erzeugt werden oder eine Sammlung von Bildern, Buttons und Eingabefeldern kann in einem Tab dargestellt werden.
    SmartStore.biz 6 beinhaltet die Multipanel Module Tab, Splitter und Content-Slider.
    Ereigniskonsole
    Die Ereigniskonsole zeigt Fehlermeldungen und Ereignisse beim Testen und Erstellen an.
    Mit ihr lassen sich leicht Fehler in Skripten, Modulen und Plug-Ins finden. Fehler werden mit einer Beschreibung, dem Zeitpunkt des Auftritts, dem Fehler-Typ und dem Ursprung der Meldung angezeigt.
    Designer und Entwickler bekommen so direkt ein Feedback über Fehler. Über Aufrufe in eigenen Anwendungen können Entwickler Zeitmessungen vornehmen oder beliebige Nachrichten in der Ereigniskonsole anzeigen
    Payment-Schnittstellen
    masterpayment Zahlungsschnittstelle
    MASTERPAYMENT bietet das Rundum-Sorglos-Paket wie Rechnungskauf, Kreditkarte, Ratenzahlung, Sofortüberweisung jetzt für SmartStore-Händler an.
    Wer in seinem SmartStore-Shop MASTERPAYMENT bis zum 31.12.2011 aktiviert, spart sich sämtliche Grundgebühren und Set-Up-Gebühren für alle Zahlarten!
    Klarna Zahlungsschnittstelle
    Mit Klarna Rechnung und Ratenkauf anbieten!
    Klarna ist Europas führender Anbieter von rechnungsbasierten Zahlungs- und Finanzierungslösungen im Internethandel. Rechnung und Ratenkauf mit Klarna bieten Onlineshoppern entscheidende Vorteile.
    BillSafe Zahlunsschnittstelle
    Mit BillSAFE bieten Sie Ihren Kunden die beliebteste Zahlart in Deutschland – den Kauf auf Rechnung! Dadurch steigern Sie Ihren Umsatz, gewinnen
    neue Käufergruppen und erhöhen den Anteil an Bestandskunden. Das alles geht mit
    BillSAFE völlig ohne Ausfallrisiko..
    ";2;True;0;;;SmartStore.Biz 6;_smartstorebiz-6;True;True;P-6000;;MYEAN-65487;False;0;False;;False;False;0;True;0;1;False;;False;;False;100;0;10;True;False;0,0000;False;False;1;2;10000;True;True;0;0;0;0;False;1;10000;;False;False;False;False;190.0000;0.0000;0.0000;166.0000;42248,5157986111;42250,9999884259;False;100.0000;200.0000;0.0000;0.0000;0.0000;0.0000;40218,6501736111;"29;78;81;2095";42;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000070-_smartstorebiz-6.png;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000071-_smartstorebiz-6.png;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000072-_smartstorebiz-6.png;3;1;True;kg;2.0000;1;;False;False;False;;;;;False;;Toll Software DE;"

    Langbeschreibung

    ";SmartStore Biz EN;Nice software;"

    Long descriiption

    " -5;0;True;Sandisk Sansa Clip 2 GB rot;Sandisk Sansa Clip 2 GB mit integriertem FM-Tuner rot;"

    Sandisk Sansa Clip 2 GB mit integriertem FM-Tuner rot

    digitaler SanDisk Player für MP3, WMA, Secure WMA und FM Radio
    kleines, kompaktes Design, kaum größer als eine Streichholzschachtel
    FM-Radio mit 40 Stationsspeicherplätzen
    Diktiergerät-Funktion über integriertes Mikrofon
    4-zeiliges OLED-Display
     
    Sortierung der Titel nach versch. Kriterien möglich, wie z.B. Künstler, Album, Genre, u.a.
    bis zu 15-h-Wiedergabe mittels internem, wiederaufladbaren Akku
    inkl. abnehmbarem Trageclip, Ohrhörer, USB 2.0 Kabel, Installations-CD mit Bedienungsanleitung
    unterstützt Win 2000 / XP / Vista
     
    Lieferumfang:
    Player inkl. abnehmbarem Trageclip, Ohrhörer, USB 2.0 Kabel, Installations-CD mit Bedienungsanleitung
    ";2;False;0;;;"Sandisk Sansa Clip 2 GB mit integriertem FM-Tuner ";sandisk-sansa-clip-2-gb-rot;True;True;P-1620;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;42.9000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;40206,8077430556;52;8;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000571-sandisk-sansa-clip-2-gb-rot.jpg;;;2;;False;;;;;False;False;False;;;;;False;;;;;; -5;0;True;Sandisk Sansa Fuze 8 GB silber;"Sandisk Sansa Fuze MP3-/Video-Player 8 GB mit Radio silber ";"

    Sandisk Sansa Fuze MP3-/Video-Player 8 GB mit Radio silber

     
     
    Mit der verfügbaren Akkuleistung können Sie 24 Stunden lang Musik hören, Bilder anschauen oder spielen.
    Der neue Sansa Fuze von SanDisk ist der ideale tragbare Musikplayer für Sie.
    Er steht mit einer Speicherkapazität 4 GB in schwarz,rot,pink zur Verfügung.
    Sehen Sie sich Ihre Lieblingsvideoclips auf dem 1,9""-Farbdisplay des Sansa Fuze an.
    Lauschen Sie dem FM-Radio mit 40 voreingestellten Sendern oder probieren Sie den integrierten Sprachrekorder aus. Mit einer unglaublich starken Akkuleistung in einem 0,3"" schmalen Gerät setzt der Sansa Fuze Zeichen.
    ";2;False;0;;;Sandisk Sansa Fuze MP3-/Video-Player 4 GB mit Radio;sandisk-sansa-fuze-8-gb-silber;True;True;P-1610;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;89.9000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;40206,8019444444;52;8;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000570-sandisk-sansa-fuze-8-gb-silber.jpg;;;2;;False;;;;;False;False;False;;;;;False;;;;;; -5;0;True;Asus Eee PC 1001HA 10,1 Zoll Netbook;Asus Eee PC 1001HA 10,1 Zoll Netbook;"
    Eee PC™ 1001HA: Klasse Leistung zu unschlagbarem Preis
     
    Der Eee PC™ 1001HA unterscheidet sich von seinen großen Brüdern durch Prozessor und Akkukapazität. Ausgestattet mit einem Intel® Atom™ N270 Prozessor, einem 3 Zellen Akku für bis zu 4 Stunden Laufzeit, WLAN 802.11n Standard sowie weiteren Top Merkmalen, überzeugt der Eee PC™ 1001HA zu einem wirklich unschlagbaren Preis.
     
    Eee PC™ 1001HA: Funktionalität meets Design
     
    Mit dem kompakten Eee PC™ 1001HA trägt ASUS seinem Anspruch, in den Produkten höchste Funktionalität mit formvollendetem Design zu verbinden, ein weiteres Mal Rechnung. So besticht der neue Eee PC™ durch sein elegantes und gleichzeitig unempfindliches Gehäuse, das mit klaren Linien und nach unten schmaler zulaufenden Kanten dem schlanken Design einer Muschel nachempfunden ist. Aber auch das Innenleben der Kleinen kommt ganz groß raus. Als gewohnt kontaktfreudig erweisen sich die Neulinge dank VGA Port für den Anschluss eines Monitors sowie drei USB 2.0 Schnittstellen, um Maus, Tastatur oder Digicam anzuschließen. Wer Bilder direkt von der SD oder MMC Speicherkarte auf den Eee PC™ übertragen möchte, nutzt den integrierten Kartenleser. Für das Speichern der Fotos stehen bei beiden Modellen eine 160 GB S-ATA Festplatte zur Verfügung.. Das Modell basiert auf Microsoft® Windows® XP Home und ist – wie alle Eee Familienmitglieder – ausgesprochen einfach zu bedienen. Das 10 Zoll WSVGA Display mit stromsparender LED-Hintergrundbeleuchtung sowie die große Tastatur, die zu 92% einer Standard Notebooktastatur entspricht, gewähren zusätzlichen Komfort. Für Chats oder Videokonferenzen hat ASUS die Minis zudem mit einer 0.3 Megapixel Web-/Videokamera sowie einem Mikrofon ausgestattet.
     
     
    ";2;False;0;;;Asus Eee PC 1001HA 10,1 Zoll;asus-eee-pc-1001ha-101-zoll-netbook;True;True;P-0890;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;243.9000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;40205,9519907407;6;37;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000563-asus-eee-pc-1001ha-101-zoll-netbook.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000564-asus-eee-pc-1001ha-101-zoll-netbook.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000565-asus-eee-pc-1001ha-101-zoll-netbook.jpg;2;;False;;;;;False;False;False;;;;;False;;;;;; -5;0;True;Canon PGI 520BK Tintenpatrone schwarz;Canon PGI 520BK Tintenpatrone schwarz;"
    Canon PGI 520BK ,Tintenpatrone, schwarz, 19ml
     
     
     
    kompatibel  PIXMA iP3600/iP4600/IP4700 und MP540/620/630/640

     
     
    ";2;False;0;;;"Canon CLI-521, Tintenpatrone, cyan, 9ml, für PIXMA iP3600/iP4600/IP4700 und MP540/620/630/980 - ""R"" ";canon-pgi-520bk-tintenpatrone-schwarz;True;True;P-2280;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;-1,2000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;11.9900;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;40205,7303009259;23;25;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000562-canon-pgi-520bk-tintenpatrone-schwarz.jpg;;;2;;False;;;;;False;False;False;;;;;False;;;;;; -5;0;True;Canon CLI-521 Tintenpatrone schwarz;Canon CLI-521 Tintenpatrone;"
    Canon CLI-521BK,Tintenpatrone, schwarz, 9ml
     
     
     
    kompatibel  PIXMA iP3600/iP4600/IP4700 und MP540/620/630/640

     
     
    ";2;False;0;;;"Canon CLI-521, Tintenpatrone, cyan, 9ml, für PIXMA iP3600/iP4600/IP4700 und MP540/620/630/980 - ""R"" ";canon-cli-521-tintenpatrone-schwarz;True;True;P-2270;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;-1,2000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;11.9900;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;40205,7265509259;23;25;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000555-canon-cli-521-tintenpatrone-schwarz.jpg;;;2;;False;;;;;False;False;False;;;;;False;;;;;; -5;0;True;Canon CLI-521 Tintenpatrone magenta;Canon CLI-521 Tintenpatrone;"
    Canon CLI-521M,Tintenpatrone, magenta, 9ml
     
     
     
    kompatibel  PIXMA iP3600/iP4600/IP4700 und MP540/620/630/640

     
     
    ";2;False;0;;;"Canon CLI-521, Tintenpatrone, cyan, 9ml, für PIXMA iP3600/iP4600/IP4700 und MP540/620/630/980 - ""R"" ";canon-cli-521-tintenpatrone-magenta;True;True;P-2260;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;-1,2000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;11.9900;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;40205,7246643519;"23;2095";25;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000554-canon-cli-521-tintenpatrone-magenta.jpg;;;2;;False;;;;;False;False;False;;;;;False;;;;;; -5;0;True;Canon CLI-521 Tintenpatrone cyan;Canon CLI-521 Tintenpatrone;"
    Canon CLI 521C,Tintenpatrone, cyan, 9ml
     
     
     
    kompatibel  PIXMA iP3600/iP4600/IP4700 und MP540/620/630/640

     
     

     
     
    ";2;False;0;;;"Canon CLI-521, Tintenpatrone, cyan, 9ml, für PIXMA iP3600/iP4600/IP4700 und MP540/620/630/980 - ""R"" ";canon-cli-521-tintenpatrone-cyan;True;True;P-2250;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;-1,2000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;11.9900;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;40205,7210416667;23;25;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000553-canon-cli-521-tintenpatrone-cyan.jpg;;;2;;False;;;;;False;False;False;;;;;False;;;;;; -5;0;True;Canon CLI-521 Tintenpatrone gelb;Canon CLI-521 Tintenpatrone;"
    Canon CLI-521Y,Tintenpatrone, gelb, 9ml
     
     
     
    kompatibel  PIXMA iP3600/iP4600/IP4700 und MP540/620/630/640

     
     
    ";2;False;0;;;"Canon CLI-521, Tintenpatrone, cyan, 9ml, für PIXMA iP3600/iP4600/IP4700 und MP540/620/630/980 - ""R"" ";canon-cli-521-tintenpatrone-gelb;True;True;P-2240;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;-1,2000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;11.9900;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;40205,6889814815;23;25;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000552-canon-cli-521-tintenpatrone-gelb.jpg;;;2;;False;;;;;False;False;False;;;;;False;;;;;; -5;0;True;"Philips DC 200 iPod Soundsytem ";"Philips DC 200 iPod Soundsytem ";"
    Philips DC 200 iPod Soundsytem  - Radio, USB, Apple iPod kompatibel

    Genießen Sie Ihre MP3-Lieblingsmusik auch beim Aufladen Ihres iPods! Dank der Docking-Station können Sie Ihren iPod direkt an das Docking-Entertainment-System anschließen und Ihre Lieblingsmusik in ausgezeichneter Soundqualität wiedergeben.
     
    Ihr iPod wird während der Wiedergabe aufgeladen, sodass Sie Ihre Musik genießen können, ohne sich Gedanken über den Ladestand des Akkus machen zu müssen. Verwenden Sie zum Durchsuchen, Auswählen und Wiedergeben der auf dem iPod gespeicherten Musiktitel die Fernbedienung.
     
    Das Docking-Entertainment-System lädt Ihren iPod automatisch auf, solange er sich in der Station befindet.
    Durch den direkten USB-Anschluss können Sie einfach Musik auf einem USB-Gerät auswählen und wiedergeben.
    Um Musik wiederzugeben oder Inhalte zu exportieren, stecken Sie das USB-Gerät einfach ein.
    Das digitale UKW-Radio bietet Ihnen zusätzliche Musikoptionen für die Musiksammlung auf Ihrem Philips Player.
    Stellen Sie einfach den gewünschten Radiosender ein, und halten Sie die Speichertaste gedrückt, um die Frequenz zu speichern.
     
    Dank der voreingestellten und gespeicherten Radiosender können Sie ganz einfach Ihren Lieblingssender hören,
    ohne die Frequenz jedes Mal manuell einstellen zu müssen.
     
    Das Bassreflex-Lautsprechersystem sorgt bei kompakten Lautsprecher-Systemen für tiefe Bässe.
    Der Unterschied zu konventionellen Lautsprecher-Systemen liegt in der Tiefbassröhre, die akustisch auf den Woofer abgestimmt ist,
     
    um den Low Frequency Roll Off des Systems zu optimieren. Ergebnis sind tiefer gesteuerte Bässe und weniger Verzerrung.
     
    Das Prinzip besteht darin, dass die Luftmasse in der Tiefbassröhre mitschwingt und wie ein herkömmlicher Woofer vibriert.
     
    In Kombination mit der Reaktion des Woofers erweitert das System alle niederfrequenten Töne und erzeugt tiefe Bässe in einer völlig neuen Dimension.
     
    Lieferumfang: 3,5 mm Stereo-Line-Eingangskabel;AC/DC-Adapter;Schnellstartanleitung;Benutzerhandbuch
    ";2;False;0;;;;philips-dc-200-ipod-soundsytem;True;True;P-1540;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;82.9000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;40203,8622569444;"51;2095";6;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000544-philips-dc-200-ipod-soundsytem.jpg;;;1;;False;;;;;False;False;False;;;;;False;;;;;; -5;0;True;"Logitech G500 Gaming Maus ";"Logitech G500 Gaming Maus ";"
     Logitech G500 Gaming Maus
     
     
     
    Der spieletaugliche Laser geben Ihnen bei jeder Bewegungsgeschwindigkeit eine atemberaubende Präzision
    Durch Feintuning mit bis zu 27 Gramm an zusätzlichen Gewichten bestimmen Sie exakt, wie die Maus in der Hand liegt
     
    Der integrierte Speicher ermöglicht es Ihnen, die Einstellungen für Dein Lieblingsspiel zu speichern und mitzunehmen – es ist keine Software erforderlich

    Das Tastenrad bietet Ihnen zwei Einstellungen – den präzisen Click-to-Click-Modus oder hyperschnelle Bildläufe
     
    Lieferumfang:
    Logitech G500 Gaming Maus, Anpassbares Gewichtsmagazin, Tuninggewichte und Etui, Bedienungsanleitung
    ";2;False;0;;;"Logitech G500 Gaming Maus ";logitech-g500-gaming-maus;True;True;P-2820;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;59.0000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;40203,8042476852;21;11;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000543-logitech-g500-gaming-maus.jpg;;;2;;False;;;;;False;False;False;;;;;False;;;;;; -5;0;True;Garmin nüvi 205 Navigationssystem DACH;Garmin nüvi 205 Navigationssystem DACH;"
    Garmin nüvi 205 Navigationssystem DACH
     
     
    3,5 Zoll Touchscreen Display, PhotoNavigation, MicroSD-Kartenslot und ecoRoute
     
     
    Bedienerfreundliches Einsteigernavigationsgerät mit elegantem, ultra-schlankem Design
    und brillantem 3,5 Zoll (8,9cm Bilddiagonale) Touchscreen Display
    Detailkarten für Deutschland, Österreich, Schweiz + CZ intern vorinstalliert
    ecoRoute: reduziert den Kraftstoffverbrauch, CO2-Emissionen
    und schont die Umwelt, spart bares Geld und füllt die Reisekasse auf.
    PhotoNavigation mit Garmin Connect: Sie können Sehenswürdigkeiten und Bilder herunterladen und als Ziel auswählen
    Lieferumfang: Garmin nüvi 205 mit Kartenmaterial DACH,
    Saugnapfhalterung für die Windschutzscheibe, Armaturenhalterung, Schnellstartanleitung, KFZ-Anschlusskabel
    ";2;False;0;;;Garmin nüvi 205 Navigationssystem DACH;garmin-nuevi-205-navigationssystem-dach;True;True;P-2110;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;139.0000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;40200,8638078704;67;44;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000542-garmin-nuvi-205-navigationssystem-dach.jpg;;;2;;False;;;;;False;False;False;;;;;False;;;;;; -5;0;True;"AVM FRITZ!Fon C3 VoIP Dect-Telefon ";"AVM FRITZ!Fon C3 VoIP Dect-Telefon ";"
    FRITZ!Fon C3: HD-Telefonie und komfortable Internetdienste mit DECT.
    Telefonieren Sie mit dem Schnurlostelefon FRITZ!Fon C3 in bestechender Qualität über das Internet und nutzen Sie komfortable Webdienste. Als intelligentes Telefon der neuesten DECT-Generation vereint das FRITZ!Fon den Komfort der schnurlosen Telefonie mit den Qualitäts- und Leistungsmerkmalen der Internettelefonie (VoIP) in einem Gerät.
     
    Bei der Internettelefonie mit einem FRITZ!Fon wird durch HD-Telefonie (High Definition) ein brillantes, natürliches Klanggefühl erreicht. Sprache lässt sich mit dem FRITZ!Fon in ihrem gesamten Frequenzspektrum wiedergeben, was die Klangqualität von Festnetzverbindungen deutlich übertrifft.
     
    FRITZ!Fon unterstützt die übertragung großer Bandbreiten. Dies ermöglicht neben HD-Telefonie auch die Nutzung komfortabler Internetdienste wie den Empfang von E-Mails, Podcasts, RSS-Feeds und Internetradio.
     
    Die Steuerung von FRITZ!Box-Anwendungen am Handgerät bietet viel zusätzlichen Komfort. Und durch DECT-Eco wird Funkabstrahlung bei Nichtnutzung der Telefone verhindert.
     
    Die FRITZ!Box-Modelle FRITZ!Box Fon WLAN 7390, 7320, 7270, 7240 sowie FRITZ!Box 6360 Cable stellen mit der integrierten DECT-Basisstation, mehreren Anrufbeantwortern und Telefonbüchern für bis zu 300 Einträge den idealen Partner für das FRITZ!Fon dar. Mit der umfangreichen Prozessor- und Speicherausstattung ist auch der Grundstein für neue Anwendungen gelegt. Denn das FRITZ!Fon ist lernfähig:
     
    Als eines der ersten intelligenten Schnurlostelefone wird es auch künftig per Firmware-Updates aktualisiert und um neue Funktionen erweitert werden können.
     
    Umfangreicher Komfort
    Das FRITZ!Fon C3 ist mit zahlreichen Komfortfunktionen ausgestattet. Dazu zählen Lauthören und Freisprechen in HD-Qualität sowie ISDN-Leistungsmerkmale wie Namensanzeige bei bekannten Rufnummern, Halten, Makeln, Anklopfen, Rufumleitung oder Dreierkonferenz. Die Internettelefonie in HD-Qualität lässt sich so in ihrem vollen Umfang und Komfort nutzen, ohne dass der Computer eingeschaltet sein muss.
     
    FRITZ!Fon informiert zudem aktiv über unbeantwortete Anrufe, Nachrichten auf dem Anrufbeantworter und zeigt eingegangene E-Mails an. An der DECT-Basisstation der FRITZ!Box Fon WLAN 7390, 7320, 7270, 7240 oder FRITZ!Box 6360 Cable lassen sich bis zu 6 FRITZ!Fon-Handgeräte oder andere DECT-Telefone anmelden. Die Erstinstallation und individuelle Einstellungen erfolgen dabei bequem über einfache Assistenten.
     
    FRITZ!Box als idealer Partner
    Das FRITZ!Fon C3 kann als Mobilteil an jeder DECT-Basisstation eingesetzt werden. Im Zusammenspiel mit der FRITZ!Box Fon WLAN 7390, 7320, 7270, 7240 oder FRITZ!Box 6360 Cable kann jedoch das volle Spektrum der Möglichkeiten beim Telefonieren und Surfen über das Internet ausgenutzt werden.
     
    Die FRITZ!Box Fon WLAN 7390 zum Beispiel vereint eine bisher nicht erreichte Vielfalt in einem Gerät: VDSL- und ADSL-Unterstützung, DECT-Basisstation fürs schnurlose Telefonieren sowie WLAN N für die optimale Datenübertragung. über den Mediaserver sind gespeicherte Filme, Musik und Bilder auch bei ausgeschaltetem Computer im gesamten Netzwerk verfügbar. Darüber hinaus kann der Online-Speicher wie eine lokale Festplatte genutzt werden. So wird die FRITZ!Box Fon WLAN 7390 zur idealen Plattform für vernetzte Anwendungen wie IPTV, Video on Demand oder Mediastreaming.
     
    Bedienung
    - Schnelle Anmeldung: Einschalten, Suchtaste der FRITZ!Box drücken, fertig.
     
    - Einfache Bedienung über intuitives Menü.
     
    - Telefonbuch komfortabel über FRITZ!Box-Oberfläche einrichten und anzeigen.
     
    - In FRITZ!Box integrierte Anrufbeantworter einfach am C3 einrichten und abhören.
     
    - Blinkendes Nachrichtensymbol signalisiert eingegangene Anrufe, neue Nachrichten auf dem Anrufbeantworter und neue E-Mails.
     

    Telefonieren Sie mit dem Schnurlostelefon C3 in bestechender Qualität über das Internet und nutzen Sie komfortable Webdienste.
     
    Highlights
    - DECT-Telefon für Internet- und Festnetztelefonie, ideal geeignet für die FRITZ!Box Modelle 7270, 7240, 7390 und 6360 Cable
    - Farbdisplay und beleuchtete Tastatur
    - Telefonbücher für bis zu 300 Einträge, Online-Telefonbuch verfügbar
    - Mehrere Anrufbeantworter mit Menüsteuerung und Fernabfrage
    - Full-Duplex-Freisprechen
    - Unterstützt HD-Telefonie nach CAT-iq
    - Per Software-Update einfach um neue Funktionen erweiterbar
     
    Eigenschaften DECT-Telefon
    - Mobilteilbreite: 49 mm
    - Mobilteilhöhe: 138 mm
    - Mobilteiltiefe: 26 mm
    - Gewicht Mobilteil inkl. Akku: 133 g
    - Feldstärkeanzeige
    - Freisprechfunktion
    - CAT-iq Standard
    - Strahlungsarm
    - GAP-fähig
    - Reichweite im Freien bis zu 300 m
    - Reichweite in Gebäuden bis zu 40 m
     
    Telefoneigenschaften
    - Anruferanzeige (CLIP)
    - Picture-CLIP
    - Anruferliste
    - Anzeige Datum/Uhrzeit
    - Anzeige Gesprächsdauer
    - Polyphone Klingeltöne: ja
    - Hörerlautstärke einstellbar
    - Stummschaltung möglich
    - Bis zu 300 Telefonbucheinträge
    - Wecker
    - Telefontyp: Schnurlostelefon
     
    Grundeigenschaften
    - Farbe: Silber
     
    Lieferumfang
    - FRITZ!Fon C3
    - AAA-Akkupack
    - Ladestation
    - Netzteil zum Anschluss an das 230-Volt-Stromnetz
    - Gedrucktes deutschsprachiges Handbuch
     

    Kompatibel zu:
    FRITZ!Box Fon WLAN 7270, FRITZ!Box Fon WLAN 7240, FRITZ!Box Fon WLAN 7320, FRITZ!Box Fon WLAN 7390, FRITZ!Box 6360 Cable
    ";2;False;0;;;"AVM FRITZ!Fon C3 VoIP Dect-Telefon ";avm-fritzfon-c3-voip-dect-telefon;True;True;P-2750;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;69.0000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;40200,5014467593;20;34;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000537-avm-fritzfon-c3-voip-dect-telefon.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000538-avm-fritzfon-c3-voip-dect-telefon.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000539-avm-fritzfon-c3-voip-dect-telefon.jpg;3;;False;;;;;False;False;False;;;;;False;;;;;; -5;0;True;Canon PIXMA MP560 Multifunktionsgerät 3 in 1;Canon PIXMA MP560 Multifunktionsgerät 3 in 1;"Canon PIXMA MP560 Multifunktionsgerät
     
    3 in 1, Drucken, Kopieren, Scannen

    Multifunktionssystem: Fotodrucker, Farbscanner und Farbkopierer
    Druckgeschwindigkeit: ca. 9,2 (SW) bzw. 6,0 (Farbe) ISO-Seiten/Min; einzelne Tintentanks
    ca. 39 Sek. für den druck eines 10 x 15 cm Randlosprint in Laborqualität
    Benutzerfreundliches und intuitives Interface; 5 cm Display und Easy-Scroll-Bedienrad
    Lieferumfang: PIXMA MP560, Netzkabel, Druckkopf, Tintentanks, Kurzanleitung,CD mit Installations-Software und Benutzerhandbuch, ";2;False;0;;;"Canon PIXMA MP640 ";canon-pixma-mp560-multifunktionsgeraet-3-in-1;True;True;P-2230;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;2,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;139.0000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;40194,5747453704;22;25;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000460-canon-pixma-mp560-multifunktionsgerat-3-in-1.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000461-canon-pixma-mp560-multifunktionsgerat-3-in-1.jpg;;2;;False;;;;;False;False;False;;;;;False;;;;;; -5;0;True;Panasonic Lumix DMC-FS7 Digitalkamera schwarz;"Panasonic Lumix DMC-FS7 Digitalkamera schwarz ";"
    Panasonic Lumix DMC-FS7 Digitalkamera schwarz

    10 Megapixel, 4-fach opt. Zoom, 6,9 cm Display, Bildstabilisator
     
    Im Intelligenten Automatik (iA)-Modus werden die 5 wichtigsten Motivprogramme automatisch optimal auf die jeweilige Szene eingestellt.
    Neben der Motiverkennung kombiniert iA weitere wichtige Funktionen, wie den optischen Bildstabilisator OIS,
    die Bewegungserkennung (Intelligente ISO-Steuerung), eine optimierte Gesichtserkennung mit digitaler Rotaugen-Korrektur. So sind scharfe, natürliche und schöne Fotos selbst für (Neu-)Einsteiger möglich.
     
    Lichtstarkes F2,8 Leica DC Vario-Elmarit Objektiv
    Hochauflösendes 6,9 cm LC-Display [230.000 Pixel]
    4x optischer Zoom [KB: 33-132 mm]
    Intelligente Automatik [u.a. Gesichtserkennung]
     
    Lieferumfang:
    Digitalkamera, Lithium Ionen Akku, Ladegerät, USB-Kabel, Trageriemen, Audio / Video-Kabel, CD-ROM, Sotware
    ";2;False;0;;;"Panasonic Lumix DMC-FS6 ";panasonic-lumix-dmc-fs7-digitalkamera-schwarz;True;True;P-1780;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;169.0000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;40189,6771412037;58;12;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000453-panasonic-lumix-dmc-fs7-digitalkamera-schwarz.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000454-panasonic-lumix-dmc-fs7-digitalkamera-schwarz.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000455-panasonic-lumix-dmc-fs7-digitalkamera-schwarz.jpg;2;;False;;;;;False;False;False;;;;;False;;;;;; -5;0;True;Casio EX-H10 SR Digitalkamera silber;Casio EX-H10 SR Digitalkamera silber;"
    Casio EX-H10 SR Digitalkamera silber
     
    12 Megapixel, 10-fach opt. Zoom, 7,6 cm  Display, Bildstabilisator
     
    Die Kombination aus einem energiesparenden Prozessor und einem extrem leistungsstarken Lithium-Ionen-Akku sorgt dafür, dass der EXILIM EX-H10 auch an langen, erlebnisreichen Tagen nicht der Strom ausgeht und sie mit einer Akkuladung bis zu 1000 Fotos machen kann.
     
    12,1 Megapixel CCD-Chip
    10fach optischer Zoom mit mechanischem Bildstabilisator, 4fach digitaler Zoom, 24 mm Weitwinkel Objektiv
    7,6 cm (3,0 Zoll) TFT-Farbdisplay (Super Clear LCD)
    Bis zu 1000 Fotos mit einer Akkuladung
     
    Lieferumfang:
    Digitalkamera EX-H10 silber, wiederaufladbarer Lithium-Ionen-Akku , Ladegerät, AC-Anschlusskabel, USB-Kabel, AV-Kabel, Trageriemen, CD-ROM
    ";2;False;0;;;"Casio EX-H10 SR Digitalkamera ";casio-ex-h10-sr-digitalkamera-silber;True;True;P-1760;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;289.0000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;40189,6684375;57;9;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000450-casio-ex-h10-sr-digitalkamera-silber.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000451-casio-ex-h10-sr-digitalkamera-silber.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000452-casio-ex-h10-sr-digitalkamera-silber.jpg;2;;False;;;;;False;False;False;;;;;False;;;;;; -5;0;True;BenQ G2420HDBL 61 cm 24 Zoll TFT Monitor schwarz;BenQ G2420HDBL 61 cm (24 Zoll) Full-HD LED-Monitor (DVI, VGA, Reaktionszeit 5ms) schwarz;"
    BenQ G2420HDBL - Der High-End-Entertainer!
    Der G2420HDBL LED-Monitor mit seiner BenQ LED-Edge-Backlight-Technologie im 16:9 Widescreen-Format und einer Bilddiagonale von 61 cm (24 Zoll) verfügt über eine Full-HD-Auflösung (1920 x 1080p), einen dynamischen Kontrast von 5.000.000:1, eine Reaktionszeit von 5 ms sowie eine Helligkeit von 250 cd/m². Zusätzlich sorgt die BenQ Senseye®-Photo-Technologie für eine perfekte Bildqualität bei jeder Anwendung. Mit seinem schwarz glänzenden Design ergänzt dieses PC-Display elegant jedes Büro und jedes Zuhause.
     
    Sparen Sie Energie - und Geld!
    Aufgrund der stetig zunehmenden globalen Erderwärmung wird es immer wichtiger, CO²-Emissionen zu reduzieren. Die LED Monitore von BenQ haben einen um 36% verringerten Energieverbrauch im Vergleich zu herkömmlichen Monitoren. Im Eco-Modus sparen Sie nochmal 30% der Energie! Und schonen zusätzlich auch noch Ihren Geldbeutel!
     
    BenQ Senseye® Human Vision Technology
    Mit 6 proprietären Verfahren für die Kalibrierung eines perfekten Bildes.
    Dank der Senseye® Technologie und der 6 verschiedenen Techniken zur Farbkalibrierung, zeigen BenQ LED Monitore echte Farben.
     
    Comfortable
    Die Helligkeit des Monitors lässt sich so fein einstellen, dass Sie ein perfekt ausgeleuchtetes Bild erhalten.
     
    Clear
    Exakte Ränder und Bilder, die scharf bis ins kleinste Detail sind.
     
    Detailed
    Detaillierte Bilder dank des hohen dynamischen Kontrasts von 5.000.000:1.
     
    Clean
    Sämtliche Darstellungen sind frei von Bildrauschen.
     
    Brilliant
    Klarere Bilder und leuchtend echte Farben lassen die Bilder farbenfroh erscheinen.
     
    Balanced
    Dank eines integrierten Algorithmus enthält die Bilddarstellung ein ausgewogenes Farbbild.
       
    Herausragende LED Farbgestaltung
     
    1080p Full-HD (1920x1080 High Definition)
    Full-HD-Displays bieten ein breitformatiges Vollbild mit 1080p-Auflösung nach dem HD-Standard (High-Definition). So kann z. B. mit Blu-ray-Playern, Multimedia-PCs, Notebooks oder Spielekonsolen der neuesten Generation das volle Bild digital ohne Kompromisse in brillantester Bildqualität dargestellt werden. Mit dem 16:9-Wide-Format, das perfekt für die Darstellung von Full-HD-Filmen ist, wird zudem bis zu 30 % mehr Bildfläche dargestellt als beim 4:3-Format.
     
    Dynamischer Kontrast von 5.000.000:1!
    Der extrem hohe dynamische Kontrast von 5.000.000:1 zeigt - insbesondere in dunkleren und komplexen Bewegungsbildern, wie bei Filmen und Video-Spielen - sogar die kleinsten Details in brillanter Schärfe. Sie erhalten fantastische Bilddetails sowie ein klares Bild auch bei dunklen, komplexen und bewegten Bildern. Noch nie haben Sie ein reineres weiß oder ein tieferes schwarz gesehen!
     
    16:9 Format - Die 10%, die Ihr visuelles Vergnügen vervollständigen!
    Wenn ein traditioneller 16:10 Monitor 16:9 Signale in Full-HD Bilder umwandelt, geschieht dies normalerweise auf zwei Wegen. Die erste Möglichkeit wäre, die Bilder zu strecken, was zu Verzerrungen führt. Eine andere Variante wäre, das überschüssige Bild mit schwarzen Balken zu verdecken. Beide Wege, ob eine Streckung von 10 % oder eineVerdeckung von 10 % des Bildes, haben einen erheblichen Einfluss auf den Bildgenuss.
     
    Die BenQ Full-HD 16:9 LED-Monitore hingegen bieten Ihnen eine Punkt-für-Punkt Full-HD Bildübermittlung, um die Probleme der 16:10 Monitore zu lösen. Nun können Sie endlich eine 100 %-ige Full-HD Performance genießen, auf die Sie gewartet haben!
     
    Für eine saubere Umwelt
     
    Umweltschutz durch Reduzierung des Verpackungsmaterials
    Unser Beitrag zum Umweltschutz: 80% des Verpackungsmaterials besteht aus recyceltem Papier, das Verpackungsmaterial insgesamt wird stark reduziert. Dank der schlanken LED-Panels erhöht sich beim Transport der Monitore das freie Ladevolumen um 56% (im Vergleich zur letzten Modellreihe E2400HD). Wir helfen, die Wälder zu schützen und CO2-Emissionen zu reduzieren!
     
    Wasserressourcen schützen
    Quecksilber-freie LED-Panels reduzieren die Umweltverschmutzung auf der Erde. Da im Produktionsprozess kein Quecksilber verwendet wird und beim Recycling der Altgeräte kein Quecksilber entsorgt werden muss, halten sie die Wasserressourcen frei von giftigen Schadstoffen.
     
    Abfallbelastung reduzieren
    BenQ LED Monitore sind nicht beschichtet und zu 100% recycelbar. Um die Ressourcen zu schonen, besteht der Displayrahmen zu 28% aus recycelten Plastikmaterialien. Für das Bedrucken des Verpackungsmaterials verwendet BenQ Tinte aus einem natürlichen Rohstoff: der Sojabohne. Damit lässt sich der Tintenverbrauch um 70% reduzieren.
     
    ";2;False;0;;;BenQ G2420HDBL 61 cm 24 Zoll TFT Monitor schwarz;benq-g2420hdbl-61-cm-24-zoll-tft-monitor-schwarz;True;True;P-2510;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;2,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;149.0000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;40187,661724537;"10;2095";;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000443-benq-g2420hdbl-61-cm-24-zoll-tft-monitor-schwarz.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000444-benq-g2420hdbl-61-cm-24-zoll-tft-monitor-schwarz.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000445-benq-g2420hdbl-61-cm-24-zoll-tft-monitor-schwarz.jpg;2;;False;;;;;False;False;False;;;;;False;;;;;; -5;0;True;Benq E2220HD 21,5 Zoll TFT Monitor schwarz;Benq E2220HD 21,5 Zoll TFT Monitor schwarz glänzend;"
    1080p Full HD (1920x1080 High-Definition)
    Im Gegensatz zu konventionellen LCD-Monitoren bieten Full-HD-Displays ein breitformatiges Vollbild mit 1080p-Auflösung nach dem HD-Standard (High-Definition). So kann z. B. mit Blu-ray-Playern, Multimedia-PCs, Notebooks oder Spielekonsolen der neuesten Generation das volle Bild digital ohne Kompromisse in brillantester Bildqualität dargestellt werden. Mit dem 16:9-Wide-Format, das perfekt für die Darstellung von Full-HD-Filmen ist, wird zudem bis zu 30 % mehr Bildfläche dargestellt als beim 4:3-Format.
     
    HDMI (High-Definition Multimedia Interface)
    Der HDMI-Anschluss ist eine digitale Schnittstelle, die für den Videobereich entwickelt wurde und neben dem Bild auch den Ton überträgt. HDMI ermöglicht nicht nur Datentransfers von 5 GB/s, sondern verhindert auch Wandlungsverluste und sorgt so für eine ausgezeichnete Bildqualität. Die HDMI-Schnittstelle ist der neue Standard für die digitale Signalübertragung, unter anderem für DVD-Player oder Spielkonsolen. Ab dem Standard HDMI 1.3 sind Übertragungsraten von bis zu 10 GB/s (je nach Kabelqualität und -länge) möglich. Dadurch werden die großen Datenströme ohne Kompressionen und damit ohne Bildstörungen übertragen. Dies ist für die Abbildung von Full-HD (1080p) wichtig, um einen ruckelfreien Bildfluss zu gewährleisten. Das BenQ E2220HD Display verfügt über 2 HDMI 1.3-Schnittstellen.
     
    Vier USB-Schnittstellen
    Das E2220HD verfügt über gleich vier USB-Schnittstellen, so dass Sie gleichzeitig Ihre Tastatur, die Maus, ein Handy und z.B. Game-Controller anschließen können!
     
    Dynamischer Kontrast von 50.000:1
    Mit einem dynamischen Kontrast von 50.000:1 werden Ihre Bilder lebendiger! Sie erhalten fantastische Bilddetails sowie ein klares Bild auch bei dunklen, komplexen und bewegten Bildern. Um die Funktion zu steuern, schalten Sie einfach den Q-Pilot ein.
     
    Stereo-Lautsprecher
    Das E2220HD verfügt über 2 1,5 Watt Stereo-Lautsprecher, die Ihnen ein perfektes Klangerlebnis liefern.
    ";2;False;0;;;Benq E2220HD 21,5 Zoll TFT Monitor schwarz;benq-e2220hd-215-zoll-tft-monitor-schwarz;True;True;P-2500;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;2,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;199.0000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;40187,6466435185;10;;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000438-benq-e2220hd-215-zoll-tft-monitor-schwarz.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000439-benq-e2220hd-215-zoll-tft-monitor-schwarz.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000440-benq-e2220hd-215-zoll-tft-monitor-schwarz.jpg;1;;False;;;;;False;False;False;;;;;False;;;;;; -5;0;True;Apple iPod Touch 32 GB schwarz;Apple iPod Touch 32 GB schwarz;"
    Apple iPod Touch 32 GB schwarz
     
    mit integrierter WiFi Funktion
     
    Ein großartiger iPod. Ein großartiger Taschencomputer. Großartiger mobiler Spielspaß. Und das Ganze in einem unglaublich schlanken, eleganten neuen Design aus Edelstahl. Filme, Videos und Fernsehsendungen auf einem 3,5"" Display ansehen!
     
    Im Web surfen, mailen!
    Multitouch-Oberfläche: Die revolutionäre Technologie des iPhone und die Software Version 3.1 stecken in diesem genialen iPod. Das brillante Breitformat-Display rückt Ihre Videos und Spiele ins beste Licht
     
    Surfen Sie mit Safari im Web und sehen Sie YouTube Videos auf dem iPod mit integrierter Wi-Fi Funktionalität an.
    Mit Ihrem iPod touch können Sie im iTunes Wi-Fi Music Store nach Songs suchen, Hörproben abspielen und Titel kaufen.  Lieferumfang: iPod touch, Ohrhörer, USB 2.0 Kabel, Dock-Adapter, Kurzanleitung
     
    Der iPod touch kann alles, was du am iPod toll findest. Und noch vielmehr.
    Du kannst Filme, Videos und Fernsehsendungen auf einem 3,5"" Display ansehen. Mit der revolutionären Multi-Touch-Technologie kannst du dein Musikarchiv mit Cover Flow durchblättern. Und wenn dir nach mehr ist, tipp einfach auf iTunes, um durch das Angebot zu stöbern und sofort einzukaufen. Hör dir Wiedergabelisten an, die automatisch für dich erstellt werden. Schau Filme auf dem brillanten 3,5"" Display. Und kauf mit einem Fingertipp bei iTunes ein - wann immer du willst. All das und noch viel mehr mit dem iPod touch, den es schon ab 189 € gibt. Wi-Fi ist schon integriert. So kannst du im Web surfen, mailen, deinen Facebook Status aktualisieren, mit AIM chatten und noch viel mehr - und das alles auf einem Gerät, das locker in jede Tasche passt. Hier hast du die Finger im Spiel. Und nicht nur die. Denn mit den Spielen auf dem iPod touch tauchst du richtig in die Action ein - einfach neigen, tippen, drehen. Und via Wi-Fi kannst du jederzeit im App Store neue Spiele kaufen. Die iPhone 3.1 Software ist auf dem iPod touch bereits installiert, sodass der Spaß gleich beginnen kann. Damit kannst du nützliche Funktionen wie Peer-to-Peer-Spiele und Cut, Copy & Paste direkt nach dem Auspacken nutzen.
    Next Level Fun: Der neue iPod touch
     
    Musik
    Stöber durch deine Alben. Hör dir einen einzigartigen Mix an, der nur für dich erstellt wurde. Oder schau das Video deines Lieblingssongs an. Mit dem iPod touch kannst du mehr als nur Musik hören.
     
    Cover Flow
    Auf dem iPod touch gibt's Musik nicht nur auf die Ohren. Mit Cover Flow ist Musik auch etwas für Augen und Finger. Dreh den iPod touch einfach auf die Seite und blätter durch deine Albumcover. Tipp auf ein Albumcover, um es umzudrehen und die Songliste zu sehen. Tipp noch einmal und Musik ab.
     
    Genius Mixe
    Die Genius Funktion wurde weiter verbessert. Jetzt gibt es Genius Mixe. Du brauchst den iPod touch nur mit iTunes zu synchronisieren. Genius durchsucht dann automatisch deine Mediathek nach Songs, die gut zusammenpassen und erstellt bis zu zwölf Mixe.
    Diese Mixe sind wie Radiosender, auf denen nur deine Musik läuft.
     
    Genius Wiedergabelisten
    Angenommen du hörst einen Song auf deinem iPod touch, der dir gut gefällt, und du möchtest weitere Titel hören, die dazu passen. Genius findet weitere Songs auf deinem iPod touch und erstellt eine Genius Wiedergabeliste für dich. Hör dir die Wiedergabeliste sofort an, speichere sie für später oder versuch's noch einmal und sieh, was dabei herauskommt. Verlass dich auf Genius, wenn du einen Mix willst, auf den du selbst nie gekommen wärst.
     
    Shake to Shuffle
    Die Dinge mal aufrütteln. Musikalisch natürlich. Wenn du das nächste Mal Musik hörst, aktiviere die Schüttelfunktion und wenn du den iPod touch dann kurz schüttelst, springt er nach dem Zufallsprinzip zu einem anderen Song aus deiner Sammlung.
     
    iTunes
    Pack Musik und Videos aus der iTunes Mediathek deines Computers auf den iPod touch. Oder kauf und lade neue Songs auf den iPod touch, wenn du über Wi-Fi auf iTunes zugreifst. Wenn du den iPod touch das nächste Mal mit dem Computer verbindest, werden alle Songs, die du auf dem iPod touch gekauft hast, auf den Mac oder PC übertragen.
     
    Bluetooth
    Schau mal, keine Kabel. Der iPod touch enthält die iPhone 3.1 Software, sodass du Bluetooth Stereokopfhörer anschließen kannst. Lass den iPod in deiner Tasche stecken oder auf dem Schreibtisch aufladen, während du weiter Musik hörst.
     
    Filme und Fernsehsendungen
    Ein Kinohit. Ein Video-Podcast. Deine Lieblingsserie. Jetzt laufen sie auch in einer U-Bahn oder einem Flugzeug in deiner Nähe.
    Widescreen-Display
    Du kannst Videos für viele Stunden überallhin mitnehmen und auf dem gestochen scharfen 3,5"" Widescreen-Farbdisplay ansehen. Kauf im iTunes Store und wähle unter tausenden vonFilmen, Fernsehsendungen und Video-Podcasts, die du auf den iPod touch laden kannst. Von Hollywood-Hits bis zu Indie-Streifen - es gibt etwas für jeden Geschmack. Mit wenigen Fingertipps kannst du Filme kaufen und laden. Du magst lieber Fernsehsendungen? Lade eine einzelne Folge oder die gesamte Staffel.
     
    On-Screen Steuerung
    Auch während du Video guckst, kannst du die Steuerung einblenden - ein Fingertipp auf das Display genügt. Du kannst die Wiedergabe starten oder unterbrechen, einzelne Kapitel anzeigen und die Lautstärke anpassen. Natürlich kannst du auch die Lautstärkeregler links am iPod touch verwenden. Du willst zwischen Widescreen und bildschirmfüllender Anzeige wechseln? Einfach aufs Display doppeltippen.
     
    iTunes
    Du brauchst Unterhaltung für deinen nächsten Flug oder die Autofahrt? Mit iTunes auf dem iPod touch und einer Wi-Fi-Verbindung kannst du auch unterwegsFilme und Fernsehsendungen kaufen. Du kannst Filme auch leihen, wenn du dir nicht sicher bist, ob du den Film behalten willst. Und natürlich kannst du Filme und Fernsehsendungen auf dem Mac oder PC kaufen und dann mit dem iPod touch synchronisieren.
     
    App Store
    Kaufe im App Store und entdecke über 65.000 Apps, mit denen du noch mehr auf dem iPod touch machen kannst. Stöbere in tausenden von Apps in verschiedenen Kategorien. Von Spielen über Lifestyle und Soziale Netzwerke bis zu Unterhaltung und mehr.
     
    Apps durchstöbern
    Du kannst auf verschiedene Arten im App Store shoppen. Tipp auf ""Neu"" und ""Topaktuell"", um eine Liste der aktuellen und angesagten Apps zu erhalten. Stöbere nach Kategorien. Schau dir die topaktuellen Apps an. Wenn du genau weißt, wonach du suchst, kannst du auch eine Schnellsuche durchführen.
     
    Genius Empfehlungen für Apps
    Es gibt tausende von Apps im App Store, und jeden Tag kommen mehr dazu. Mit dieser neuen Funktion des iPod touch findest du coole neue Apps noch einfacher. Genius für Apps. Funktioniert genau wie Genius für deine Musik. Tipp auf das Genius Symbol und du bekommst Empfehlungen für Apps anhand der Apps, die du und andere schon geladen haben.
     
    Apps laden
    Wenn du eine App findest, die dich interessiert, kannst du sie überall, wo eine Wi-Fi-Verbindung besteht, drahtlos kaufen, auf den iPod laden und dann sofort loslegen.
     
    Updates für Apps
    iPod touch sagt dir, wenn ein App Update verfügbar ist, damit du immer die neuesten Versionen deiner Lieblings-Apps hast.
     
    iTunes
    Entdecke und lade neue Musik, Filme, Fernsehsendungen, Podcasts und Hörbücher in iTunes auf dem iPod touch.
     
    Einkaufen, immer und überall
    Greif über die im iPod touch integrierte Wi-Fi-Funktion auf den iTunes Store zu. Durchsuche Millionen von iTunes Plus Songs in brillanter Audioqualitätund tausende von Filmen, Fernsehsendungen, Hörbüchern und kostenlosen Podcasts und Vorlesungen von iTunes U. Stöbere nach Neuerscheinungen, Top-Titeln und Genres. Oder finde mit der Schnellsuche genau das, wonach du suchst. Hör in einen Song oder sieh dir eine Videovorschau an. Wenn du dann etwas kaufen möchtest, brauchst du nur darauf zu tippen. Nicht sicher, ob es sich lohnt, den Film zu kaufen? Dann leih ihn einfach. Alles was du auf dem iPod touch kaufst, hat denselben Preis wie im iTunes Store auf deinem Computer.
     
    Synchronisieren mit iTunes
    Sobald du den iPod touch mit dem Computer verbindest, werden die Songs, Filme, Fernsehsendungen, Hörbücher und Podcasts, die du unterwegs geladen hast, mit deiner iTunes Mediathek auf deinem Mac oder PC synchronisiert. Wenn du etwas nur teilweise auf den iPod touch geladen hast, beendet der Computer den Download automatisch für dich.
     
    Sprachsteuerung
    Mit der Sprachsteuerung beim neuen 32 GB und 64 GB iPod touch kannst du deine Musik mit Sprachbefehlen steuern. Und der iPod hört aufs Wort. Auf ""Spiel"", ""Shuffle"" oder ""Wie heißt das Lied?"".
     
    Sagen und abspielen.
    Die Sprachsteuerung kennt die Musik auf deinem iPod touch. Wenn du etwas Bestimmtes hören willst, sag es einfach. Zum Beispiel ""Spiel Bob Dylan"" und der iPod touch hört aufs Wort. Frag ihn, welcher Song grad läuft, und der iPod touch sagt es dir. Sag ihm, dass er dein Lieblingsalbum, deinen Lieblingssänger oder deine Lieblingswiedergabeliste spielen soll. Verwende einfache Befehle wie ""shuffle"", ""nächster Song"" und ""anhalten"". Du kannst dem iPod touch sogar sagen, dass er mehr Songs wie den, der gerade läuft, abspielen soll.
     
    Sprich ins Mikro
    Der neue 32 GB und 64 GB iPod touch wird mit den Apple Earphones mit Fernbedienung und Mikro geliefert. So kannst du die Sprachsteuerung auch dann nutzen, wenn der iPod touch in der Tasche steckt. Zum Aktivieren der Sprachsteuerung über die Kopfhörer hältst du einfach die Mitteltaste der Fernbedienung gedrückt.
     
    Die Sprachsteuerung unterstützt die folgenden Sprachen:
    Chinesisch (China), Chinesisch (Kantonesisch), Chinesisch (Taiwan), Deutsch, Englisch (Großbritannien), Englisch (USA), Finnisch, Französisch (Frankreich), Französisch (Kanada), Italienisch, Japanisch, Koreanisch, Niederländisch, Norwegisch, Polnisch, Portugiesisch (Brasilien), Portugiesisch (Portugal), Russisch, Schwedisch, Spanisch (Mexiko), Spanisch (Spanien)
     
    Fotos
    Der iPod touch hat für bis zu 90.000 deiner Lieblingsfotos Platz. Durch Streichen kannst du sie durchschauen und all die Erinnerst-du-dich-noch-Momente mit anderen teilen.
     
    Fotos sichern
    Wenn dir tolle Bilder gemailt werden, kannst du sie einfach im Fotoarchiv auf dem iPod touch sichern und dann wie jedes andere Foto nutzen. Du kannst sie zum Beispiel als Hintergrundbilder verwenden, im Internet teilen oder weitergeben.
     
    Fotos teilen
    Du hast tausende Fotos immer zur Hand. Blätter durch Streichen auf dem Display durch Miniaturen. Mit einem Fingertipp siehst du Fotos bildschirmfüllend. Spiel Diashows mit Musik und Übergängen ab. Maile Fotos an Freunde oder teile sie in einer MobileMe Galerie.
     
    Fotos synchronisieren
    Fotos aus iPhoto auf einem Mac oder Adobe Photoshop Elements und Adobe Photoshop Album auf einem PC werden via iTunes mit dem iPod touch synchronisiert. Einfach nur die Fotos und Alben aussuchen, die mit dem iPod touch synchronisiert werden sollen. Dann kannst du sie überall ansehen und mit anderen teilen.
     
    Homescreen
    Angenommen du möchtest ""Karten"" als erste App in der zweiten Zeile haben. Oder Mail unten im Dock. Mit den anpassbaren Homescreens kannst du den iPod touch zu deinem iPod touch machen.
     
    Individuelles Anpassen
    Ordne die Symbole auf deinem Homescreen an wie du willst - direkt auf dem iPod touch oder auf deinem Computer in iTunes 9. Bewege eine App eine Zeile nach oben, zwei Apps nach rechts oder auf einen anderen Homescreen. Du kannst bis zu 11 Homescreens erstellen und hast so schnellen Zugriff auf Spiele und Apps, die du aus dem App Store lädst, und auf deine Safari Weblinks.
     
    Hometaste
    Was auch immer du gerade mit deinem iPod touch machst – die Hometaste bringt dich immer zurück zum ersten Homescreen. Wenn du auf die Hometaste drückst, kannst du von jedem Homescreen wieder zurück zum ersten springen.
     
    Apps und Weblinks hinzufügen
    Für jede App, die du aus dem App Store lädst, erscheint ein neues Symbol auf dem Homescreen. Von häufig besuchten Websites kannst du praktische Weblinks erstellen. Sie erscheinen auf dem Homescreen und du kannst per Fingertipp darauf zugreifen.
     
    Spotlight Suche
    Du suchst was? Von einem Ort aus kannst du die gesamten Inhalte des iPod touch durchsuchen. Streich auf dem ersten Homescreen einfach nach rechts, um Spotlight zu öffnen. Sobald du anfängst zu tippen, durchsucht Spotlight deine gesamten Songs, Videos, Kontakte, Mails, Kalender, Notizen und sogar deine Hörbücher und Podcasts.
     
    Safari
    Safari, der fortschrittlichste Webbrowser auf einem Mobilgerät, ist auch auf dem iPod touch integriert. Damit erlebst du das Internet in deiner Hand genauso wie auf dem Computer zuhause. Alles was du brauchst ist eine Wi-Fi-Verbindung.
     
    Überall ins Internet
    Der iPod touch ist der einzige iPod mit integriertem drahtlosen Internetzugriff. Bei bestehender Wi-Fi-Verbindung kannst du im Internet surfen und Nachrichten lesen, Sportergebnisse sehen, Rechnungen bezahlen und online einkaufen. Und beim 32 GB oder 64 GB iPod touch wirst du sehen, dass Webseiten jetzt noch schneller als vorher geladen werden.
     
    Im Web stöbern
    Der iPod touch synchronisiert deine Lesezeichen vom PC oder Mac, sodass du ruckzuck auf deine Lieblingsseiten zugreifen kannst. Außerdem ist die Google- und Yahoo!-Suche schon integriert, sodass du im Web schnell findest, was du suchst.
     
    Weblinks
    Wenn du eine Website öfter besuchst - etwa die einer Zeitung, eines Blogs oder eine Sport-Website - kannst du einfach ein Symbol, einen sogenannten Weblink, auf dem Homescreen erstellen. Wenn du mit Safari Weblinks erstellst, sind deine Lieblingsseiten nur einen Fingertipp entfernt.
     
    Zoom
    Wenn du eine Website öfter besuchst, brauchst du nur mit dem Finger auf das Multi-Touch-Display zu tippen oder die Anzeige aufzuziehen. Websites lassen sich im Hoch- oder Querformat anzeigen. Einfach den iPod touch um 90 Grad drehen, und schon wird auch die Darstellung der Webseite gedreht.
     
    Mail
    Mails auf dem iPod touch funktionieren genau wie auf deinem Computer und sehen auch genau so aus. Und sie funktionieren mit deinen vorhandenen Accounts.
     
    Nachrichten und Anhänge ansehen
    Der iPod touch unterstützt Rich-HTML-E-Mail, sodass Bilder und Fotos zusammen mit dem Text einer E-Mail angezeigt werden. Anhänge siehst du in ihrem Originalformat und nicht als abgespeckte Version. Du kannst in mehr als einem Dutzend standardmäßigen Datei- und Bildformaten drehen, zoomen und schwenken, darunter PDF, Microsoft Word, Excel, PowerPoint und iWork.
     
    Zugriff auf alle Accounts
    Mails von gängigen Anbietern wie MobileMe, Google Mail, Microsoft Exchange, Yahoo! und den meisten standardmäßigen IMAP- und POP-Systemen kannst du mit dem iPod touch ganz einfach abrufen.
     
    Schnellere Eingabe
    Der iPod touch erkennt E-Mail-Adressen in verschiedenen Programmen. Wenn du auf einer Webseite oder in einer Karte eine E-Mail-Adresse siehst, reicht ein Fingertipp auf dem iPod touch, um eine neue Mail zu öffnen, in der die Adresse bereits eingetragen ist.
     
    Intelligente Eingabe
    Die innovative iPod touch Tastatur mit integriertem Wörterbuch* schlägt während der Eingabe Wörter vor. So kannst du ganz schnell und einfach Mails schreiben. Dreh den iPod touch einfach. Dann wird die Tastatur vom Hochformat ins Querformat gedreht und du hast größere Tasten und mehr Platz zum Tippen.
     
    Postfach durchsuchen
    Du musst das Postfach jetzt nicht mehr Mail für Mail durchsuchen. Durch schnelles Abwärtsstreichen wird jetzt ein Suchfeld geöffnet, mit dem du deine Mails nach Absender, Empfänger, Betreff oder Titelzeilen durchsuchen kannst.
     
    Karten
    Finde deinen Weg und die nächste Pizzeria. Mit Karten und einer Wi-Fi-Verbindung kannst du Wegbeschreibungen abrufen, Firmen finden und Verkehrsinformationen prüfen.
     
    Finde dich selbst
    Der iPod touch zeigt dir mithilfe von bekannten Wi-Fi-Hot-Spots, wo du bist. Mit der Stichwortsuche kannst du auch interessante Orte finden. Wenn du z. B. ""Kaffee"" eingibst, werden dir alle Cafés in der Nähe angezeigt.
     
    Wo geht's lang?
    Gib einfach eine Adresse ein, um Wegbeschreibungen abzurufen - von jedem Ort aus. Wähle das Transportmittel wie Auto, öffentliches Verkehrsmittel oder zu Fuß. Die Route lässt sich dann Schritt für Schritt anzeigen. Du kannst dem markierten Weg auf der Karte folgen und selbst die Fahrtdauer wird angezeigt. Oder markiere zwei Orte und lass dir die beste Route zwischen diesen anzeigen.
     
    Verschiedene Kartendarstellungen
    Wie bei Google Karten auf deinem Computer kannst du mit dem Programm ""Karten"" auf dem iPod touch zwischen unterschiedlichen Darstellungen von Google-Karten, Satellitenbildern und einer Hybriddarstellung wechseln. Und mit Multi-Touch kannst du unterwegs zoomen, den Ausschnitt bewegen und die Darstellung ändern.
     
    Verkehrsinformationen
    Die Verkehrsinformationen geben dir anhand der grünen, roten und gelben Markierungen einen Überblick über die Verkehrssituation auf deiner Route.
     
    YouTube
    Skateboard Moves, die so nicht geplant waren. Witzige Werbespots aus anderen Ländern. Was auch immer du gern auf YouTube ansiehst - der iPod touch ist für dich da.
     
    Videogrüße von unterwegs.
    Maile Links deiner Lieblingsvideos an Freunde. Tippe auf der Detailseite des YouTube Videos auf ""Senden"", und schon erstellt der iPod touch eine Mail mit dem zugehörigen Videolink.
     
    Auf YouTube suchen.
    Stöber in Videokategorien wie ""Highlights"", ""Topvideos"", ""Neue Videos"" oder ""Bestwertung"". Du kannst auch per Schlagwort nach einem Video suchen. Etwas Passendes gefunden? Mit einem Lesezeichen kannst du das Video auch vormerken und später ansehen.
     
    Nike + iPod Kompatibilität
    Rock dein Training. Der iPod touch hat eine integrierte Unterstützung für Nike + iPod. Das ist Musik und Motivation in einem.
    Finetuning für dein Lauftraining.
     
    Nike + iPod Sensor
    Der iPod touch hat eine integrierte Unterstützung für Nike + iPod. Einfach den Nike + iPod Sensor (separat erhältlich) in die Nike+ Schuhe stecken und los geht's. Der Sensor überträgt deine Laufdaten drahtlos an den iPod touch und zeichnet Laufzeit, Laufstrecke und Kalorienverbrauch auf. Du erhältst sogar Feedback zum Trainingsfortschritt.
     
    Finetuning für dein Cardio Workout
    Diese Funktion kann auch zusammen mit neuen, in vielen Fitnessstudios vorhandenen Geräten für das Ausdauertraining gekoppelt werden. Such dir einfach ein mit Nike + iPod kompatibles Fitnessgerät wie beispielsweise Laufbänder, Ellipsentrainer, Stepper und Hometrainer.
     
    Synchronisieren mit nikeplus.com
    Später kannst du am Computer den iPod touch via iTunes synchronisieren und deine Trainingsdaten an nikeplus.com übertragen. Auf dieser Website kannst du dein Training verfolgen, dir Ziele setzen und deine Freunde herausfordern.
     
    Sprachmemos
    Du hast vielleicht ein ganz gutes Gedächtnis, aber manchmal ist es besser, kleine (und große) Infos einfach irgendwo festzuhalten. Mit ""Sprachmemos"" kein Problem.
     
    Memos (oder alles andere)aufnehmen
    Nimm eine Aufgabenliste, geniale Ideen oder eine Wette zwischen dir und deinem Freund auf. Mit dem Programm ""Sprachmemos"" kannst du über die Apple Earphones mit Fernbedienung und Mikro oder ein externes Mikrofon aufnehmen, was immer du willst. Sprachmemos kannst du selbst dann aufnehmen, wenn du den iPod touch gerade verwendest, um Mails zu checken oder im Web zu surfen.
     
    Memos bearbeiten
    Aufgenommene Memos kannst du direkt auf dem iPod touch trimmen. So behältst du nur das, was du wirklich brauchst.
     
    Memos sortieren
    Ordne deine Memos mithilfe von Etiketten aus einer vordefinierten Liste oder erstelle eigene Etiketten.
     
    Memos teilen
    Maile Memos an Freunde und Kollegen. Mit dem iPod touch aufgenommene Memos werden via iTunes mit deinem Mac oder PC synchronisiert, damit du sie später mit anderen teilen kannst.
     
    Weitere Funktionen
    Auf dem iPod touch ist die neueste Software schon installiert. Und außerdem gibt's praktische Apps wie Kontakte, Kalender, Notizen, Aktien und Wetter.
     
    iPod touch 3.1 Softwarefunktionen.
     
    Genius Mixe
    Diese neue Funktion ist wie ein privater DJ, der deine iTunes Mediathek durchsucht, um Songs zu finden, die gut zusammenpassen und aus diesen dann tolle Mixe erstellt. Alles ganz automatisch.
     
    Genius Empfehlungen für Apps
    Im App Store gibt's zehntausende Apps. Wie soll man da die richtig collen neuen finden? Mit Genius. Denn Genius sieht sich die Apps an, die du schon hast, und empfiehlt dir weitere.
     
    Peer-to-Peer-Spiele
    Die neusten Spiele kannst du ganz leicht mit Freunden spielen - egal, ob sie neben dir oder in einer anderen Ecke des Landes sitzen.
     
    Kauf Filme, Fernsehsendungen und Hörbücher via Wi-Fi
    Lade via Wi-Fi Filme, Fernsehsendungen, Musikvideos und Hörbücher aus dem iTunes Store auf deinen iPod touch.
     
    Tastatur im Querformat
    Du brauchst mehr Platz zum Tippen? Dreh den iPod touch ins Querformat, um in Mail, Notizen und Safari mit einer größeren Tastatur zu arbeiten.
     
    Cut, Copy & Paste
    Einfach Text und Fotos ausschneiden, kopieren und wieder einsetzen - selbst zwischen Programmen. Du kannst auch Inhalte aus dem Web kopieren.
     
    Spotlight Suche
    Gesucht, gefunden - von einem Ort aus. Spotlight durchsucht alle deine Kontakte, E-Mails, Kalender und Notizen und auch alle Songs und Videos.
     
    Stereo Bluetooth
    Hör Musik und andere Audioinhalte drahtlos. Verbinde den iPod touch mit kompatiblen Bluetooth Stereokopfhörern.
     
    Automatischer Wi-Fi-Login
    Wenn du dich einmal bei einem Wi-Fi-Hotspot anmeldest, loggt der iPod touch sich beim nächsten Mal automatisch ein.
     
    Shake to Shuffle
    Schüttel den iPod kurz, und schon springt er nach dem Zufallsprinzip zu einem anderen Song in deiner Sammlung. Lass dich einfach überraschen.
     
    Bedienungshilfen
    Der neue iPod touch hat standardmäßig Bedienungshilfen integriert, mit denen auch Menschen mit Beeinträchtigungen alles, was der iPod touch zu bieten hat, erleben können. Alle Bedienungshilfen des iPod touch ansehen
     
    Kindersicherung
    Du entscheidest, welche Musik, Videos und Apps auf dem iPod touch für deine Kinder geeignet sind.
    Der iPod touch hat auch die folgenden praktischen Apps:
     
    Kalender
    Das Programm ""Kalender"" funktioniert mit Yahoo!, Google, Microsoft Outlook, iCal, MobileMe und Microsoft Exchange ActiveSync für Unternehmen. Füge Termine hinzu, lass dich an Termine erinnern, und abonniere Kalender, damit du über Feiertage und Sportveranstaltungen auf dem Laufenden bleibst.
     
    Kontakte
    Namen, E-Mail-Adressen, Telefonnummern und mehr - immer zur Hand. Synchronisier Kontakte in iTunes auf dem Mac oder PC mit dem iPod touch. Neue Kontakte kannst du auch unterwegs mit einem einfachen Fingertipp hinzufügen.
     
    Notizen
    Schluss mit Papier und Bleistift. Mach dir mit ""Notizen"" auf dem iPod schnell eine Notiz, damit du wichtige Infos immer parat hast. Maile deine Gedanken mit der integrierten Mail-Funktion an dich oder andere.
     
    Aktien
    Die Aktien App auf dem iPod touch zeigt dir Börseninformationen für die Aktien, die dich interessieren. Wenn du nähere Details über eine Aktie brauchst, tipp auf ""Y!"", um im Handumdrehen Yahoo! Finance zu öffnen.
     
    Wetter
    Informier dich über das Wetter in der ganzen Welt oder zuhause. Füge die gewünschten Städte hinzu und zeige eine sechstägige Vorhersage für alle an. Tipp auf ""Y!"", um den Yahoo! Stadtführer zu öffnen, der dir zeigt, wo was los ist.
     
    Rechner
    Im Programm ""Rechner"" des iPod touch stecken gleich zwei Rechner. Im Hochformat kannst du ihn als einfachen Taschenrechner verwenden. Dreh den iPod touch ins Querformat, um aus ihm einen wissenschaftlichen Rechner zu machen.
     
    iPod touch Technologie
    Dank der revolutionären Hardwaretechnologie im iPod touch kannst du alle Funktionen mit Streichen, Tippen und Auf- oder Zuziehen steuern. Deswegen wirkt das Autorennen so echt. Deswegen kannst du das, was du eben im Café mitbekommen hast, sofort twittern. Und genau deswegen ist der iPod touch der beste iPod aller Zeiten.
     
    Multi-Touch
    Das Multi-Touch-Display besitzt einen Schutzfilm über der kapazitiven Sensorik, die Berührungen anhand elektrischer Felder erkennt. Diese Informationen werden an das darunterliegende LCD-Display übertragen. Dank der Software des iPod touch kannst du mit Cover Flow durch Alben stöbern, durch deine Fotos blättern, mit Auf- und Zuziehen Bildausschnitte von Websites zoomen und Spiele superpräzise steuern.
     
    Beschleunigungssensor
    Der iPod touch reagiert über einen integrierten Beschleunigungssensor auf Bewegungen. Dieser Sensor erkennt, wenn du deinen iPod touch ins Querformat drehst und verändert automatisch den Inhalt des Displays. Die Technologie des Beschleunigungssensors kommt besonders bei Spielen gut, denn damit bist du mitten im Spielgeschehen. Das ist perfekt für Autorennen, bei denen der ganze iPod zum Lenkrad wird, und Geschicklichkeitsspiele wie Rolando, bei denen du das Spiel mit deinen Bewegungen steuerst
     
    Drahtlos
    Der iPod touch hat eine integrierte Unterstützung für drahtlosen 802.11b/g Internetzugriff. Überall, wo es ein Wi-Fi-Netzwerk gibt, kommst du mit deinem iPod touch ins Internet. Im Café mailen. Am Flughafen im Web surfen. Spiele vom Sofa aus kaufen. Im iTunes Store stöbern und Musik kaufen und laden. Der iPod touch findet nahegelegene Wi-Fi-Hot-Spots, auch geschützte Netzwerke. Wenn du ein bestimmtes Netzwerk bisher noch nicht verwendet hast, Drahtlos Symbol musst du beim ersten Mal ein Kennwort eingeben, das sich der iPod touch dann merkt. Wenn du dann das nächste Mal in Reichweite dieses Netzwerks bist, loggt er sich automatisch ein.
     
    Bluetooth
    Bluetooth ist eine drahtlose Technologie, mit der du Geräte ohne lästige Kabel verwenden kannst. Was bedeutet das für den iPod touch? Du kannst jetzt mit dem iPod touch und Bluetooth Kopfhörern Musik hören, ganz egal, wo im Raum der iPod ist. Du kannst also auf dem Bett relaxen, während der iPod auf dem Schreibtisch aufgeladen wird. Bluetooth auf dem iPod touch eignet sich auch besonders für Peer-to-Peer-Spiele.
     
    Design
    Der iPod touch ist von außen genau so großartig wie von innen. Du brauchst nur einen in die Hand zu nehmen. Das Gehäuse des iPod touch ist gerade einmal 8,5 mm hoch. Das optische Glas auf der Vorderseite und die Rückseite aus poliertem Edelstahl geben ihm einen eleganten Touch und fühlen sich in der Hand einfach gut an. Schalte ihn ein und du wirst über das brillante 3,5"" Display einfach staunen. Der iPod touch ist die perfekte Kombination aus großartigem Design und revolutionärer Technologie - das perfekte Paket.
    ";2;False;0;;;Apple iPod Touch schwarz mit integrierter WiFi Funktion;apple-ipod-touch-32-gb-schwarz-2;True;True;P-1290;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;269.9000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;40186,8623263889;44;1;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000434-apple-ipod-touch-64-gb-schwarz.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000435-apple-ipod-touch-64-gb-schwarz.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000436-apple-ipod-touch-64-gb-schwarz.jpg;2;;False;;;;;False;False;False;;;;;False;;;;;; -5;0;True;Apple iPod Touch 64 GB schwarz;Apple iPod Touch 64 GB schwarz;"
    Apple iPod Touch 64 GB schwarz
    mit integrierter WiFi Funktion


    Ein großartiger iPod. Ein großartiger Taschencomputer. Großartiger mobiler Spielspaß. Und das Ganze in einem unglaublich schlanken, eleganten neuen Design aus Edelstahl. Filme, Videos und Fernsehsendungen auf einem 3,5"" Display ansehen!
    Im Web surfen, mailen!
    Multitouch-Oberfläche: Die revolutionäre Technologie des iPhone und die Software Version 3.1 stecken in diesem genialen iPod. Das brillante Breitformat-Display rückt Ihre Videos und Spiele ins beste Licht
    Surfen Sie mit Safari im Web und sehen Sie YouTube Videos auf dem iPod mit integrierter Wi-Fi Funktionalität an.
    Mit Ihrem iPod touch können Sie im iTunes Wi-Fi Music Store nach Songs suchen, Hörproben abspielen und Titel kaufen. Lieferumfang: iPod touch, Ohrhörer, USB 2.0 Kabel, Dock-Adapter, Kurzanleitung
     
    Der iPod touch kann alles, was du am iPod toll findest. Und noch vielmehr.
    Du kannst Filme, Videos und Fernsehsendungen auf einem 3,5"" Display ansehen. Mit der revolutionären Multi-Touch-Technologie kannst du dein Musikarchiv mit Cover Flow durchblättern. Und wenn dir nach mehr ist, tipp einfach auf iTunes, um durch das Angebot zu stöbern und sofort einzukaufen. Hör dir Wiedergabelisten an, die automatisch für dich erstellt werden. Schau Filme auf dem brillanten 3,5"" Display. Und kauf mit einem Fingertipp bei iTunes ein - wann immer du willst. All das und noch viel mehr mit dem iPod touch, den es schon ab 189 € gibt. Wi-Fi ist schon integriert. So kannst du im Web surfen, mailen, deinen Facebook Status aktualisieren, mit AIM chatten und noch viel mehr - und das alles auf einem Gerät, das locker in jede Tasche passt. Hier hast du die Finger im Spiel. Und nicht nur die. Denn mit den Spielen auf dem iPod touch tauchst du richtig in die Action ein - einfach neigen, tippen, drehen. Und via Wi-Fi kannst du jederzeit im App Store neue Spiele kaufen. Die iPhone 3.1 Software ist auf dem iPod touch bereits installiert, sodass der Spaß gleich beginnen kann. Damit kannst du nützliche Funktionen wie Peer-to-Peer-Spiele und Cut, Copy & Paste direkt nach dem Auspacken nutzen.
    Next Level Fun: Der neue iPod touch
     
    Musik
    Stöber durch deine Alben. Hör dir einen einzigartigen Mix an, der nur für dich erstellt wurde. Oder schau das Video deines Lieblingssongs an. Mit dem iPod touch kannst du mehr als nur Musik hören.
     
    Cover Flow
    Auf dem iPod touch gibt's Musik nicht nur auf die Ohren. Mit Cover Flow ist Musik auch etwas für Augen und Finger. Dreh den iPod touch einfach auf die Seite und blätter durch deine Albumcover. Tipp auf ein Albumcover, um es umzudrehen und die Songliste zu sehen. Tipp noch einmal und Musik ab.
     
    Genius Mixe
    Die Genius Funktion wurde weiter verbessert. Jetzt gibt es Genius Mixe. Du brauchst den iPod touch nur mit iTunes zu synchronisieren. Genius durchsucht dann automatisch deine Mediathek nach Songs, die gut zusammenpassen und erstellt bis zu zwölf Mixe.
    Diese Mixe sind wie Radiosender, auf denen nur deine Musik läuft.
     
    Genius Wiedergabelisten
    Angenommen du hörst einen Song auf deinem iPod touch, der dir gut gefällt, und du möchtest weitere Titel hören, die dazu passen. Genius findet weitere Songs auf deinem iPod touch und erstellt eine Genius Wiedergabeliste für dich. Hör dir die Wiedergabeliste sofort an, speichere sie für später oder versuch's noch einmal und sieh, was dabei herauskommt. Verlass dich auf Genius, wenn du einen Mix willst, auf den du selbst nie gekommen wärst.
     
    Shake to Shuffle
    Die Dinge mal aufrütteln. Musikalisch natürlich. Wenn du das nächste Mal Musik hörst, aktiviere die Schüttelfunktion und wenn du den iPod touch dann kurz schüttelst, springt er nach dem Zufallsprinzip zu einem anderen Song aus deiner Sammlung.

    iTunes
    Pack Musik und Videos aus der iTunes Mediathek deines Computers auf den iPod touch. Oder kauf und lade neue Songs auf den iPod touch, wenn du über Wi-Fi auf iTunes zugreifst. Wenn du den iPod touch das nächste Mal mit dem Computer verbindest, werden alle Songs, die du auf dem iPod touch gekauft hast, auf den Mac oder PC übertragen.
     
    Bluetooth
    Schau mal, keine Kabel. Der iPod touch enthält die iPhone 3.1 Software, sodass du Bluetooth Stereokopfhörer anschließen kannst. Lass den iPod in deiner Tasche stecken oder auf dem Schreibtisch aufladen, während du weiter Musik hörst.
     
    Filme und Fernsehsendungen
    Ein Kinohit. Ein Video-Podcast. Deine Lieblingsserie. Jetzt laufen sie auch in einer U-Bahn oder einem Flugzeug in deiner Nähe.
     
    Widescreen-Display
    Du kannst Videos für viele Stunden überallhin mitnehmen und auf dem gestochen scharfen 3,5"" Widescreen-Farbdisplay ansehen. Kauf im iTunes Store und wähle unter tausenden vonFilmen, Fernsehsendungen und Video-Podcasts, die du auf den iPod touch laden kannst. Von Hollywood-Hits bis zu Indie-Streifen - es gibt etwas für jeden Geschmack. Mit wenigen Fingertipps kannst du Filme kaufen und laden. Du magst lieber Fernsehsendungen? Lade eine einzelne Folge oder die gesamte Staffel.
     
    On-Screen Steuerung
    Auch während du Video guckst, kannst du die Steuerung einblenden - ein Fingertipp auf das Display genügt. Du kannst die Wiedergabe starten oder unterbrechen, einzelne Kapitel anzeigen und die Lautstärke anpassen. Natürlich kannst du auch die Lautstärkeregler links am iPod touch verwenden. Du willst zwischen Widescreen und bildschirmfüllender Anzeige wechseln? Einfach aufs Display doppeltippen.
     
    iTunes
    Du brauchst Unterhaltung für deinen nächsten Flug oder die Autofahrt? Mit iTunes auf dem iPod touch und einer Wi-Fi-Verbindung kannst du auch unterwegsFilme und Fernsehsendungen kaufen. Du kannst Filme auch leihen, wenn du dir nicht sicher bist, ob du den Film behalten willst. Und natürlich kannst du Filme und Fernsehsendungen auf dem Mac oder PC kaufen und dann mit dem iPod touch synchronisieren.
     
    App Store
    Kaufe im App Store und entdecke über 65.000 Apps, mit denen du noch mehr auf dem iPod touch machen kannst. Stöbere in tausenden von Apps in verschiedenen Kategorien. Von Spielen über Lifestyle und Soziale Netzwerke bis zu Unterhaltung und mehr.
     
    Apps durchstöbern
    Du kannst auf verschiedene Arten im App Store shoppen. Tipp auf ""Neu"" und ""Topaktuell"", um eine Liste der aktuellen und angesagten Apps zu erhalten. Stöbere nach Kategorien. Schau dir die topaktuellen Apps an. Wenn du genau weißt, wonach du suchst, kannst du auch eine Schnellsuche durchführen.
     
    Genius Empfehlungen für Apps
    Es gibt tausende von Apps im App Store, und jeden Tag kommen mehr dazu. Mit dieser neuen Funktion des iPod touch findest du coole neue Apps noch einfacher. Genius für Apps. Funktioniert genau wie Genius für deine Musik. Tipp auf das Genius Symbol und du bekommst Empfehlungen für Apps anhand der Apps, die du und andere schon geladen haben.
     
    Apps laden
    Wenn du eine App findest, die dich interessiert, kannst du sie überall, wo eine Wi-Fi-Verbindung besteht, drahtlos kaufen, auf den iPod laden und dann sofort loslegen.
     
    Updates für Apps
    iPod touch sagt dir, wenn ein App Update verfügbar ist, damit du immer die neuesten Versionen deiner Lieblings-Apps hast.
     
    iTunes
    Entdecke und lade neue Musik, Filme, Fernsehsendungen, Podcasts und Hörbücher in iTunes auf dem iPod touch.
     
    Einkaufen, immer und überall
    Greif über die im iPod touch integrierte Wi-Fi-Funktion auf den iTunes Store zu. Durchsuche Millionen von iTunes Plus Songs in brillanter Audioqualitätund tausende von Filmen, Fernsehsendungen, Hörbüchern und kostenlosen Podcasts und Vorlesungen von iTunes U. Stöbere nach Neuerscheinungen, Top-Titeln und Genres. Oder finde mit der Schnellsuche genau das, wonach du suchst. Hör in einen Song oder sieh dir eine Videovorschau an. Wenn du dann etwas kaufen möchtest, brauchst du nur darauf zu tippen. Nicht sicher, ob es sich lohnt, den Film zu kaufen? Dann leih ihn einfach. Alles was du auf dem iPod touch kaufst, hat denselben Preis wie im iTunes Store auf deinem Computer.
     
    Synchronisieren mit iTunes
    Sobald du den iPod touch mit dem Computer verbindest, werden die Songs, Filme, Fernsehsendungen, Hörbücher und Podcasts, die du unterwegs geladen hast, mit deiner iTunes Mediathek auf deinem Mac oder PC synchronisiert. Wenn du etwas nur teilweise auf den iPod touch geladen hast, beendet der Computer den Download automatisch für dich.
     
    Sprachsteuerung
    Mit der Sprachsteuerung beim neuen 32 GB und 64 GB iPod touch kannst du deine Musik mit Sprachbefehlen steuern. Und der iPod hört aufs Wort. Auf ""Spiel"", ""Shuffle"" oder ""Wie heißt das Lied?"".
    Sagen und abspielen.
    Die Sprachsteuerung kennt die Musik auf deinem iPod touch. Wenn du etwas Bestimmtes hören willst, sag es einfach. Zum Beispiel ""Spiel Bob Dylan"" und der iPod touch hört aufs Wort. Frag ihn, welcher Song grad läuft, und der iPod touch sagt es dir. Sag ihm, dass er dein Lieblingsalbum, deinen Lieblingssänger oder deine Lieblingswiedergabeliste spielen soll. Verwende einfache Befehle wie ""shuffle"", ""nächster Song"" und ""anhalten"". Du kannst dem iPod touch sogar sagen, dass er mehr Songs wie den, der gerade läuft, abspielen soll.
     
    Sprich ins Mikro
    Der neue 32 GB und 64 GB iPod touch wird mit den Apple Earphones mit Fernbedienung und Mikro geliefert. So kannst du die Sprachsteuerung auch dann nutzen, wenn der iPod touch in der Tasche steckt. Zum Aktivieren der Sprachsteuerung über die Kopfhörer hältst du einfach die Mitteltaste der Fernbedienung gedrückt.
    Die Sprachsteuerung unterstützt die folgenden Sprachen:
    Chinesisch (China), Chinesisch (Kantonesisch), Chinesisch (Taiwan), Deutsch, Englisch (Großbritannien), Englisch (USA), Finnisch, Französisch (Frankreich), Französisch (Kanada), Italienisch, Japanisch, Koreanisch, Niederländisch, Norwegisch, Polnisch, Portugiesisch (Brasilien), Portugiesisch (Portugal), Russisch, Schwedisch, Spanisch (Mexiko), Spanisch (Spanien)
     
    Fotos
    Der iPod touch hat für bis zu 90.000 deiner Lieblingsfotos Platz. Durch Streichen kannst du sie durchschauen und all die Erinnerst-du-dich-noch-Momente mit anderen teilen.
     
    Fotos sichern
    Wenn dir tolle Bilder gemailt werden, kannst du sie einfach im Fotoarchiv auf dem iPod touch sichern und dann wie jedes andere Foto nutzen. Du kannst sie zum Beispiel als Hintergrundbilder verwenden, im Internet teilen oder weitergeben.
     
    Fotos teilen
    Du hast tausende Fotos immer zur Hand. Blätter durch Streichen auf dem Display durch Miniaturen. Mit einem Fingertipp siehst du Fotos bildschirmfüllend. Spiel Diashows mit Musik und Übergängen ab. Maile Fotos an Freunde oder teile sie in einer MobileMe Galerie.
     
    Fotos synchronisieren
    Fotos aus iPhoto auf einem Mac oder Adobe Photoshop Elements und Adobe Photoshop Album auf einem PC werden via iTunes mit dem iPod touch synchronisiert. Einfach nur die Fotos und Alben aussuchen, die mit dem iPod touch synchronisiert werden sollen. Dann kannst du sie überall ansehen und mit anderen teilen.

    Homescreen
    Angenommen du möchtest ""Karten"" als erste App in der zweiten Zeile haben. Oder Mail unten im Dock. Mit den anpassbaren Homescreens kannst du den iPod touch zu deinem iPod touch machen.
     
    Individuelles Anpassen
    Ordne die Symbole auf deinem Homescreen an wie du willst - direkt auf dem iPod touch oder auf deinem Computer in iTunes 9. Bewege eine App eine Zeile nach oben, zwei Apps nach rechts oder auf einen anderen Homescreen. Du kannst bis zu 11 Homescreens erstellen und hast so schnellen Zugriff auf Spiele und Apps, die du aus dem App Store lädst, und auf deine Safari Weblinks.
     
    Hometaste
    Was auch immer du gerade mit deinem iPod touch machst – die Hometaste bringt dich immer zurück zum ersten Homescreen. Wenn du auf die Hometaste drückst, kannst du von jedem Homescreen wieder zurück zum ersten springen.
     
    Apps und Weblinks hinzufügen
    Für jede App, die du aus dem App Store lädst, erscheint ein neues Symbol auf dem Homescreen. Von häufig besuchten Websites kannst du praktische Weblinks erstellen. Sie erscheinen auf dem Homescreen und du kannst per Fingertipp darauf zugreifen.
     
    Spotlight Suche
    Du suchst was? Von einem Ort aus kannst du die gesamten Inhalte des iPod touch durchsuchen. Streich auf dem ersten Homescreen einfach nach rechts, um Spotlight zu öffnen. Sobald du anfängst zu tippen, durchsucht Spotlight deine gesamten Songs, Videos, Kontakte, Mails, Kalender, Notizen und sogar deine Hörbücher und Podcasts.
     
    Safari
    Safari, der fortschrittlichste Webbrowser auf einem Mobilgerät, ist auch auf dem iPod touch integriert. Damit erlebst du das Internet in deiner Hand genauso wie auf dem Computer zuhause. Alles was du brauchst ist eine Wi-Fi-Verbindung.
     
    Überall ins Internet
    Der iPod touch ist der einzige iPod mit integriertem drahtlosen Internetzugriff. Bei bestehender Wi-Fi-Verbindung kannst du im Internet surfen und Nachrichten lesen, Sportergebnisse sehen, Rechnungen bezahlen und online einkaufen. Und beim 32 GB oder 64 GB iPod touch wirst du sehen, dass Webseiten jetzt noch schneller als vorher geladen werden.
     
    Im Web stöbern
    Der iPod touch synchronisiert deine Lesezeichen vom PC oder Mac, sodass du ruckzuck auf deine Lieblingsseiten zugreifen kannst. Außerdem ist die Google- und Yahoo!-Suche schon integriert, sodass du im Web schnell findest, was du suchst.
     
    Weblinks
    Wenn du eine Website öfter besuchst - etwa die einer Zeitung, eines Blogs oder eine Sport-Website - kannst du einfach ein Symbol, einen sogenannten Weblink, auf dem Homescreen erstellen. Wenn du mit Safari Weblinks erstellst, sind deine Lieblingsseiten nur einen Fingertipp entfernt.
     
    Zoom
    Wenn du eine Website öfter besuchst, brauchst du nur mit dem Finger auf das Multi-Touch-Display zu tippen oder die Anzeige aufzuziehen. Websites lassen sich im Hoch- oder Querformat anzeigen. Einfach den iPod touch um 90 Grad drehen, und schon wird auch die Darstellung der Webseite gedreht.
     
    Mail
    Mails auf dem iPod touch funktionieren genau wie auf deinem Computer und sehen auch genau so aus. Und sie funktionieren mit deinen vorhandenen Accounts.
     
    Nachrichten und Anhänge ansehen
    Der iPod touch unterstützt Rich-HTML-E-Mail, sodass Bilder und Fotos zusammen mit dem Text einer E-Mail angezeigt werden. Anhänge siehst du in ihrem Originalformat und nicht als abgespeckte Version. Du kannst in mehr als einem Dutzend standardmäßigen Datei- und Bildformaten drehen, zoomen und schwenken, darunter PDF, Microsoft Word, Excel, PowerPoint und iWork.
     
    Zugriff auf alle Accounts
    Mails von gängigen Anbietern wie MobileMe, Google Mail, Microsoft Exchange, Yahoo! und den meisten standardmäßigen IMAP- und POP-Systemen kannst du mit dem iPod touch ganz einfach abrufen.
     
    Schnellere Eingabe
    Der iPod touch erkennt E-Mail-Adressen in verschiedenen Programmen. Wenn du auf einer Webseite oder in einer Karte eine E-Mail-Adresse siehst, reicht ein Fingertipp auf dem iPod touch, um eine neue Mail zu öffnen, in der die Adresse bereits eingetragen ist.
     
    Intelligente Eingabe
    Die innovative iPod touch Tastatur mit integriertem Wörterbuch* schlägt während der Eingabe Wörter vor. So kannst du ganz schnell und einfach Mails schreiben. Dreh den iPod touch einfach. Dann wird die Tastatur vom Hochformat ins Querformat gedreht und du hast größere Tasten und mehr Platz zum Tippen.
     
    Postfach durchsuchen
    Du musst das Postfach jetzt nicht mehr Mail für Mail durchsuchen. Durch schnelles Abwärtsstreichen wird jetzt ein Suchfeld geöffnet, mit dem du deine Mails nach Absender, Empfänger, Betreff oder Titelzeilen durchsuchen kannst.
     
    Karten
    Finde deinen Weg und die nächste Pizzeria. Mit Karten und einer Wi-Fi-Verbindung kannst du Wegbeschreibungen abrufen, Firmen finden und Verkehrsinformationen prüfen.
     
    Finde dich selbst
    Der iPod touch zeigt dir mithilfe von bekannten Wi-Fi-Hot-Spots, wo du bist. Mit der Stichwortsuche kannst du auch interessante Orte finden. Wenn du z. B. ""Kaffee"" eingibst, werden dir alle Cafés in der Nähe angezeigt.
     
    Wo geht's lang?
    Gib einfach eine Adresse ein, um Wegbeschreibungen abzurufen - von jedem Ort aus. Wähle das Transportmittel wie Auto, öffentliches Verkehrsmittel oder zu Fuß. Die Route lässt sich dann Schritt für Schritt anzeigen. Du kannst dem markierten Weg auf der Karte folgen und selbst die Fahrtdauer wird angezeigt. Oder markiere zwei Orte und lass dir die beste Route zwischen diesen anzeigen.
     
    Verschiedene Kartendarstellungen
    Wie bei Google Karten auf deinem Computer kannst du mit dem Programm ""Karten"" auf dem iPod touch zwischen unterschiedlichen Darstellungen von Google-Karten, Satellitenbildern und einer Hybriddarstellung wechseln. Und mit Multi-Touch kannst du unterwegs zoomen, den Ausschnitt bewegen und die Darstellung ändern.
     
    Verkehrsinformationen
    Die Verkehrsinformationen geben dir anhand der grünen, roten und gelben Markierungen einen Überblick über die Verkehrssituation auf deiner Route.
     
    YouTube
    Skateboard Moves, die so nicht geplant waren. Witzige Werbespots aus anderen Ländern. Was auch immer du gern auf YouTube ansiehst - der iPod touch ist für dich da.
     
    Videogrüße von unterwegs.
    Maile Links deiner Lieblingsvideos an Freunde. Tippe auf der Detailseite des YouTube Videos auf ""Senden"", und schon erstellt der iPod touch eine Mail mit dem zugehörigen Videolink.
     
    Auf YouTube suchen.
    Stöber in Videokategorien wie ""Highlights"", ""Topvideos"", ""Neue Videos"" oder ""Bestwertung"". Du kannst auch per Schlagwort nach einem Video suchen. Etwas Passendes gefunden? Mit einem Lesezeichen kannst du das Video auch vormerken und später ansehen.
     
    Nike + iPod Kompatibilität
    Rock dein Training. Der iPod touch hat eine integrierte Unterstützung für Nike + iPod. Das ist Musik und Motivation in einem.
    Finetuning für dein Lauftraining.
     
    Nike + iPod Sensor
    Der iPod touch hat eine integrierte Unterstützung für Nike + iPod. Einfach den Nike + iPod Sensor (separat erhältlich) in die Nike+ Schuhe stecken und los geht's. Der Sensor überträgt deine Laufdaten drahtlos an den iPod touch und zeichnet Laufzeit, Laufstrecke und Kalorienverbrauch auf. Du erhältst sogar Feedback zum Trainingsfortschritt.
     
    Finetuning für dein Cardio Workout
    Diese Funktion kann auch zusammen mit neuen, in vielen Fitnessstudios vorhandenen Geräten für das Ausdauertraining gekoppelt werden. Such dir einfach ein mit Nike + iPod kompatibles Fitnessgerät wie beispielsweise Laufbänder, Ellipsentrainer, Stepper und Hometrainer.
     
    Synchronisieren mit nikeplus.com
    Später kannst du am Computer den iPod touch via iTunes synchronisieren und deine Trainingsdaten an nikeplus.com übertragen. Auf dieser Website kannst du dein Training verfolgen, dir Ziele setzen und deine Freunde herausfordern.
     
    Sprachmemos
    Du hast vielleicht ein ganz gutes Gedächtnis, aber manchmal ist es besser, kleine (und große) Infos einfach irgendwo festzuhalten. Mit ""Sprachmemos"" kein Problem.

    Memos (oder alles andere)aufnehmen
    Nimm eine Aufgabenliste, geniale Ideen oder eine Wette zwischen dir und deinem Freund auf. Mit dem Programm ""Sprachmemos"" kannst du über die Apple Earphones mit Fernbedienung und Mikro oder ein externes Mikrofon aufnehmen, was immer du willst. Sprachmemos kannst du selbst dann aufnehmen, wenn du den iPod touch gerade verwendest, um Mails zu checken oder im Web zu surfen.
    Memos bearbeiten
    Aufgenommene Memos kannst du direkt auf dem iPod touch trimmen. So behältst du nur das, was du wirklich brauchst.
    Memos sortieren
    Ordne deine Memos mithilfe von Etiketten aus einer vordefinierten Liste oder erstelle eigene Etiketten.
    Memos teilen
    Maile Memos an Freunde und Kollegen. Mit dem iPod touch aufgenommene Memos werden via iTunes mit deinem Mac oder PC synchronisiert, damit du sie später mit anderen teilen kannst.
    Weitere Funktionen
    Auf dem iPod touch ist die neueste Software schon installiert. Und außerdem gibt's praktische Apps wie Kontakte, Kalender, Notizen, Aktien und Wetter.
     
    iPod touch 3.1 Softwarefunktionen.
     
    Genius Mixe
    Diese neue Funktion ist wie ein privater DJ, der deine iTunes Mediathek durchsucht, um Songs zu finden, die gut zusammenpassen und aus diesen dann tolle Mixe erstellt. Alles ganz automatisch.
    Genius Empfehlungen für Apps
    Im App Store gibt's zehntausende Apps. Wie soll man da die richtig collen neuen finden? Mit Genius. Denn Genius sieht sich die Apps an, die du schon hast, und empfiehlt dir weitere.
     
    Peer-to-Peer-Spiele
    Die neusten Spiele kannst du ganz leicht mit Freunden spielen - egal, ob sie neben dir oder in einer anderen Ecke des Landes sitzen.
     
    Kauf Filme, Fernsehsendungen und Hörbücher via Wi-Fi
    Lade via Wi-Fi Filme, Fernsehsendungen, Musikvideos und Hörbücher aus dem iTunes Store auf deinen iPod touch.
     
    Tastatur im Querformat
    Du brauchst mehr Platz zum Tippen? Dreh den iPod touch ins Querformat, um in Mail, Notizen und Safari mit einer größeren Tastatur zu arbeiten.
     
    Cut, Copy & Paste
    Einfach Text und Fotos ausschneiden, kopieren und wieder einsetzen - selbst zwischen Programmen. Du kannst auch Inhalte aus dem Web kopieren.
     
    Spotlight Suche
    Gesucht, gefunden - von einem Ort aus. Spotlight durchsucht alle deine Kontakte, E-Mails, Kalender und Notizen und auch alle Songs und Videos.
     
    Stereo Bluetooth
    Hör Musik und andere Audioinhalte drahtlos. Verbinde den iPod touch mit kompatiblen Bluetooth Stereokopfhörern.

    Automatischer Wi-Fi-Login
    Wenn du dich einmal bei einem Wi-Fi-Hotspot anmeldest, loggt der iPod touch sich beim nächsten Mal automatisch ein.
     
    Shake to Shuffle
    Schüttel den iPod kurz, und schon springt er nach dem Zufallsprinzip zu einem anderen Song in deiner Sammlung. Lass dich einfach überraschen.
     
    Bedienungshilfen
    Der neue iPod touch hat standardmäßig Bedienungshilfen integriert, mit denen auch Menschen mit Beeinträchtigungen alles, was der iPod touch zu bieten hat, erleben können. Alle Bedienungshilfen des iPod touch ansehen
     
    Kindersicherung
    Du entscheidest, welche Musik, Videos und Apps auf dem iPod touch für deine Kinder geeignet sind.
    Der iPod touch hat auch die folgenden praktischen Apps:
     
    Kalender
    Das Programm ""Kalender"" funktioniert mit Yahoo!, Google, Microsoft Outlook, iCal, MobileMe und Microsoft Exchange ActiveSync für Unternehmen. Füge Termine hinzu, lass dich an Termine erinnern, und abonniere Kalender, damit du über Feiertage und Sportveranstaltungen auf dem Laufenden bleibst.
     
    Kontakte
    Namen, E-Mail-Adressen, Telefonnummern und mehr - immer zur Hand. Synchronisier Kontakte in iTunes auf dem Mac oder PC mit dem iPod touch. Neue Kontakte kannst du auch unterwegs mit einem einfachen Fingertipp hinzufügen.
     
    Notizen
    Schluss mit Papier und Bleistift. Mach dir mit ""Notizen"" auf dem iPod schnell eine Notiz, damit du wichtige Infos immer parat hast. Maile deine Gedanken mit der integrierten Mail-Funktion an dich oder andere.
     
    Aktien
    Die Aktien App auf dem iPod touch zeigt dir Börseninformationen für die Aktien, die dich interessieren. Wenn du nähere Details über eine Aktie brauchst, tipp auf ""Y!"", um im Handumdrehen Yahoo! Finance zu öffnen.
     
    Wetter
    Informier dich über das Wetter in der ganzen Welt oder zuhause. Füge die gewünschten Städte hinzu und zeige eine sechstägige Vorhersage für alle an. Tipp auf ""Y!"", um den Yahoo! Stadtführer zu öffnen, der dir zeigt, wo was los ist.
     
    Rechner
    Im Programm ""Rechner"" des iPod touch stecken gleich zwei Rechner. Im Hochformat kannst du ihn als einfachen Taschenrechner verwenden. Dreh den iPod touch ins Querformat, um aus ihm einen wissenschaftlichen Rechner zu machen.
     
    iPod touch Technologie
    Dank der revolutionären Hardwaretechnologie im iPod touch kannst du alle Funktionen mit Streichen, Tippen und Auf- oder Zuziehen steuern. Deswegen wirkt das Autorennen so echt. Deswegen kannst du das, was du eben im Café mitbekommen hast, sofort twittern. Und genau deswegen ist der iPod touch der beste iPod aller Zeiten.
     
    Multi-Touch
    Das Multi-Touch-Display besitzt einen Schutzfilm über der kapazitiven Sensorik, die Berührungen anhand elektrischer Felder erkennt. Diese Informationen werden an das darunterliegende LCD-Display übertragen. Dank der Software des iPod touch kannst du mit Cover Flow durch Alben stöbern, durch deine Fotos blättern, mit Auf- und Zuziehen Bildausschnitte von Websites zoomen und Spiele superpräzise steuern.

    Beschleunigungssensor
    Der iPod touch reagiert über einen integrierten Beschleunigungssensor auf Bewegungen. Dieser Sensor erkennt, wenn du deinen iPod touch ins Querformat drehst und verändert automatisch den Inhalt des Displays. Die Technologie des Beschleunigungssensors kommt besonders bei Spielen gut, denn damit bist du mitten im Spielgeschehen. Das ist perfekt für Autorennen, bei denen der ganze iPod zum Lenkrad wird, und Geschicklichkeitsspiele wie Rolando, bei denen du das Spiel mit deinen Bewegungen steuerst
     
    Drahtlos
    Der iPod touch hat eine integrierte Unterstützung für drahtlosen 802.11b/g Internetzugriff. Überall, wo es ein Wi-Fi-Netzwerk gibt, kommst du mit deinem iPod touch ins Internet. Im Café mailen. Am Flughafen im Web surfen. Spiele vom Sofa aus kaufen. Im iTunes Store stöbern und Musik kaufen und laden. Der iPod touch findet nahegelegene Wi-Fi-Hot-Spots, auch geschützte Netzwerke. Wenn du ein bestimmtes Netzwerk bisher noch nicht verwendet hast, Drahtlos Symbol musst du beim ersten Mal ein Kennwort eingeben, das sich der iPod touch dann merkt. Wenn du dann das nächste Mal in Reichweite dieses Netzwerks bist, loggt er sich automatisch ein.
     
    Bluetooth
    Bluetooth ist eine drahtlose Technologie, mit der du Geräte ohne lästige Kabel verwenden kannst. Was bedeutet das für den iPod touch? Du kannst jetzt mit dem iPod touch und Bluetooth Kopfhörern Musik hören, ganz egal, wo im Raum der iPod ist. Du kannst also auf dem Bett relaxen, während der iPod auf dem Schreibtisch aufgeladen wird. Bluetooth auf dem iPod touch eignet sich auch besonders für Peer-to-Peer-Spiele.
     
    Design
    Der iPod touch ist von außen genau so großartig wie von innen. Du brauchst nur einen in die Hand zu nehmen. Das Gehäuse des iPod touch ist gerade einmal 8,5 mm hoch. Das optische Glas auf der Vorderseite und die Rückseite aus poliertem Edelstahl geben ihm einen eleganten Touch und fühlen sich in der Hand einfach gut an. Schalte ihn ein und du wirst über das brillante 3,5"" Display einfach staunen. Der iPod touch ist die perfekte Kombination aus großartigem Design und revolutionärer Technologie - das perfekte Paket.
    ";2;False;0;;;Apple iPod Touch 64 GB schwarz mit integrierter WiFi Funktion;apple-ipod-touch-64-gb-schwarz;True;True;P-1280;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;349.9000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;40186,8528819444;44;1;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000434-apple-ipod-touch-64-gb-schwarz.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000435-apple-ipod-touch-64-gb-schwarz.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000436-apple-ipod-touch-64-gb-schwarz.jpg;2;;False;;;;;False;False;False;;;;;False;;;;;; -5;0;True;Apple iPod shuffle 2 GB grün;Apple iPod shuffle 2 GB grün;"

    Apple iPod shuffle 2GB grün
     

    Wie seine größeren Geschwister besitzt auch der iPod shuffle kreisförmig angeordnete, ergonomische Bedienelemente.
    Der Kopfhöreranschluss am iPod shuffle dient gleichzeitig als Dock-Anschluss. Drehen Sie den iPod shuffle auf die Seite und setzen Sie ihn in das mitgelieferte Dock ein.
    Dank eines stabilen, integrierten Clips lässt sich der iPod shuffle fast überall befestigen. Klemmen Sie ihn am T-Shirt, am Hemdkragen oder am Trageriemen von Rucksack oder Handtasche fest.
    Lassen Sie sich aufs Ungewisse ein: Verwenden Sie den Schalter für die Zufallswiedergabe, um den Inhalt Ihres iPod shuffle neu zu mischen.
    verbesserte Kopfhörer und das neue iTunes 8.0
     
    Einfach Musik anhaben mit dem Apple iPOD SHUFFLE 2GB.Tragen Sie bis zu 500 Songs am Ärmel. Oder am Gürtel. Oder am Sportoutfit. Das Erkennungszeichen für Musikfans - den Apple iPOD SHUFFLE. Füllen Sie Ihren Apple iPOD SHUFFLE silber 1GB spielend einfach. iTunes ist der Store für Unterhaltungsinhalte. Ihre super organisierte Musiksammlung und Jukebox. Und die Software, mit der Sie Ihren Apple iPOD SHUFFLE mit einem Mausklick füllen. Das farbige Gehäuse aus eloxiertem Aluminium in silber passt zum genial einfachen Design des Apple iPOD SHUFFLE.
     
    Leistungseigenschaften
     
    2 GB Flash-Memory Speicher
    min. Audio-Datenrate: 8 KBit/s
    max. Audio-Datenrate: 320 KBit/s
    Frequenzgang-Untergrenze: 20 Hz
    Frequenzgang-Obergrenze: 20000 Hz
     
    Formate/Standards
     
    MP3-Standard
    AAC + MP3 Standard
    WAV-Dateiformat kompatibel
    Audible-Format kompatibel
    AIFF-Format kompatibel
     
    Bedienung
     
    Musiktitel-Verwaltung
     
    Leistungsaufnahme/Spannungsversorgung

    Li-Polymer Akku
    12 Std. Spieldauer mit Akku
    Ladezeit für Akku: 4 Std.
     
    Anschlüsse
     
    Kopfhörer-Anschluß
    USB-Schnittstelle
    Anschluß für Docking-Station
     
    Gehäuse-Eigenschaften
     
    Breite: 4.12 cm
    Höhe: 2.73 cm
    Tiefe: 1.05 cm
    Gewicht: 15.5 g

    ";2;False;0;;;Apple iPod shuffle 2 GB grün;apple-ipod-shuffle-2-gb-gruen;True;True;P-1140;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;64.9000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;40186,8481481482;37;1;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000429-apple-ipod-shuffle-2-gb-grun.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000430-apple-ipod-shuffle-2-gb-grun.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000431-apple-ipod-shuffle-2-gb-grun.jpg;2;;False;;;;;False;False;False;;;;;False;;;;;; -5;0;True;Apple iPod shuffle 2 GB schwarz;Apple iPod shuffle 2 GB schwarz;"
    Apple iPod shuffle 2GB schwarz
     
     
    Der kleinste iPod der Welt
     
     
    Um den kleinsten iPod der Welt zu bauen, haben wir die Steuerung vom iPod shuffle in das Ohrhörerkabel integriert.
    So wird der iPod shuffle noch kleiner und die Steuerung ist genau da, wo du sie einfach erreichst.
    Wenn du einen Song abspielen, anhalten oder überspringen möchtest,
    musst du nicht lange nach dem iPod shuffle suchen - greif einfach zum Kabel und drücke auf eine der Tasten.
    Dieser Entertainment-Winzling sagt Ihnen auf Knopfdruck, welchen Titel er gerade abspielt
    Organisieren Sie Ihre Musik in verschiedenen Wiedergabeslisten
    Dank eines stabilen, integrierten Clips lässt sich der iPod shuffle fast überall befestigen.
    Lassen Sie sich aufs Ungewisse ein: Verwenden Sie den Schalter für die Zufallswiedergabe,
    um den Inhalt Ihres iPod shuffle neu zu mischen.
    Lieferumfang: Apple Earphones mit Remote Fernbedienung
     
    iPod shuffle - In leuchtenden neuen Farben spricht Musik dich richtig an
     
    Der kleinste iPod der Welt
    Um den kleinsten iPod der Welt zu bauen, haben wir die Steuerung vom iPod shuffle in das Ohrhörerkabel integriert. So wird der iPod shuffle noch kleiner und die Steuerung ist genau da, wo du sie einfach erreichst. Wenn du einen Song abspielen, anhalten oder überspringen möchtest, musst du nicht lange nach dem iPod shuffle suchen - greif einfach zum Kabel und drücke auf eine der Tasten.
     
    Der erste iPod, der mit dir spricht
    Die VoiceOver Funktion ist mit Sicherheit der nächste Hit auf dem iPod shuffle.1 Angenommen du hörst einen Song und willst wissen, wie er heißt oder von wem er ist: Einfach Knopf drücken und VoiceOver sagt es dir. Sogar die Namen deiner Wiedergabelisten verrät es dir. Und wenn die Batterie aufgeladen werden muss, sagt VoiceOver dir das auch.
     
    Leichtbedienung
    Die Steuerung befindet sich am Kabel des rechten Ohrstöpsels. Dadurch, dass die Steuerung jetzt hier angebracht ist, kannst du deine Musiktitel durchsuchen - und die VoiceOver Funktion aktivieren - ohne vom Joggen, Rad fahren oder anderen Aktivitäten abgelenkt zu werden. Der iPod shuffle wird mit dieser einfachen Steuerung geliefert. Du kannst aber auch Kopfhörer mit ähnlichen Bedienelementen von Herstellern wie Scosche, Klipsch, V-MODA und Belkin verwenden.
     

    Dein Musikarchiv. Für unterwegs
    Der iPod shuffle kommt jetzt mit 2 GB oder 4 GB. Mit dem 4 GB Modell hast du jede Menge Platz, um Musik für viele Stunden - bis zu 1.000 Songs - zu speichern.2 Damit bist du im Fitnessstudio oder auf dem Weg zur Arbeit bestens gerüstet. Außerdem kannst du jetzt mehrere Wiedergabelisten und auch Hörbücher verwenden.
     
    Mehrere Wiedergabelisten
    Wahrscheinlich hast du dir in iTunes schon einige Wiedergabelisten zusammengestellt. Eine für unterwegs. Eine fürs Fitnessstudio. Eine zum Chillen. Jetzt kannst du deine Wiedergabelisten auf dem Computer mit dem iPod shuffle synchronisieren und hast immer genau den richtigen Mix - egal, was du gerade machst oder in welcher Stimmung du bist. VoiceOver nennt dir den Namen jeder Wiedergabeliste. So kannst du ganz leicht zwischen ihnen wechseln und genau die auswählen, nach der dir gerade ist.
     
    Farbe bekennen
    Mit dem flachen, robusten Gehäuse aus eloxiertem Aluminium ist der iPod shuffle immer das passende Accessoire. In leuchtendem Pink, Blau, Grün, Schwarz oder Silber ist er ein echtes Fashion Statement. Ganz neu dabei: der iPod shuffle Special Edition in poliertem Edelstahl (So werden Rockstars nun mal behandelt). Sogar der iPod shuffle Clip sieht stylish aus. Er klemmt sicher an Hemd, Jacke, Sportzeug oder am Rucksack. So wird der iPod shuffle zum perfekten Fashtech-Accessoire. Und klar, natürlich ist noch Platz für eine persönliche Gravur.

    Mehrsprachig
    Ein französisches Chanson. Ein spanischer Bolero. Eine italienische Arie. Dein Musikarchiv enthält Musik aus allen Ländern der Welt. Deshalb spricht VoiceOver 20 Sprachen und kann die Namen von Songs und Interpreten mit der richtigen Aussprache sprechen.
     
    Zufall oder kein Zufall?
    Der Schalter am iPod shuffle hat drei Einstellungen. Links wird deine Musik zufällig durcheinander gewürfelt. In der Mitte werden deine Songs in der normalen Reihenfolge gespielt. Rechts wird der iPod shuffle ausgeschaltet.
    ";2;False;0;;;Apple iPod shuffle Tragbarer MP3-Player 4 GB 3. Generation;apple-ipod-shuffle-2-gb-schwarz;True;True;P-1200;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;61.9000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;40186,8421875;39;1;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000585-apple-ipod-shuffle-4-gb-schwarz.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000586-apple-ipod-shuffle-4-gb-schwarz.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000587-apple-ipod-shuffle-4-gb-schwarz.jpg;2;;False;;;;;False;False;False;;;;;False;;;;;; -5;0;True;Apple iPod shuffle 2 GB pink;Apple iPod shuffle 2 GB pink;"

    Apple iPod shuffle 2 GB pink 

    Der kleinste iPod der Welt
     
     
    Um den kleinsten iPod der Welt zu bauen, haben wir die Steuerung vom iPod shuffle in das Ohrhörerkabel integriert.
    So wird der iPod shuffle noch kleiner und die Steuerung ist genau da, wo du sie einfach erreichst.
    Wenn du einen Song abspielen, anhalten oder überspringen möchtest,
    musst du nicht lange nach dem iPod shuffle suchen - greif einfach zum Kabel und drücke auf eine der Tasten.
    Dieser Entertainment-Winzling sagt Ihnen auf Knopfdruck, welchen Titel er gerade abspielt
    Organisieren Sie Ihre Musik in verschiedenen Wiedergabeslisten
    Dank eines stabilen, integrierten Clips lässt sich der iPod shuffle fast überall befestigen.
    Lassen Sie sich aufs Ungewisse ein: Verwenden Sie den Schalter für die Zufallswiedergabe,
    um den Inhalt Ihres iPod shuffle neu zu mischen.
    Lieferumfang: Apple Earphones mit Remote Fernbedienung
     
    iPod shuffle - In leuchtenden neuen Farben spricht Musik dich richtig an
     
    Der kleinste iPod der Welt
    Um den kleinsten iPod der Welt zu bauen, haben wir die Steuerung vom iPod shuffle in das Ohrhörerkabel integriert. So wird der iPod shuffle noch kleiner und die Steuerung ist genau da, wo du sie einfach erreichst. Wenn du einen Song abspielen, anhalten oder überspringen möchtest, musst du nicht lange nach dem iPod shuffle suchen - greif einfach zum Kabel und drücke auf eine der Tasten.
     
    Der erste iPod, der mit dir spricht
    Die VoiceOver Funktion ist mit Sicherheit der nächste Hit auf dem iPod shuffle.1 Angenommen du hörst einen Song und willst wissen, wie er heißt oder von wem er ist: Einfach Knopf drücken und VoiceOver sagt es dir. Sogar die Namen deiner Wiedergabelisten verrät es dir. Und wenn die Batterie aufgeladen werden muss, sagt VoiceOver dir das auch.
     
    Leichtbedienung
    Die Steuerung befindet sich am Kabel des rechten Ohrstöpsels. Dadurch, dass die Steuerung jetzt hier angebracht ist, kannst du deine Musiktitel durchsuchen - und die VoiceOver Funktion aktivieren - ohne vom Joggen, Rad fahren oder anderen Aktivitäten abgelenkt zu werden. Der iPod shuffle wird mit dieser einfachen Steuerung geliefert. Du kannst aber auch Kopfhörer mit ähnlichen Bedienelementen von Herstellern wie Scosche, Klipsch, V-MODA und Belkin verwenden.
     

    Dein Musikarchiv. Für unterwegs
    Der iPod shuffle kommt jetzt mit 2 GB oder 4 GB. Mit dem 4 GB Modell hast du jede Menge Platz, um Musik für viele Stunden - bis zu 1.000 Songs - zu speichern.2 Damit bist du im Fitnessstudio oder auf dem Weg zur Arbeit bestens gerüstet. Außerdem kannst du jetzt mehrere Wiedergabelisten und auch Hörbücher verwenden.
     
    Mehrere Wiedergabelisten
    Wahrscheinlich hast du dir in iTunes schon einige Wiedergabelisten zusammengestellt. Eine für unterwegs. Eine fürs Fitnessstudio. Eine zum Chillen. Jetzt kannst du deine Wiedergabelisten auf dem Computer mit dem iPod shuffle synchronisieren und hast immer genau den richtigen Mix - egal, was du gerade machst oder in welcher Stimmung du bist. VoiceOver nennt dir den Namen jeder Wiedergabeliste. So kannst du ganz leicht zwischen ihnen wechseln und genau die auswählen, nach der dir gerade ist.
     
    Farbe bekennen
    Mit dem flachen, robusten Gehäuse aus eloxiertem Aluminium ist der iPod shuffle immer das passende Accessoire. In leuchtendem Pink, Blau, Grün, Schwarz oder Silber ist er ein echtes Fashion Statement. Ganz neu dabei: der iPod shuffle Special Edition in poliertem Edelstahl (So werden Rockstars nun mal behandelt). Sogar der iPod shuffle Clip sieht stylish aus. Er klemmt sicher an Hemd, Jacke, Sportzeug oder am Rucksack. So wird der iPod shuffle zum perfekten Fashtech-Accessoire. Und klar, natürlich ist noch Platz für eine persönliche Gravur.

    Mehrsprachig
    Ein französisches Chanson. Ein spanischer Bolero. Eine italienische Arie. Dein Musikarchiv enthält Musik aus allen Ländern der Welt. Deshalb spricht VoiceOver 20 Sprachen und kann die Namen von Songs und Interpreten mit der richtigen Aussprache sprechen.
     
    Zufall oder kein Zufall?
    Der Schalter am iPod shuffle hat drei Einstellungen. Links wird deine Musik zufällig durcheinander gewürfelt. In der Mitte werden deine Songs in der normalen Reihenfolge gespielt. Rechts wird der iPod shuffle ausgeschaltet.
    ";2;False;0;;;Apple iPod shuffle 1GB;apple-ipod-shuffle-2-gb-pink-2;True;True;P-1190;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;59.9000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;40186,8385648148;39;1;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000588-apple-ipod-shuffle-2-gb-pink.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000579-apple-ipod-shuffle-4-gb-blau.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000580-apple-ipod-shuffle-4-gb-blau.jpg;2;;False;;;;;False;False;False;;;;;False;;;;;; -5;0;True;Apple iPod shuffle 2 GB blau;Apple iPod shuffle 2 GB blau;"
    Apple iPod shuffle 2GB blau
     
     
    Der kleinste iPod der Welt
     
     
    Um den kleinsten iPod der Welt zu bauen, haben wir die Steuerung vom iPod shuffle in das Ohrhörerkabel integriert.
    So wird der iPod shuffle noch kleiner und die Steuerung ist genau da, wo du sie einfach erreichst.
    Wenn du einen Song abspielen, anhalten oder überspringen möchtest,
    musst du nicht lange nach dem iPod shuffle suchen - greif einfach zum Kabel und drücke auf eine der Tasten.
    Dieser Entertainment-Winzling sagt Ihnen auf Knopfdruck, welchen Titel er gerade abspielt
    Organisieren Sie Ihre Musik in verschiedenen Wiedergabeslisten
    Dank eines stabilen, integrierten Clips lässt sich der iPod shuffle fast überall befestigen.
    Lassen Sie sich aufs Ungewisse ein: Verwenden Sie den Schalter für die Zufallswiedergabe,
    um den Inhalt Ihres iPod shuffle neu zu mischen.
    Lieferumfang: Apple Earphones mit Remote Fernbedienung
     
    iPod shuffle - In leuchtenden neuen Farben spricht Musik dich richtig an
     
    Der kleinste iPod der Welt
    Um den kleinsten iPod der Welt zu bauen, haben wir die Steuerung vom iPod shuffle in das Ohrhörerkabel integriert. So wird der iPod shuffle noch kleiner und die Steuerung ist genau da, wo du sie einfach erreichst. Wenn du einen Song abspielen, anhalten oder überspringen möchtest, musst du nicht lange nach dem iPod shuffle suchen - greif einfach zum Kabel und drücke auf eine der Tasten.
     
    Der erste iPod, der mit dir spricht
    Die VoiceOver Funktion ist mit Sicherheit der nächste Hit auf dem iPod shuffle.1 Angenommen du hörst einen Song und willst wissen, wie er heißt oder von wem er ist: Einfach Knopf drücken und VoiceOver sagt es dir. Sogar die Namen deiner Wiedergabelisten verrät es dir. Und wenn die Batterie aufgeladen werden muss, sagt VoiceOver dir das auch.
     
    Leichtbedienung
    Die Steuerung befindet sich am Kabel des rechten Ohrstöpsels. Dadurch, dass die Steuerung jetzt hier angebracht ist, kannst du deine Musiktitel durchsuchen - und die VoiceOver Funktion aktivieren - ohne vom Joggen, Rad fahren oder anderen Aktivitäten abgelenkt zu werden. Der iPod shuffle wird mit dieser einfachen Steuerung geliefert. Du kannst aber auch Kopfhörer mit ähnlichen Bedienelementen von Herstellern wie Scosche, Klipsch, V-MODA und Belkin verwenden.
     

    Dein Musikarchiv. Für unterwegs
    Der iPod shuffle kommt jetzt mit 2 GB oder 4 GB. Mit dem 4 GB Modell hast du jede Menge Platz, um Musik für viele Stunden - bis zu 1.000 Songs - zu speichern.2 Damit bist du im Fitnessstudio oder auf dem Weg zur Arbeit bestens gerüstet. Außerdem kannst du jetzt mehrere Wiedergabelisten und auch Hörbücher verwenden.
     
    Mehrere Wiedergabelisten
    Wahrscheinlich hast du dir in iTunes schon einige Wiedergabelisten zusammengestellt. Eine für unterwegs. Eine fürs Fitnessstudio. Eine zum Chillen. Jetzt kannst du deine Wiedergabelisten auf dem Computer mit dem iPod shuffle synchronisieren und hast immer genau den richtigen Mix - egal, was du gerade machst oder in welcher Stimmung du bist. VoiceOver nennt dir den Namen jeder Wiedergabeliste. So kannst du ganz leicht zwischen ihnen wechseln und genau die auswählen, nach der dir gerade ist.
     
    Farbe bekennen
    Mit dem flachen, robusten Gehäuse aus eloxiertem Aluminium ist der iPod shuffle immer das passende Accessoire. In leuchtendem Pink, Blau, Grün, Schwarz oder Silber ist er ein echtes Fashion Statement. Ganz neu dabei: der iPod shuffle Special Edition in poliertem Edelstahl (So werden Rockstars nun mal behandelt). Sogar der iPod shuffle Clip sieht stylish aus. Er klemmt sicher an Hemd, Jacke, Sportzeug oder am Rucksack. So wird der iPod shuffle zum perfekten Fashtech-Accessoire. Und klar, natürlich ist noch Platz für eine persönliche Gravur.

    Mehrsprachig
    Ein französisches Chanson. Ein spanischer Bolero. Eine italienische Arie. Dein Musikarchiv enthält Musik aus allen Ländern der Welt. Deshalb spricht VoiceOver 20 Sprachen und kann die Namen von Songs und Interpreten mit der richtigen Aussprache sprechen.
     
    Zufall oder kein Zufall?
    Der Schalter am iPod shuffle hat drei Einstellungen. Links wird deine Musik zufällig durcheinander gewürfelt. In der Mitte werden deine Songs in der normalen Reihenfolge gespielt. Rechts wird der iPod shuffle ausgeschaltet.
    ";2;False;0;;;Apple iPod shuffle Tragbarer MP3-Player 4 GB 3. Generation;apple-ipod-shuffle-2-gb-blau-2;True;True;P-1180;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;59.9000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;40186,8361921296;39;1;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000578-apple-ipod-shuffle-4-gb-blau.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000579-apple-ipod-shuffle-4-gb-blau.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000580-apple-ipod-shuffle-4-gb-blau.jpg;2;;False;;;;;False;False;False;;;;;False;;;;;; -5;0;True;Apple iPod shuffle 2 GB grün;Apple iPod shuffle 2 GB grün;"
    Apple iPod shuffle 2GB grün
     
     
    Der kleinste iPod der Welt
     
     
    Um den kleinsten iPod der Welt zu bauen, haben wir die Steuerung vom iPod shuffle in das Ohrhörerkabel integriert.
    So wird der iPod shuffle noch kleiner und die Steuerung ist genau da, wo du sie einfach erreichst.
    Wenn du einen Song abspielen, anhalten oder überspringen möchtest,
    musst du nicht lange nach dem iPod shuffle suchen - greif einfach zum Kabel und drücke auf eine der Tasten.
    Dieser Entertainment-Winzling sagt Ihnen auf Knopfdruck, welchen Titel er gerade abspielt
    Organisieren Sie Ihre Musik in verschiedenen Wiedergabeslisten
    Dank eines stabilen, integrierten Clips lässt sich der iPod shuffle fast überall befestigen.
    Lassen Sie sich aufs Ungewisse ein: Verwenden Sie den Schalter für die Zufallswiedergabe,
    um den Inhalt Ihres iPod shuffle neu zu mischen.
    Lieferumfang: Apple Earphones mit Remote Fernbedienung
     
    iPod shuffle - In leuchtenden neuen Farben spricht Musik dich richtig an
     
    Der kleinste iPod der Welt
    Um den kleinsten iPod der Welt zu bauen, haben wir die Steuerung vom iPod shuffle in das Ohrhörerkabel integriert. So wird der iPod shuffle noch kleiner und die Steuerung ist genau da, wo du sie einfach erreichst. Wenn du einen Song abspielen, anhalten oder überspringen möchtest, musst du nicht lange nach dem iPod shuffle suchen - greif einfach zum Kabel und drücke auf eine der Tasten.
     
    Der erste iPod, der mit dir spricht
    Die VoiceOver Funktion ist mit Sicherheit der nächste Hit auf dem iPod shuffle.1 Angenommen du hörst einen Song und willst wissen, wie er heißt oder von wem er ist: Einfach Knopf drücken und VoiceOver sagt es dir. Sogar die Namen deiner Wiedergabelisten verrät es dir. Und wenn die Batterie aufgeladen werden muss, sagt VoiceOver dir das auch.
     
    Leichtbedienung
    Die Steuerung befindet sich am Kabel des rechten Ohrstöpsels. Dadurch, dass die Steuerung jetzt hier angebracht ist, kannst du deine Musiktitel durchsuchen - und die VoiceOver Funktion aktivieren - ohne vom Joggen, Rad fahren oder anderen Aktivitäten abgelenkt zu werden. Der iPod shuffle wird mit dieser einfachen Steuerung geliefert. Du kannst aber auch Kopfhörer mit ähnlichen Bedienelementen von Herstellern wie Scosche, Klipsch, V-MODA und Belkin verwenden.
     

    Dein Musikarchiv. Für unterwegs
    Der iPod shuffle kommt jetzt mit 2 GB oder 4 GB. Mit dem 4 GB Modell hast du jede Menge Platz, um Musik für viele Stunden - bis zu 1.000 Songs - zu speichern.2 Damit bist du im Fitnessstudio oder auf dem Weg zur Arbeit bestens gerüstet. Außerdem kannst du jetzt mehrere Wiedergabelisten und auch Hörbücher verwenden.
     
    Mehrere Wiedergabelisten
    Wahrscheinlich hast du dir in iTunes schon einige Wiedergabelisten zusammengestellt. Eine für unterwegs. Eine fürs Fitnessstudio. Eine zum Chillen. Jetzt kannst du deine Wiedergabelisten auf dem Computer mit dem iPod shuffle synchronisieren und hast immer genau den richtigen Mix - egal, was du gerade machst oder in welcher Stimmung du bist. VoiceOver nennt dir den Namen jeder Wiedergabeliste. So kannst du ganz leicht zwischen ihnen wechseln und genau die auswählen, nach der dir gerade ist.
     
    Farbe bekennen
    Mit dem flachen, robusten Gehäuse aus eloxiertem Aluminium ist der iPod shuffle immer das passende Accessoire. In leuchtendem Pink, Blau, Grün, Schwarz oder Silber ist er ein echtes Fashion Statement. Ganz neu dabei: der iPod shuffle Special Edition in poliertem Edelstahl (So werden Rockstars nun mal behandelt). Sogar der iPod shuffle Clip sieht stylish aus. Er klemmt sicher an Hemd, Jacke, Sportzeug oder am Rucksack. So wird der iPod shuffle zum perfekten Fashtech-Accessoire. Und klar, natürlich ist noch Platz für eine persönliche Gravur.

    Mehrsprachig
    Ein französisches Chanson. Ein spanischer Bolero. Eine italienische Arie. Dein Musikarchiv enthält Musik aus allen Ländern der Welt. Deshalb spricht VoiceOver 20 Sprachen und kann die Namen von Songs und Interpreten mit der richtigen Aussprache sprechen.
     
    Zufall oder kein Zufall?
    Der Schalter am iPod shuffle hat drei Einstellungen. Links wird deine Musik zufällig durcheinander gewürfelt. In der Mitte werden deine Songs in der normalen Reihenfolge gespielt. Rechts wird der iPod shuffle ausgeschaltet.
    ";2;False;0;;;Apple iPod shuffle Tragbarer MP3-Player 4 GB 3. Generation;apple-ipod-shuffle-2-gb-gruen-2;True;True;P-1170;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;59.9000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;40186,8328587963;39;1;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000584-apple-ipod-shuffle-4-gb-grun.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000579-apple-ipod-shuffle-4-gb-blau.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000580-apple-ipod-shuffle-4-gb-blau.jpg;2;;False;;;;;False;False;False;;;;;False;;;;;; -5;0;True;Apple iPod shuffle 2 GB silber;Apple iPod shuffle 2 GB silber;"
    Apple iPod shuffle 2GB silber  
     
    Der kleinste iPod der Welt
     
     
    Um den kleinsten iPod der Welt zu bauen, haben wir die Steuerung vom iPod shuffle in das Ohrhörerkabel integriert.
    So wird der iPod shuffle noch kleiner und die Steuerung ist genau da, wo du sie einfach erreichst.
    Wenn du einen Song abspielen, anhalten oder überspringen möchtest,
    musst du nicht lange nach dem iPod shuffle suchen - greif einfach zum Kabel und drücke auf eine der Tasten.
    Dieser Entertainment-Winzling sagt Ihnen auf Knopfdruck, welchen Titel er gerade abspielt
    Organisieren Sie Ihre Musik in verschiedenen Wiedergabeslisten
    Dank eines stabilen, integrierten Clips lässt sich der iPod shuffle fast überall befestigen.
    Lassen Sie sich aufs Ungewisse ein: Verwenden Sie den Schalter für die Zufallswiedergabe,
    um den Inhalt Ihres iPod shuffle neu zu mischen.
    Lieferumfang: Apple Earphones mit Remote Fernbedienung
     
    iPod shuffle - In leuchtenden neuen Farben spricht Musik dich richtig an
     
    Der kleinste iPod der Welt
    Um den kleinsten iPod der Welt zu bauen, haben wir die Steuerung vom iPod shuffle in das Ohrhörerkabel integriert. So wird der iPod shuffle noch kleiner und die Steuerung ist genau da, wo du sie einfach erreichst. Wenn du einen Song abspielen, anhalten oder überspringen möchtest, musst du nicht lange nach dem iPod shuffle suchen - greif einfach zum Kabel und drücke auf eine der Tasten.
     
    Der erste iPod, der mit dir spricht
    Die VoiceOver Funktion ist mit Sicherheit der nächste Hit auf dem iPod shuffle.1 Angenommen du hörst einen Song und willst wissen, wie er heißt oder von wem er ist: Einfach Knopf drücken und VoiceOver sagt es dir. Sogar die Namen deiner Wiedergabelisten verrät es dir. Und wenn die Batterie aufgeladen werden muss, sagt VoiceOver dir das auch.
     
    Leichtbedienung
    Die Steuerung befindet sich am Kabel des rechten Ohrstöpsels. Dadurch, dass die Steuerung jetzt hier angebracht ist, kannst du deine Musiktitel durchsuchen - und die VoiceOver Funktion aktivieren - ohne vom Joggen, Rad fahren oder anderen Aktivitäten abgelenkt zu werden. Der iPod shuffle wird mit dieser einfachen Steuerung geliefert. Du kannst aber auch Kopfhörer mit ähnlichen Bedienelementen von Herstellern wie Scosche, Klipsch, V-MODA und Belkin verwenden.
     

    Dein Musikarchiv. Für unterwegs
    Der iPod shuffle kommt jetzt mit 2 GB oder 4 GB. Mit dem 4 GB Modell hast du jede Menge Platz, um Musik für viele Stunden - bis zu 1.000 Songs - zu speichern.2 Damit bist du im Fitnessstudio oder auf dem Weg zur Arbeit bestens gerüstet. Außerdem kannst du jetzt mehrere Wiedergabelisten und auch Hörbücher verwenden.
     
    Mehrere Wiedergabelisten
    Wahrscheinlich hast du dir in iTunes schon einige Wiedergabelisten zusammengestellt. Eine für unterwegs. Eine fürs Fitnessstudio. Eine zum Chillen. Jetzt kannst du deine Wiedergabelisten auf dem Computer mit dem iPod shuffle synchronisieren und hast immer genau den richtigen Mix - egal, was du gerade machst oder in welcher Stimmung du bist. VoiceOver nennt dir den Namen jeder Wiedergabeliste. So kannst du ganz leicht zwischen ihnen wechseln und genau die auswählen, nach der dir gerade ist.
     
    Farbe bekennen
    Mit dem flachen, robusten Gehäuse aus eloxiertem Aluminium ist der iPod shuffle immer das passende Accessoire. In leuchtendem Pink, Blau, Grün, Schwarz oder Silber ist er ein echtes Fashion Statement. Ganz neu dabei: der iPod shuffle Special Edition in poliertem Edelstahl (So werden Rockstars nun mal behandelt). Sogar der iPod shuffle Clip sieht stylish aus. Er klemmt sicher an Hemd, Jacke, Sportzeug oder am Rucksack. So wird der iPod shuffle zum perfekten Fashtech-Accessoire. Und klar, natürlich ist noch Platz für eine persönliche Gravur.

    Mehrsprachig
    Ein französisches Chanson. Ein spanischer Bolero. Eine italienische Arie. Dein Musikarchiv enthält Musik aus allen Ländern der Welt. Deshalb spricht VoiceOver 20 Sprachen und kann die Namen von Songs und Interpreten mit der richtigen Aussprache sprechen.
     
    Zufall oder kein Zufall?
    Der Schalter am iPod shuffle hat drei Einstellungen. Links wird deine Musik zufällig durcheinander gewürfelt. In der Mitte werden deine Songs in der normalen Reihenfolge gespielt. Rechts wird der iPod shuffle ausgeschaltet.
    ";2;False;0;;;Apple iPod shuffle Tragbarer MP3-Player 4 GB 3. Generation;apple-ipod-shuffle-2-gb-silber;True;True;P-1160;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;61.9000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;40186,8309259259;39;1;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000220-apple-ipod-shuffle-4-gb-silber.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000221-apple-ipod-shuffle-4-gb-silber.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000222-apple-ipod-shuffle-4-gb-silber.jpg;2;;False;;;;;False;False;False;;;;;False;;;;;; -5;0;True;Apple iPod shuffle 4 GB schwarz;Apple iPod shuffle 4 GB schwarz;"
    Apple iPod shuffle 4GB schwarz
     
     
    Der kleinste iPod der Welt
     
     
    Um den kleinsten iPod der Welt zu bauen, haben wir die Steuerung vom iPod shuffle in das Ohrhörerkabel integriert.
    So wird der iPod shuffle noch kleiner und die Steuerung ist genau da, wo du sie einfach erreichst.
    Wenn du einen Song abspielen, anhalten oder überspringen möchtest,
    musst du nicht lange nach dem iPod shuffle suchen - greif einfach zum Kabel und drücke auf eine der Tasten.
    Dieser Entertainment-Winzling sagt Ihnen auf Knopfdruck, welchen Titel er gerade abspielt
    Organisieren Sie Ihre Musik in verschiedenen Wiedergabeslisten
    Dank eines stabilen, integrierten Clips lässt sich der iPod shuffle fast überall befestigen.
    Lassen Sie sich aufs Ungewisse ein: Verwenden Sie den Schalter für die Zufallswiedergabe,
    um den Inhalt Ihres iPod shuffle neu zu mischen.
    Lieferumfang: Apple Earphones mit Remote Fernbedienung
     
    iPod shuffle - In leuchtenden neuen Farben spricht Musik dich richtig an
     
    Der kleinste iPod der Welt
    Um den kleinsten iPod der Welt zu bauen, haben wir die Steuerung vom iPod shuffle in das Ohrhörerkabel integriert. So wird der iPod shuffle noch kleiner und die Steuerung ist genau da, wo du sie einfach erreichst. Wenn du einen Song abspielen, anhalten oder überspringen möchtest, musst du nicht lange nach dem iPod shuffle suchen - greif einfach zum Kabel und drücke auf eine der Tasten.
     
    Der erste iPod, der mit dir spricht
    Die VoiceOver Funktion ist mit Sicherheit der nächste Hit auf dem iPod shuffle.1 Angenommen du hörst einen Song und willst wissen, wie er heißt oder von wem er ist: Einfach Knopf drücken und VoiceOver sagt es dir. Sogar die Namen deiner Wiedergabelisten verrät es dir. Und wenn die Batterie aufgeladen werden muss, sagt VoiceOver dir das auch.
     
    Leichtbedienung
    Die Steuerung befindet sich am Kabel des rechten Ohrstöpsels. Dadurch, dass die Steuerung jetzt hier angebracht ist, kannst du deine Musiktitel durchsuchen - und die VoiceOver Funktion aktivieren - ohne vom Joggen, Rad fahren oder anderen Aktivitäten abgelenkt zu werden. Der iPod shuffle wird mit dieser einfachen Steuerung geliefert. Du kannst aber auch Kopfhörer mit ähnlichen Bedienelementen von Herstellern wie Scosche, Klipsch, V-MODA und Belkin verwenden.
     

    Dein Musikarchiv. Für unterwegs
    Der iPod shuffle kommt jetzt mit 2 GB oder 4 GB. Mit dem 4 GB Modell hast du jede Menge Platz, um Musik für viele Stunden - bis zu 1.000 Songs - zu speichern.2 Damit bist du im Fitnessstudio oder auf dem Weg zur Arbeit bestens gerüstet. Außerdem kannst du jetzt mehrere Wiedergabelisten und auch Hörbücher verwenden.
     
    Mehrere Wiedergabelisten
    Wahrscheinlich hast du dir in iTunes schon einige Wiedergabelisten zusammengestellt. Eine für unterwegs. Eine fürs Fitnessstudio. Eine zum Chillen. Jetzt kannst du deine Wiedergabelisten auf dem Computer mit dem iPod shuffle synchronisieren und hast immer genau den richtigen Mix - egal, was du gerade machst oder in welcher Stimmung du bist. VoiceOver nennt dir den Namen jeder Wiedergabeliste. So kannst du ganz leicht zwischen ihnen wechseln und genau die auswählen, nach der dir gerade ist.
     
    Farbe bekennen
    Mit dem flachen, robusten Gehäuse aus eloxiertem Aluminium ist der iPod shuffle immer das passende Accessoire. In leuchtendem Pink, Blau, Grün, Schwarz oder Silber ist er ein echtes Fashion Statement. Ganz neu dabei: der iPod shuffle Special Edition in poliertem Edelstahl (So werden Rockstars nun mal behandelt). Sogar der iPod shuffle Clip sieht stylish aus. Er klemmt sicher an Hemd, Jacke, Sportzeug oder am Rucksack. So wird der iPod shuffle zum perfekten Fashtech-Accessoire. Und klar, natürlich ist noch Platz für eine persönliche Gravur.

    Mehrsprachig
    Ein französisches Chanson. Ein spanischer Bolero. Eine italienische Arie. Dein Musikarchiv enthält Musik aus allen Ländern der Welt. Deshalb spricht VoiceOver 20 Sprachen und kann die Namen von Songs und Interpreten mit der richtigen Aussprache sprechen.
     
    Zufall oder kein Zufall?
    Der Schalter am iPod shuffle hat drei Einstellungen. Links wird deine Musik zufällig durcheinander gewürfelt. In der Mitte werden deine Songs in der normalen Reihenfolge gespielt. Rechts wird der iPod shuffle ausgeschaltet.
    ";2;False;0;;;Apple iPod shuffle Tragbarer MP3-Player 4 GB 3. Generation;apple-ipod-shuffle-4-gb-schwarz;True;True;P-1240;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;79.9000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;40186,8276273148;40;1;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000585-apple-ipod-shuffle-4-gb-schwarz.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000586-apple-ipod-shuffle-4-gb-schwarz.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000587-apple-ipod-shuffle-4-gb-schwarz.jpg;2;;False;;;;;False;False;False;;;;;False;;;;;; -5;0;True;Apple iPod shuffle 4 GB grün;Apple iPod shuffle 4 GB grün;"
    Apple iPod shuffle 4GB grün
     
     
    Der kleinste iPod der Welt
     
     
    Um den kleinsten iPod der Welt zu bauen, haben wir die Steuerung vom iPod shuffle in das Ohrhörerkabel integriert.
    So wird der iPod shuffle noch kleiner und die Steuerung ist genau da, wo du sie einfach erreichst.
    Wenn du einen Song abspielen, anhalten oder überspringen möchtest,
    musst du nicht lange nach dem iPod shuffle suchen - greif einfach zum Kabel und drücke auf eine der Tasten.
    Dieser Entertainment-Winzling sagt Ihnen auf Knopfdruck, welchen Titel er gerade abspielt
    Organisieren Sie Ihre Musik in verschiedenen Wiedergabeslisten
    Dank eines stabilen, integrierten Clips lässt sich der iPod shuffle fast überall befestigen.
    Lassen Sie sich aufs Ungewisse ein: Verwenden Sie den Schalter für die Zufallswiedergabe,
    um den Inhalt Ihres iPod shuffle neu zu mischen.
    Lieferumfang: Apple Earphones mit Remote Fernbedienung
     
    iPod shuffle - In leuchtenden neuen Farben spricht Musik dich richtig an
     
    Der kleinste iPod der Welt
    Um den kleinsten iPod der Welt zu bauen, haben wir die Steuerung vom iPod shuffle in das Ohrhörerkabel integriert. So wird der iPod shuffle noch kleiner und die Steuerung ist genau da, wo du sie einfach erreichst. Wenn du einen Song abspielen, anhalten oder überspringen möchtest, musst du nicht lange nach dem iPod shuffle suchen - greif einfach zum Kabel und drücke auf eine der Tasten.
     
    Der erste iPod, der mit dir spricht
    Die VoiceOver Funktion ist mit Sicherheit der nächste Hit auf dem iPod shuffle.1 Angenommen du hörst einen Song und willst wissen, wie er heißt oder von wem er ist: Einfach Knopf drücken und VoiceOver sagt es dir. Sogar die Namen deiner Wiedergabelisten verrät es dir. Und wenn die Batterie aufgeladen werden muss, sagt VoiceOver dir das auch.
     
    Leichtbedienung
    Die Steuerung befindet sich am Kabel des rechten Ohrstöpsels. Dadurch, dass die Steuerung jetzt hier angebracht ist, kannst du deine Musiktitel durchsuchen - und die VoiceOver Funktion aktivieren - ohne vom Joggen, Rad fahren oder anderen Aktivitäten abgelenkt zu werden. Der iPod shuffle wird mit dieser einfachen Steuerung geliefert. Du kannst aber auch Kopfhörer mit ähnlichen Bedienelementen von Herstellern wie Scosche, Klipsch, V-MODA und Belkin verwenden.
     

    Dein Musikarchiv. Für unterwegs
    Der iPod shuffle kommt jetzt mit 2 GB oder 4 GB. Mit dem 4 GB Modell hast du jede Menge Platz, um Musik für viele Stunden - bis zu 1.000 Songs - zu speichern.2 Damit bist du im Fitnessstudio oder auf dem Weg zur Arbeit bestens gerüstet. Außerdem kannst du jetzt mehrere Wiedergabelisten und auch Hörbücher verwenden.
     
    Mehrere Wiedergabelisten
    Wahrscheinlich hast du dir in iTunes schon einige Wiedergabelisten zusammengestellt. Eine für unterwegs. Eine fürs Fitnessstudio. Eine zum Chillen. Jetzt kannst du deine Wiedergabelisten auf dem Computer mit dem iPod shuffle synchronisieren und hast immer genau den richtigen Mix - egal, was du gerade machst oder in welcher Stimmung du bist. VoiceOver nennt dir den Namen jeder Wiedergabeliste. So kannst du ganz leicht zwischen ihnen wechseln und genau die auswählen, nach der dir gerade ist.
     
    Farbe bekennen
    Mit dem flachen, robusten Gehäuse aus eloxiertem Aluminium ist der iPod shuffle immer das passende Accessoire. In leuchtendem Pink, Blau, Grün, Schwarz oder Silber ist er ein echtes Fashion Statement. Ganz neu dabei: der iPod shuffle Special Edition in poliertem Edelstahl (So werden Rockstars nun mal behandelt). Sogar der iPod shuffle Clip sieht stylish aus. Er klemmt sicher an Hemd, Jacke, Sportzeug oder am Rucksack. So wird der iPod shuffle zum perfekten Fashtech-Accessoire. Und klar, natürlich ist noch Platz für eine persönliche Gravur.

    Mehrsprachig
    Ein französisches Chanson. Ein spanischer Bolero. Eine italienische Arie. Dein Musikarchiv enthält Musik aus allen Ländern der Welt. Deshalb spricht VoiceOver 20 Sprachen und kann die Namen von Songs und Interpreten mit der richtigen Aussprache sprechen.
     
    Zufall oder kein Zufall?
    Der Schalter am iPod shuffle hat drei Einstellungen. Links wird deine Musik zufällig durcheinander gewürfelt. In der Mitte werden deine Songs in der normalen Reihenfolge gespielt. Rechts wird der iPod shuffle ausgeschaltet.
     
    ";2;False;0;;;Apple iPod shuffle Tragbarer MP3-Player 4 GB 3. Generation;apple-ipod-shuffle-4-gb-gruen;True;True;P-1230;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;77.9000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;40186,8252662037;40;1;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000584-apple-ipod-shuffle-4-gb-grun.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000579-apple-ipod-shuffle-4-gb-blau.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000580-apple-ipod-shuffle-4-gb-blau.jpg;2;;False;;;;;False;False;False;;;;;False;;;;;; -5;0;True;Apple iPod shuffle 4 GB blau;Apple iPod shuffle 4GB blau;"
    Apple iPod shuffle 4GB blau
     
     
    Der kleinste iPod der Welt
     
     
    Um den kleinsten iPod der Welt zu bauen, haben wir die Steuerung vom iPod shuffle in das Ohrhörerkabel integriert.
    So wird der iPod shuffle noch kleiner und die Steuerung ist genau da, wo du sie einfach erreichst.
    Wenn du einen Song abspielen, anhalten oder überspringen möchtest,
    musst du nicht lange nach dem iPod shuffle suchen - greif einfach zum Kabel und drücke auf eine der Tasten.
    Dieser Entertainment-Winzling sagt Ihnen auf Knopfdruck, welchen Titel er gerade abspielt
    Organisieren Sie Ihre Musik in verschiedenen Wiedergabeslisten
    Dank eines stabilen, integrierten Clips lässt sich der iPod shuffle fast überall befestigen.
    Lassen Sie sich aufs Ungewisse ein: Verwenden Sie den Schalter für die Zufallswiedergabe,
    um den Inhalt Ihres iPod shuffle neu zu mischen.
    Lieferumfang: Apple Earphones mit Remote Fernbedienung
     
    iPod shuffle - In leuchtenden neuen Farben spricht Musik dich richtig an
     
    Der kleinste iPod der Welt
    Um den kleinsten iPod der Welt zu bauen, haben wir die Steuerung vom iPod shuffle in das Ohrhörerkabel integriert. So wird der iPod shuffle noch kleiner und die Steuerung ist genau da, wo du sie einfach erreichst. Wenn du einen Song abspielen, anhalten oder überspringen möchtest, musst du nicht lange nach dem iPod shuffle suchen - greif einfach zum Kabel und drücke auf eine der Tasten.
     
    Der erste iPod, der mit dir spricht
    Die VoiceOver Funktion ist mit Sicherheit der nächste Hit auf dem iPod shuffle.1 Angenommen du hörst einen Song und willst wissen, wie er heißt oder von wem er ist: Einfach Knopf drücken und VoiceOver sagt es dir. Sogar die Namen deiner Wiedergabelisten verrät es dir. Und wenn die Batterie aufgeladen werden muss, sagt VoiceOver dir das auch.
     
    Leichtbedienung
    Die Steuerung befindet sich am Kabel des rechten Ohrstöpsels. Dadurch, dass die Steuerung jetzt hier angebracht ist, kannst du deine Musiktitel durchsuchen - und die VoiceOver Funktion aktivieren - ohne vom Joggen, Rad fahren oder anderen Aktivitäten abgelenkt zu werden. Der iPod shuffle wird mit dieser einfachen Steuerung geliefert. Du kannst aber auch Kopfhörer mit ähnlichen Bedienelementen von Herstellern wie Scosche, Klipsch, V-MODA und Belkin verwenden.
     

    Dein Musikarchiv. Für unterwegs
    Der iPod shuffle kommt jetzt mit 2 GB oder 4 GB. Mit dem 4 GB Modell hast du jede Menge Platz, um Musik für viele Stunden - bis zu 1.000 Songs - zu speichern.2 Damit bist du im Fitnessstudio oder auf dem Weg zur Arbeit bestens gerüstet. Außerdem kannst du jetzt mehrere Wiedergabelisten und auch Hörbücher verwenden.
     
    Mehrere Wiedergabelisten
    Wahrscheinlich hast du dir in iTunes schon einige Wiedergabelisten zusammengestellt. Eine für unterwegs. Eine fürs Fitnessstudio. Eine zum Chillen. Jetzt kannst du deine Wiedergabelisten auf dem Computer mit dem iPod shuffle synchronisieren und hast immer genau den richtigen Mix - egal, was du gerade machst oder in welcher Stimmung du bist. VoiceOver nennt dir den Namen jeder Wiedergabeliste. So kannst du ganz leicht zwischen ihnen wechseln und genau die auswählen, nach der dir gerade ist.
     
    Farbe bekennen
    Mit dem flachen, robusten Gehäuse aus eloxiertem Aluminium ist der iPod shuffle immer das passende Accessoire. In leuchtendem Pink, Blau, Grün, Schwarz oder Silber ist er ein echtes Fashion Statement. Ganz neu dabei: der iPod shuffle Special Edition in poliertem Edelstahl (So werden Rockstars nun mal behandelt). Sogar der iPod shuffle Clip sieht stylish aus. Er klemmt sicher an Hemd, Jacke, Sportzeug oder am Rucksack. So wird der iPod shuffle zum perfekten Fashtech-Accessoire. Und klar, natürlich ist noch Platz für eine persönliche Gravur.

    Mehrsprachig
    Ein französisches Chanson. Ein spanischer Bolero. Eine italienische Arie. Dein Musikarchiv enthält Musik aus allen Ländern der Welt. Deshalb spricht VoiceOver 20 Sprachen und kann die Namen von Songs und Interpreten mit der richtigen Aussprache sprechen.
     
    Zufall oder kein Zufall?
    Der Schalter am iPod shuffle hat drei Einstellungen. Links wird deine Musik zufällig durcheinander gewürfelt. In der Mitte werden deine Songs in der normalen Reihenfolge gespielt. Rechts wird der iPod shuffle ausgeschaltet.
    ";2;False;0;;;Apple iPod shuffle Tragbarer MP3-Player 4 GB 3. Generation;apple-ipod-shuffle-4-gb-blau;True;True;P-1220;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;77.9000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;40186,8199537037;40;1;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000578-apple-ipod-shuffle-4-gb-blau.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000579-apple-ipod-shuffle-4-gb-blau.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000580-apple-ipod-shuffle-4-gb-blau.jpg;2;;False;;;;;False;False;False;;;;;False;;;;;; -5;0;True;Canon EOS 1000D SLR-Digitalkamera Kit;"Canon EOS 1000D SLR-Digitalkamera Kit inkl. EF-S 18-55 Objektiv ";"
    Canon EOS 1000D:Anpfiff für den Aufstieg
     
    Wer bislang mit der digitalen Spiegelreflexfotografie nur geliebäugelt hat, wird dieser Canon-Neuheit nur schwerlich widerstehen können: EOS 1000D heißt die neue Kamera. Die Neue punktet mit einem Preis-Leistungsverhältnis, das eine neue Canon- Liga kennzeichnet: 10,1 Megapixel CMOS-Sensor, Sieben-Punkt-Weitbereich- Autofokus und Reihenaufnahmen mit bis zu drei JPEG-komprimierten Bildern pro Sekunde. Die Marke, der die Profis vertrauen, ist also jetzt auch für den Einsteiger in die digitale Spiegelreflexfotografie erschwinglich… und dank benutzerfreundlicher Menüführung auch leicht bedienbar.
     
    Die EOS 1000D ist die bislang leichteste aller digitalen EOS-Kameras und basiert auf intuitiver Bedienung und einer Reihe von innovativen Spitzentechnologien, die auch in der professionellen Serie der Canon EOS-1 Kameras zum Einsatz kommen. Dies sind beispielsweise der DIGIC-III-Bildprozessor, Livebild-Funktion und EOSIntegrated- Cleaning-System, das integrierte Sensor-Reinigungsprogramm von Canon. Die EOS 1000D gibt es auch im kostengünstigen Paket mit dem Objektiv EF-S 18- 55mm IS: Dieses Canon-Objektiv hat einen optischen Bildstabilisator, der eine längere Belichtungszeit erlaubt, weil diese Technologie Verwacklungen entgegenwirkt. Das zahlt sich besonders bei schlechten Lichtverhältnissen aus.
    Intelligenter Fokus und Blitz

    Bei dynamischen Aufnahmesituationen ist eine schnelle Fokussierung sehr wichtig – hier macht sich der Sieben-Punkt-Weitbereich-Autofokus der EOS 1000D durch die Scharfstellung in Sekundenbruchteilen bezahlt. Das zentrale AF-Messfeld ist ein Kreuzsensor, der sich vor allem in Aufnahmesituationen mit wenig Licht beziehungsweise schwach ausgeprägtem Kontrast bewährt. Hinzu kommt ein weiteres von den professionellen EOS-Modellen bekanntes Leistungsmerkmal: das entfernungsgekoppelte Blitzsteuerungssystem E-TTL II.
     
    Konzipiert für mehr Leistung
    Wie bei allen EOS-Modellen werden auch die Kernelemente der EOS 1000D von Canon selbst konzipiert und gefertigt, eine Kombination für bestmögliche Bildqualität. Der 10,1 Megapixel CMOS-Sensor sorgt für präzise, rauscharme Bilder und bietet mehr als genug Auflösung für den Fotodruck bis DIN A4. Zum Schutz vor störenden Staubpartikeln ist der Sensor der Neuen mit dem bekannten EOS Integrated Cleaning System ausgestattet, das den Staub in drei separaten Schritten bekämpft: reduzieren, abweisen und entfernen.
    Die EOS 1000D verfügt mit dem DIGIC III über einen Bildprozessor, der auch bei den professionellen digitalen Canon-Spiegelreflexkameras zum Einsatz kommt. Dies ermöglicht kontinuierliche Reihenaufnahmen bis zur Kapazitätsgrenze der jeweilig eingesetzten SD- oder SDHC-Speicherkarte bei Geschwindigkeiten von bis zu drei Bildern pro Sekunde. Darüber hinaus ist der DIGIC-III-Prozessor für hochwertige Bildwiedergabe, schnelle Signalverarbeitung und nahezu umgehende Startzeiten verantwortlich.
     
     
    Hoher Anwenderkomfort
    Mit gerade einmal 450 Gramm (nur Gehäuse) ist die EOS 1000D die bislang leichteste digitale Canon Spiegelreflexkamera von Canon. Das kompakte, ergonomisch gestaltete Gehäuse ist konsequent auf effiziente Handhabung ausgelegt.^ Auf dem hellen 2,5 Zoll großen LC-Monitor lassen sich die Bilder umgehend überprüfen oder auch – dank des weiten Betrachtungswinkels – von mehreren Personen gleichzeitig einsehen. Ferner bietet das LC-Display Zugriff auf eine intuitive, leicht verständliche Menüstruktur mit praktischen Reitern – das ist übersichtlich und erleichtert das Auffinden von Menüpunkten.
     
    Live View
    Bei Aufnahmen vom Stativ oder wenn sich der Sucher als unpraktisch erweist, ermöglicht die Livebild-Funktion die Kontrolle des Motivs über das Display. Dabei wird das Livebild als Videosequenz mit 30 Bildern pro Sekunde dargestellt. Zur Beurteilung von Bildkomposition oder Belichtungseinstellung lassen sich Gitternetzlinien oder ein Histogramm einblenden. Für die Livebild-Funktion stehen zwei AF-Modi zur Verfügung: Quick AF, der zur Aktivierung des AF-Sensors umgehend den Kameraspiegel hochklappt und Live AF, der Kontrastinformationen für die Scharfstellung wie bei einer Kompaktkamera einsetzt.
     
    Software
    Zum Lieferumfang der EOS 1000D gehört ein umfassendes Softwarepaket mit den notwendigen Tools zur Bearbeitung und Verwaltung der Bilder. Zum Beispiel Digital Photo Professional (DPP), ein leistungsstarkes Programm zur Bearbeitung von RAWBildern. DPP bewährt sich auch im Zusammenspiel mit Kamerafunktionen wie Dust Delete Data und Picture Styles. Die im Lieferumfang enthaltene Software Picture Style Editor kann eingesetzt werden, um individuelle Picture Styles für die Feinabstimmung von Farben zu erstellen. Weitere mitgelieferte Softwareanwendungen sind EOS Utility, Image/Zoom Browser und Photostitch. 
     
    EF-S 18-55 Objektiv
    Speziell für digitale EOS Kameras mit EF-S-Bjonett entwickeltes Standard-Zoom
    Kompakt und leicht
    Hohe Bildqualität bei allen Brennweiten
    Optimierte Vergütungsschichten minimieren Streulicht und Reflexe
    Hohe AF-Geschwindigkeit
    Sehr kurze Naheinstellgrenze
    Bleifreie Optik
    ";2;False;0;;;"Canon EOS 1000D SLR-Digitalkamera Kit inkl. EF-S 18-55 Objektiv ";canon-eos-1000d-slr-digitalkamera-kit;True;True;P-1740;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;429.0000;0.0000;409.9000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;40166,6718402778;"56;2095";25;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000481-canon-eos-1000d-slr-digitalkamera-kit.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000482-canon-eos-1000d-slr-digitalkamera-kit.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000483-canon-eos-1000d-slr-digitalkamera-kit.jpg;1;;False;;;;;False;False;False;;;;;False;;;;;; -5;0;True;Sandisk Sansa Fuze 8 GB schwarz;"Sandisk Sansa Fuze MP3-/Video-Player 8 GB mit Radio schwarz ";"

    Sandisk Sansa Fuze MP3-/Video-Player 8 GB mit Radio schwarz

     
    Mit der verfügbaren Akkuleistung können Sie 24 Stunden lang Musik hören, Bilder anschauen oder spielen.
    Der neue Sansa Fuze von SanDisk ist der ideale tragbare Musikplayer für Sie.
    Er steht mit einer Speicherkapazität 4 GB in schwarz,rot,pink zur Verfügung.
    Sehen Sie sich Ihre Lieblingsvideoclips auf dem 1,9""-Farbdisplay des Sansa Fuze an.
    Lauschen Sie dem FM-Radio mit 40 voreingestellten Sendern oder probieren Sie den integrierten Sprachrekorder aus. Mit einer unglaublich starken Akkuleistung in einem 0,3"" schmalen Gerät setzt der Sansa Fuze Zeichen.
    ";2;False;0;;;Sandisk Sansa Fuze MP3-/Video-Player 4 GB mit Radio;sandisk-sansa-fuze-8-gb-schwarz;True;True;P-1600;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;89.0000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;40166,6556365741;52;8;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000480-sandisk-sansa-fuze-8-gb-schwarz.jpg;;;2;;False;;;;;False;False;False;;;;;False;;;;;; -5;0;True;Apple iPod shuffle 1 GB blau;Apple iPod shuffle 1 GB blau;"

    Apple iPod shuffle 1GB blue 

     
    Wie seine größeren Geschwister besitzt auch der iPod shuffle kreisförmig
    angeordnete, ergonomische Bedienelemente.
    Der Kopfhöreranschluss am iPod shuffle dient gleichzeitig als Dock-Anschluss.
    Drehen Sie den iPod shuffle auf die Seite und setzen Sie ihn in das mitgelieferte Dock ein.
    Dank eines stabilen, integrierten Clips lässt sich der iPod shuffle fast überall befestigen.
    Klemmen Sie ihn am T-Shirt, am Hemdkragen oder am Trageriemen von Rucksack oder Handtasche fest.
    Lassen Sie sich aufs Ungewisse ein: Verwenden Sie den Schalter für die Zufallswiedergabe,
    um den Inhalt Ihres iPod shuffle neu zu mischen.
    verbesserte Kopfhörer und das neue iTunes 8.0
     
    Größe ist relativ
    Natürlich kennen Sie das Sprichwort ""Weniger ist mehr"". Wie wahr dieses Sprichwort ist, beweist der neue iPod shuffle, der gerade einmal 4,1 cm lang ist, nur etwa 15 Gramm wiegt und Platz für bis zu 240 Songs bietet. Hinzu kommt, dass Sie Ihre Musik damit bis zu 12 Stunden lang ohne Unterbrechung hören können.(2) Man kann also mit Fug und Recht behaupten, dass der winzige iPod shuffle bei halber Größe viel mehr zu bieten hat, als man ihm auf den ersten Blick zutraut.
    Immer im Trend
    Klemmen Sie ihn an die Jeans. Oder an Ihre Handtasche. Egal, wo Sie ihn anklippen, mit Ihrem iPod shuffle haben Sie Ihre Musik jederzeit griffbereit. Das Gehäuse aus eloxiertem Aluminium passt übrigens zu jedem Outfit. Einfach festklemmen und einschalten - Sie werden ohne Zweifel viele begehrliche Blicke auf sich ziehen.
     
     
    Perfekt synchronisiert
    Damit Sie Ihren iPod shuffle mit bis zu 240 Songs füllen können, müssen Sie zuerst iTunes gratis laden. Danach können Sie für je 99 Cent Musiktitel aus dem iTunes Store laden oder von Ihren CDs importieren. Zum Synchronisieren schließen Sie das mitgelieferte Dock an den USB-Anschluss Ihres Mac oder PC an und übertragen die Musik aus iTunes, indem Sie den iPod shuffle in das Dock einsetzen.
     
     
    Neu abgemischt
    In Ihrer iTunes Bibliothek befinden sich mehr als 240 Titel? Kein Problem. Überlassen Sie es iTunes, Ihren iPod shuffle automatisch zu füllen und genießen Sie Ihre Musik jedes Mal neu. Pop folgt auf Jazz, Rock auf Ra!

     
    ";2;False;0;;;Apple iPod shuffle 1 GB blau;apple-ipod-shuffle-1-gb-blau;True;True;P-1110;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;49.9000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;40160,8793055556;36;1;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000398-apple-ipod-shuffle-2-gb-blau.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000399-apple-ipod-shuffle-2-gb-blau.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000400-apple-ipod-shuffle-2-gb-blau.jpg;3;;False;;;;;False;False;False;;;;;False;;;;;; -5;0;True;Apple iPod shuffle 1 GB pink;Apple iPod shuffle 1 GB pink;"

    Apple iPod shuffle 1GB pink 

     
    Wie seine größeren Geschwister besitzt auch der iPod shuffle
    kreisförmig angeordnete, ergonomische Bedienelemente.
    Der Kopfhöreranschluss am iPod shuffle dient gleichzeitig als Dock-Anschluss.
    Drehen Sie den iPod shuffle auf die Seite und setzen Sie ihn in das mitgelieferte Dock ein.
    Dank eines stabilen, integrierten Clips lässt sich der iPod shuffle fast überall befestigen.
    Klemmen Sie ihn am T-Shirt, am Hemdkragen oder am Trageriemen von Rucksack oder Handtasche fest.
    Lassen Sie sich aufs Ungewisse ein: Verwenden Sie den Schalter für die Zufallswiedergabe,
    um den Inhalt Ihres iPod shuffle neu zu mischen.
    verbesserte Kopfhörer und das neue iTunes 8.0
     
    Größe ist relativ
    Natürlich kennen Sie das Sprichwort ""Weniger ist mehr"". Wie wahr dieses Sprichwort ist, beweist der neue iPod shuffle, der gerade einmal 4,1 cm lang ist, nur etwa 15 Gramm wiegt und Platz für bis zu 240 Songs bietet. Hinzu kommt, dass Sie Ihre Musik damit bis zu 12 Stunden lang ohne Unterbrechung hören können.(2) Man kann also mit Fug und Recht behaupten, dass der winzige iPod shuffle bei halber Größe viel mehr zu bieten hat, als man ihm auf den ersten Blick zutraut.
    Immer im Trend
    Klemmen Sie ihn an die Jeans. Oder an Ihre Handtasche. Egal, wo Sie ihn anklippen, mit Ihrem iPod shuffle haben Sie Ihre Musik jederzeit griffbereit. Das Gehäuse aus eloxiertem Aluminium passt übrigens zu jedem Outfit. Einfach festklemmen und einschalten - Sie werden ohne Zweifel viele begehrliche Blicke auf sich ziehen.
     
     
    Perfekt synchronisiert
    Damit Sie Ihren iPod shuffle mit bis zu 240 Songs füllen können, müssen Sie zuerst iTunes gratis laden. Danach können Sie für je 99 Cent Musiktitel aus dem iTunes Store laden oder von Ihren CDs importieren. Zum Synchronisieren schließen Sie das mitgelieferte Dock an den USB-Anschluss Ihres Mac oder PC an und übertragen die Musik aus iTunes, indem Sie den iPod shuffle in das Dock einsetzen.
     
     
    Neu abgemischt
    In Ihrer iTunes Bibliothek befinden sich mehr als 240 Titel? Kein Problem. Überlassen Sie es iTunes, Ihren iPod shuffle automatisch zu füllen und genießen Sie Ihre Musik jedes Mal neu. Pop folgt auf Jazz, Rock auf Ra!
    ";2;False;0;;;Apple iPod shuffle 1GB pink;apple-ipod-shuffle-1-gb-pink;True;True;P-1120;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;49.9000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;40158,9546990741;36;1;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000118-apple-ipod-shuffle-2-gb-pink.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000119-apple-ipod-shuffle-2-gb-pink.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000120-apple-ipod-shuffle-2-gb-pink.jpg;2;;False;;;;;False;False;False;;;;;False;;;;;; -5;0;True;Apple iPod shuffle 1 GB grün;Apple iPod shuffle 1 GB grün;"
    Apple iPod shuffle 1GB grün

     
    Wie seine größeren Geschwister besitzt auch der iPod shuffle kreisförmig angeordnete, ergonomische Bedienelemente.
    Der Kopfhöreranschluss am iPod shuffle dient gleichzeitig als Dock-Anschluss.
    Drehen Sie den iPod shuffle auf die Seite und setzen Sie ihn in das mitgelieferte Dock ein.
    Dank eines stabilen, integrierten Clips lässt sich der iPod shuffle fast überall befestigen.
    Klemmen Sie ihn am T-Shirt, am Hemdkragen oder am Trageriemen von Rucksack oder Handtasche fest.
    Lassen Sie sich aufs Ungewisse ein: Verwenden Sie den Schalter für die Zufallswiedergabe, um den Inhalt Ihres iPod shuffle neu zu mischen.
    verbesserte Kopfhörer und das neue iTunes 8.0
     
    Größe ist relativ
    Natürlich kennen Sie das Sprichwort ""Weniger ist mehr"". Wie wahr dieses Sprichwort ist, beweist der neue iPod shuffle, der gerade einmal 4,1 cm lang ist, nur etwa 15 Gramm wiegt und Platz für bis zu 240 Songs bietet. Hinzu kommt, dass Sie Ihre Musik damit bis zu 12 Stunden lang ohne Unterbrechung hören können.(2) Man kann also mit Fug und Recht behaupten, dass der winzige iPod shuffle bei halber Größe viel mehr zu bieten hat, als man ihm auf den ersten Blick zutraut.
    Immer im Trend
    Klemmen Sie ihn an die Jeans. Oder an Ihre Handtasche. Egal, wo Sie ihn anklippen, mit Ihrem iPod shuffle haben Sie Ihre Musik jederzeit griffbereit. Das Gehäuse aus eloxiertem Aluminium passt übrigens zu jedem Outfit. Einfach festklemmen und einschalten - Sie werden ohne Zweifel viele begehrliche Blicke auf sich ziehen.
     
     
    Perfekt synchronisiert
    Damit Sie Ihren iPod shuffle mit bis zu 240 Songs füllen können, müssen Sie zuerst iTunes gratis laden. Danach können Sie für je 99 Cent Musiktitel aus dem iTunes Store laden oder von Ihren CDs importieren. Zum Synchronisieren schließen Sie das mitgelieferte Dock an den USB-Anschluss Ihres Mac oder PC an und übertragen die Musik aus iTunes, indem Sie den iPod shuffle in das Dock einsetzen.
     
     
    Neu abgemischt
    In Ihrer iTunes Bibliothek befinden sich mehr als 240 Titel? Kein Problem. Überlassen Sie es iTunes, Ihren iPod shuffle automatisch zu füllen und genießen Sie Ihre Musik jedes Mal neu. Pop folgt auf Jazz, Rock auf Ra!
    ";2;False;0;;;Apple iPod shuffle 1 GB grün;apple-ipod-shuffle-1-gb-gruen;True;True;P-1100;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;49.9000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;40158,9517476852;36;1;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000429-apple-ipod-shuffle-2-gb-grun.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000430-apple-ipod-shuffle-2-gb-grun.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000431-apple-ipod-shuffle-2-gb-grun.jpg;2;;False;;;;;False;False;False;;;;;False;;;;;; -5;0;True;Panasonic DMR EX 72 SEG DVD HDD RECORDER;Panasonic DMR EX 72 SEG DVD- und HDD-Rekorder 160 GB;"

    Panasonic DMR EX 72 SEG DVD- und HDD-Rekorder 160 GB

    mit integriertem DVB-S Tuner
     
    HDD/DVD Recorder/Farbe: schwarz/ Festplattenspeicher: 160 GB/ Tuner: DVB-S/ Sonderfunktionen: EPG/ Anschlüsse: 2x Scart, 3x Cinch (Komponenten/YUV),
    Cinch (Composite / Video / FBas), HDMI (mit HDCP), S-Video (Hosiden), USB/ B: 430 mm/ H: 59 mm
    Art HDD/DVD Recorder
    Farbe schwarz
    Festplattenspeicher 160 GB
    Tuner DVB-S
    Sonderfunktionen EPG
    Anschlüsse 2x Scart / 3x Cinch (Komponenten/YUV) / Cinch (Composite / Video / FBas) / HDMI (mit HDCP) / S-Video (Hosiden) / USB
    Breite 430 mm
    Höhe   59 mm
    Tiefe  286 mm
    Gewicht netto 3,7 kg
    Aufnahme DVD+R / DVD+RW / DVD-R / DVD-RAM / DVD-RW
    Wiedergabe Audio-CD / CD-R / CD-RW / DVD / DVD+R / DVD+RW / DVD-R / DVD-RAM / DVD-RW / JPEG / MP3 / S-Video CD / WMA
    ";2;False;0;;;Panasonic DMR EX 72 SEG DVD HDD RECORDER;panasonic-dmr-ex-72-seg-dvd-hdd-recorder;True;True;P-1850;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;2,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;399.0000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;40155,86625;62;12;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000471-panasonic-dmr-ex-72-seg-dvd-hdd-recorder.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000472-panasonic-dmr-ex-72-seg-dvd-hdd-recorder.jpg;;1;;False;;;;;False;False;False;;;;;False;;;;;; -5;0;True;Panasonic DMR EH 495 EG K 160 GB DVD/ HDD Rekorder;Panasonic DMR EH 495 EG K 160 GB DVD/ HDD Rekorder;"
    Panasonic DMR EH 495 EG K 160 GB DVD/ HDD Rekorder

    HDMI, DivX-zertifiziert, USB 2.0

    Mit dem DMR-EH495 präsentiert Panasonic, Marktführer bei DVD-Rekordern, neue Multiformat-DVD-Festplatten-Kombinationen. Sie bieten alle Komfortmerkmale der testbewährten Vorjahresmodelle, begeistern mit noch mehr Details sowie einer intuitiven Benutzerführung. Die mit einem analogen Tuner ausgestatteten Geräte verfügen über eine integrierte Festplatte und zeichnen auf alle gängigen DVD-Formate auf. Neben der Aufnahme des Fernsehprogramms überzeugen die neuen Rekorder als digitales Fotoalbum sowie Musik-Jukebox und werden somit zur Unterhaltungszentrale im Wohnzimmer. Komfortfunktionen wie der elektronische Programmführer Guide Plus+ mit Suchfunktion, eine automatische Kapitelerstellung, umfangreiche Anschlussmöglichkeiten sowie ein hochwertiger Upscaler machen die Rekorder zu Multitalenten. Darüber hinaus schont der weiterentwickelte Eco-Modus Umwelt und Geldbeutel.
     
    Die Rekorder DMR-EH495 zeigen sich als wahre Alleskönner und zeichnen auf Festplatte oder DVD auf.
    Sie verarbeiten alle gängigen DVD-Formate wie DVD-RW, -R (DL), DVD+RW/+R (DL) sowie DVD-RAM. Außerdem können CDs, CD-R/-RWs sowie MP3- und JPEG-Daten sowohl von DVD als auch CD abgespielt werden.
    Die integrierte Festplatte erlaubt die Aufzeichnung von Fernsehprogrammen. Somit ist auch bei längerer Abwesenheit genügend Platz für die Lieblingsserie vorhanden.
    Dank des integrierten, elektronischen Programmführers Gemstar Guide Plus+ erfolgen die Programmauswahl und Timerprogrammierung kinderleicht und intuitiv.
    Die übersichtliche Darstellung des Fernsehprogramms bietet neben einer Genre-Auswahl zusätzlich eine gezielte Suche nach Stichworten.
     
    So kann beispielsweise direkt nach Schauspielern, Themen oder Sportarten gesucht werden. Neben dieser Funktion arbeiten die neuen Rekorder mit einer automatischen Kapitelerstellung bei der Aufzeichnung.
    Dadurch können während der anschließenden Wiedergabe unerwünschte Programmsequenzen auf Knopfdruck übersprungen oder eine Szene blitzschnell gefunden werden.
    Mit Pause Live TV kann zudem das laufende Fernsehprogramm jederzeit mit einem Druck auf die Pause-Taste angehalten und zu einem späteren Zeitpunkt weitergeschaut werden.
    Dank Quick Start-Funktion sind die Rekorder innerhalb einer Sekunde einsatzbereit, so dass kein Film und keine Aufzeichnung verpasst werden.
     
    • Multiformat-DVD-Festplatten-Kombination
    • Intuitive Benutzerführung
    • Neben der Aufnahme des Fernsehprogramms überzeugen die neuen Rekorder als digitales Fotoalbum sowie
    • Musik-Jukebox
    • Elektronische Programmführer Guide Plus+ mit Suchfunktion
    • Umfangreiche Anschlussmöglichkeiten
    ";2;False;0;;;Panasonic DMR EH 495 EG K;panasonic-dmr-eh-495-eg-k-160-gb-dvd-hdd-rekorder;True;True;P-1840;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;319.0000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;40155,8616898148;62;12;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000428-panasonic-dmr-eh-495-eg-k-160-gb-dvd-hdd-rekorder.jpg;;;3;;False;;;;;False;False;False;;;;;False;;;;;; -5;0;True;"HP Compaq Mini 110c-1110sg 10.1 Zoll Netbook ";"HP Compaq Mini 110c-1110sg 10.1 Zoll Netbook ";"
    HP Compaq Mini 110c-1110sg 10.1 Zoll Netbook
     
    Intel Atom N270 1.6GHz, 1GB RAM, 160GB HDD, Intel GMA 950, Win XP Home
     
    Leicht und kompakt
    Der Compaq Mini 110c wiegt 1,3 kg (mit 6-Zellen-Akku) und ist ca. 5,5 cm hoch – er ist damit sehr kompakt und fällt ins Auge
     
    Elegantes Design
    Der Compaq Mini 110c glänzt mit einem eleganten Gehäuse im neuem Imprint-Finish ""Unity"", einem Karomuster, das ins Auge fällt.
     
    Ständig in Verbindung
    Webcam und Mikrofon sind im Compaq Mini integriert und bieten per WLAN und optionalem WWAN zahlreiche Möglichkeiten zur Pflege sozialer Kontakte; Video-Chats und Video-Konferenzen, die bislang nur zuhause möglich waren, können jetzt im Park, im Cafe oder am Flughafen geführt werden
     
    Information und Kommunikation auch unterwegs
    Mit dem 10,1-Zoll-BrightView-Display, Original Windows® XP Home, der großen Tastatur (92 % der vollen Größe), drei USB-Anschlüssen und einem 5-in-1 Kartenleser sind Informationen, Kommunikation und Unterhaltung im Internet überall bequem zugänglich.
    ";2;False;0;;;"HP Compaq Mini 110c-1110sg 10.1 Zoll Netbook ";hp-compaq-mini-110c-1110sg-101-zoll-netbook;True;True;P-0870;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;259.9000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;40151,9990046296;6;39;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000598-hp-compaq-mini-110c-1110sg-101-zoll-netbook.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000599-hp-compaq-mini-110c-1110sg-101-zoll-netbook.jpg;;2;;False;;;;;False;False;False;;;;;False;;;;;; -5;0;True;Apple iPod Classic 120 GB schwarz;"Apple iPod Classic 120 GB schwarz ";"

    Apple iPod Classic 120 GB schwarz

     
    iPod classic: Freiraum -Und zwar jede Menge.
    120 GB sind wirklich eine ganze Menge Platz. Da lässt sich eine komplette Mediathek locker unterbringen und überallhin mitnehmen.
     
    Ein musikalisches Genie
    Stellen Sie vor, Sie hören einen Song. Toll wären jetzt andere Titel, die gut dazu passen. Was machen Sie? Ganz einfach: Sie verwenden die neue Funktion ""Genius"". Diese findet die Songs in Ihrer Mediathek, die gut zusammenpassen. Sie erhalten eine Genius Wiedergabeliste, die Sie sofort anhören, sichern oder sogar aktualisieren können. Verlassen Sie sich also auf den Genius von iTunes, wenn Sie einen Mix wollen, auf den Sie selbst nicht gekommen wären.
     
    Platz satt
    Der iPod classic bietet mit seinen 120 GB Speicherkapazität Platz für bis zu 30.000 Songs, 180 Stunden Videos, 20.000 Fotos oder eine beliebige Kombination dieser Inhalte. Und mit bis zu 36 Stunden Batterielaufzeit beweist der iPod classic auch ganz schön viel Kondition.
     
    Spaß auf Knopfdruck
    Sie findeen immer ganz leicht genau das, was Sie sehen oder hören wollen. Mit dem Click Wheel können Sie mit ""Cover Flow"" Ihre Alben durchblättern, oder Sie stöbern über verschiedene Kategorien wie Wiedergabeliste, Künstler, Album oder Musikrichtung in Ihren Songs und Videos. Sie können natürlich auch nach einem bestimmten Titel oder Interpreten suchen. Lust auf einen neuen Mix? Klicken Sie einfach auf ""Zufällige Titel"".
     
    Filme und Fernsehsendungen ansehen
    Auf dem fantastischen 2,5"" Display kommen Videos richtig zur Geltung. Sie können im iTunes Store Filme kaufen oder ausleihen, Fernsehsendungen kaufen und Video-Podcasts laden. Dann können Sie alles mit Ihrem iPod classic synchronisieren und immer und überall ansehen.
     
     
    Spiele auf dem iPod
    Wenige Fingertipps, viele Stunden Spielspaß. Vortex, iQuiz und Klondike sind schon auf dem iPod classic vorinstalliert, im iTunes Store können Sie weitere dazukaufen, z. B. Cake Mania. Alle iPod Spiele sind speziell für die iPod Oberfläche optimiert.
     
    Fotos zeigen
    Ihre Fotos aus iPhoto auf einem Mac oder aus Adobe Photoshop Elements und Adobe Photoshop Album auf einem PC bekommen Sie mit iTunes auf den iPod classic. Sie können Diashows mit Musik und Übergängen auf dem iPod classic oder mit optional erhältlichen Apple Komponenten oder mit einem Composite-AV-Kabel sogar auf dem Fernseher zeigen.
     
    Umweltverträglichkeit
    Der iPod classic steht für das kontinuierliche Engagement von Apple in puncto Umweltschutz. Die folgenden Merkmale tragen zu einer geringen Umweltbelastung bei:
     
        Arsenfreies Displayglas
        Ohne bromhaltige Flammschutzmittel
        Display mit LED-Hintergrundbeleuchtung ohne Quecksilber
        Frei von PVC
        Recyclingfähiges Gehäuse aus Aluminium und Edelstahl
     
    Produktbeschreibungen
    Freiraum. Und zwar jede Menge. 160 GB sind wirklich eine ganze Menge Platz. Da lässt sich eine komplette Mediathek locker unterbringen und überallhin mitnehmen.
     
    > Highlights
    - Click Wheel
    - Frequenzbereich: 20 Hz bis 20.000 Hz
    - Weitere unterstützte Audioformate: Protected AAC (aus dem iTunes Store), MP3 VBR, Audible (Formate 2, 3, 4, Audible Enhanced Audio, AAX und AAX+), Apple Lossless und WAV
    - Platz für bis zu 35.000 Songs im 128 KBit/Sek. AAC-Format
    - Platz für bis zu 20.000 vom iPod anzeigbare Fotos
    - Platz für bis zu 180 Stunden Videomaterial
    - Speichert Daten auf einer USB-Festplatte
    - Akkuladezeit: ca. 4 Std. (schnelles Laden auf 80%ige Kapazität in 2 Std.)
     
    > Grundeigenschaften
    - Breite: 103.5 mm
    - Höhe: 61.8 mm
    - Tiefe: 10.5 mm
    - Gewicht: 140.0 g
    - Farbe: Schwarz
     
    > Wiedergabeformate Audio
    - AAC
    - MP3
    - WAV
     
    > Akku
    - Akkutyp: Li-Ion
     
    > Display
    - Displaytechnologie: LCD
    - 2.5- Display
    - Bilddiagonale: 6.35 cm
    - Auflösung Breite: 320 Pixel
    - Auflösung Höhe: 240 Pixel
    - Hintergrundbeleuchtung: ja
     
    > Speicher
    - Speicherkapazität 120 GB
     
    > Anschlüsse
    - USB
    - USB-Standard 2.0
     
    > Audio-Anschlüsse
    - Headsetanschluss: 3,5 mm Klinke
    - ipod-Anschluss via IPOD Connector
     
    > Lieferumfang
    - iPod classic
    - Apple Earphones
    - USB 2.0 Kabel
    - Dock-Adapter
    - Dokumentation
     
    > Umweltverträglichkeit
    Der iPod nano steht exemplarisch für das Engagement von Apple in puncto Umweltschutz. Die folgenden Merkmale des iPod nano tragen zu seiner geringeren Umweltbelastung bei:
    - Arsenfreies Glas
    - Frei von bromhaltigen Flammschutzmitteln
    - Frei von Quecksilber
    - Frei von PVC
    - Besonders recyclingfähig
    ";2;False;0;;;Apple iPod Classic 120 GB schwarz;apple-ipod-classic-120-gb-schwarz;True;True;P-1420;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;209.9000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;40151,9525462963;50;1;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000284-apple-ipod-classic-160-gb-schwarz.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000285-apple-ipod-classic-160-gb-schwarz.jpg;;2;;False;;;;;False;False;False;;;;;False;;;;;; -5;0;True;"Garmin nüvi 1370T Navigationssystem ";"Garmin nüvi 1370T Navigationssystem Europa USA ";"
    Garmin nüvi 1370T Navigationssystem
     
     

    TMC, 4,3"" Display, Europa / USA / Kanada, ecoRoute, Fußgängernavigation, Bluetooth

     
     
     
    Mobile Navigation für die ganze Familie, dank Fahrspurassistent, intelligentem TMC, und Text-to-Speech eine rund-um-sorglos Navigation
    Übersichtliche und einfache Navigation mit 4,3 Zoll Display mit Fahrspurassistent + TMC Verkehrsfunkempfänger zur Stauumfahrung
    Kartenmaterial für Europa, USA und Canada intern vorinstalliert
    Inklusive ecoRoute die Garmin Spritspar-Funktion und echter Fußgängernavigation mit optionalen CityXplorer Stadtplänen für Bus und Bahn
    Lieferumfang: Garmin nüvi 1370T mit Kartenmaterial Europa/ USA/ Canada, KFZ-Anschlusskabel mit TMC Verkehrsfunkempfänger,
    Saugnapfhalterung für die Windschutzscheibe, Armaturenhalterung, Kurzanleitung
    ";2;False;0;;;"Garmin nüvi 1370T Navigationssystem ";garmin-nuevi-1370t-navigationssystem;True;True;P-2100;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;359.0000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;40148,9306828704;67;44;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000589-garmin-nuvi-1370t-navigationssystem.jpg;;;2;;False;;;;;False;False;False;;;;;False;;;;;; -5;0;True;NAVIGON 8410 Navigationssystem Europa;" NAVIGON 8410 Navigationssystem Europa 5"" Echtglas-Display";"
    NAVIGON 8410 Navigationssystem Europa
     
     
    5"" Echtglas-Display, West & Osteuropa 40 Länder, Bluetooth, TMC Pro, Real City 3D, Voice Interaction Pro
     
     
    5-Zoll-Touchdisplay 16:9
    Fußgängernavigation
    Reality View Pro
    Fahrspurassistent Pro
    Radar-Info
    Geschwindigkeitsassistent
    Reale Beschilderung Pro
    Clever Parking
    Text-to-Speech für Straßennamen
    Bluetooth Freisprecheinrichtung
    Professionelle Sprachsteuerung 2.0
    Landmark View 3D/City View 3D
    Panorama View 3D
    Latest Map Guarantee
    Europakarte (40 Länder)
    Abmessungen: 138 mm x 83,5 mm x 18,7mm (B/H/T)
    Lieferumfang: NAVIGON 8410, Kurzanleitung, KfZ-Ladekabel mit integrierter TMC Antenne,
    Design-Aktivhalterung, USB-Kabel, vorinstalliertes Europa-Kartenmaterial
    ";2;False;0;;;"NAVIGON 8410 Navigationssystem ";navigon-8410-navigationssystem-europa;True;True;P-2170;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;449.0000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;40148,9205902778;"68;2095";14;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000470-navigon-8410-navigationssystem-europa.jpg;;;2;;False;;;;;False;False;False;;;;;False;;;;;; -5;0;True;Apple iPod shuffle 2 GB blau;Apple iPod shuffle 2 GB blue;"

    Apple iPod shuffle 2GB blau 

     
     
    Wie seine größeren Geschwister besitzt auch der iPod shuffle kreisförmig
    angeordnete, ergonomische Bedienelemente.
    Der Kopfhöreranschluss am iPod shuffle dient gleichzeitig als Dock-Anschluss.
    Drehen Sie den iPod shuffle auf die Seite und setzen Sie ihn in das mitgelieferte Dock ein.
    Dank eines stabilen, integrierten Clips lässt sich der iPod shuffle fast überall befestigen.
    Klemmen Sie ihn am T-Shirt, am Hemdkragen oder am Trageriemen von Rucksack oder Handtasche fest.
    Lassen Sie sich aufs Ungewisse ein: Verwenden Sie den Schalter für die Zufallswiedergabe,
    um den Inhalt Ihres iPod shuffle neu zu mischen.
    verbesserte Kopfhörer und das neue iTunes 8.0
     
    Einfach Musik anhaben mit dem Apple iPOD SHUFFLE 2GB.Tragen Sie bis zu 500 Songs am Ärmel. Oder am Gürtel. Oder am Sportoutfit. Das Erkennungszeichen für Musikfans - den Apple iPOD SHUFFLE. Füllen Sie Ihren Apple iPOD SHUFFLE silber 1GB spielend einfach. iTunes ist der Store für Unterhaltungsinhalte. Ihre super organisierte Musiksammlung und Jukebox. Und die Software, mit der Sie Ihren Apple iPOD SHUFFLE mit einem Mausklick füllen. Das farbige Gehäuse aus eloxiertem Aluminium in silber passt zum genial einfachen Design des Apple iPOD SHUFFLE.
     
    Leistungseigenschaften
     
    2 GB Flash-Memory Speicher
    min. Audio-Datenrate: 8 KBit/s
    max. Audio-Datenrate: 320 KBit/s
    Frequenzgang-Untergrenze: 20 Hz
    Frequenzgang-Obergrenze: 20000 Hz
     
    Formate/Standards
     
    MP3-Standard
    AAC + MP3 Standard
    WAV-Dateiformat kompatibel
    Audible-Format kompatibel
    AIFF-Format kompatibel
     
    Bedienung
     
    Musiktitel-Verwaltung
     
    Leistungsaufnahme/Spannungsversorgung

    Li-Polymer Akku
    12 Std. Spieldauer mit Akku
    Ladezeit für Akku: 4 Std.
     
    Anschlüsse
     
    Kopfhörer-Anschluß
    USB-Schnittstelle
    Anschluß für Docking-Station
     
    Gehäuse-Eigenschaften
     
    Breite: 4.12 cm
    Höhe: 2.73 cm
    Tiefe: 1.05 cm
    Gewicht: 15.5 g
    ";2;False;0;Apple iPod shuffle 2 GB blau;Apple iPod shuffle 2 GB blau;Apple iPod shuffle 2 GB blau;apple-ipod-shuffle-2-gb-blau;True;True;P-1150;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;64.9000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;40148,0555902778;37;1;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000398-apple-ipod-shuffle-2-gb-blau.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000399-apple-ipod-shuffle-2-gb-blau.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000400-apple-ipod-shuffle-2-gb-blau.jpg;2;;False;;;;;False;False;False;;;;;False;;;;;; -5;0;True;"Logitech EX 110 Desktop Tastatur/Maus ";Logitech EX 110 Desktop Tastatu / Maus;"
    Logitech EX 110 Desktop Tastatur/Maus
     
     
    Zuverlässig und kabellos:
    Schnelle, kabellose 27-MHz-Leistung
    Sondertasten: Zugriff auf Musik, Video, Lautstärke, E-Mail, Internet und mehr.
    Programmierbare F-Tasten: öffnen häufig genutzter Anwendungen, Websites oder Dateien.
    Spritzwassergeschütztes Design
    Maus: Schnell ansprechende Optik: Erleben Sie eine Auflösung von 800 dpi.
     
    Lieferumfang:
    Logitech Cordless Keyboard und Cordless Optical Mouse,
    kompakter USB-/PS/2-Funkempfänge, USB-PS/2-Adapter
     
    ";2;False;0;;;"Logitech EX 110 Desktop Tastatur/Maus ";logitech-ex-110-desktop-tastaturmaus;True;True;P-2810;;;False;0;False;;False;False;0;False;0;1;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;24.9000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;40143,0133101852;"21;2095";11;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000392-logitech-ex-110-desktop-tastaturmaus.jpg;;;1;;False;;;;;False;False;False;;;;;False;;;;;; -5;0;True;"TomTom GO 940 Live Navigationssystem ";"TomTom Go 940 Live Navigationssystem Europa Nordamerika ";"
    TomTom GO 940 Live Navigationsgerät mit Sprachsteuerung

     
    inkl. Europa-Karten, USA, Kanada, TMC, Live Services

     
    Clevere Navigation mit Echtzeitinfos für Vielfahrer und dem neuesten Kartenmaterial von West- und Osteuropa, USA und Kanada, TomTom IQ Routes -
    jeden Tag zu jeder Tageszeit die optimalste Route, TomTom Map Share, vereinfachte Bedienung durch brillianten 4,3-Zoll-Touchscreen und Sprachsteuerung,
    verbesserter Fahrspurassistent zur einfacheren Orientierung an unübersichtlichen Autobahnkreuzen, hochwertiger Bluetooth-Kfz-Freisprecheinrichtung sowie einem FM-Transmitter und MP3-Player.
    TomTom GO 940 Live inklusive 3 Monate Probe-Abo zu Live-Dienste in allen LIVE Ländern. Echtzeit-Empfang von Premiuminformationen zu Ihrer Route: HD Traffic, Lokale Suche mit Google, Sicherheitswarnungen und mehr
     Sprachsteuerung - mehr als 100 Funktionen einfach per Sprachbefehl aktivieren
    Verbesserte Positionsbestimmung - unterbrechungsfreie Navigation, sogar in Tunneln
    Fahrspurassistent - zum einfachen Navigieren an unübersichtlichen Kreuzungspunkten
    GO 940 LIVE: Karten von Europa (WE u. OE), den USA und Kanada vorinstalliert, LIVE-Services- fahren Sie immer aktuell und zuverlässig informiert mit Echtzeit-Informationen
    sowie mit IQ Routes damit fahren Sie zu jeder Tageszeit auf der cleversten Route
    Lieferumfang: TomTom GO 940 LIVE, aktive Halterung, Autoladegerät, Halterung für Zuhause, Benutzerhandbuch, CD-ROM (TomTom HOME )

     
    ";2;False;0;;;;tomtom-go-940-live-navigationssystem;True;True;P-2010;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;304.9000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;40136,6372800926;66;4;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000391-tomtom-go-940-live-navigationssystem.jpg;;;2;;False;;;;;False;False;False;;;;;False;;;;;; -5;0;True;Apple iPod Touch 8 GB schwarz;"Apple iPod Touch 8 GB schwarz mit integrierter WiFi Funktion ";"
    Apple iPod Touch 32 GB schwarz mit integrierter WiFi Funktion

    Der iPod touch kann alles, was du am iPod toll findest. Und noch vielmehr. Schlankes neues Design. Mit seinem fantastisch flachen Edelstahl-Design liegt der iPod touch mit dem 3.5 Zoll Touch-Display jetzt noch besser in der Hand. Mobil im Spiel. Durch revolutionäre Technologien wie das Multi-Touch-Display, der Beschleunigungssensor und 3D-Grafiken macht das Spielen auf dem iPod touch besonders viel Spaß. Schlaue Musik Mit der neuen Funktion ""Genius"" wird der iPod touch zu Deinem superintelligenten, persönlichen DJ.
    Nur ein paar Fingertipps, und Genius erzeugt eine Wiedergabeliste mit Songs Deiner Mediathek, die gut zusammenpassen. Internet überall Internetzugang überall, wo ein drahtloses Netzwerk zur Verfügung steht, damit Sie immer mit dabei sind. Multitouch-Oberfläche: Die revolutionäre Technologie des iPhone und die Software Version 3.1 stecken in diesem genialen iPod. Das brillante Breitformat-Display rückt Ihre Videos und Spiele ins beste Licht und dank OpenGL sehen die Spiele jetzt noch besser aus Surfen Sie mit Safari im Web und sehen Sie YouTube Videos auf dem iPod mit integrierter Wi-Fi Funktionalität an. Mit Ihrem iPod touch können Sie im iTunes Wi-Fi Music Store nach Songs suchen, Hörproben abspielen und Titel kaufen.
    Lieferumfang: iPod touch, Ohrhörer, USB 2.0 Kabel, Kurzanleitung
     
    Schlankes neues Design
    Mit seinem fantastisch flachen Edelstahl-Design liegt der iPod touch so gut in der Hand wie nie zuvor. Ebenfalls Eindruck machen der neue Lautstärkeregler und der integrierte Lautsprecher.

    Spiele
    Speziell auf die iPod touch Technologie zugeschnittene Spiele sind nur noch einen Fingertipp entfernt. Stöbere in hunderten von Spielen im App Store direkt auf Deinem iPod touch, und wenn Du gefunden hast, was Du suchst, kannst Du es einfach laden und dann kann es losgehen.
     
    Steuerung per Fingertipp
    Viele Spiele auf dem iPod touch nutzen die Multi-Touch-Technologie für besonders exakte Fingertipp-Steuerung der verschiedenen Spielelemente. Beim Schach ziehst Du mit dem Finger die Figuren, bei Würfelspielen bewegst Du die Würfel. Durch Ziehen mit zwei Fingern kannst Du die Anzeige vergrößern und verkleinern, Deine Figur nach links oder rechts drehen, und durch einfaches Antippen triffst Du eine Auswahl.
     
    Musik
    Blättere in den Albumcovern Deiner Musiksammlung. Erstelle immer wieder neue Genius Wiedergabelisten und erweitere Deine Sammlung aus dem iTunes Wi-Fi Music Store überall, wo ein Wi-Fi-Hotspot in der Nähe ist.
    Mit Cover Flow lebt das Flair einer CD- oder Plattensammlung wieder auf. Wer erinnerst sich nicht an das Gefühl beim Durchblättern der Sammlung? Das gibt es jetzt auch auf dem iPod touch: einfach iPod drehen, durch die Cover blättern, ein Album auswählen, fertig. Ein Fingertipp aufs Cover, und schon siehst Du die Titelliste, ein weiterer Tipp spielt die Musik ab, und dabei kannst Du sogar die Songtexte anzeigen.
     
    Ein Musikgenie
    Stell Dir vor, Du hörst einen Song. Toll wären jetzt andere Titel, die gut dazu passen. Was machst du? Ganz einfach: Du verwendest die neue Funktion ""Genius"". Diese findet die Songs in Deiner Mediathek, die gut zusammenpassen. Du erhältst eine Genius Wiedergabeliste, die Du sofort anhören, sichern oder sogar aktualisieren kannst. Verlass Dich also auf den Genius von iTunes, wenn Du einen Mix willst, auf den Du selbst nicht gekommen wärst.
     
    Lautsprecher integriert
    Mit dem integrierten Lautsprecher kannst Du Musik und Gespräche ohne Kopfhörer hören – perfekt für zwangloses Hörvergnügen.

    Längere Batterielaufzeit
    Jetzt kannst Du noch länger rocken (und ansehen und spielen). Der iPod touch hält bis zu 36 Stunden bei Musik oder bis zu 6 Stunden bei Videos durch. Das reicht für drei oder vier Filme zwischen den Ladevorgängen.
     
    Internet
    Surfe im Internet mit Wi-Fi. Du kannst detailgenaue HTML-E-Mails mit Anlagen empfangen und Wegbeschreibungen und aktuelle Verkehrsinformationen abrufen. Auch als YouTube-Fan entgeht Dir nichts.
     
    Überall ins Internet
    Der iPod touch ist der einzige iPod mit kabellosem 802.11b/g Internetzugriff. Bei bestehender Wi-Fi-Verbindung kannst Du im Internet surfen und Nachrichten lesen, Sportergebnisse sehen, Rechnungen bezahlen und online einkaufen.
     
    Wer suchet, der findet
    Der iPod touch synchronisiert Deine Lesezeichen vom PC oder Mac, sodass Du ruck zuck auf Deine Lieblingsseiten zugreifen kannst. Die Google- und Yahoo!-Suche ist schon integriert, sodass Du im Web schnell findest, was Du suchst.
     
    Zoom mit Aussicht
    Jeden beliebigen Ausschnitt einer Webseite kannst Du vergrößern, indem Du mit dem Finger darauf tippst oder mit zwei Fingern die Anzeige aufziehst. Websites lassen sich im Hoch- oder Querformat anzeigen: einfach den iPod touch um 90 Grad drehen, und schon wird auch die Darstellung der Website gedreht.
     
    Eigene Weblinks
    Für häufig besuchte Websites, etwa die einer Zeitung, eines Blogs oder eine Sport-Website, kannst Du einfach ein Symbol auf dem Home-Bildschirm erstellen. Deine Lieblingsseiten sind über mit Safari erstellte Weblinks nur einen Fingertipp entfernt.
     
    Rock 'n' Run mit Nike+
    Im iPod touch ist kabellose Unterstützung für Nike + iPod integriert. Du brauchst nur einen Nike + iPod Sensor in Deinem Schuh, und schon kann's losgehen.
     
    Das optimale Lauftraining
    Im iPod touch ist jetzt Unterstützung für Nike + iPod integriert. Einfach den Nike + iPod Sensor (separat erhältlich) in den Nike+ Laufschuh einsetzen, und es kann losgehen. Der Sensor überträgt die Laufdaten drahtlos an den iPod touch – er erfasst die gelaufene Zeit, die zurückgelegte Strecke und die verbrauchten Kalorien. Außerdem gibt er Dir gesprochenes Feedback zu Deinen Trainingsfortschritten.
     
    Das optimale Fitnesstraining
    Diese Funktion kann auch zusammen mit neuen, in vielen Fitnessstudios vorhandenen Geräten für das Ausdauertraining gekoppelt werden. Suche einfach nach mit Nike + iPod kompatiblen Laufbändern, Elliptical Trainern, Steppern und Hometrainern.
    ";2;False;0;;;Apple iPod Touch 8 GB schwarz mit integrierter WiFi Funktion;apple-ipod-touch-8-gb-schwarz;True;True;P-1270;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;169.9000;169.9000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;40134,2799768519;43;1;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000141-apple-ipod-touch-16-gb-schwarz.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000142-apple-ipod-touch-16-gb-schwarz.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000143-apple-ipod-touch-16-gb-schwarz.jpg;2;;False;;;;;False;False;False;;;;;False;;;;;; -5;0;True;"Philips DVP 5990 / 12 DVD Player ";Philips DVP 5990 / 12 DVD Player schwarz;"
    Philips DVP 5990 / 12 DVD Player schwarz
     
    DivX-zertifiziert, HDMI 1080p, Upscaling 1080i
     
    Der ideale DVD-Player für Ihr HDTV
    mit True High-Definition-HDMI 1080p
    Lassen Sie sich von diesem DVD-Player von Philips mit HDMI Digital Video- und
    Audioverbindung beeindrucken. Erleben Sie wahres Home Entertainment, und tauchen
    Sie in High Definition Video ein (720p / 1080i / 1080p).
    Digitaler HDMI-Ausgang für eine einfache Verbindung mit nur einem Kabel
    DivX Ultra-zertifiziert für verbesserte Wiedergabe von DivX-Videos
    192 kHz/24 Bit Audio-DAC für verbesserte analoge Klangausgabe
    Hochwertige Ausgänge für Analog- und Digital-Audio
     
    Lieferumfang:
    DVD Player; 2 AAA-Batterien; Schnellstartanleitung; Fernbedienung; Benutzerhandbuch
    ";2;False;0;;;"Philips DVP 5990 / 12 DVD Player ";philips-dvp-5990-12-dvd-player;True;True;P-1930;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;2,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;89.0000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;40132,644837963;60;6;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000383-philips-dvp-5990-12-dvd-player.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000384-philips-dvp-5990-12-dvd-player.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000385-philips-dvp-5990-12-dvd-player.jpg;2;;False;;;;;False;False;False;;;;;False;;;;;; -5;0;True;Sandisk Sansa Clip+ schwarz 8GB;Sandisk Sansa Clip+ schwarz 8 GB;"
    Sandisk Sansa Clip+ schwarz 8 GB
     
     
     
    Die neuen Sandisk Sansa Clip+ - Modelle unterstützen nun die Anzeige von sortierbaren Ordnerstrukturen.
    digitaler SanDisk Player für MP3, WMA, Secure WMA, Ogg Vorbis, FLAC-Formate, Hörbücher und FM-Radio
    kleines, kompaktes Design, kaum größer als eine Streichholzschachtel
    microSD-/microSDHC-Slot zur Erweiterung der Speicherkapazität und zum Datentransfer
    FM-Radio mit 40 Stationsspeicherplätzen
    Diktiergerät-Funktion über integriertes Mikrofon
    4-zeiliges OLED-Display
    Sortierung der Titel nach verschiedenen Kriterien möglich, wie z.B. Künstler, Album, Genre, u.a.
    bis zu 15-h-Wiedergabe mittels internem, wiederaufladbaren Akku
    inkl. abnehmbarem Trageclip, Ohrhörer, USB 2.0 Kabel und Bedienungsanleitung
    unterstützt Win 2000, Vista, XP SP2 und Mac OS X 10.3 oder höher
    Speicherkapazität extern: wird über microSD-Karte definiert
    Speicherkapazität intern: 8 GB
    Speicher: intern + extern

    Lieferumfang:
    Sansa Clip+ MP3 Player, Ohrhörer, USB 2.0 Kabel, Quick Start Guide
    ";2;False;0;;;Sandisk Sansa Clip+;sandisk-sansa-clip-schwarz-8gb;True;True;P-1590;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;59.9000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;40125,6367476852;52;8;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000572-sandisk-sansa-clip-schwarz-8gb.jpg;;;2;;False;;;;;False;False;False;;;;;False;;;;;; -5;0;True;"Me2 ME600HD-1000 Multimediafestplatte ";"Me2 ME600HD-1000 Multimediafestplatte1 TB ";"

    Me2 ME600HD-1000  Multimediafestplatte 1 TB

     
     
    3,5 Zoll, USB 2.0,Scart,HDMI Multimedia
     
     
     
    Externe USB 2.0 Multimedia Festplatte• Kapazität: 1000 GB• High-speed
    USB 2.0 Schnittstelle• Aluminium Gehäuse• Stand-alone Media Player zur Wiedergabe von MPEG-1, MPEG-2,
    D ivX/Xvid, JPEG, GMC, Qpel, MP3 (ID3 tag) WAV Media Daten• direkte Wiedergabe von DVD Ordnern&bu
    Ordner-Navigation• Eigene Playlist benutzen und bearbeiten• einfache Dateiführung,
     intuitive Bedienung• unterstützt NTSC und PAL TV Standard• geeignet für HDTV (skaliert auf 10
    ";2;False;0;;;;me2-me600hd-1000-multimediafestplatte;True;True;P-2670;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;169.0000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;40124,2896180556;16;;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000117-me2-me600hd-500-gb-multimediafestplatte.jpg;;;2;;False;;;;;False;False;False;;;;;False;;;;;; -5;0;True;Apple iPod Classic 160 GB silber;"Apple iPod Classic 160 GB silber ";"
    Apple iPod Classic 160 GB silber


    iPod classic: Freiraum -Und zwar jede Menge.
    160 GB sind wirklich eine ganze Menge Platz. Da lässt sich eine komplette Mediathek locker unterbringen und überallhin mitnehmen.
     
    Ein musikalisches Genie
    Stellen Sie vor, Sie hören einen Song. Toll wären jetzt andere Titel, die gut dazu passen. Was machen Sie? Ganz einfach: Sie verwenden die neue Funktion ""Genius"". Diese findet die Songs in Ihrer Mediathek, die gut zusammenpassen. Sie erhalten eine Genius Wiedergabeliste, die Sie sofort anhören, sichern oder sogar aktualisieren können. Verlassen Sie sich also auf den Genius von iTunes, wenn Sie einen Mix wollen, auf den Sie selbst nicht gekommen wären.
     
    Platz satt
    Der iPod classic bietet mit seinen 160 GB Speicherkapazität Platz für bis zu 40.000 Songs, 200 Stunden Videos, 25.000 Fotos oder eine beliebige Kombination dieser Inhalte. Und mit bis zu 36 Stunden Batterielaufzeit beweist der iPod classic auch ganz schön viel Kondition.
     
    Spaß auf Knopfdruck
    Sie findeen immer ganz leicht genau das, was Sie sehen oder hören wollen. Mit dem Click Wheel können Sie mit ""Cover Flow"" Ihre Alben durchblättern, oder Sie stöbern über verschiedene Kategorien wie Wiedergabeliste, Künstler, Album oder Musikrichtung in Ihren Songs und Videos. Sie können natürlich auch nach einem bestimmten Titel oder Interpreten suchen. Lust auf einen neuen Mix? Klicken Sie einfach auf ""Zufällige Titel"".
     
    Filme und Fernsehsendungen ansehen
    Auf dem fantastischen 2,5"" Display kommen Videos richtig zur Geltung. Sie können im iTunes Store Filme kaufen oder ausleihen, Fernsehsendungen kaufen und Video-Podcasts laden. Dann können Sie alles mit Ihrem iPod classic synchronisieren und immer und überall ansehen.
     
     
    Spiele auf dem iPod
    Wenige Fingertipps, viele Stunden Spielspaß. Vortex, iQuiz und Klondike sind schon auf dem iPod classic vorinstalliert, im iTunes Store können Sie weitere dazukaufen, z. B. Cake Mania. Alle iPod Spiele sind speziell für die iPod Oberfläche optimiert.
     
    Fotos zeigen
    Ihre Fotos aus iPhoto auf einem Mac oder aus Adobe Photoshop Elements und Adobe Photoshop Album auf einem PC bekommen Sie mit iTunes auf den iPod classic. Sie können Diashows mit Musik und Übergängen auf dem iPod classic oder mit optional erhältlichen Apple Komponenten oder mit einem Composite-AV-Kabel sogar auf dem Fernseher zeigen.
     
    Umweltverträglichkeit
    Der iPod classic steht für das kontinuierliche Engagement von Apple in puncto Umweltschutz. Die folgenden Merkmale tragen zu einer geringen Umweltbelastung bei:
     
        Arsenfreies Displayglas
        Ohne bromhaltige Flammschutzmittel
        Display mit LED-Hintergrundbeleuchtung ohne Quecksilber
        Frei von PVC
        Recyclingfähiges Gehäuse aus Aluminium und Edelstahl
     
    Produktbeschreibungen
    Freiraum. Und zwar jede Menge. 160 GB sind wirklich eine ganze Menge Platz. Da lässt sich eine komplette Mediathek locker unterbringen und überallhin mitnehmen.
     
    > Highlights
    - Click Wheel
    - Frequenzbereich: 20 Hz bis 20.000 Hz
    - Weitere unterstützte Audioformate: Protected AAC (aus dem iTunes Store), MP3 VBR, Audible (Formate 2, 3, 4, Audible Enhanced Audio, AAX und AAX+), Apple Lossless und WAV
    - Platz für bis zu 40.000 Songs im 128 KBit/Sek. AAC-Format
    - Platz für bis zu 25.000 vom iPod anzeigbare Fotos
    - Platz für bis zu 200 Stunden Videomaterial
    - Speichert Daten auf einer USB-Festplatte
    - Akkuladezeit: ca. 4 Std. (schnelles Laden auf 80%ige Kapazität in 2 Std.)
     
    > Grundeigenschaften
    - Breite: 103.5 mm
    - Höhe: 61.8 mm
    - Tiefe: 10.5 mm
    - Gewicht: 140.0 g
    - Farbe: Schwarz
     
    > Wiedergabeformate Audio
    - AAC
    - MP3
    - WAV
     
    > Akku
    - Akkutyp: Li-Ion
     
    > Display
    - Displaytechnologie: LCD
    - 2.5- Display
    - Bilddiagonale: 6.35 cm
    - Auflösung Breite: 320 Pixel
    - Auflösung Höhe: 240 Pixel
    - Hintergrundbeleuchtung: ja
     
    > Speicher
    - Speicherkapazität 160 GB
     
    > Anschlüsse
    - USB
    - USB-Standard 2.0
     
    > Audio-Anschlüsse
    - Headsetanschluss: 3,5 mm Klinke
    - ipod-Anschluss via IPOD Connector
     
    > Lieferumfang
    - iPod classic
    - Apple Earphones
    - USB 2.0 Kabel
    - Dock-Adapter
    - Dokumentation
     
    > Umweltverträglichkeit
    Der iPod nano steht exemplarisch für das Engagement von Apple in puncto Umweltschutz. Die folgenden Merkmale des iPod nano tragen zu seiner geringeren Umweltbelastung bei:
    - Arsenfreies Glas
    - Frei von bromhaltigen Flammschutzmitteln
    - Frei von Quecksilber
    - Frei von PVC
    - Besonders recyclingfähig
    ";2;False;0;;;Apple iPod Classic 120 GB schwarz;apple-ipod-classic-160-gb-silber;True;True;P-1410;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;249.9000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;40124,2541319444;50;1;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000285-apple-ipod-classic-160-gb-schwarz.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000284-apple-ipod-classic-160-gb-schwarz.jpg;;2;;False;;;;;False;False;False;;;;;False;;;;;; -5;0;True;Apple iPod Nano 16 GB verschiedene Farben;Apple iPod Nano 16 GB;"
    Apple iPod Nano 16 GB
     
     
    Neues gebogenes Design, der dünnste iPod, den es je gab mit neuen Farben zu Auswahl
    Die Bedieung optimiert: ein einziges Handschütteln und ein anderes Lied wird gespielt
    Die neue Funktion ""Genius"" findet die Songs in Ihrer Mediathek, die besonders gut zusammenpassen, und erstellt daraus eine Genius Wiedergabeliste.
    Viele Abspielformate: z.B. MP3, AAC, Apple Lossless, AIFF, WAV, H.264, MPEG-4
    Lieferumfang: iPod Nano, Ohrhörer, USB 2.0 Kabel, Dock-Adapter, Dokumentation
     
    Neues gebogenes Design, der dünnste iPod, den es je gab mit neuen Farben zu Auswahl
    Die Bedieung optimiert: ein einziges Handschütteln und ein anderes Lied wird gespielt
    Die neue Funktion ""Genius"" findet die Songs in Ihrer Mediathek, die besonders gut zusammenpassen, und erstellt daraus eine Genius Wiedergabeliste.
    Viele Abspielformate: z.B. MP3, AAC, Apple Lossless, AIFF, WAV, H.264, MPEG-4
    Lieferumfang: iPod Nano, Ohrhörer, USB 2.0 Kabel, Dock-Adapter, Dokumentation
     
    Ein musikalisches Genie
    Stell Dir vor, Du hörst einen Song. Toll wären jetzt andere Titel, die gut dazu passen. Was machst du? Ganz einfach: Du verwendest die neue Funktion ""Genius"". Diese findet die Songs in Deiner Mediathek, die gut zusammenpassen. Du erhältst eine Genius Wiedergabeliste, zusammengestellt von Deinem persönlichen, superintelligenten DJ.  
    Musik schneller finden
    Auch einen Song, den Du hören willst, findest Du jetzt viel einfacher. Du kannst Deine Alben mit Cover Flow anzeigen oder hältst einfach die mittlere Taste gedrückt und blätterst in Deinen Alben oder Interpreten. Den gewünschten Song gefunden? Einmal auf die mittlere Taste gedrückt, und schon hast Du ihn zur aktuellen Wiedergabeliste hinzugefügt. 
     
    Aufdrehen und rumdrehen
    Neige Deinen iPod nano in die Waagerechte, und schon kannst Du hören, sehen oder spielen wie nie zuvor. Deine Alben kannst Du mit Cover Flow durchblättern und siehst so viel mehr Alben oder Interpreten gleichzeitig auf dem Display.
     
    Shake it, Baby!
    Manchmal hat man einfach Lust auf eine kleine Überraschung. Darum kannst Du jetzt komplett dem Zufall überlassen, welches Lied Du als Nächstes hörst. Einfach den iPod nano kurz schütteln – und er springt zu irgendeinem anderen Song aus Deiner Musik-Bibliothek. Lass dich überraschen, was er Dir als Nächstes präsentiert.   
    Spiel ab!
    Jetzt kannst Du Dir mit Spielen die Zeit vertreiben, die ganz speziell auf den iPod nano und den Beschleunigungssensor zugeschnitten sind. Sie reagieren auf Deine Bewegungen und wirken dadurch so überzeugend, dass sie fast schon süchtig machen können. In jedem Fall wirst Du begeistert sein. Bereits vorinstalliert ist Maze, wo Du Dich durch Neigen, Kippen und allerlei andere Bewegungen durch riesige Labyrinthe manövrieren musst. Im iTunes Store stehen natürlich noch viele weitere Spiele zur Auswahl.
     
    Sogar Deine Fotos rocken
    Jetzt kannst Du gleich hunderte von Fotos aus der Tasche zaubern und überall vorführen. Senkrecht gehalten zeigt der iPod nano Deine Fotos im Hochformat an, wenn Du ihn um 90 Grad drehst, wechseln auch die Fotos ins Querformat. Die Fotos wirken in ihrem richtigen Größen- und Seitenverhältnis auf dem brillanten Display mit 320 x 240 Pixeln einfach hervorragend. 
    Der größte kleine Bildschirm der Welt
    Filme, Fernsehsendungen und Videos auf dem iPod nano anzusehen, ist das pure Vergnügen. Die hochauflösende Anzeige wirkt auf dem kristallklaren 2"" Breitbild-Display besonders brillant und lebendig. So hast Du mit dem iPod nano Dein eigenes Kino im Taschenformat immer dabei.  
     
    Produktbeschreibungen
    Flach, flacher, am flachsten mit nur 6,2mm bringt der iPod nano, in leuchtenden Farben, neuen Schwung ins Leben.
    Mit brilianterem Display, höherer Speicherkapazität und noch längerer Batterielaufzeit schütteln Sie sich einfach durch Ihre Mediathek.
    Leistungsmerkmale
    - Verschieden Menüs: Musik, Fernsehsendungen, Videos, Hörbücher, Podcasts, Diashows, Spiele
    - Geschwungenen Aluminium-Design mit gewölbtem Glas
    - HxBxT: 90,7 x 38,7 x 6,2 mm
    - Gewicht: 36,8 g
    Lieferumfang
    - iPod nano
    - Ohrhörer
    - USB 2.0-Kabel
    - Dock-Adapter
    - Dokumentation
    Display
    - 2- Farb-LCD mit LED-Hintergrundbeleuchtung
    - 320 x 240 Pixel
    Kapazität
    - 8 GB Flash-Laufwerk1 für bis zu 2.000 Songs, 7.000 Fotos, 8 Std. Videomaterial
    Batterie
    - Integrierte, wiederaufladbare Lithium-Ionen-Batterie
    - Musikwiedergabe: bis zu 24 Stunden bei voller Ladung
    - Videowiedergabe: bis zu 4 Stunden bei voller Ladung
    Audio
    - Unterbrechungsfreie Wiedergabe
    - Frequenzbereich: 20 Hz bis 20.000 Hz
    - Unterstützte Audioformate: AAC, Protected AAC, MP3, MP3 VBR, Audible, Apple Lossless, AIFF und WAV
    Systemvoraussetzungen
    - USB 2.0-Anschluss
    - mind. Mac OS X 10.4.11 bzw. mind. Windows Vista oder Windows XP Home oder Professional
    - mind. iTunes 8  

     
     
     
    ";2;False;0;;;Apple iPod Nano 16 GB;apple-ipod-nano-16-gb-verschiedene-farben;True;True;P-1370;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;159.9000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;40123,68375;47;1;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000075-apple-ipod-nano-8-gb-verschiedene-farben.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000076-apple-ipod-nano-8-gb-verschiedene-farben.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000077-apple-ipod-nano-8-gb-verschiedene-farben.jpg;1;;False;;;;;False;False;False;;;;;False;;;;;; -5;0;True;Acer Aspire 1810TZ-412G32n rot 29,5 cm (11,6 Zoll) Notebook;4 GB, 17 Zoll, 400 GB, Intel, 3;"
    Aspire 1810T:
    Das Aspire 1810T bietet die perfekte Balance aus unabhängiger Mobilität und flexibler Anwendung. Dieses handliche 29,46cm (11,6"") Notebook ist weniger als 1"" schmal, wartet aber auf mit einer vollausgestatteten Tastatur, HD Audio/Visual Unterhaltung und bis zu 8 Stunden mobiler Energie. Zusätzlich können Sie unter drei angesagten Farben auswählen: rubinrot, diamantschwarz und saphirblau.
     
     Kompaktes Design, excellente Anwendung
    Dieses Notebook wiegt nur 1,35kg, so daß Sie es mühelos überall mitführen können. Mit der Acer Fine Tip Tastatur können Sie auch auf die übliche Notebook Nutzung zugreifen, dank der fortschrittlichen Kontrolle ohne Maus über das multifunktionale Touchpad.
     
    8 Stunden Batterielaufzeit
    Das Aspire 1810T ist mit einem Niedrig_Volt-Prozessor (ULV) versehen, der weniger Energie verbraucht und Sie von Ihrem Stromanschluß unabhängig macht. Einmal aufladen und Sie haben es von morgens bis abends zur Verfügung.
     
    HD Erfahrung auf dem Vormarsch
    Erleben Sie grandiose visuelle Effekte, brillant in Farbe und Bild, via 3D Grafik und einem 16:9 Bildschirm. Der integrierte HDMI Port ermöglicht Ihnen auch den leichten Anschluß an periphere Displays. Was den Klang angeht, erhalten Sie die optimierte 2. Generation des Dolby Sound Room für eine Tonerfahrung über viele Kanäle, zu empfangen über ein simples Paar Kopfhörer.
     
    Auf den Punkt gekühlt
    Die Acer ComfyTouch Technologie nutzt das innovative Design, um den Prozessor und das Gehäuse luftzukühlen. Auch wenn Sie das Notebook rund um die Uhr in Betrieb haben, bleibt es stets bei optimaler Temperatur.
     

    Umweltbewußtsein als Motiv
    Nehmen Sie die Energieersparnis wahr, ob unterwegs oder zuhause. In der Anwendung braucht das Aspire 1810T bis zu 40% weniger Strom als handelsübliche Notebooks.
     
     Nutzen Sie die Vorteile der mobilen Welt und schreiben Sie E-Mails oder chatten Sie mit Ihren Lieben, wo auch immer Sie gerade sind. Mit der erweiterten Netzwerkverbindung Wi-Fi CERTIFIED™ können Sie sich problemlos auf eine große Zahl von Verbindungen überall auf der Welt verlassen. Sie müssen sich an ein LAN anschließen? Kein Problem! Der Gigabit-Ethernet-Port garantiert eine ultraschnelle Verbindung.
     
     Die Acer Crystal Eye Webcam mit verbesserter Bilderfassung garantiert auch bei nicht optimaler Beleuchtung ein klares Bild bei Video-Chats und Webkonferenzen.
     
     HD-Ready (engl. „Bereit für HD“) ist ein von der der EICTA geschaffenes Label für Geräte (z.B.: Notebooks) die hochauflösendes Fernsehen (High Definition Television (HDTV)) wiedergeben können. Mindestvorsausetzungen für dieses Label sind unter anderem eine native 16:9-Auflösung von wenigstens 720 Zeilen, mindestens ein digitaler Eingang (DVI-D/-I oder HDMI), und eine Auflösung von 1280 × 720 Pixeln (Vollbilder) bzw. 1920 × 1080 Pixeln (Halbbilder). Ein Gerät das diesen Anforderungen gerecht wird kann hochauflösendes Fernsehen wiedergeben und verspricht ein gestochen scharfes Bilderlebnis.
     
    ";2;False;0;;;"Acer Aspire Timeline 1810TZ 11.6 Zoll Notebook ";acer-aspire-1810tz-412g32n-rot-295-cm-116-zoll-notebook;True;True;P-0830;;;False;0;False;;False;False;0;False;0;1;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;1;9999;False;False;0;1;1;0;False;1;10000;;False;False;False;False;547.9000;0.0000;0.0000;499.0000;41640;41820,9999884259;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;40121,6691898148;"5;2095";37;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000527-acer-aspire-1810tz-412g32n-rot-295-cm-116-zoll-notebook.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000528-acer-aspire-1810tz-412g32n-rot-295-cm-116-zoll-notebook.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000529-acer-aspire-1810tz-412g32n-rot-295-cm-116-zoll-notebook.jpg;2;;True;ml;2.0000;1;;False;False;False;;;;;False;;;;;; -5;0;True;Canon PIXMA MP640 Multifunktionsgerät 3 in 1;"Canon PIXMA MP640 Multifunktionsgerät ";"
    Canon PIXMA MP640 Multifunktionsgerät
     
     
    3 in 1, Drucken, Kopieren, Scannen
     
     
    Der PIXMA MP640 ist ein Multifunktionssystem der Spitzenklasse für exzellenten Fotodruck, schnellen Dokumentendruck und mit vielfältigen Scan- und Kopierfunktionen.
    Dank WiFi- und Ethernet-Unterstützung kann er in ein kabelgebundenes und kabelloses Netzwerk integriert werden.

    Multifunktionssystem: Fotodrucker, Farbscanner und Farbkopierer
    Druckgeschwindigkeit: ca. 9,2 (SW) bzw. 8,1 (Farbe) ISO-Seiten/Min; einzelne Tintentanks
    ca. 20 Sek. für den druck eines 10 x 15 cm Randlosprint
    Automatischer Duplexdruck, doppelte Papierzufuhr und DVD/CD-Druck
    Lieferumfang: PIXMA MP640, Netzkabel, Druckkopf, Tintentanks, DVD/CD-Halter, Kurzanleitung, CD mit Installations-Software und Benutzerhandbuch, Garantiekarte,
    Druckmedien-Broschüre, Fotoglanzpapier Plus II PP-201, MP-101 zur Druckkopfausrichtung
    ";2;False;0;;;"Canon PIXMA MP640 ";canon-pixma-mp640-multifunktionsgeraet-3-in-1;True;True;P-2220;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;2,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;219.0000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;40120,6418055556;22;25;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000523-canon-pixma-mp640-multifunktionsgerat-3-in-1.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000524-canon-pixma-mp640-multifunktionsgerat-3-in-1.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000525-canon-pixma-mp640-multifunktionsgerat-3-in-1.jpg;2;;False;;;;;False;False;False;;;;;False;;;;;; -5;0;True;"Trekstor DataStation pocket x.u s ";Trekstor DataStation pocket x.u s 250 GB;"
    Trekstor DataStation pocket x.u s 250 GB
     
     
    Externe 2.5 Zoll Festplatte
    Exklusives Aluminiumgehäuse für optimale Kühlung der Festplatte
    Speichergröße 250 GB
    Geeignet für das neue Windows® Vista
    Lieferumfang: Festplatte, Nero BackItUp 2 Essentials, Software- / Treiber-CD, USB 2.0-Y-Anschlusskabel, Kurzanleitung, Transportetui
    ";2;False;0;;;"Trekstor DataStation pocket x.u s ";trekstor-datastation-pocket-xu-s;True;True;P-2640;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;89.0000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;40120,6286921296;15;2;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000522-trekstor-datastation-pocket-xu-s.jpg;;;2;;False;;;;;False;False;False;;;;;False;;;;;; -5;0;True;Canon Digital IXUS 100 IS Digitalkamera silber;"Canon Digital IXUS 100 IS Digitalkamera silber ";"

    Canon Digital IXUS 100 IS Digitalkamera silber

    12 Megapixel, 3-fach opt. Zoom, 2,5"" Display, HDMI, SLIM
     
    Die Digital Ixus 100 IS präsentiert sich im atemberaubend-exquisiten, nur 18,4 Millimeter flachen Edelstahlgehäuse. Sie ist in den vier Farben Silber, Schwarz, Gold und Rot erhältlich.

    Ob großformatige Fotoprints oder gezielte Ausschnittvergrößerungen: Die hohe Auflösung von 12,1 Megapixeln sorgt für eine überzeugende Detailwiedergabe.
     
    Für hohe Geschwindigkeit und exzellente Bildqualität mit brillanten Farben und minimiertem Bildrauschen steht der aktuelle Canon-Bildprozessor DIGIC 4.
    12,1 Megapixel Sensor
    3-fach optisches Zoom
    Großes hochauflösendes 2,5 Zoll PureColor LCD II
    Superschlank; HD-Movie und HDMI-Anschluß ¿ mehr Details im Film
     
    Lieferumfang:
    Digital IXUS 100 IS, Trageriemen, Akku, Akku-Ladegerät, USB-Kabel, Video-Kabel
    ";2;False;0;;;"Canon Digital IXUS 100 IS Digitalkamera ";canon-digital-ixus-100-is-digitalkamera-silber;True;True;P-1730;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;199.0000;199.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;40119,9167824074;"56;2095";25;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000514-canon-digital-ixus-100-is-digitalkamera-silber.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000515-canon-digital-ixus-100-is-digitalkamera-silber.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000516-canon-digital-ixus-100-is-digitalkamera-silber.jpg;2;;False;;;;;False;False;False;;;;;False;;;;;; -5;0;True;"Samsung N130-@nyNet 10,1 Zoll Netbook ";5 GB, 16 Zoll, 500 GB, AMD, 4;"
    Samsung N130-@nyNet 10.1 Zoll Netbook  schwarz
     
    Intel Atom N270 1.6GHz, 1GB RAM, 160GB HDD, Intel GMA 950, , Win 7 Starter
     
    Mit dem N130 präsentiert Samsung Electronics ein preisgünstiges und leistungsstarkes Netbook der N-Serie. Ultraleicht und funktional arbeitet das N130 mit aktuellster Samsung Technologie und überzeugt durch Qualität, Design und Performance auf hohem Niveau. Das 1,26 kg leichte Netbook ist mit einem spiegelfreien 10,1-Zoll-Non-Gloss-Display ausgestattet. Mit einer Laufzeit von bis zu 6,5 Stunden gehört es zu den Langläufern im Netbook-Markt.
     
    Flaches und elegantes Gehäuse-Design
    Das N130 mit hochwertigen Komponenten und Materialien steckt in einem flachen, eleganten Design-Gehäuse. Mit seiner umfangreichen Funktionalität und gerade einmal 1,26 kg ist das N130 das leichteste Gerät seiner Klasse und bietet damit Mobilität auf höchstem Niveau.
     
    Optimale Mobilität durch geringen Stromverbrauch
    Das 10,1-Zoll-Non-Gloss-Display des N130 ist extrem energieeffizient und brilliert mit einem scharfen und hellen Bild ohne Spiegelungen sogar bei extremer Sonneneinstrahlung. Der geringe Stromverbrauch garantiert optimale Mobilität durch Samsungs führende Lithium-Ionen-Akku-Technik und ermöglicht eine außergewöhnliche Laufzeit von bis zu 6,5 Stunden.
     
    Immer in Verbindung - mit WLAN
    Schnellen Zugriff auf Internet und andere Inhalte gewährleistet das Netbook via 802.11b/g/n WLAN - jederzeit und überall. Darüber hinaus ist das Netbook mit einem eingebauten Mikrofon und Kopfhöreranschluss - beispielsweise für VoIP-Telefonie - ausgestattet. Mit drei USB 2.0-Anschlüssen und einem 3-in-1-Kartenleser erlaubt das N130 die Wahl zwischen zahlreichen Datenaustausch-Optionen. So lassen sich Informationen, Bilder, Musiktitel und Filme mit allen modernen Peripheriegeräten wie Kameras, externen Festplatten oder Audio/Video-Geräten blitzschnell austauschen. 
    ";2;False;0;;;"Samsung N130@nynet-N270BN 10.1 Zoll Netbook ";samsung-n130-nynet-101-zoll-netbook;True;True;P-0810;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;284.9000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;40116,2153125;5;5;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000307-samsung-n130-nynet-101-zoll-netbook.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000308-samsung-n130-nynet-101-zoll-netbook.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000309-samsung-n130-nynet-101-zoll-netbook.jpg;2;;False;;;;;False;False;False;;;;;False;;;;;; -5;0;True;"Asus EEE PC 1005HA-M 10,1 Zoll Netbook ";2 GB, 16 Zoll, 350 GB, Tantel, 4;"
    Asus EEE PC 1005HA-M 10,1 Zoll Netbook mit Windows 7 Starter weiß
     
     
    Langläufer: Eee PC 1005HA. Mit dem Eee PC 1005HA hat ASUS ein stylisches Geräte im Portfolio, das sich durch ihre lange Akkulaufzeit und ein mattes, nicht spiegelndes Display auszeichnen. Der Eee PC 1005HA-M inklusive Intel Atom N270 Prozessor kommt auf eine Akkulaufzeit von 8,5 Stunden. Die Geräte arbeiten mit dem Microsoft Windows 7 Betriebssystem und sind dadurch besonders intuitiv und komfortabel zu bedienen.
     
    Das Betriebssystem Microsoft Windows 7
    Mit Windows 7 stellt Microsoft ein Betriebssystem vor, das sich durch eine leichte Bedienung und einen ressourcensparenden Umgang mit der Hardware auszeichnet. Selbst auf Rechnern mit begrenzter Prozessorpower läuft das Betriebssystem mühelos. So benötigt der PC nur noch wenige Augenblicke zum Hochfahren und auf der übersichtlichen Taskleiste lassen sich anhand von Symbolen schnell die passenden Files erkennen. Spielend leicht wird auch die Verwaltung von Filmen, Bildern und Videos. Mithilfe der Bibliotheken lassen sich diese schnell organisieren. Und in punkto Sicherheit bringt das Betriebssystem einiges mit. Darunter die Benutzerkontensteuerung, die sich individuell konfigurieren lässt. 
     
    Ehe PC 1005HA-M: Klasse Leistung zu unschlagbarem Preis
    Der Eee PC 1005HA-M unterscheidet sich von seinem großen Bruder durch Prozessor, Akkukapazität sowie durch die integrierten Wireless Funktionen. Ausgestattet mit einem Intel Atom N270 Prozessor, einem 4400 mAh 6 Zellen Akku für bis zu 8,5 Stunden Laufzeit, WLAN 802.11n Standard sowie weiteren Top Merkmalen, überzeugt der Eee PC 1005HA-M zu einem unschlagbaren Preis.
     
    Eee PC 1005HA-M: Funktionalität meets Design
    Mit dem kompakten Eee PC 1005HA-M trägt ASUS seinem Anspruch, in den Produkten höchste Funktionalität mit formvollendetem Design zu verbinden, ein weiteres Mal Rechnung. So besticht der Eee PC durch sein elegantes und gleichzeitig unempfindliches Gehäuse, das mit klaren Linien und nach unten schmaler zulaufenden Kanten dem schlanken Design einer Muschel nachempfunden ist. 
      
    Aber auch das Innenleben der Kleinen kommt ganz groß raus. Als gewohnt kontaktfreudig erweisen sich die Neulinge dank VGA Port für den Anschluss eines Monitors sowie drei USB 2.0 Schnittstellen, um Maus, Tastatur oder Digicam anzuschließen. Wer Bilder direkt von der SD oder MMC Speicherkarte auf den Eee PC übertragen möchte, nutzt den integrierten Kartenleser. Für das Speichern der Fotos stehen bei den Modellen eine 160 GB S-ATA Festplatte zur Verfügung. Die Modelle sind - wie alle Eee Familienmitglieder - ausgesprochen einfach zu bedienen. Das 10 Zoll WSVGA Display mit stromsparender LED-Hintergrundbeleuchtung sowie die große Tastatur, die zu 92% einer Standard Notebooktastatur entspricht, gewähren zusätzlichen Komfort. Für Chats oder Videokonferenzen hat ASUS die Minis zudem mit einer 1.3 Megapixel Web-/Videokamera sowie einem Mikrofon ausgestattet.
    ";2;False;0;;;"Asus EEE PC 1005HA-M 10,1 Zoll Netbook ";asus-eee-pc-1005ha-m-101-zoll-netbook;True;True;P-0800;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;291.9000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;40115,7052199074;5;37;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000300-asus-eee-pc-1005ha-m-101-zoll-netbook.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000301-asus-eee-pc-1005ha-m-101-zoll-netbook.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000302-asus-eee-pc-1005ha-m-101-zoll-netbook.jpg;2;;False;;;;;False;False;False;;;;;False;;;;;; -5;0;True;"Trekstor DataStation maxi g.u 1,5 TB ";"Trekstor DataStation maxi g.u externe Festplatte 1,5 TB ";"

    Trekstor DataStation maxi g.u Externe Festplatte 1,5 TB

     
     
    USB 2.0 inkl. Nero BackItUp 2 Essentials
     
     
     
    Optimale Speicherplatzerweiterung
    Die DataStation maxi g.u ist die perfekte Lösung für das
    tägliche Backup oder die Speicherplatzerweiterung Ihres PCs.
    Die externe 3,5“ Festplatte bietet ausreichend Platz
    zum Speichern und Archivieren der heimischen Musik-
    und Videosammlung, digitaler Fotos oder anderer Dateien. 
     Schnell und bedienungsfreundlich
    Mit dem Hi-Speed USB 2.0 Anschluss bietet die
    DataStation maxi g.u einen schnellen Datentransfer.
    Die Festplatte ist zudem bereits vorformatiert und
    ohne Treiber sofort betriebsbereit.
    Unterstützt werden alle gängigen
    Dateisysteme von Windows®, Linux® und Mac® OS X,
    sowie die Betriebssysteme Microsoft
    Windows® 2000 / XP/ Vista, Mac® OS X ab 10.3 und Linux® ab Kernel 2.6.x.
    Die Festplatte wird über das mitgelieferte Netzteil mit Strom versorgt. 
    Der Ein-/Ausschalter am Festplattengehäuse verhindert überflüssigen Stromverbrauch. 
    Exklusives Aluminiumgehäuse
    Das exklusive Aluminiumgehäuse der DataStation maxi g.u
    sorgt für die optimale Kühlung der Festplatte,
    so kommt die externe Festplatte
    ohne Lüfter aus und ist leise während des Betriebs 
    Inklusive Nero Software „BackItUp2 Essentials“
    Die ebenfalls im Lieferumfang enthaltene
    Nero Software rundet das Bild der mobilen, externen Festplatte perfekt ab.
    Mit Nero BackItUp2 Essentials können Sie Backups Ihrer Daten sehr einfach planen.
    So können einzelne Dateien oder ganze Laufwerke gesichert werden.
    Um die Datenmenge gering zu halten, komprimiert die Software die Backups direkt „on the fly“.
    Auf Wunsch lassen sich die gesicherten Daten auch per Passwortschutz vor unbefugtem Zugriff schützen.
    ";2;False;0;;;"Trekstor DataStation maxi g.u-externe Festplatte 1,5 TB ";trekstor-datastation-maxi-gu-15-tb;True;True;P-2630;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;139.0000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;40101,7793981481;15;2;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000129-trekstor-datastation-maxi-gu-1tb.jpg;;;2;;False;;;;;False;False;False;;;;;False;;;;;; -5;0;True;"NAVIGON 2410 Navigationssystem inkl. TMC ";"NAVIGON 2410 Navigationssystem inkl. TMC ";"

    NAVIGON 2410 Navigationssystem inkl. TMC

     
     
    3,5"" Display, EU Kartenmaterial mit 40 Ländern, Fußgängernavigation im Hochformat
     
     
    Fußgänger-Navigation
    bringt Sie ohne Umwege ans Ziel, auch wenn Sie mal nicht im Auto unterwegs sind.
    So können Sie z. B. unbekannte Städte ganz gezielt erkunden und finden auch die verstecktesten Plätze und Sehenswürdigkeiten.
    Dabei halten Sie Ihr NAVIGON übrigens ganz bequem im Hochformat in einer Hand – und haben so die andere jederzeit frei.
     
    NAVIGON Zielgerade
    navigiert Sie nach dem Parken die letzten Meter zu Ihrem eigentlichen Ziel. Denn: Nicht vor jedem geplanten Ziel ist auch ein Parkplatz für Ihr Fahrzeug.
    Deshalb lotst Ihr NAVIGON Sie sicher auf dem letzten Stück zu Fuß. Und findet auf dem Rückweg auch Ihr Auto für Sie wieder.
     
    E-Kompass
    Großstädte können auch zu Fuß sehr unübersichtlich sein. Damit Sie nicht mit den Himmelsrichtungen durcheinander kommen, unterstützt Sie im Fußgängermodus ein elektronischer Kompass.
    So wissen Sie sofort, ob Sie nach links, rechts, oben oder unten laufen müssen. Beziehungsweise nach Westen, Osten, Norden oder Süden.
     
    Clever Parking
    hilft Ihnen bei der Parkplatzsuche. Kurz vor Ihrem Ziel zeigt Ihnen Clever Parking Parkplätze in der näheren Umgebung an.
    In Deutschland, Österreich, Schweiz und Luxemburg werden Sie sogar über Parkgebühren und Öffnungszeiten informiert. So vermeiden Sie langes Suchen und sparen dabei Geld.
     
    NAVIGON MyRoutes
    Je nachdem, welcher Fahrertyp Sie sind, empfiehlt Ihnen NAVIGON MyRoutes die beste Route – zugeschnitten auf Ihren persönlichen Fahrstil, den Wochentag und die Tageszeit.
    Darüber hinaus zeigt Ihnen Ihr NAVIGON bis zu zwei weitere Routen. Das schafft Transparenz. Sie entscheiden, ob Sie unserer Empfehlung folgen oder eine der Alternativen wählen.
     
    TMC-Routeninfo
    zeigt Ihnen im Fall einer Staumeldung eine Alternativroute mit aktualisierter Entfernung und Ankunftszeit.
    Sie entscheiden, ob eine Umfahrung in Ihrem Fall sinnvoll ist oder ob Sie die ursprüngliche Route beibehalten wollen.
     
    Lieferumfang
    NAVIGON 2410, Kurzanleitung, KfZ-Ladekabel mit integrierter TMC Antenne, KfZ Halterung, USB-Kabel, Europa Kartenmaterial
    ";2;False;0;;;"NAVIGON 2410 Navigationssystem inkl. TMC ";navigon-2410-navigationssystem-inkl-tmc;True;True;P-2160;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;169.0000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;40097,6045833333;68;14;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000299-navigon-2410-navigationssystem-inkl-tmc.jpg;;;2;;False;;;;;False;False;False;;;;;False;;;;;; -5;0;True;Adobe Premiere Elements 8;Adobe Premiere Elements 8 deutsch WIN;"

    Adobe Premiere Elements 8 deutsch WIN


    Mit Adobe® Premiere® Elements 8 erstellen Sie ohne Aufwand erstklassige Videos, die Sie mit professionellen Effekten bereichern und auf nahezu jedem Medium präsentieren können.
    Dank eines leistungsfähigen und bedienungsfreundlichen Organizer behalten Sie den Überblick über Ihre Videos und Fotos.
     
    Arbeiten Sie wie die Profis, indem Sie beispielsweise Grafiken und Effekte einfügen, die sich mit den zugehörigen Objekten zusammen bewegen.
    Vielseitigkeit und Benutzerfreundlichkeit
    Filmproduktion in wenigen Schritten
    Filmerstellung per Drag-and-Drop
    Zentrale Umgebung für Bearbeitung und Vorschau
    Professionelle Spezialeffekte und Überblendungen
    Aufwertung von Videos mit Musik
     
    Systemanforderungen:
    Prozessor mit 2 GHz und SSE2-Unterstützung; für HD oder Blu-ray: Prozessor mit 3 GHz; für AVCHD: Dual-Core-Prozessor
     
    Microsoft® Windows® XP mit Service Pack 2, Windows Media Center, Windows Vista® oder Windows 7
    Für Windows XP: 512 MB RAM (2 GB für HD-Bearbeitung einschließlich HDV, AVCHD oder Blu-ray)
    Für Windows Vista and Windows 7: (1 GB RAM (2 GB für HD-Bearbeitung einschließlich HDV, AVCHD oder Blu-ray)
    4,5 GB freier Festplattenspeicher
    Farbmonitor mit 16-Bit-Grafikkarte
    1024 x 768 Punkt Monitorauflösung mit 96 dpi oder geringer
    Mit Microsoft DirectX 9 oder 10 kompatibler Sound- und Grafikkartentreiber
    DVD-ROM-Laufwerk (kompatibler DVD-Brenner für die Erstellung von DVDs, kompatibler Blu-ray-Brenner für die Erstellung von Blu-ray Discs erforderlich)
     
    ";2;False;0;;;Adobe Premiere Elements 8;adobe-premiere-elements-8;True;False;P-3030;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;9200;False;False;0;1;1;0;False;1;10000;;False;False;False;False;112.9000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;40097,5865856481;31;20;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000297-adobe-premiere-elements-8.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000298-adobe-premiere-elements-8.jpg;;2;;True;ml;1.0000;1;;False;False;False;;;;;False;;;;;; -5;0;True;Adobe Photoshop Elements 8;Adobe Photoshop Elements 8 deutsch WIN;"

    Adobe Photoshop Elements 8 deutsch WIN

     

    Adobe® Photoshop® Elements 8 ist die ideale Kombination aus Leistungsfähigkeit und Benutzerfreundlichkeit.
    Verwalten Sie Ihre Bilder und Videos bequem zentral, machen Sie aus alltäglichen Motiven eindrucksvolle Kunstwerke, und gestalten Sie unverwechselbare Kreationen für Print und Web.
    Jetzt können Sie perfekt ausgeleuchtete Bilder erstellen oder mit verschiedenen Bildgrößen experimentieren, ohne dass Verzerrungseffekte auftreten. Mit den erweiterten Suchfunktionen lassen sich Bilder wahlweise nach Qualität oder nach Motiv sortieren.

    Vielseitigkeit und Benutzerfreundlichkeit
    Praktischer Medien-Manager
    Sekundenschnell retuschieren
    Intuitive Anpassung von Farbe und Belichtung
    Praktische Hilfestellungen
    Herausragende Ergebnisse
    Gelungene Präsentation im Web
    Effiziente Umsetzung kreativer Ideen
     
    Systemanforderungen:
    Prozessor mit mindestens 1,6 GHz
    Microsoft® Windows® XP mit Service Pack 2 oder 3, Windows Vista® oder Windows 7
    1 GB RAM
    2 GB freier Festplattenspeicher
    Farbmonitor mit 16-Bit-Grafikkarte
    1024 x 576 Punkt Monitorauflösung mit 96 dpi oder geringer
    Mit Microsoft DirectX 9 kompatibler Grafikkartentreiber
    DVD-ROM-Laufwerk
     
    ";2;False;0;;;Adobe Photoshop Elements 8;adobe-photoshop-elements-8;True;False;P-3020;;;False;0;False;;False;False;0;False;0;1;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;109.0000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;40097,5787731481;31;20;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000295-adobe-photoshop-elements-8.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000296-adobe-photoshop-elements-8.jpg;;2;;False;;;;;False;False;False;;;;;False;;;;;; -5;0;True;"Garmin nüvi 255T Navigationssystem Europa ";"Garmin nüvi 255T Navigationssystem Europa inkl. TMC ";"
    Garmin nüvi 255T Navigationssystem Europa inkl. TMC
     

    3,5"" Touchscreen Display, PhotoNavigation, MicroSD-Kartenslot und ecoRoute 
     
    Bedienerfreundliches Einsteigernavigationsgerät mit elegantem, ultra-schlankem Design und brillantem 3,5 (8,9cm Bilddiagonale)
    Touchscreen Display + TMC Verkehrsfunkempfänger
    Kartenmaterial für 40 Länder in West- und Osteuropa intern vorinstalliert ecoRoute:
    reduziert den Kraftstoffverbrauch, CO2-Emissionen und schont die Umwelt, spart bares Geld und füllt die Reisekasse auf.
    PhotoNavigation mit Garmin Connect: Sie können Sehenswürdigkeiten und Bilder herunterladen und als Ziel auswählen
    Lieferumfang: Garmin nüvi 255T mit Kartenmaterial Europa, TMC Verkehrsfunkempfänger,
    Saugnapfhalterung für die Windschutzscheibe, Armaturenhalterung, Schnellstartanleitung, KFZ-Anschlusskabel
     
    ";2;False;0;;;"Garmin nüvi 255T Navigationssystem Europa ";garmin-nuevi-255t-navigationssystem-europa;True;True;P-2090;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;129.0000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;40096,6680208333;67;44;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000294-garmin-nuvi-255t-navigationssystem-europa.jpg;;;2;;False;;;;;False;False;False;;;;;False;;;;;; -5;0;True;"Logitech Webcam C200 ";"Logitech Webcam C200 ";"
    Sie suchen nach einem Basispaket für eine einfache, klare Videokommunikation? Die preisgünstige Logitech
    Webcam C200 stellt Ihnen alle Funktionen zur Verfügung, die Sie für realitätsnahe Videogespräche benötigen. Sie bezahlen nicht für Zusatzfeatures, die Sie wahrscheinlich ohnehin nicht nutzen. Ihre Webkamera wird mit der Logitech Vid-Software geliefert, die Ihnen mit nur einem Mausklick das Führen von Videogesprächen ermöglicht – schnell, kostenlos, einfach. Der VGA-Sensor erfasst Ihre Live-Videobilder in natürlichen und realistischen Farben. Sie können auch Schnappschüsse machen, die per Software auf eine Auflösung von 1,3 Megapixeln hochgerechnet werden. Und das praktische eingebaute Mikrofon sorgt mit der Logitech RightSound- Technologie dafür, dass Ihre Stimme klar verständlich ist. Dank der Universalmonitorhalterung können Sie diese Webkamera problemlos an jedem Desktopmonitor oder Notebookrechner befestigen.
     

    Seien Sie persönlich dabei - mit dem Basispaket für eine kostenlose und klare Videokommunikation
     
    Ein Besuch bei Ihren Freunden und Verwandten in der Ferne ist ab sofort wesentlich einfacher. Mit der preiswerten Logitech Webcam C200 sind Sie nämlich direkt bei den Menschen, die Ihnen am Herzen liegen. Installieren Sie einfach Ihre Webkamera, und schon können Sie Ihr erstes Videogespräch führen. Dazu ist nur ein einfacher Mausklick erforderlich, wenn Sie die Vid-Software nutzen, die mit Ihrer Webkamera mitgeliefert wird. Plaudern Sie persönlich mit Ihren Enkeln in der Nachbarstadt – oder mit Ihrer besten Freundin am anderen Ende der Welt. Der VGA-Sensor sorgt dafür, dass Ihre Gesprächspartner Sie in ganz natürlichen Farben sehen. Und dank dem eingebauten Mikrofon mit der Logitech RightSound-Technologie, die störende Nebengeräusche herausfiltert, können sie jedes Wort aus Ihrem Mund deutlich verstehen. Wenn Sie ein praktisches Basispaket für Videogespräche suchen und auf komplizierte Zusatzfunktionen verzichten können, ist dies die richtige Webkamera für Sie.
     
    Die wichtigsten Funktionen
     
    Webkameras von Logitech - bessere Videoqualität kommt nicht von ungefähr
     
    Sobald Sie Ihr erstes Videogespräch führen, wird Ihnen klar werden, warum Logitech die erste Wahl von Webkamera-Anwendern auf der ganzen Welt ist. Bei der Entwicklung jeder Webkamera ist das oberste Designziel von Logitech, eine erheblich klarere Bild- und Tonqualität als andere Webkameras zum gleichen Preis zur Verfügung zu stellen. Dabei geht es geht nicht nur um Features wie Qualität des Objektivs, Sensor-Auflösung und Software. Es geht viel mehr darum, wie alle diese Dinge ineinandergreifen, um Ihnen eine Videokommunikation mit mehr Komfort und Vergnügen zu ermöglichen.
       
    Der VGA-Sensor zeigt Ihr wahres Ich
     
    Nur weil Sie nicht so viel Geld ausgeben wollen, heißt das noch lange nicht, dass Sie auf Qualität verzichten müssen. Ihre Logitech-Webkamera bietet Ihnen Extras, die Sie bei einer so preisgünstigen Webkamera wahrscheinlich gar nicht erwarten würden. Dazu zählt ein Sensor, der Live-Videobilder mit echter VGA-Auflösung in realitätsnahen Farben aufnimmt. Keine grünlich-bleichen oder verschwommenen Gesichter. Ihre Gesprächspartner bekommen Ihr wahres, natürliches Ich zu sehen. 
    Auflösung mit bis zu 1,3 Megapixeln – verschicken Sie brillante digitale Schnappschüsse
     
    Sie möchten Ihre Webkamera auch noch anderweitig nutzen? Drücken Sie einfach auf den Schnappschussauslöser, um realitätsnahe Fotos aufzunehmen, die per Software auf 1,3 Megapixel hochgerechnet werden. Und da sich die Schnappschüsse schon auf Ihrem Rechner befinden, können Sie sie ganz einfach per E-Mail an Verwandte oder Freunde verschicken.   
     
    Eingebautes Mikrofon mit geräuschdämpfender RightSound- Technologie
     
    Sprechen Sie ganz natürlich, das eingebaute Mikrofon der Webkamera nimmt jedes Wort, jedes Lachen, jedes Flüstern auf. Die RightSound-Technologie filtert automatisch störende Hintergrundgeräusche heraus, sodass Sie Ihre Gespräche immer mit kristallklarer Tonqualität führen können. 
     
    Vielseitige Universalhalterung für die Befestigung an jedem Desktop- oder Notebook-Rechner
     
    Was das praktische Design anbetrifft, hat Logitech an alles gedacht. Die Webkamera lässt sich problemlos und sicher an LCD-Bildschirmen ebenso wie an ultraflachen Notebook-Monitoren befestigen. Die Halterung kann auch eingeklappt werden, sodass Sie die Kamera auf einer ebenen Oberfläche wie beispielsweise einem Regal über Ihrem Computer aufstellen können.   
     
    Problemlose Videogespräche dank Unterstützung aller Instant-Messaging-Programme
     
     
    Alles, was Sie für Videogespräche benötigen, ist die Webkamera, ein schneller Internet-Zugang und ein Videokommunikations-Programm. Wenn Sie Ihre Freunde und Verwandten schnell, einfach und kostenlos von Angesicht zu Angesicht sprechen wollen, empfehlen wir Ihnen Logitech Vid als Software der Wahl. Sie können aber auch andere IM-Programme vom Internet herunterladen. Im Gegensatz zu den Produkten manch anderer Anbieter funktionieren die Webkameras von Logitech mit allen Instant-Messaging-Programmen, die Sie nutzen und die Ihre Gesprächspartner verwenden. Sie können also ganz problemlos und ohne großen Aufwand Videogespräche führen.
     
    Mit der Logitech Webcam C200 und kostenlosen Video-Anwendungen können Sie „persönlich vor Ort“ sein – in Ihrer Stadt oder an jedem anderen Fleck der Erde. 
     
     
    ";2;False;0;;;"Logitech Webcam C200 ";logitech-webcam-c200;True;True;P-2920;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;34.9000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;40096,6475;"27;2095";11;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000290-logitech-webcam-c200.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000291-logitech-webcam-c200.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000292-logitech-webcam-c200.jpg;2;;False;;;;;False;False;False;;;;;False;;;;;; -5;0;True;Western Digital My Book 1 TB;"Western Digital BAAF0010HBK My Book Essential 1TB ";"
    Western Digital BAAF0010HBK My Book Essential

    1TB externe Festplatte 
     
    Elegantes Design
    Ihre gesamten Daten auf einen Blick und einfache Datei-Wiederherstellung
    Passwortschutz und 256-bit Hardware basierte Verschlüsselung
    Automatische, kontinuierliche Datensicherung für alle Computer in Ihrem Netzwerk
    Lieferumfang: Western Digital My Book Essential 1TB externes Festplattenlaufwerk,
    WD SmartWare-Software, USB-Kabel, Netzteil, Schnellanleitung
    ";2;False;0;;;"Western Digital My Book Essential Edition 1 TB ";western-digital-my-book-1-tb;True;True;P-2600;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;129.0000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;40090,625150463;14;21;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000286-western-digital-my-book-1-tb.jpg;;;2;;False;;;;;False;False;False;;;;;False;;;;;; -5;0;True;Apple iPod Classic 160 GB schwarz;"Apple iPod Classic 160 GB schwarz ";"

    Apple iPod Classic 160 GB schwarz

     
    iPod classic: Freiraum -Und zwar jede Menge.
    160 GB sind wirklich eine ganze Menge Platz. Da lässt sich eine komplette Mediathek locker unterbringen und überallhin mitnehmen.
     
    Ein musikalisches Genie
    Stellen Sie vor, Sie hören einen Song. Toll wären jetzt andere Titel, die gut dazu passen. Was machen Sie? Ganz einfach: Sie verwenden die neue Funktion ""Genius"". Diese findet die Songs in Ihrer Mediathek, die gut zusammenpassen. Sie erhalten eine Genius Wiedergabeliste, die Sie sofort anhören, sichern oder sogar aktualisieren können. Verlassen Sie sich also auf den Genius von iTunes, wenn Sie einen Mix wollen, auf den Sie selbst nicht gekommen wären.
     
    Platz satt
    Der iPod classic bietet mit seinen 160 GB Speicherkapazität Platz für bis zu 40.000 Songs, 200 Stunden Videos, 25.000 Fotos oder eine beliebige Kombination dieser Inhalte. Und mit bis zu 36 Stunden Batterielaufzeit beweist der iPod classic auch ganz schön viel Kondition.
     
    Spaß auf Knopfdruck
    Sie findeen immer ganz leicht genau das, was Sie sehen oder hören wollen. Mit dem Click Wheel können Sie mit ""Cover Flow"" Ihre Alben durchblättern, oder Sie stöbern über verschiedene Kategorien wie Wiedergabeliste, Künstler, Album oder Musikrichtung in Ihren Songs und Videos. Sie können natürlich auch nach einem bestimmten Titel oder Interpreten suchen. Lust auf einen neuen Mix? Klicken Sie einfach auf ""Zufällige Titel"".
     
    Filme und Fernsehsendungen ansehen
    Auf dem fantastischen 2,5"" Display kommen Videos richtig zur Geltung. Sie können im iTunes Store Filme kaufen oder ausleihen, Fernsehsendungen kaufen und Video-Podcasts laden. Dann können Sie alles mit Ihrem iPod classic synchronisieren und immer und überall ansehen.
     
     
    Spiele auf dem iPod
    Wenige Fingertipps, viele Stunden Spielspaß. Vortex, iQuiz und Klondike sind schon auf dem iPod classic vorinstalliert, im iTunes Store können Sie weitere dazukaufen, z. B. Cake Mania. Alle iPod Spiele sind speziell für die iPod Oberfläche optimiert.
     
    Fotos zeigen
    Ihre Fotos aus iPhoto auf einem Mac oder aus Adobe Photoshop Elements und Adobe Photoshop Album auf einem PC bekommen Sie mit iTunes auf den iPod classic. Sie können Diashows mit Musik und Übergängen auf dem iPod classic oder mit optional erhältlichen Apple Komponenten oder mit einem Composite-AV-Kabel sogar auf dem Fernseher zeigen.
     
    Umweltverträglichkeit
    Der iPod classic steht für das kontinuierliche Engagement von Apple in puncto Umweltschutz. Die folgenden Merkmale tragen zu einer geringen Umweltbelastung bei:
     
        Arsenfreies Displayglas
        Ohne bromhaltige Flammschutzmittel
        Display mit LED-Hintergrundbeleuchtung ohne Quecksilber
        Frei von PVC
        Recyclingfähiges Gehäuse aus Aluminium und Edelstahl
     
    Produktbeschreibungen
    Freiraum. Und zwar jede Menge. 160 GB sind wirklich eine ganze Menge Platz. Da lässt sich eine komplette Mediathek locker unterbringen und überallhin mitnehmen.
     
    > Highlights
    - Click Wheel
    - Frequenzbereich: 20 Hz bis 20.000 Hz
    - Weitere unterstützte Audioformate: Protected AAC (aus dem iTunes Store), MP3 VBR, Audible (Formate 2, 3, 4, Audible Enhanced Audio, AAX und AAX+), Apple Lossless und WAV
    - Platz für bis zu 40.000 Songs im 128 KBit/Sek. AAC-Format
    - Platz für bis zu 25.000 vom iPod anzeigbare Fotos
    - Platz für bis zu 200 Stunden Videomaterial
    - Speichert Daten auf einer USB-Festplatte
    - Akkuladezeit: ca. 4 Std. (schnelles Laden auf 80%ige Kapazität in 2 Std.)
     
    > Grundeigenschaften
    - Breite: 103.5 mm
    - Höhe: 61.8 mm
    - Tiefe: 10.5 mm
    - Gewicht: 140.0 g
    - Farbe: Schwarz
     
    > Wiedergabeformate Audio
    - AAC
    - MP3
    - WAV
     
    > Akku
    - Akkutyp: Li-Ion
     
    > Display
    - Displaytechnologie: LCD
    - 2.5- Display
    - Bilddiagonale: 6.35 cm
    - Auflösung Breite: 320 Pixel
    - Auflösung Höhe: 240 Pixel
    - Hintergrundbeleuchtung: ja
     
    > Speicher
    - Speicherkapazität 160 GB
     
    > Anschlüsse
    - USB
    - USB-Standard 2.0
     
    > Audio-Anschlüsse
    - Headsetanschluss: 3,5 mm Klinke
    - ipod-Anschluss via IPOD Connector
     
    > Lieferumfang
    - iPod classic
    - Apple Earphones
    - USB 2.0 Kabel
    - Dock-Adapter
    - Dokumentation
     
    > Umweltverträglichkeit
    Der iPod nano steht exemplarisch für das Engagement von Apple in puncto Umweltschutz. Die folgenden Merkmale des iPod nano tragen zu seiner geringeren Umweltbelastung bei:
    - Arsenfreies Glas
    - Frei von bromhaltigen Flammschutzmitteln
    - Frei von Quecksilber
    - Frei von PVC
    - Besonders recyclingfähig
     
    ";2;False;0;;;Apple iPod Classic 120 GB schwarz;apple-ipod-classic-160-gb-schwarz;True;True;P-1400;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;239.9000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;40089,850162037;50;1;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000284-apple-ipod-classic-160-gb-schwarz.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000285-apple-ipod-classic-160-gb-schwarz.jpg;;2;;False;;;;;False;False;False;;;;;False;;;;;; -5;0;True;"Logitech MK300 schnurlose Tastatur + Maus schwarz ";"Logitech MK300 schnurlose Tastatur + Maus schwarz ";"

    Logitech MK300 schnurlose Tastatur + Maus schwarz
     

     
    Kabellose Technologie für eine schnelle und zuverlässige Verbindung, die sofort einsatzbereit ist
    Sondertasten und programmierbare F-Tasten
    Flüssigere und reaktionsschnellere Abtastung als herkömmliche optische Mäuse
    Automatischer Energiesparmodus
     
    Lieferumfang:
    Logitech MK300 Tastatur schnurlos, Logitech MK300 Maus schnurlos, USB-Empfänger, Batterien vom Typ AA, Handbuch, CD mit Software.
    ";2;False;0;;;;logitech-mk300-schnurlose-tastatur-maus-schwarz;True;True;P-2800;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;49.0000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;40081,7438194444;21;11;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000513-logitech-mk300-schnurlose-tastatur-maus-schwarz.jpg;;;1;;False;;;;;False;False;False;;;;;False;;;;;; -5;0;True;Samsung NC10 anyNet 10,2 Zoll Netbook;"Samsung NC10 anyNet 10,2 Zoll Netbook schwarz ";"
    Samsung NC10 anyNet10,2"" Netbook

    Intel Atom N270 1.6GHz, 1GB RAM, 160GB HDD, Intel GMA 950 XP Home
     
    NC10-anyNet: Entwickelt für das ""mobile Leben"". Entwickelt für höchste Ansprüche in innovativem Design. Das ultrakompakte und leichte Gehäuse bietet eine Reihe von praktischen Features, die das mobile Leben vereinfachen. Brillante Technologie angepasst an das rasante und digitale Leben für noch mehr Mobilität.
     
    Schlankes Design
    Mit einem optimierten 10,2 Zoll Breitbild Display für ein makelloses visuelles Erlebnis, ist das schlanke NC10 lediglich 1,19 cm hoch und passt nahezu in alle Taschen. Das widerstandsfähige Gehäuse bietet ein Maximum an Tragekomfort und Verlässlichkeit sowie hochwertiger Ergonomie und Stil.
     
    Videokonferenz
    Ob Videokonferenzen oder Live Messaging - die integrierte 1,3 Megapixel Kamera lässt sie noch leichter mit Freunden, Familie und Kollegen in Kontakt bleiben. Die Kamera verbindet die Auflösung und die Bildqualität einer Fotokamera mit der nachhaltig hohen Bildfrequenz einer Videokamera.
     
    Robustes Gehäuse, langlebig und verlässlich
    Fühlen Sie sich sicher mit dem robusten Protect-o-Edge Gehäuse, das für Langlebigkeit und Verlässlichkeit steht. Eine aufwendige Serie von 54 Qualitätstests, die von schnellen Temperaturwechseln bis zu elektrischen Überspannungen reichen, gewährleistet neue Standards in Punkto Belastbarkeit und Ausdauer.
     
    Antibakterielle Tastatur
    Die SilverNano Technologie beschichtet die Tastatur mit nano-kleinen Silberionen, die das Überleben und die Neuentstehung von Bakterien verhindern. Innerhalb von 24 Stunden werden 99,9% aller Bakterien abgetötet und es entsteht eine hygienische Arbeitsatmosphäre.
     
    Leichtgewicht
    Als eines der weltweit leichtesten 10,2 Zoll Mini Notebooks seiner Klasse, mit einem Gewicht von nur 1,45 kg, ist das NC10 voll bepackt mit neuester Technologie und garantiert dabei maximale Mobilität und Leistung.
      
    Vollständige Notebook-Tastatur
    Die vollständige Notebook-Tastatur bietet optimalen Schreibkomfort. Ergonomisches Design und optimierte Tastenabstände machen das Arbeiten und Kommunizieren angenehmer und ermöglichen schnelleres sowie fehlerloses Schreiben.
     
    Voll ausgestattet für einfachen Datenaustausch
    Einfacher Datenaustausch dank einer Vielzahl an Anschlussmöglichkeiten, inklusive einem Kartenleser und drei USB-Anschlüssen, so dass Sie problemlos Bilder, Filme und Daten auf und von nahezu allen modernen Kameras, periphären oder audiovisuellen Geräten transferieren können.
    ";2;False;0;;;;samsung-nc10-anynet-102-zoll-netbook;True;True;P-0860;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;329.9000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;40066,9226388889;6;5;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000511-samsung-nc10-anynet-102-zoll-netbook.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000512-samsung-nc10-anynet-102-zoll-netbook.jpg;;2;;False;;;;;False;False;False;;;;;False;;;;;; -5;0;True;Casio EXILIM EX-Z2 Digitalkamera schwarz;"Casio EXILIM EX-Z2 Digitalkamera schwarz ";"
    Casio EXILIM EX-Z2 SR Digitalkamera schwarz
     
    12 Megapixel, 3-fach opt. Zoom, 2,7"" Display


    Die EX-Z2 versteckt in ihrem flachen Designgehäuse leistungsstarke 12,1 Megapixel.
    Der CCD-Chip mit 12,1 Megapixel erlaubt nicht nur brillante Fotos zu machen, sondern auch Bildausschnitte zu bearbeiten, zu vergrößern und im Wunschformat auszudrucken – bei hervorragender Qualität und ohne Verlust von Bildinformationen.
     
    12,0 Megapixel CCD-Chip
    3fach optischer Zoom, 4fach digitaler Zoom
    6,9 cm (2.7 Zoll) Wide Screen TFT- Farbdisplay
    23 BEST SHOT Programme, Gesichtserkennung, Selbstauslöser, Speicherkartenslot für SD-/SDHC, MMC-/MMCplus und Eye-Fi Wireless Speicherkarten
     
    Lieferumfang:
    Digitalkamera, Akku, Ladegerät, USB-Kabel, AV-Kabel, Trageriemen, Grundlegende Referenz, CD-ROM
    ";2;False;0;;;"Casio EXILIM EX-Z2 SR Digitalkamera ";casio-exilim-ex-z2-digitalkamera-schwarz;True;True;P-1750;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;149.0000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;40064,7887268519;"57;2095";9;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000499-casio-exilim-ex-z2-digitalkamera-schwarz.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000500-casio-exilim-ex-z2-digitalkamera-schwarz.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000501-casio-exilim-ex-z2-digitalkamera-schwarz.jpg;2;;False;;;;;False;False;False;;;;;False;;;;;; -5;0;True;Samsung Syncmaster P2250 21,5 Zoll TFT Monitor schwarz;"Samsung Syncmaster P2250 21,5 Zoll TFT Monitor schwarz ";"
    Samsung Syncmaster P2250 21,5 Zoll TFT Monitor schwarz

    DVI ,Kontrast 50000:1, 2ms Reaktionszeit

    DieSyncMaster 50er Serie überzeugt mit schlichtem Design und moderner Technik.
    Der elegant schmale Rahmen in Verbindung mit dem dezenten roten Farbverlauf macht diese Modelle zu einem echten Blickfang.
    Das praktische 16:9-Format bietet eine Full HD Auflösung mit 1.920 x 1.080 Pixel.
    Das sehr hohe dynamische Kontrastverhältnis von 50.000:1 und die schnelle Reaktionszeit von nur 2 ms (G/G) sorgen
    stets für klare und detailreiche Bilder - auch bei schnell bewegten Bildinhalten.
    Das praktische 16:9-Widescreen-Format ermöglicht ein noch angenehmeres Arbeiten bei gleichzeitiger Steigerung Ihrer Produktivität.
    Das Breitbildformat entspricht dem natürlichen Sichtfeld des Betrachters. Somit haben Sie immer alles im Blick, ohne auf wichtige Informationen verzichten zu müssen.
    Dieses SyncMaster Large Format Display verfügt über ein Full HD-Panel mit einer nativen Auflösung von 1.920 x 1.080 Pixel.
    Somit können Bildinhalte im 1.080p-Format, der derzeit besten HD-Auflösung, wiedergegeben werden. 
    Genießen Sie beste Bildqualität mit hoher Bildschärfe und Detailreichtum selbst in dunklen Szenen.
    Mit einem dynamischen Kontrast von 50.000:1 werden Sie jedes Detail auf dem Bildschirm erkennen können.
    Lieferumfang: Monitor, Signalkabel, Netzkabel, Treiber CD, Handbuch (CD)
    ";2;False;0;;;"Samsung Syncmaster P2250 21,5 Zoll ";samsung-syncmaster-p2250-215-zoll-tft-monitor-schwarz;True;True;P-2470;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;2,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;219.9000;219.9000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;40048,6219907407;9;5;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000376-samsung-syncmaster-p2250-215-zoll-tft-monitor-schwarz.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000377-samsung-syncmaster-p2250-215-zoll-tft-monitor-schwarz.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000378-samsung-syncmaster-p2250-215-zoll-tft-monitor-schwarz.jpg;2;;False;;;;;False;False;False;;;;;False;;;;;; -5;0;True;"Panasonic DMR EH 595 EG K DVD-/HDD-Rekorder 250 GB ";"Panasonic DMR EH 595 EG K DVD-/HDD-Rekorder 250 GB ";"

    Panasonic DMR EH 595 EG K DVD-/HDD-Rekorder 250 GB

      
    HDMI, DivX-zertifiziert, USB 2.0
     
      
    Die Rekorder DMR-EH595 zeigen sich als wahre Alleskönner und zeichnen auf Festplatte oder DVD auf.
    Sie verarbeiten alle gängigen DVD-Formate wie DVD-RW, -R (DL), DVD+RW/+R (DL) sowie DVD-RAM. Außerdem können CDs, CD-R/-RWs sowie MP3- und JPEG-Daten sowohl von DVD als auch CD abgespielt werden.
    Die integrierte Festplatte erlaubt die Aufzeichnung von Fernsehprogrammen. Somit ist auch bei längerer Abwesenheit genügend Platz für die Lieblingsserie vorhanden.
    Dank des integrierten, elektronischen Programmführers Gemstar Guide Plus+ erfolgen die Programmauswahl und Timerprogrammierung kinderleicht und intuitiv.
    Die übersichtliche Darstellung des Fernsehprogramms bietet neben einer Genre-Auswahl zusätzlich eine gezielte Suche nach Stichworten.
    So kann beispielsweise direkt nach Schauspielern, Themen oder Sportarten gesucht werden.
    Neben dieser Funktion arbeiten die neuen Rekorder mit einer automatischen Kapitelerstellung bei der Aufzeichnung.
    Dadurch können während der anschließenden Wiedergabe unerwünschte Programmsequenzen auf Knopfdruck übersprungen oder eine Szene blitzschnell gefunden werden.
    Mit Pause Live TV kann zudem das laufende Fernsehprogramm jederzeit mit einem Druck auf die Pause-Taste angehalten und zu einem späteren Zeitpunkt weitergeschaut werden.
    Dank Quick Start-Funktion sind die Rekorder innerhalb einer Sekunde einsatzbereit, so dass kein Film und keine Aufzeichnung verpasst werden.

    Multiformat-DVD-Festplatten-Kombination
    Intuitive Benutzerführung
    Neben der Aufnahme des Fernsehprogramms überzeugen die neuen Rekorder als digitales Fotoalbum sowie Musik-Jukebox
    Elektronische Programmführer Guide Plus+ mit Suchfunktion
    Umfangreiche Anschlussmöglichkeiten
    ";2;False;0;;;Panasonic DMR EH 595 EG K;panasonic-dmr-eh-595-eg-k-dvd-hdd-rekorder-250-gb;True;True;P-1800;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;2,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;379.0000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;40046,702650463;63;12;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000375-panasonic-dmr-eh-595-eg-k-dvd-hdd-rekorder-250-gb.jpg;;;2;;False;;;;;False;False;False;;;;;False;;;;;; -5;0;True;"Garmin Freizeitguide Deutschland ";"Garmin Freizeitguide Deutschland ";"

    Garmin Freizeitguide Deutschland

     
     
    Wander- und Freizeitkarten von 21 Regionen 



    Freizeit- und Wanderkarten von 21 Nationalparks und Freizeitregionen vom Bayrischen Wald bis zur Insel Rügen im Maßstab 1:25.000 (Auflistung der Regionen auf www.garmin.de)
    Kompatibel mit allen aktuellen Garmin nüvi-Straßennavigationsgeräten und kartenfähigen Outdoor-GPS Geräten
    Sonderziele (POIs) wie Freizeitparks, Schlösser, Burgen, Denkmäler, Museen, Zoos, Bäder und Thermen können direkt angesteuert werden
    Micro SD Karte kann einfach in den Kartenslot eingeschoben werden - Installation oder Freischaltung entfällt
    Lieferumfang: Micro SD Karte mit Freizeitguide Deutschland
    ";2;False;0;;;;garmin-freizeitguide-deutschland;True;True;P-2080;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;29.0000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;40041,5175231481;"67;2095";44;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000364-garmin-freizeitguide-deutschland.jpg;;;2;;False;;;;;False;False;False;;;;;False;;;;;; -5;0;True;"Garmin Nüvi 1490 Tpro Navigationssystem Europa ";"Garmin Nüvi 1490 Tpro Navigationssystem Europa ";"

    Garmin Nüvi 1490 Tpro Navigationssystem Europa

     
     
     
    5"" Touchscreen-Display, TMC Pro, ecoRoute, Fußgänger- und PhotoNavigation, Bluetooth
     
     
     
    Mobile Navigation ohne Grenzen im Großformat, im ultra-flachem Design an die Bedürfnisse professioneller Anwender ausgerichtet
    Übersichtliche und einfache Navigation im 5 Zoll Display mit Fahrspurassistent und 3D-Kreuzungsansicht,
    TMC Pro Europa Premium Verkehrsfunkempfänger
    Kartenmaterial für 41 Länder in West- und Osteuropa intern vorinstalliert;
    Inklusive ecoRoute die Garmin Spritspar-Funktion und echter Fußgängernavigation mit optionalen CityXplorer Stadtplänen für Bus und Bahn
    Lieferumfang: Garmin nüvi 1490Tpro mit Kartenmaterial Europa, KFZ-Anschlusskabel mit TMC Pro-Verkehrsfunkempfänger,
    Saugnapfhalterung für die Windschutzscheibe, Armaturenhalterung, Schnellstartanleitung
    ";2;False;0;;;"Garmin Nüvi 1490Tpro Navigationssystem Europa ";garmin-nuevi-1490-tpro-navigationssystem-europa;True;True;P-2070;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;289.0000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;40041,5110416667;67;44;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000363-garmin-nuvi-1490-tpro-navigationssystem-europa.jpg;;;2;;False;;;;;False;False;False;;;;;False;;;;;; -5;0;True;"Garmin nüvi 255WT Navigationssystem Europa ";Garmin nüvi 255WT Navigationssystem Europa inklusive TMC;"

    Garmin nüvi 255WT Navigationssystem Europa

    inklusive TMC, 4,3"" Touchscreen Display, PhotoNavigation, SD-Kartenslot und ecoRoute
     
    Bedienerfreundliches Einsteigernavigationsgerät mit elegantem, ultra-schlankem Design und brillantem 4,3“ großem Touchscreen Display + TMC Verkehrsfunkempfänger Kartenmaterial für 40 Länder in West- und Osteuropa intern vorinstalliert; ecoRoute: reduziert den Kraftstoffverbrauch, CO2-Emissionen und schont die Umwelt, spart bares Geld und füllt die Reisekasse auf. PhotoNavigation mit Garmin Connect: Sie können Sehenswürdigkeiten und Bilder herunterladen und als Ziel auswählen Lieferumfang: Garmin nüvi 255W mit Kartenmaterial Europa, + TMC Verkehrsfunkempfänger (=WT), Saugnapfhalterung für die Windschutzscheibe, Armaturenhalterung, Schnellstartanleitung, KFZ-Anschlusskabel
    ";2;False;0;;;"Garmin nüvi 255WT Navigationssystem Europa ";garmin-nuevi-255wt-navigationssystem-europa;True;True;P-2060;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;169.0000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;40041,5046064815;67;44;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000362-garmin-nuvi-255wt-navigationssystem-europa.jpg;;;2;;False;;;;;False;False;False;;;;;False;;;;;; -5;0;True;"Canon PowerShot SX200 IS ";Canon PowerShot SX200 IS;"

    Canon PowerShot SX200 IS

    12 Megapixel, 12-fach opt. Zoom, 3"" Display

    Das neue Super-Zoom-Modell unter den Canon PowerShot-Digitalkameras zeigt große Stärke im kompakten Format:
    28 Millimeter-Weitwinkelobjektiv, 12-fach optischen Zoom, DIGIC-4-Bildprozessor und starke 12,1 Megapixel machen die PowerShot SX200 IS zu einem idealen Reisebegleiter.
    Für Spitzenqualität können Movieclips in High Definition mit 720p und 30 B/s aufgezeichnet und über die integrierte HDMI™-Schnittstelle auf einem HDFernseher wiedergegeben werden.
    Ein Aufnahmemodus für die vollständig manuelle Steuerung bringt ambitionierten Fotografen kreative Freiheit pur.
     
    Die Leistungsstärke des neuen DIGIC-4-Bildprozessors führt zu einer optimierten Motion- und Face-Detection-Technologie.
    Motion Detection unterscheidet Kameraverwacklungen von bewussten Bewegungen des Motivs und stimmt in Kombination mit dem Servo AF darauf die Einstellungen der Kamera zur Minimierung von Verwacklungsunschärfen ab.
    Face Detection erkennt Gesichter im Motiv, auf die die Kamera dann kontinuierlich scharf stellt.
    Starke Pluspunkte bei der Canon Face Detection sind der FaceSelf-Timer für Gruppenfotos, in denen der Fotograf bequem mit auf das Bild kommt, und die Rote-Augen-Korrektur.
     
    Als weitere Technologie-Komponente spielt die innovative Canon-i-Contrast- Technologie ihre Stärken bei Bildern mit dunklen Bildbereichen aus:
    Sie erhöht den Kontrast ausschließlich in diesen Bildpartien, anstatt lediglich die Gesamthelligkeit zu steigern, was zu überbelichteten Bildern führen würde. Der Canon-DIGIC-4- Prozessor ist zudem die Basis für schnelle Reaktionszeiten, effizientes Pufferspeicher-Handling und minimiertes Bildrauschen.
     
    Manche Motive muss man einfach in bewegten Bildern festhalten:
    Dafür hat die PowerShot SX200 IS einen Movie-Modus, in dem Movieclips sogar in High- Definition-Auflösung (720p) aufgezeichnet werden.
    Ideal für die Wiedergabe der Clips auf einen High-Definition-Fernseher ist die integrierte HDMI™-Schnittstelle für den Anschluss der Kamera.
    Das 3,0 Zoll große LC-Display der Kamera macht nicht nur Bildkomposition und Bildprüfung angenehm einfach, der große Betrachtungswinkel ist auch ideal für das direkte Betrachten von Bildern und Movieclips.
    Die neue Benutzeroberfläche verfügt zudem über eine intelligente Funktion zur Einblendung praktischer Tipps und Tricks für die unterschiedlichen Einstellungen und ihre Auswirkungen auf die Aufnahmen.
     
    Lieferumfang:
    PowerShot SX200 IS, Trageriemen, Akku, Akku-Ladegerät, USB-Kabel, Video-Kabel
    ";2;False;0;;;Canon PowerShot SX200 IS;canon-powershot-sx200-is;True;True;P-1720;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;259.9000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;40039,860474537;"56;2095";25;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000351-canon-powershot-sx200-is.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000352-canon-powershot-sx200-is.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000353-canon-powershot-sx200-is.jpg;2;;False;;;;;False;False;False;;;;;False;;;;;; -5;0;True;"Philips DLA 1619 H/10 Neopren-Tasche für iPod Shuffle ";"Philips DLA 1619 H/10 Neopren-Tasche für iPod Shuffle schwarz ";"

    Philips DLA 1619 H/10 Neopren-Tasche für iPod Shuffle schwarz

    Armband, Sichtfenster und Gürtel-Clip
     
    Ob für Sport oder Erholung, Ihr iPod ist immer dabei. Dafür ist das Action Jacket die allumfassende Lösung.
    Verwenden Sie das verstellbare Armband beim Sport und bewahren Sie den iPod shuffle nach dem Sport in der schützenden Hülle auf.
     
    • Aktiver Schutz
    • Durchsichtiges Fenster zum Schutz des Bildschirms
    • Neopren schützt vor Schweiß
    • Vielseitige Positionierung
    • Anpassbares Sportarmband
    • Das anpassbare Sportarmband ist dehnbar und passt sich so unterschiedlichsten Größen an. Es ist mit einem
    • Klettverschluss versehen, sodass Ihr Gerät bei jeder Aktivität sicher verstaut ist.
    • Sichtfenster für das Display
    • Beim Sport schützt dieses durchsichtige Fenster den Bildschirm des Geräts und ermöglicht gleichzeitig die
    • Bedienung des Geräts.
    • Feuchtigkeitsbeständiges Neopren
    • Diese Neoprentasche bietet eine gepolsterte, feuchtigkeitsbeständige Schicht für Ihr Gerät und schützt es beim
    • Sport vor Schweiß und den Elementen.
    ";2;False;0;;;"Philips DLA 1619 H/10 Neopren-Tasche für iPod Shuffle ";philips-dla-1619-h10-neopren-tasche-fuer-ipod-shuffle;True;True;P-1520;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;24.9000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;40035,8124652778;51;6;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000350-philips-dla-1619-h10-neopren-tasche-fur-ipod-shuffle.jpg;;;2;;False;;;;;False;False;False;;;;;False;;;;;; -5;0;True;Hama MP3-Tasche iPod nano 5G;Hama MP3-Tasche iPod nano 5G Transparent;"
    Hama MP3-Tasche iPod nano 5G Transparent 

     
    robuste, passgenaue Silikontasche; perfekte Passform, sitzt wie eine zweite Haut;
    Ausstattung: Aussparungen für Bedienelemente und Anschlüsse;
    3D-Sticker für bessere clickwheel Steuerung; abnehmbares Trageband
    Displayschutzfolie; Serie: Sport Case; Farbe: Transparent; Material: Silikon;
    Medium: MP3-Player; Typ: Fenstertasche; für MP3-Marke: für iPod Nano 5G
    ";2;False;0;;;;hama-mp3-tasche-ipod-nano-5g;True;True;P-1510;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;14.9000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;40035,80875;"51;2095";18;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000349-hama-mp3-tasche-ipod-nano-5g.jpg;;;2;;False;;;;;False;False;False;;;;;False;;;;;; -5;0;True;Panasonic DMR EH 695 EG DVD- und Festplatten-Rekorder 320 GB;"Panasonic DMR EH 695 EG DVD- und Festplatten-Rekorder 320 GB ";"
    Panasonic DMR EH 695 EG DVD- HDD-Rekorder 320 GB

     
    HDMI, SDHC-Kartenslot, USB 2.0

    Der neue DIGA DVD-Recorder DMR-EH695 mit analogen Kabeltuner steht für hervorragende Aufnahme- und Wiedergabequalität, Musikgenuss sowie ein Maximum an Kompatibilität.
     
    Auf die 320 GB Festplatte können bis zu 567 Stunden (EP Modus) oder aufgrund eines sehr guten Encoders bis zu 284 Stunden Aufnahmekapazität in DVD Qualität (LP-Modus) gespeichert werden.
     
    Die Super Multi Format Aufnahmefähigkeit des DMR-EH695 verarbeitet alle DVD Formate [DVD-RAM, -RW, -R, -R (DL), +RW, +R, +R (DL)] und spielt neben diesen Formaten zusätzlich JPEG, MP3, WMA und DivX Daten ab. Auf die integrierte ""Jukebox"" lassen sich schnell und einfach Ihre Musik CDs in 12-facher Kopiergeschwindigkeit (6min.)
    in unkomprimiertem LPCM auf die Festplatte kopieren.
     
    Die Album, Interpreten und Titelinformationen sind bereits auf der vorinstallierten Gracenote-Datenbank auf der Festplatte hinterlegt, sodass eine lästige Eingabe entfällt.
     
    Über den USB Eingang können Sie Ihre MP3/WMA-Musikinhalte, JPEG Bilder oder MPEG2 Filme vom Camcorder ebenfalls auf die Festplatte kopieren oder abspielen. Neben diesen Formaten können auch DivX-Dateien abgespielt werden. Ebenfalls in Front bietet ein SDHC Slot die Möglichkeit, HD-JPEG oder MPEG2 Aufnahmen auf die Festplatte zu kopieren oder abzuspielen.
     
    Der DMR-EH695 skaliert jedes Bildmaterial über die HDMI-Schnittstelle in eine maximale HDTV Auflösung mit 1080 Zeilen (Full HD).
     
    Die neue praktische VIERA LINK Funktion, ausschließlich über HDMI mit den VIERA Flachbildschirmen nutzbar, bietet Ihnen komfortable Bedienung aller Panasonic Geräte mit nur einer Fernbedienung! Einfach, schnell und problemlos.
     
    HDMI-Ausgang (HDMI Ver. 1.3)
    USB-Anschluss (USB 2.0 High Speed)
    SD-HC Karten-Slot
    DV Eingang (IEEE1394/iLink)
    Komponentenausgang (YUV)
    2x Scart-Anschluss
    Front-AV (S-Video/Video/Audio-IN)
    S-Video Ausgang (Hosiden)
    Video-Ausgang (Cinch)
    Audio Ausgang (Cinch)
    Optischer Digitalausgang (PCM, Dolby Digital, DTS, MPEG)
     
    Lieferumfang:
    Panasonic DMR-EH695EGK, Fernbedienung
    ";2;False;0;;;"Panasonic DMR EH 695 EG DVD- und Festplatten-Rekorder ";panasonic-dmr-eh-695-eg-dvd-und-festplatten-rekorder-320-gb;True;True;P-1790;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;2,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;419.0000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;40035,2792476852;64;12;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000348-panasonic-dmr-eh-695-eg-dvd-und-festplatten-rekorder-320-gb.jpg;;;3;;False;;;;;False;False;False;;;;;False;;;;;; -5;0;True;"Qualitätsakku für Canon EOS 450D, 500D und 1000D ";"Qualitätsakku für Canon EOS 450D, 500D und 1000D Typ: Lithium-Ion-Akku ";"

    Qualitätsakku für Canon EOS 450D, 500D und 1000D

    Typ: Lithium-Ion-Akku
     
    Leistungsstark - hohe Qualität und doch günstig
    Dieser Qualitätsakku zeichnet sich durch seine Langlebigkeit und Zuverlässigkeit aus und steht dem Original von Canon LP-E5 in nichts nach.
    Dieser Akku passt auch in den Batteriegriff Canon BG-E5. Der Akku ist mit einem Chip ausgestattet, welcher Überladung und Überhitzung verhindert.
     
    Technische Details
    • Typ: Lithium-Ion-Akku
    • Spannung: 7,4v
    • Kapazität: 1080mAh
    • Gewicht: 50g
    • Überladungs-/Überspannungsschutz
    ";2;False;0;;;Qualitätsakku für Canon EOS 1000D;qualitaetsakku-fuer-canon-eos-450d-500d-und-1000d;True;True;P-1710;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;29.9000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;40035,2271412037;56;25;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000347-qualitatsakku-fur-canon-eos-450d-500d-und-1000d.jpg;;;2;;False;;;;;False;False;False;;;;;False;;;;;; -5;0;True;"Logitech V150 Laser Mouse ";"Logitech V150 optische Notebook Maus schnurgebunden silber ";"Logitech V150 optische Notebook Maus schnurgebunden silber
     
     
     
    Plug & Play: Die Maus muss nur an einem USB-Anschluss angeschlossen werden und ist sofort einsatzbereit.
    Laserabtastung: Erleben Sie Laser für präzise, flüssige Abtastung auf fast jeder Oberfläche
    Tilt Wheel Plus Zoom¿: Horizontale Bildläufe. Vergrößern und verkleinern Sie mühelos Fotos und Tabellen.
    Handgerechte Form: Komfort für Rechts- und Linkshänder.
    Besonders kompaktes Design: Praktisch für unterwegs. ";2;False;0;;;"Logitech V150 Laser Mouse for Notebooks ";logitech-v150-laser-mouse;True;True;P-2790;;;False;0;False;;False;False;0;False;0;1;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;29.0000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;40028,639212963;21;11;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000346-logitech-v150-laser-mouse.jpg;;;2;;False;;;;;False;False;False;;;;;False;;;;;; -5;0;True;Panasonic DMP-BD60EG-K Blu-ray Player;"Panasonic DMP-BD60EG-K Blu-ray Player schwarz ";"

    Panasonic DMP-BD60EG-K Blu-ray Player schwarz

     
    HDMI, Upscaling 1080p, USB 2.0

     
     Glänzt als wahre Allround-Unterhaltunskünstler
    Moderne Schnittstellen wie SD/SDHC-Slot und USB-Eingang mit Multimediamöglichkeiten
    Über den Ethernet-Port Zugriff auf den I/P-Service VIERA Cast
    Z.B. YouTube-Videos und Fotos über den Online-Bilderdienst Picasa ansehen
    Zahlreiche Komfortmerkmalen wie BD-Live und Bonus View
    Wiedergabe-Formate: Blu-ray Video, Blu-ray Disc (BD-R), Blu-ray Disc wiederbeschreibbar (BD-RE), DVD-Video, DVD+R, DVD-R, DVD+RW, DVD-RW, DVD+R DL, DVD-R DL, DVD-RAM,
    CD-Audio, CD-R, CD-RW, MP3, DivX, Foto-Formate JPEG
    Audio: Dolby Digital Plus, Dolby TrueHD, DTS-HD, MPEG2
    Anschlüsse: Audio-Ausgang, Video-Ausgang, Video-Farbkomponenten-Ausgang (YPbPr / YUV), Digital-Ausgang Optisch, Speicherkarten-Steckplatz, HDMI, USB, Netzwerk
    Farbe: schwarz
    ";2;False;0;;;Panasonic DMP-BD60EG-K Blu-ray Player;panasonic-dmp-bd60eg-k-blu-ray-player;True;True;P-1900;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;2,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;164.9000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;40025,7325578704;"61;2095";12;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000343-panasonic-dmp-bd60eg-k-blu-ray-player.jpg;;;2;;False;;;;;False;False;False;;;;;False;;;;;; -5;0;True;"LG W2261VP 54,6 cm (21,5 Zoll) Widescreen TFT Monitor HDMI/ DVI-D/ VGA ";"LG W2261VP 54,6 cm (21,5 Zoll) Widescreen TFT Monitor HDMI/ DVI-D/ VGA (Kontrastverhältnis 50000:1, Reaktionszeit 2ms) schwarz ";"
    LG Electronics präsentiert: TFT Monitor FLATRON W2261VP
    Multimedia Monitor mit erstklassigen Werten
    Dank HDMI bietet dieser 22 Zoll LG Monitor vielfältige und zukunftssichere Anschlussmöglichkeiten. Mit seinem natürlichen 16:9 Blickfeld-Format eignet er sich perfekt für Gamer und Multimedia-Fans – nicht zuletzt auch aufgrund der schnellen Reaktionszeit von 2ms und dem hohen Kontrast von 50.000:1. Genießen Sie mit den innovativen Fun-Funktionen absoluten Bedienkomfort, dank Full HD und f-Engine perfekte Bildqualität und ein wertiges, edles Design in einem!
     
    Beschreibung der Features
     
    Perfektion in Full HD
    Höchste Präzision und beste Qualität in der Darstellung sind in allen Bereichen – ob für Filme, Computerspiele, Multimedia- und Of?ce-Anwendungen – garantiert. Pixel für Pixel stellt dieser LG Monitor in einer Auflösung von 1920x1080 die Bilder unskaliert genauso dar, wie sie die Quelle liefert. Das sorgt für eine reibungslose Wiedergabe und garantiert extrem scharfe und kristallklare Bilder, die selbst bei Action-Szenen oder Sportübertragungen nicht ins Ruckeln geraten.
     
    Hochgenuss im 16:9 Breitbildformat
    Der W2261VP LG Monitor mit integriertem 16:9 Panel bringt überragende Bildqualität mit Full HD-Au?ösung im Breitbildformat zu Ihnen nach Hause. Das 16:9 Panel ist ein natürliches Blickfeld-Format, das Ihre Augen nicht übermäßig beansprucht. So können Sie Ihren Monitor sowohl für actiongeladene BluRay- oder DVD-Filme, zum digitalen Fernsehen oder für professionelle Aufgaben am PC ideal nutzen. Super bequem beim Arbeiten: Es lassen sich problemlos zwei DIN-A4-Hochformate nebeneinander anzeigen.
     
    Scharfer Kontrast
    Der ultra hohe Kontrast von 50.000:1 mit DFC (Digital Fine Contrast) bringt tiefstes Schwarz und strahlend helles Weiß auf Ihren Bildschirm. Farben zeigen sich brillant und lebensecht, so dass das Filmerlebnis am PC eine neue Dimension erreicht.
     
    Schnelle Reaktionszeit
    Durch die enorm schnelle Reaktionszeit der Hintergrundbeleuchtung von nur 2 Millisekunden werden Bewegungsunschärfen eliminiert und ein ruckelfreies Bilderlebnis garantiert. Bei Action?lmen, Sportübertragen oder Videogames verpassen Sie nun nichts mehr! Und dank des angenehm großen Blickwinkels von 170° kommen auch die richtig anspruchsvollen Multimedia- und Office-Anwender voll auf ihre Kosten.
     
    Connected: HDMI
    HDMI steht für ""High Definition Multimedia Interface"". Hierbei handelt es sich um eine zukunftssichere Schnittstelle für die volldigitale Übertragung von Audio- und Video-Daten in der Unterhaltungselektronik. Dieser Anschluss verbindet portable HDMI-Abspielgeräte mit Ihrem Display und ermöglicht eine verlustfreie High-Definition Bild- und Tonübertragung wobei eine Bildtiefe von bis zu 48-bit erreicht werden kann. Beim W2261VP Monitor haben Sie diesen komfortabel nutzbaren HDMI- sowie einen DVI-D Eingang mit HDCP Kopierschutzunterstützung.
     
    Innovative FUN-Funktionen
    Nutzen Sie praktische Photoeffekte für Farbkorrekturen in Bildern und Filmen oder die ez-Zooming-Funktion zur hochauflösenden Ausschnittvergrößerung von Bild und Text. Die 4:3 Formatumschaltung sorgt zudem für verzerrungsfreien Film- und Spielgenuss.
     
    Alle Daten im Überblick
     
    22"" TFT Monitor für den anspruchsvollen Multimedia Anwender im 16:9 Breitbildformat.
    Funktionelles edles Design in hochglänzendem Schwarz
    Ultra schnelles Panel mit kurzer Reaktionszeit von nur 2 ms (ISO) und sehr großem Blickwinkel von 170°; ideal für Multimedia-Anwender oder Gamer.
    Ultra hoher Kontrast von 50.000:1 mit DFC (Digital Fine Contrast)
    Full HD Auflösung (1920 x 1080 Pixel). Formatfüllende Darstellung von zwei DIN-A4 Seiten gleichzeitig.
    f-Engine – LG's welterster Bildverbesserer Chip garantiert kristallklare und brillante Bilder ohne Farbverfälschung in Echtzeit für Film, Foto oder Anwender.
    Neue ergonomische Menüführung mit Visual OSD
    Fun Taste für Photoeffekte zur kreativen Darstellung von Bildern wie z.B. Sepia, kalt, und Gaussche Unschärfe. ez Zooming zur Änderung der Auflösung, oder ARC Formatumschaltung von 4:3 auf 16:9 zur formatgetreuen Darstellung von älteren Programmen.
    HD fähig und zukunftssicher HDMI Eingang (bis 1080p) und DVI-D Eingang mit HDCP Kopierschutzunterstützung. Zusätzlicher VGA 15 Pin D-Sub Eingang zum Betrieb an zwei Rechnern.
    Integriertes Netzteil
    Kopfhörerausgang
    Externes Netzteil 
    ";2;False;0;;;"LG W2261VP 54,6 cm (21,5 Zoll) Widescreen TFT Monitor HDMI/ DVI-D/ VGA ";lg-w2261vp-546-cm-215-zoll-widescreen-tft-monitor-hdmi-dvi-d-vga;True;True;P-2520;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;2,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;239.0000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;40025,6372800926;"11;2095";19;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000337-lg-w2261vp-546-cm-215-zoll-widescreen-tft-monitor-hdmi-dvi-d-vga.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000338-lg-w2261vp-546-cm-215-zoll-widescreen-tft-monitor-hdmi-dvi-d-vga.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000339-lg-w2261vp-546-cm-215-zoll-widescreen-tft-monitor-hdmi-dvi-d-vga.jpg;2;;False;;;;;False;False;False;;;;;False;;;;;; -5;0;True;"Western Digital My Passport Essential 500 GB ";"Western Digital BAAA5000ABK My Passport Essential 500GB ";"
    Western Digital BAAA5000ABK My Passport Essential 500GB 
     
    Unsere kleinste tragbare Festplatte aller Zeiten
    Ihre gesamten Daten auf einen Blick und mühelose Widerhergestellung Ihrer Daten
    Passwortschutz und 256-bit Hardware basierte Verschlüsselung
    Plug-and-play-bereit für Windows-PCs
    Lieferumfang: Western Digital My Passport Essential 500GB externe Festplatte,
    SmartWare-Software, USB-Kabel, Schnellinstallationsanleitung
    ";2;False;0;;;Western Digital My Passport Ess. 500GB schwarz;western-digital-my-passport-essential-500-gb;True;True;P-2570;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;109.0000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;40015,1174768519;14;21;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000336-western-digital-my-passport-essential-500-gb.jpg;;;2;;False;;;;;False;False;False;;;;;False;;;;;; -5;0;True;LG BD 370 Blu-ray Disc Player schwarz;"LG BD 370 Blu-ray Disc Player schwarz ";"

    LG BD 370 Blu-ray Disc Player schwarz 

    HDMI, Upscaler 1080p, BD live, You Tube-Video Client, Ethernet, USB 2.0

    Der neue BD-370 verbindet wie kein anderer Blu-ray Player das Internet mit dem Fernsehen.
    Über eine LAN-Verbindung können Sie YouTube Video-Streams wiedergeben.
    Die BD-Live Funktion versorgt Sie über das Internet mit Zusatzinformationen zu den Filmen,
    wie z.B. Kommentare oder Extra-Material. Wie von LG gewohnt, liefert der BD-370 perfekte Bildqualität
    und ist, kombiniert mit einem FullHD TV, unschlagbar in Sachen Bildqualität.
     
    Blu-ray Disc Player zur Wiedergabe von: Blu-ray Discs, BD-R(E), Video DVDs (PAL & NTSC), DVD+R(W), DVD-Dual Layer,
    DVD+R Double Layer, Audio-CD, DTS-CD, MP3 CD, WMA CD, PNG, CD, DivX CD, JPEG CD, CD-R(W)
    Unterstützung interaktiver Blu-ray Disc Standard-Inhalte & BD Live 2.0
    YouTube™ Video-Streaming Wiedergabe über LAN
    USB 2.0 und HDMI 1.3 1080p Ausgang mit SIMPLINK & Deep Colour,
    A/V-Ausgang (Cinch), Komponentenausgang YUV, RJ45 LAN-Anschluß
    Dolby TrueHD, Dolby Digital, Dolby Digital Plus, DTS-HD, DTS, LPCM, MP3, WMA, MPEG1/2 L2
    ";2;False;0;;;LG BD 370 Blu-ray Disc Player schwarz;lg-bd-370-blu-ray-disc-player-schwarz;True;True;P-1890;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;2,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;147.9000;147.9000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;40013,6568865741;61;19;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000333-lg-bd-370-blu-ray-disc-player-schwarz.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000334-lg-bd-370-blu-ray-disc-player-schwarz.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000335-lg-bd-370-blu-ray-disc-player-schwarz.jpg;2;;False;;;;;False;False;False;;;;;False;;;;;; -5;0;True;"Samsung DVD-HR 775 A DVD-/Festplatten-Rekorder ";"Samsung DVD-HR 775 A DVD-/Festplatten-Rekorder 250 GB ";"
    Multiformat DVD-Recorder im 55 Millimeter Slim Design mit 250 GB HDD,
     
    USB 2.0, MPEG4 (DivX), HDMI™-Ausgang (1.080p/ 1.080i / 720p),
     
    Anynet+ (HDMI-CEC), TimeShift, TimeSlip und ShowView.
     
     
    Aufnahme auf Festplatte
    Die eingebaute Festplatte mit 320 / 250 / 160 GB im DVD-HDD-Recorder macht‘s möglich: Im EP-Modus können Sie bis zu 534 / 421 / 264 Stunden Filme aufzeichnen.
     
    One-Touch-Aufnahme
    Die Samsung DVD-Recorder machen das Aufzeichnen leichter denn je. Ein Knopfdruck genügt – schon sucht der Samsung Recorder nach dem verfügbaren Aufnahmeplatz auf der Disc und beginnt mit der Aufnahme. Einmal drücken bedeutet Aufnahme bis zu 30 Minuten, zweimal drücken bis zu einer Stunde. Mit jedem Tastendruck zeichnet der Samsung DVD-Recorder weitere 30 Minuten des ausgewählten Programms auf. Die Aufnahmezeit auf einer Disc beträgt je nach Aufnahmemodus maximal 240 Minuten.
     
    Automatische Fehlerkorrektur
    Die Bildqualität der auf DVD gespeicherten Daten kann bei einer verbogenen Disc verzerren. Der Grund: Diese Disc lässt sich aufgrund der Unregelmäßigkeit der Laserreflexion nicht korrekt lesen. Zur Verbesserung der Lesbarkeit sind Samsung Recorder mit einer automatischen Fehlerkorrektur-Technologie ausgestattet. Diese Technik verbessert die Datenleserlichkeit selbst bei Discs, die Unregelmäßigkeiten aufweisen.  VBR-Technologie
    Mit der VBR (Variable Bit Rate)-Technologie kann die Aufnahmezeit durch Einstellen des Aufnahmemodus auf bis zu 16 Stunden verlängert werden. Um Bilder auf DVD-RW und DVD-R aufzuzeichnen, steuert die VBR-Kodiertechnik die Komprimierungsrate von MPEG2 in Echtzeit und maximiert dadurch den verfügbaren Speicherplatz auf der Disc.
     
    Was bedeutet White Strategy?
    Bei der ""Präzise Aufzeichnung und Wiedergabe""-Technologie passen sich die gespeicherten Daten sauber in den optimalen Bereich an. Die Daten, die ohne diese Technik gespeichert werden, viel mehr Platz ein, was zu einer Datenüberlappung führen kann. Dank der ""Präzisen Aufzeichnung und Wiedergabe"" werden die Daten im Samsung DVD-Recorder noch präziser gespeichert. So entstehen kristallklare Bilder.
     
    Was ist HDMI™?
    HDMI™ (kurz für High-Definition Multimedia Interface) ist eine volldigitale Audio/Video-Schnittstelle, die Bild- und Tondaten mit einem einzigen Digitalkabel zwischen Digital- und Audiogeräten überträgt. Es unterstützt die Videoformate Standard, Enhanced oder High-Definition sowie die Audioformate Standard bis mehrkanaligen Surround-Sound. Die Vorteile: unkomprimierte digitale Videodaten (mit Bandbreiten bis zu 5 Gigabyte pro Sekunde), ein Anschluss statt vieler Kabel und Datenaustausch zwischen Bildquelle und DTV. 
    ";2;False;0;;;;samsung-dvd-hr-775-a-dvd-festplatten-rekorder;True;True;P-1940;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;2,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;269.0000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;40013,6237847222;63;5;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000331-samsung-dvd-hr-775-a-dvd-festplatten-rekorder.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000332-samsung-dvd-hr-775-a-dvd-festplatten-rekorder.jpg;;2;;False;;;;;False;False;False;;;;;False;;;;;; -5;0;True;Canon Digital IXUS 95 IS Digitalkamera Silver;"Canon Digital IXUS 95 IS Digitalkamera Silver ";"
    Canon Digital IXUS 95 IS Digitalkamera Silver

    10 Megapixel, 3-fach opt. Zoom, 2,5"" Display, Bildstabilisator
     
    Die Digital IXUS 95 IS vereint exquisiten Schick mit exzellenter Leistung und hohem Komfort.
    Der innovative Smart-Auto-Modus nutzt auf intelligente Art die Scene-Detection-Technologie.
    Das Ergebnis: optimierte Einstellungen für tolle Bilder. Kompaktes und schickes IXUS-Design mit 10 Megapixeln in 3,0fach optisches Zoom

    mit optischem Bildstabilisator Scene-Detection-Technologie Brillante Aufnahmen Face-Detection-Technologie DIGIC 4 2,5-Zoll-PureColor-LCD II i-Contrast 17 Aufnahmemodi VGA-Movieclips
    Technische Daten der Canon Ixus 95 IS : Auflösung (MP) 10 Sensor-Größe 1/2.3 LCD-Größe (cm) 6.35 Speicher SD / SDHC interner Speicher (MB)

    optischer Zoom (x-fach) 3 numerischer Zoom (x-fach) 4 Bildstabilisator Ja Optischer Zoom Nein Brennweite 35 - 105 Lichtstärke 2.8 - 4.9 Video-Modus JA

    Max. Video-Auflösung(Pixel) 640 x 480 Abmessungen (B x H x T mm) 88,5 x 54,8 x 21,8 Gewicht (g) 120 Akku NB-6L
     
    Lieferumfang:
    Digital IXUS 95 IS, Trageriemen, Akku, Akku-Ladegerät, USB-Kabel, Video-Kabel
    ";2;False;0;;;"Canon Digital IXUS 95 IS Digitalkamera ";canon-digital-ixus-95-is-digitalkamera-silver;True;True;P-1700;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;189.0000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;40008,648287037;56;25;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000324-canon-digital-ixus-95-is-digitalkamera-silver.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000325-canon-digital-ixus-95-is-digitalkamera-silver.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000326-canon-digital-ixus-95-is-digitalkamera-silver.jpg;2;;False;;;;;False;False;False;;;;;False;;;;;; -5;0;True;"Garmin TOPO DVD Deutschland Digital 25 ";"Garmin TOPO DVD Deutschland Digital 25 ";"
    Garmin TOPO DVD Deutschland Digital 25 

     
    Topographische Rasterkarte von Deutschland im Maßstab von 1:25.000
     
     
    Topographische Rasterkarte
    Maßstab 1:25.000
    3D-Geländedarstellung mit Flugmodus
    Erstellen von Höhenprofilen
    Übertragen von Routen, Tracks und Wegpunkten
    ";2;False;0;;;;garmin-topo-dvd-deutschland-digital-25;True;True;P-2050;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;159.0000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;40007,1684027778;67;44;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000323-garmin-topo-dvd-deutschland-digital-25.jpg;;;2;;False;;;;;False;False;False;;;;;False;;;;;; -5;0;True;Garmin Topo DVD Deutschland V3;"Garmin Topo DVD Deutschland V3 Gesamt Digitale topographische Karte gesamt Deutschland auf DVD und MircoSD-Karte ";"

    Garmin Topo DVD Deutschland V3 Gesamt

     
    Digitale topographische Karte gesamt Deutschland auf DVD und MircoSD-Karte
     
    .
    Die neue topographische Karte gesamt Deutschland
    enthält zusätzlich zu detaillierten Straßen- und Wegedaten mehr als 8.000 km überregionale Wanderrouten und über 60.000 km Radrouten.
    Innerhalb dieses Routennetzes kann sich der Nutzer von einem bestimmten Ausgangspunkt zu einem Zielpunkt routen lassen.
    Beispiele für Routen: Rothaarsteig, Rennsteig, Altmühltal-Panoramaweg, Harzer Hexensteig, 66 Seen Wanderweg, Premiumwanderwege Saarland und viele mehr.
    Neu ist auch, dass die Kartensoftware erstmals kompatibel mit Apple MacIntosh Computern ist (ab OS X 10.4 aufwärts).
    Ob zu Fuß oder auf dem Mountain-Bike,
    wer viel draußen unterwegs ist, setzte früher Papierkarten ein. Seit mehreren Jahren gibt es von Navigationsspezialist Garmin GPS-Geräte
    die topografische Karten darstellen können (Karten im MapSource-Format). Ein Routing, wie man es von Navis aus dem Auto kennt, war mit diesen Karten bislang aber nicht möglich.
    Die neueste Version der “Topo Deutschland v3” macht nun erstmals das Routing auf 8.000 km Wanderrouten und rund 60.000 km Radrouten möglich!
    Einfach Start- und Zielpunkt eingeben, das Gerät schlägt die Route vor, und los geht’s. Visuelle Abbiegehinweise führen dann bequem und sicher zum Ziel.
    Dies sollte auch den größten GPS-Skeptiker positiv stimmen.
    Ebenfalls praktisch:
    Die neue Topo Deutschland V3 wird mit einer bereits programmierten SD-/microSD Datenkarte ausgeliefert.
    Das erspart ein Freischalten der Karte auf dem PC und das Übertragen der Karte auf das Gerät.
    Die Datenkarte wird einfach in den Slot des GPS-Gerätes geschoben und schon kann es losgehen.
    Eine Verwendung der Daten von der DVD auf dem Computer ist natürlich nach wie vor möglich.

    ";2;False;0;;;Garmin Topo DVD Deutschland V3;garmin-topo-dvd-deutschland-v3;True;True;P-2040;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;209.0000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;40007,1559606481;67;44;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000322-garmin-topo-dvd-deutschland-v3.jpg;;;2;;False;;;;;False;False;False;;;;;False;;;;;; -5;0;True;"NAVIGON 2310 Navigationssystem Europa ";"NAVIGON 2310 Navigationssystem Europa ";"

    NAVIGON 2310 Navigationssystem Europa

     
    40 Länder, inklusive TMC, NAVIGON MyRoutes, Clever Parking , TMC-Routenplanung
     
     
    NAVIGON 2310 Kann noch mehr,als das Äußere verspricht.
    Was macht eigentlich ein Schmuckstück aus? Erstmal muss es natürlich gut aussehen.
    Im ersten Moment könnte man die 23er-Serie von NAVIGON für so ein typisches, kleines Accessoire halten.
    Aber nicht nur das schicke Design begeistert. Denn auch was die Features angeht, kann die 23er-Serie locker mithalten:
    Mit TMC- Routeninfo stehen Sie nie wieder im Stau, NAVIGON MyRoutes findet jederzeit die für Sie beste Strecke und mit dem POI-Klick erhalten Sie alle Infos zu Ihrem gewählten Sonderziel.
    Und wenn Sie das immer noch nicht überzeugt, dann sehen Sie sich mal den Preis an.
     
    NAVIGON MyRoutes
    Je nachdem, welcher Fahrertyp Sie sind, empfiehlt Ihnen NAVIGON MyRoutes die beste Route – zugeschnitten auf Ihren persönlichen Fahrstil, den Wochentag und die Tageszeit.
    Darüber hinaus zeigt Ihnen Ihr NAVIGON bis zu zwei weitere Routen. Das schafft Transparenz. Sie entscheiden, ob Sie unserer Empfehlung folgen oder eine der Alternativen wählen.
     
    TMC-Routeninfo
    zeigt ihnen im Fall einer Staumeldung eine Alternativroute mit aktualisierter Entfernung und Ankunftszeit. Sie entscheiden, ob eine Umfahrung in Ihrem Fall sinnvoll ist oder ob Sie die ursprüngliche Route beibehalten wollen.
     
    Reality View Pro
    zeigt Straßen nicht als Linien, sondern realistisch aus Asphalt und mit Mittelstreifen. So behalten Sie an Autobahnkreuzen und Ausfahrten leichter den Überblick.
     
    Fahrspurassistent Pro
    hilft Ihnen selbst durch den hektischsten Straßenverkehr hindurch. Vorausschauend und übersichtlich zeigt er Ihnen an, auf welche Fahrspur Sie für Ihren nächsten und übernächsten Abbiegepunkt wechseln müssen.
     
    Clever Parking
    hilft Ihnen bei der Parkplatzsuche. Kurz vor Ihrem Ziel zeigt Ihnen Clever Parking Parkplätze in der näheren Umgebung an.
    In Deutschland werden Sie sogar über Parkgebühren informiert. So vermeiden Sie langes Suchen und sparen dabei Geld.
     
    Lieferumfang:
    PNA  2310 (3,5"" im 4:3 Format) | Kurzanleitung | Kfz-Ladekabel mit integrierter TMC-Antenne | Halterung | Vorinstalliertes Kartenmaterial für 40 Länder | USB-Kabel
    ";2;False;0;;;;navigon-2310-navigationssystem-europa;True;True;P-2150;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;159.0000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;39998,914525463;68;14;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000321-navigon-2310-navigationssystem-europa.jpg;;;2;;False;;;;;False;False;False;;;;;False;;;;;; -5;0;True;Panasonic Lumix DMC-FS6 Digitalkamera schwarz;"Panasonic Lumix DMC-FS6 Digitalkamera schwarz ";"

    Panasonic Lumix DMC-FS6 Digitalkamera schwarz

     
    8 Megapixel, 4-fach opt. Zoom, 2,5"" Display, Bildstabilisator
     
     
    Im Intelligenten Automatik (iA)-Modus werden die 5 wichtigsten Motivprogramme automatisch optimal auf die jeweilige Szene eingestellt.
    Neben der Motiverkennung kombiniert iA weitere wichtige Funktionen, wie den optischen Bildstabilisator OIS, die Bewegungserkennung (Intelligente ISO-Steuerung),
    eine optimierte Gesichtserkennung mit digitaler Rotaugen-Korrektur.
    So sind scharfe, natürliche und schöne Fotos selbst für (Neu-)Einsteiger möglich.
    Der reaktionsschnelle Venus Engine IV-Bildprozessor gehört schon bei diesem Einsteigermodell zur Grundausstattung.

    Lichtstarkes F2,8 Leica DC Vario-Elmarit Objektiv
    Hochauflösendes 6,4 cm LC-Display [230.000 Pixel]
    4x optischer Zoom [KB: 33-132 mm]
    Intelligente Automatik [u.a. Gesichtserkennung]
     
    Lieferumfang:
    Digitalkamera, Lithium Ionen Akku, Ladegerät, USB-Kabel, Trageriemen, Audio / Video-Kabel, CD-ROM, Sotware
    ";2;False;0;;;"Panasonic Lumix DMC-FS6 ";panasonic-lumix-dmc-fs6-digitalkamera-schwarz;True;True;P-1770;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;189.0000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;39998,8940393519;58;12;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000317-panasonic-lumix-dmc-fs6-digitalkamera-schwarz.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000318-panasonic-lumix-dmc-fs6-digitalkamera-schwarz.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000319-panasonic-lumix-dmc-fs6-digitalkamera-schwarz.jpg;2;;False;;;;;False;False;False;;;;;False;;;;;; -5;0;True;Western Digital WD TV HD Media Player;Western Digital WD TV HD Media Player;"
    Western Digital WD TV HD Media Player
     
     
    In Kombination mit einem tragbaren My Passport-Laufwerk ist dieser Player die bequemste Methode, Filme oder selbstgedrehte Videos wiederzugeben,
    digitale Musik in hoher Qualität abzuspielen und Diashows Ihrer Familienfotos in hoher Auslösung von der Festplatte in Ihrem Fernseher anzuzeigen.
    Auch mit gängigen USB-Laufwerken und Digitalkameras, Camcordern und tragbaren Media-Playern, die als Massenspeichereinheiten erkannt werden, kompatibel.
    Ideal geeignet für eine störungsfreie Wiedergabe von Filmen, Heimvideos, digitaler Musik und Fotos von der Festplatte auf Ihrem Fernsehgerät.
     
    HDMI- und FBAS-Anschlüsse - Der HDMI-Anschluss (HDMI – High-Definition Multimedia Interface) ermöglicht den Anschluss an HDTV-Geräte der höchsten Qualität oder an ein Heimtheater.
    Zusätzliche kombinierte (RCA-)Ausgänge gewährleisten die Kompatibilität mit praktisch allen Fernsehgeräten.
     
    Highlights
    maximale Transferrate: 480 Mb/s über USB 2.0
    USB 2.0 Anschluss
    für PC oder Macintosh Computer
    Lieferumfang: HD Media Player, kompakte Fernbedienung einschließlich Batterien,
    Software für Medienkonvertierung (nur für Windows), kombiniertes Audio/Video-Kabel, Netzteil, Schnellinstallationsanleitung
    ";2;False;0;;;Western Digital WD TV;western-digital-wd-tv-hd-media-player;True;True;P-2560;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;119.0000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;39997,7782638889;14;21;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000316-western-digital-wd-tv-hd-media-player.jpg;;;2;;False;;;;;False;False;False;;;;;False;;;;;; -5;0;True;"TomTom 220V Netzteil ";"TomTom 220V Netzteil ";
    220V Netzteil TomTom Navigation

    Ladegerät mit abgewinkeltem 90° Spezialstecker

    Steckerlader für Tom Tom Serien: ONE XL Europe HD Traffic Regional,
    Go Serien 520 Go 720 Go 740 Go 920 Live XL XL LIVE IQ Routes
    Netzteil Ladegerät 240 Volt Output: 5.5V +/- 5%
    Mit Ladekontrollleuchte (LED), nur 85 Gramm
    Hochflexibeles, kerbfestes Kabel, beste Qualität
    Auslieferung in Kartonbox und Schutzumschlag
    CE, beste Qualität original von Spartechnik
    ;2;False;0;;;"Reiseladegeraet / Netzteil / Ladegeraet fuer TomTom ";tomtom-220v-netzteil;True;True;P-1970;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;14.9000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;39986,6084953704;66;4;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000311-tomtom-220v-netzteil.jpg;;;2;;False;;;;;False;False;False;;;;;False;;;;;; -5;0;True;"Tom Tom One Hard Case XL schwarz ";"Tom Tom One Hard Case XL schwarz ";"

    Tom Tom One Hard Case XL schwarz
     
     

    Hard Case Tom Tom One XL, Schwarz
    passgenaue, stoßfeste Tasche aus Nylon/EVA
    Farbe: Schwarz
    Ausstattung:
    mit zusätzlichem Staufach für Zubehör
    Handschlaufe für einfachen Tragekomfort
    ";2;False;0;;;"Tom Tom One Hard Case XL schwarz ";tom-tom-one-hard-case-xl-schwarz;True;True;P-1960;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;20.9900;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;39986,6020023148;66;4;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000265-tom-tom-one-hard-case-xl-schwarz.jpg;;;2;;False;;;;;False;False;False;;;;;False;;;;;; -5;0;True;"TomTom XL IQ RoutesTM-Edition Europe ";"TomTom XL IQ RoutesTM-Edition Europe mit TMC ";"

    TomTom XL IQ RoutesTM-Edition Europe mit TMC
     

    42 Länderkarten, Fahrspurassistent, Text-to-Speech, Intelligente Routenberechnung,TMC
     

    TomTom Navigationsgerät XL IQ Routes Edition Europe 42 Traffic mit 4,3 Zoll Farb-Touchscreen, RDS/TMC,
    42 vorinstallierten Karten europäischer Länder sowie vielen Innovationen für eine verbesserte und komfortable Navigation IQ Routes -
    Intelligente Routenberechnung aus aktuellsten Karten unter Berücksichtigung verschiedener Umweltfaktoren wie Tag, Uhrzeit,
     
    Straßenabschnitt, Durchschnittsgeschwindigkeiten etc.
    Fahrspurassistent für komplizierte Spurenführung, zwei Ausfahrten in einer Ansicht und verbesserte Gebietsabdeckung Text-to-Speech zum Ansagen von Straßennamen und Verkehrshinweisen für einen konzentrierten Blick auf die Fahrbahn und ein entspanntes Fahren
     
    Lieferumfang:
    XL IQ Routes Edition Europe 42 Traffic, EasyPort-Halterung, USB-Kabel, Autoladegerät, Dokumentation, RDS/TMC-Verkehrsinfo-Empfänger
     
    ";2;False;0;;;"TomTom XL IQ RoutesTM-Edition Europe ";tomtom-xl-iq-routestm-edition-europe;True;True;P-1950;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;164.9000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;39986,5911689815;66;4;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000264-tomtom-xl-iq-routestm-edition-europe.jpg;;;1;;False;;;;;False;False;False;;;;;False;;;;;; -5;0;True;"Trekstor DataStation maxi g.u 500 GB ";"Trekstor DataStation maxi g.u 500 GB USB 2.0 ";"

    Trekstor DataStation maxi g.u Externe Festplatte 500 GB USB 2.0

     
     
     
    Optimale Speicherplatzerweiterung
    Die DataStation maxi g.u ist die perfekte Lösung für das tägliche Backup oder die Speicherplatzerweiterung Ihres PCs.
    Die externe 3,5“ Festplatte bietet ausreichend Platz zum Speichern und Archivieren der heimischen
    Musik- und Videosammlung, digitaler Fotos oder anderer Dateien.
    Schnell und bedienungsfreundlich
    Mit dem Hi-Speed USB 2.0 Anschluss bietet die DataStation maxi g.u einen schnellen Datentransfer.
    Die Festplatte ist zudem bereits vorformatiert und ohne Treiber sofort betriebsbereit.
    Unterstützt werden alle gängigen Dateisysteme von Windows®, Linux® und Mac® OS X, sowie die Betriebssysteme Microsoft Windows® 2000 / XP/ Vista,
    Mac® OS X ab 10.3 und Linux® ab Kernel 2.6.x. Die Festplatte wird über das mitgelieferte Netzteil mit Strom versorgt.
    Der Ein-/Ausschalter am Festplattengehäuse verhindert überflüssigen Stromverbrauch.
    Inklusive Nero Software „BackItUp2 Essentials“
    Die ebenfalls im Lieferumfang enthaltene Nero Software rundet das Bild der mobilen, externen Festplatte perfekt ab.
    Mit Nero BackItUp2 Essentials können Sie Backups Ihrer Daten sehr einfach planen.
    So können einzelne Dateien oder ganze Laufwerke gesichert werden.
    Um die Datenmenge gering zu halten, komprimiert die Software die Backups direkt „on the fly“.
    Auf Wunsch lassen sich die gesicherten Daten auch per Passwortschutz vor unbefugtem Zugriff schützen.
     
    Lieferumfang: Externes Festplattenlaufwerk, USB 2.0-Kabel, Netzteil, Schnellinstallationsanleitung
    ";2;False;0;;;Trekstor DataStation maxi g.u;trekstor-datastation-maxi-gu-500-gb;True;True;P-2650;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;99.0000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;39982,6066203704;15;2;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000129-trekstor-datastation-maxi-gu-1tb.jpg;;;2;;False;;;;;False;False;False;;;;;False;;;;;; -5;0;True;Canon Digital IXUS 100 IS Digitalkamera schwarz;"Canon Digital IXUS 100 IS Digitalkamera schwarz ";"

    Canon Digital IXUS 100 IS Digitalkamera schwarz

    12 Megapixel, 3-fach opt. Zoom, 2,5""Display, HDMI, SLIM
     
    Die Digital Ixus 100 IS präsentiert sich im atemberaubend-exquisiten, nur 18,4 Millimeter flachen Edelstahlgehäuse. Sie ist in den vier Farben Silber, Schwarz, Gold und Rot erhältlich.
     
    Ob großformatige Fotoprints oder gezielte Ausschnittvergrößerungen: Die hohe Auflösung von 12,1 Megapixeln sorgt für eine überzeugende Detailwiedergabe.
     
    Für hohe Geschwindigkeit und exzellente Bildqualität mit brillanten Farben und minimiertem Bildrauschen steht der aktuelle Canon-Bildprozessor DIGIC 4.
    12,1 Megapixel Sensor
    3-fach optisches Zoom
    Großes hochauflösendes 2,5 Zoll PureColor LCD II
    Superschlank; HD-Movie und HDMI-Anschluß  mehr Details im Film
     
    Lieferumfang:
    Digital IXUS 100 IS, Trageriemen, Akku, Akku-Ladegerät, USB-Kabel, Video-Kabel
    ";2;False;0;;;"Canon Digital IXUS 100 IS Digitalkamera ";canon-digital-ixus-100-is-digitalkamera-schwarz;True;True;P-1690;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;219.9000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;39964,877037037;"56;2095";25;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000251-canon-digital-ixus-100-is-digitalkamera-schwarz.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000252-canon-digital-ixus-100-is-digitalkamera-schwarz.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000253-canon-digital-ixus-100-is-digitalkamera-schwarz.jpg;2;;False;;;;;False;False;False;;;;;False;;;;;; -5;0;True;Apple iPod Touch 32 GB schwarz;"Apple iPod Touch 32 GB schwarz mit integrierter WiFi Funktion ";"
    Apple iPod Touch 32 GB schwarz mit integrierter WiFi Funktion

    Der iPod touch kann alles, was du am iPod toll findest. Und noch vielmehr. Schlankes neues Design. Mit seinem fantastisch flachen Edelstahl-Design liegt der iPod touch mit dem 3.5 Zoll Touch-Display jetzt noch besser in der Hand. Mobil im Spiel. Durch revolutionäre Technologien wie das Multi-Touch-Display, der Beschleunigungssensor und 3D-Grafiken macht das Spielen auf dem iPod touch besonders viel Spaß. Schlaue Musik Mit der neuen Funktion ""Genius"" wird der iPod touch zu Deinem superintelligenten, persönlichen DJ.
     
    Nur ein paar Fingertipps, und Genius erzeugt eine Wiedergabeliste mit Songs Deiner Mediathek, die gut zusammenpassen. Internet überall Internetzugang überall, wo ein drahtloses Netzwerk zur Verfügung steht, damit Sie immer mit dabei sind. Multitouch-Oberfläche: Die revolutionäre Technologie des iPhone und die Software Version 3.1 stecken in diesem genialen iPod. Das brillante Breitformat-Display rückt Ihre Videos und Spiele ins beste Licht und dank OpenGL sehen die Spiele jetzt noch besser aus Surfen Sie mit Safari im Web und sehen Sie YouTube Videos auf dem iPod mit integrierter Wi-Fi Funktionalität an. Mit Ihrem iPod touch können Sie im iTunes Wi-Fi Music Store nach Songs suchen, Hörproben abspielen und Titel kaufen.
     
    Lieferumfang: iPod touch, Ohrhörer, USB 2.0 Kabel, Kurzanleitung
     
    Schlankes neues Design
    Mit seinem fantastisch flachen Edelstahl-Design liegt der iPod touch so gut in der Hand wie nie zuvor. Ebenfalls Eindruck machen der neue Lautstärkeregler und der integrierte Lautsprecher.
     
    Spiele
    Speziell auf die iPod touch Technologie zugeschnittene Spiele sind nur noch einen Fingertipp entfernt. Stöbere in hunderten von Spielen im App Store direkt auf Deinem iPod touch, und wenn Du gefunden hast, was Du suchst, kannst Du es einfach laden und dann kann es losgehen.
     
    Steuerung per Fingertipp
    Viele Spiele auf dem iPod touch nutzen die Multi-Touch-Technologie für besonders exakte Fingertipp-Steuerung der verschiedenen Spielelemente. Beim Schach ziehst Du mit dem Finger die Figuren, bei Würfelspielen bewegst Du die Würfel. Durch Ziehen mit zwei Fingern kannst Du die Anzeige vergrößern und verkleinern, Deine Figur nach links oder rechts drehen, und durch einfaches Antippen triffst Du eine Auswahl.
     
    Musik
    Blättere in den Albumcovern Deiner Musiksammlung. Erstelle immer wieder neue Genius Wiedergabelisten und erweitere Deine Sammlung aus dem iTunes Wi-Fi Music Store überall, wo ein Wi-Fi-Hotspot in der Nähe ist.
     
    Mit Cover Flow lebt das Flair einer CD- oder Plattensammlung wieder auf. Wer erinnerst sich nicht an das Gefühl beim Durchblättern der Sammlung? Das gibt es jetzt auch auf dem iPod touch: einfach iPod drehen, durch die Cover blättern, ein Album auswählen, fertig. Ein Fingertipp aufs Cover, und schon siehst Du die Titelliste, ein weiterer Tipp spielt die Musik ab, und dabei kannst Du sogar die Songtexte anzeigen.
     
    Ein Musikgenie
    Stell Dir vor, Du hörst einen Song. Toll wären jetzt andere Titel, die gut dazu passen. Was machst du? Ganz einfach: Du verwendest die neue Funktion ""Genius"". Diese findet die Songs in Deiner Mediathek, die gut zusammenpassen. Du erhältst eine Genius Wiedergabeliste, die Du sofort anhören, sichern oder sogar aktualisieren kannst. Verlass Dich also auf den Genius von iTunes, wenn Du einen Mix willst, auf den Du selbst nicht gekommen wärst.
     
    Lautsprecher integriert
    Mit dem integrierten Lautsprecher kannst Du Musik und Gespräche ohne Kopfhörer hören – perfekt für zwangloses Hörvergnügen.

    Längere Batterielaufzeit
    Jetzt kannst Du noch länger rocken (und ansehen und spielen). Der iPod touch hält bis zu 36 Stunden bei Musik oder bis zu 6 Stunden bei Videos durch. Das reicht für drei oder vier Filme zwischen den Ladevorgängen.
     
    Internet
    Surfe im Internet mit Wi-Fi. Du kannst detailgenaue HTML-E-Mails mit Anlagen empfangen und Wegbeschreibungen und aktuelle Verkehrsinformationen abrufen. Auch als YouTube-Fan entgeht Dir nichts.
     
    Überall ins Internet
    Der iPod touch ist der einzige iPod mit kabellosem 802.11b/g Internetzugriff. Bei bestehender Wi-Fi-Verbindung kannst Du im Internet surfen und Nachrichten lesen, Sportergebnisse sehen, Rechnungen bezahlen und online einkaufen.
     
    Wer suchet, der findet
    Der iPod touch synchronisiert Deine Lesezeichen vom PC oder Mac, sodass Du ruck zuck auf Deine Lieblingsseiten zugreifen kannst. Die Google- und Yahoo!-Suche ist schon integriert, sodass Du im Web schnell findest, was Du suchst.
     
    Zoom mit Aussicht
    Jeden beliebigen Ausschnitt einer Webseite kannst Du vergrößern, indem Du mit dem Finger darauf tippst oder mit zwei Fingern die Anzeige aufziehst. Websites lassen sich im Hoch- oder Querformat anzeigen: einfach den iPod touch um 90 Grad drehen, und schon wird auch die Darstellung der Website gedreht.
     
    Eigene Weblinks
    Für häufig besuchte Websites, etwa die einer Zeitung, eines Blogs oder eine Sport-Website, kannst Du einfach ein Symbol auf dem Home-Bildschirm erstellen. Deine Lieblingsseiten sind über mit Safari erstellte Weblinks nur einen Fingertipp entfernt.
     
    Rock 'n' Run mit Nike+
    Im iPod touch ist kabellose Unterstützung für Nike + iPod integriert. Du brauchst nur einen Nike + iPod Sensor in Deinem Schuh, und schon kann's losgehen.
     
    Das optimale Lauftraining
    Im iPod touch ist jetzt Unterstützung für Nike + iPod integriert. Einfach den Nike + iPod Sensor (separat erhältlich) in den Nike+ Laufschuh einsetzen, und es kann losgehen. Der Sensor überträgt die Laufdaten drahtlos an den iPod touch – er erfasst die gelaufene Zeit, die zurückgelegte Strecke und die verbrauchten Kalorien. Außerdem gibt er Dir gesprochenes Feedback zu Deinen Trainingsfortschritten.
     
    Das optimale Fitnesstraining
    Diese Funktion kann auch zusammen mit neuen, in vielen Fitnessstudios vorhandenen Geräten für das Ausdauertraining gekoppelt werden. Suche einfach nach mit Nike + iPod kompatiblen Laufbändern, Elliptical Trainern, Steppern und Hometrainern.
    ";2;False;0;;;Apple iPod Touch 32 GB;apple-ipod-touch-32-gb-schwarz;True;True;P-1260;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;277.9000;277.9000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;39915,3405439815;43;1;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000141-apple-ipod-touch-16-gb-schwarz.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000142-apple-ipod-touch-16-gb-schwarz.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000143-apple-ipod-touch-16-gb-schwarz.jpg;2;;False;;;;;False;False;False;;;;;False;;;;;; -5;0;True;Apple iPod shuffle 4 GB silber;Apple iPod shuffle 4GB silber;"
    Apple iPod shuffle 4GB silber
     
     
    Der kleinste iPod der Welt
     
     
    Um den kleinsten iPod der Welt zu bauen, haben wir die Steuerung vom iPod shuffle in das Ohrhörerkabel integriert.
    So wird der iPod shuffle noch kleiner und die Steuerung ist genau da, wo du sie einfach erreichst.
    Wenn du einen Song abspielen, anhalten oder überspringen möchtest,
    musst du nicht lange nach dem iPod shuffle suchen - greif einfach zum Kabel und drücke auf eine der Tasten.
    Dieser Entertainment-Winzling sagt Ihnen auf Knopfdruck, welchen Titel er gerade abspielt
    Organisieren Sie Ihre Musik in verschiedenen Wiedergabeslisten
    Dank eines stabilen, integrierten Clips lässt sich der iPod shuffle fast überall befestigen.
    Lassen Sie sich aufs Ungewisse ein: Verwenden Sie den Schalter für die Zufallswiedergabe,
    um den Inhalt Ihres iPod shuffle neu zu mischen.
    Lieferumfang: Apple Earphones mit Remote Fernbedienung
     
    iPod shuffle - In leuchtenden neuen Farben spricht Musik dich richtig an
     
    Der kleinste iPod der Welt
    Um den kleinsten iPod der Welt zu bauen, haben wir die Steuerung vom iPod shuffle in das Ohrhörerkabel integriert. So wird der iPod shuffle noch kleiner und die Steuerung ist genau da, wo du sie einfach erreichst. Wenn du einen Song abspielen, anhalten oder überspringen möchtest, musst du nicht lange nach dem iPod shuffle suchen - greif einfach zum Kabel und drücke auf eine der Tasten.
     
    Der erste iPod, der mit dir spricht
    Die VoiceOver Funktion ist mit Sicherheit der nächste Hit auf dem iPod shuffle.1 Angenommen du hörst einen Song und willst wissen, wie er heißt oder von wem er ist: Einfach Knopf drücken und VoiceOver sagt es dir. Sogar die Namen deiner Wiedergabelisten verrät es dir. Und wenn die Batterie aufgeladen werden muss, sagt VoiceOver dir das auch.
     
    Leichtbedienung
    Die Steuerung befindet sich am Kabel des rechten Ohrstöpsels. Dadurch, dass die Steuerung jetzt hier angebracht ist, kannst du deine Musiktitel durchsuchen - und die VoiceOver Funktion aktivieren - ohne vom Joggen, Rad fahren oder anderen Aktivitäten abgelenkt zu werden. Der iPod shuffle wird mit dieser einfachen Steuerung geliefert. Du kannst aber auch Kopfhörer mit ähnlichen Bedienelementen von Herstellern wie Scosche, Klipsch, V-MODA und Belkin verwenden.
     

    Dein Musikarchiv. Für unterwegs
    Der iPod shuffle kommt jetzt mit 2 GB oder 4 GB. Mit dem 4 GB Modell hast du jede Menge Platz, um Musik für viele Stunden - bis zu 1.000 Songs - zu speichern.2 Damit bist du im Fitnessstudio oder auf dem Weg zur Arbeit bestens gerüstet. Außerdem kannst du jetzt mehrere Wiedergabelisten und auch Hörbücher verwenden.
     
    Mehrere Wiedergabelisten
    Wahrscheinlich hast du dir in iTunes schon einige Wiedergabelisten zusammengestellt. Eine für unterwegs. Eine fürs Fitnessstudio. Eine zum Chillen. Jetzt kannst du deine Wiedergabelisten auf dem Computer mit dem iPod shuffle synchronisieren und hast immer genau den richtigen Mix - egal, was du gerade machst oder in welcher Stimmung du bist. VoiceOver nennt dir den Namen jeder Wiedergabeliste. So kannst du ganz leicht zwischen ihnen wechseln und genau die auswählen, nach der dir gerade ist.
     
    Farbe bekennen
    Mit dem flachen, robusten Gehäuse aus eloxiertem Aluminium ist der iPod shuffle immer das passende Accessoire. In leuchtendem Pink, Blau, Grün, Schwarz oder Silber ist er ein echtes Fashion Statement. Ganz neu dabei: der iPod shuffle Special Edition in poliertem Edelstahl (So werden Rockstars nun mal behandelt). Sogar der iPod shuffle Clip sieht stylish aus. Er klemmt sicher an Hemd, Jacke, Sportzeug oder am Rucksack. So wird der iPod shuffle zum perfekten Fashtech-Accessoire. Und klar, natürlich ist noch Platz für eine persönliche Gravur.

    Mehrsprachig
    Ein französisches Chanson. Ein spanischer Bolero. Eine italienische Arie. Dein Musikarchiv enthält Musik aus allen Ländern der Welt. Deshalb spricht VoiceOver 20 Sprachen und kann die Namen von Songs und Interpreten mit der richtigen Aussprache sprechen.
     
    Zufall oder kein Zufall?
    Der Schalter am iPod shuffle hat drei Einstellungen. Links wird deine Musik zufällig durcheinander gewürfelt. In der Mitte werden deine Songs in der normalen Reihenfolge gespielt. Rechts wird der iPod shuffle ausgeschaltet.
    ";2;False;0;;;Apple iPod shuffle Tragbarer MP3-Player 4 GB 3. Generation;apple-ipod-shuffle-4-gb-silber;True;True;P-1210;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;79.9000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;39908,3107986111;40;1;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000220-apple-ipod-shuffle-4-gb-silber.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000221-apple-ipod-shuffle-4-gb-silber.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000222-apple-ipod-shuffle-4-gb-silber.jpg;2;;False;;;;;False;False;False;;;;;False;;;;;; -5;0;True;"AVM FRITZ!Fon 7150 ";"AVM FRITZ!Fon 7150 Fritz!Box Router +Telefon + VOiP ";"
    FRITZ!Fon 7150 vereint VoIP-/Festnetz- Telefonanlage, DSL-Modem, WLAN-Router und DECT-Telefon in einem Gerät.

    FRITZ!Fon 7150 kann alles, was eine FRITZ!Box auszeichnet und bringt noch ein DECT-Mobilteil mit. Das Multitalent bietet Festnetz- und Internettelefonie, schnelles Surfen im Internet und kabellosen DSL-Zugang in einem Gerät. Telefongespräche können wahlweise über Internet (Voice over IP) oder Festnetz geführt werden – auch bei ausgeschaltetem Computer. Das zugehörige Mobilteil bietet alle Vorteile der Schnurlostelefonie über DECT. Die Anmeldung von weiteren Mobilteilen an der Basisstation ist problemlos möglich. Bereits vorhandene ISDNTelefone oder ISDN-TK-Anlagen lassen sich ohne weiteres an FRITZ!Fon 7150 anschließen.
     
    Durch die Router-Funktion erhalten alle PCs im Netzwerk Zugang zum Internet über LAN und WLAN. Die WLAN-Funkverbindungen sind ab Werk mit dem sicheren WPA-Standard verschlüsselt und dank der Stick & Surf-Funktion von AVM erfolgt die Konfiguration automatisch. Über die USB-Schnittstelle können auch USB-Drucker und -Speichermedien für die gemeinsame Nutzung komfortabel vernetzt werden. Die Hard- und Software-Firewall schützt alle Geräte im Netzwerk vor Angriffen von außen. Zusätzliche Komfortfunktionen der FRITZ!Fon 7150 wie Nachtschaltung, Klingelsperre oder ein Mailservice ergänzen die Komplettlösung für Telefonie und Internet.
     
    Internettelefonie mit Festnetzqualität
    Intelligentes Codec Management sorgt für eine konstante Sprachqualität beim VoIPen. Dank Bandbreitenmanagement surfen Sie gleichzeitig mit optimaler Qualität im Internet, ohne dass Internettelefonate gestört werden. Mit zwei Mobilteilen an der Station sind auch zwei Gespräche gleichzeitig schnurlos möglich – eines als Festnetz- und eines als Internettelefonat. Neben der exzellenten Sprachqualität bietet FRITZ!Fon 7150 auch bei Internettelefonie ISDN-Leistungsmerkmale wie Makeln, Anklopfen, Rufnummernanzeige, Direktruf oder Dreierkonferenz. Bis zu 10 verschiedene VoIP-Rufnummern – auch unterschiedlicher Provider – lassen sich speichern.
     
    Schnurloses Telefonieren mit DECT-Komfort
    Das DECT-Mobilteil bietet neben einem Farbdisplay mit grafischer Darstellung und einem digitalen Anrufbeantworter ein Telefonbuch für 200 Einträge. Sowohl das Adressbuch als auch die Anrufliste lassen sich bequem über das Mobilteil pflegen. Das ist mit einer Gesprächszeit von bis zu 17 Stunden selbst langen Telefonaten gewachsen. Über das bei DECT eingesetzte GAP-Profil lassen sich bis zu fünf weitere Mobilteile anmelden.
     
    WLAN – sicher und schnell
    FRITZ!Fon 7150 bietet bereits ab Werk eine sichere WLAN-Verbindung dank aktivierter WPA-Verschlüsselung. Mit der von AVM entwickelten Stick & Surf-Technologie wird der Start ins kabellose Surfen vereinfacht. Sobald der FRITZ!WLAN Stick in den USBHost der FRITZ!Fon 7150 gesteckt wird, werden die Konfigurations- und Sicherheitseinstellungen automatisch zwischen beiden Geräten abgeglichen. FRITZ!Fon 7150 unterstützt die neuesten WLAN-Standards und ermöglicht Verbindungen bis zu 125 MBit/s. Auf Wunsch lässt sich WLAN per Tastendruck an der Basisstation abschalten.
     
    ";2;False;0;;;"AVM FRITZ!Fon 7150 (Fritz!Box Router +Telefon + VOiP) ";avm-fritzfon-7150;True;True;P-2760;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;169.0000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;39907,7783680556;20;34;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000218-avm-fritzfon-7150.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000219-avm-fritzfon-7150.jpg;;2;;False;;;;;False;False;False;;;;;False;;;;;; -5;0;True;"AVM FRITZ!Fon MT-D VoIP Dect-Telefon ";"AVM FRITZ!Fon MT-D VoIP Dect-Telefon ";"
    FRITZ!Fon MT-D: HD-Telefonie und komfortable Internetdienste mit DECT.
    Telefonieren Sie mit dem Schnurlostelefon FRITZ!Fon MT-D in bestechender Qualität über das Internet und nutzen Sie komfortable Webdienste. Als intelligentes Telefon der neuesten DECT-Generation vereint das FRITZ!Fon den Komfort der schnurlosen Telefonie mit den Qualitäts- und Leistungsmerkmalen der Internettelefonie (VoIP) in einem Gerät.
     
    Bei der Internettelefonie mit einem FRITZ!Fon wird durch HD-Telefonie (High Definition) ein brillantes, natürliches Klanggefühl erreicht. Sprache lässt sich mit dem FRITZ!Fon in ihrem gesamten Frequenzspektrum wiedergeben, was die Klangqualität von Festnetzverbindungen deutlich übertrifft.
     
    FRITZ!Fon unterstützt die übertragung großer Bandbreiten. Dies ermöglicht neben HD-Telefonie auch die Nutzung komfortabler Internetdienste wie den Empfang von E-Mails, Podcasts, RSS-Feeds und Internetradio.
     
    Die FRITZ!Box-Modelle FRITZ!Box Fon WLAN 7390, 7320, 7270 oder 7240 stellen mit der integrierten DECT-Basisstation, mehreren Anrufbeantwortern und einem Telefonbuch mit 300 Einträgen den idealen Partner für das FRITZ!Fon dar. Mit der umfangreichen Prozessor- und Speicherausstattung ist auch der Grundstein für neue Anwendungen gelegt. Denn das FRITZ!Fon ist lernfähig: Als eines der ersten intelligenten Schnurlostelefone wird es auch künftig per Firmware-Updates aktualisiert und um neue Funktionen erweitert werden können.
     
    Umfangreicher Komfort
    Das FRITZ!Fon MT-D ist mit zahlreichen Komfortfunktionen ausgestattet. Dazu zählen Lauthören und Freisprechen in HD-Qualität sowie ISDN-Leistungsmerkmale wie Namensanzeige bei bekannten Rufnummern, Halten, Makeln, Anklopfen, Rufumleitung oder Dreierkonferenz. Die Internettelefonie in HD-Qualität lässt sich so in ihrem vollen Umfang und Komfort nutzen, ohne dass der Computer eingeschaltet sein muss. FRITZ!Fon informiert zudem aktiv über unbeantwortete Anrufe, Nachrichten auf dem Anrufbeantworter und zeigt eingegangene E-Mails an. An der DECT-Basisstation der FRITZ!Box Fon WLAN 7390, 7320, 7270 und 7240 lassen sich bis zu 6 FRITZ!Fon-Handgeräte oder andere DECT-Telefone anmelden. Die Erstinstallation und individuelle Einstellungen erfolgen dabei bequem über einfache Assistenten.
     
    FRITZ!Box als idealer Partner
    Das FRITZ!Fon MT-D kann als Mobilteil an jeder DECT-Basisstation eingesetzt werden. Im Zusammenspiel mit der FRITZ!Box Fon WLAN 7390, 7320, 7270 oder 7240 kann jedoch das volle Spektrum der Möglichkeiten beim Telefonieren und Surfen über das Internet ausgenutzt werden. Die FRITZ!Box Fon WLAN 7390 zum Beispiel vereint eine bisher nicht erreichte Vielfalt in einem Gerät: VDSL- und ADSL-Unterstützung, DECT-Basisstation fürs schnurlose Telefonieren sowie WLAN N für die optimale Datenübertragung.
     
    Über den Mediaserver sind gespeicherte Filme, Musik und Bilder auch bei ausgeschaltetem Computer im gesamten Netzwerk verfügbar. Darüber hinaus kann der Online-Speicher wie eine lokale Festplatte genutzt werden. So wird die FRITZ!Box Fon WLAN 7390 zur idealen Plattform für vernetzte Anwendungen wie IPTV, Video on Demand oder Mediastreaming.
     
    Bedienung
    - Einfach einschalten und Suchtaste auf FRITZ!Box drücken.
     
    - Einfache Bedienung über intuitives Menü.
     
    - Telefonbuch komfortabel über FRITZ!Box-Oberfläche einrichten und anzeigen.
     
    - In FRITZ!Box integrierte Anrufbeantworter einfach am FRITZ!Fon MT-D einrichten und abhören.
     
    - Blinkende Leuchtdiode signalisiert eingegangene Anrufe, neue Nachrichten auf dem Anrufbeantworter und neue E-Mails.
     
    - Große Schrift und große Tasten.
    ";2;False;0;;;"AVM FRITZ!Fon MT-D VoIP Dect-Telefon ";avm-fritzfon-mt-d-voip-dect-telefon;True;True;;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;49.0000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;39907,7759837963;20;34;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000213-avm-fritzfon-mt-d-voip-dect-telefon.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000214-avm-fritzfon-mt-d-voip-dect-telefon.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000215-avm-fritzfon-mt-d-voip-dect-telefon.jpg;2;;False;;;;;False;False;False;;;;;False;;;;;; -5;0;True;"AVM FRITZ!WLAN USB Stick ";"AVM FRITZ!WLAN USB Stick - mit Stick & Surf Wireless LAN ";"
    AVM FRITZ!WLAN USB Stick - mit Stick & Surf Wireless LAN
     
    Allgemein / Breite [cm]: 2
    Allgemein / Formfaktor: Extern
    Allgemein / Gerätetyp: Netzwerkadapter
    Allgemein / Gewicht [g]: 10
    Allgemein / Höhe [cm]: 1.1
    Allgemein / Schnittstellentyp (Bustyp): Hi-Speed USB
    Allgemein / Tiefe [cm]: 5.3
    Antenne / Antenne: Intern eingebaut
    Erweiterung-Konnektivität / Verbindungen: 1 x Hi-Speed USB - USB Typ A, 4-polig
    Kopf / Hersteller: AVM
    Kopf / Kompatibilität: PC
    Kopf / Modell: USB Stick
    Kopf / Paketierte Menge: 1
    Kopf / Produktlinie: AVM FRITZ!WLAN
    Netzwerk / Anschlusstechnik: Drahtlos
    Netzwerk / Data Link Protocol: IEEE 802.11n;IEEE 802.11b;IEEE 802.11g
    Netzwerk / Datenübertragungsrate [Mbps]: 150
    Netzwerk / Frequenzband: 2.4 GHz
    Netzwerk / Leistungsmerkmale: Stromversorgung über USB;Wi-Fi Protected Setup (WPS);Firmware aktualisierbar
    Netzwerk / Produktzertifizierungen: IEEE 802.11n;IEEE 802.11g;USB 2.0;USB 1.1;IEEE 802.11b;IEEE 802.11i
    Netzwerk / Statusanzeiger: Link/Aktivität
     
    Software-Systemanforderungen / Erforderliches Betriebssystem:
     
    Microsoft Windows XP SP2;Microsoft Windows 7;Microsoft Windows Vista
    Software-Systemanforderungen / Software inbegriffen: Treiber & Utilities
    Verschiedenes / Encryption Algorithm: WPA2;128-Bit WEP;64-Bit WEP;WPA
    Verschiedenes / Enthaltene Kabel: 1 x USB-Kabel ( extern ) - 90 cm
    ";2;False;0;;;"AVM FRITZ!WLAN USB Stick N Standard 300MBit/Sek ";avm-fritzwlan-usb-stick;True;True;P-2720;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;39.9000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;39907,7691203704;19;34;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000208-avm-fritzwlan-usb-stick.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000209-avm-fritzwlan-usb-stick.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000210-avm-fritzwlan-usb-stick.jpg;2;;False;;;;;False;False;False;;;;;False;;;;;; -5;0;True;"Navigon Schutztasche 21|12|22|13|23 Serie ";"Navigon Schutztasche 21|12|22|13|23 Serie ";"

    Navigon Schutztasche 21|12|22|13|23 Serie

     
    Diese Tasche schützt Ihren PNA vor Schmutz, Kratzern und Stößen.
    Einfach den PNA in die Tasche stecken. Textiltasche mit Zipper
    ";2;False;0;;;;navigon-schutztasche-2112221323-serie;True;True;P-2140;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;24.9000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;39887,5982523148;68;14;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000197-navigon-schutztasche-2112221323-serie.jpg;;;2;;False;;;;;False;False;False;;;;;False;;;;;; -5;0;True;Hama MP3-Tasche für Sansa Clip;Hama MP3-Tasche für Sansa Clip;

    Hama MP3-Tasche für Sansa Clip

    passgenaue Silikontasche, sitzt wie eine zweite Haut
    Farbe: Transparent
    Ausstattung:
    rutschfeste Oberfläche
    Aussparung für Kabelverbindungen
    ;2;False;0;;;Hama MP3-Tasche für Sansa Clip;hama-mp3-tasche-fuer-sansa-clip;True;True;P-1580;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;14.9000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;39881,6482638889;52;8;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000196-hama-mp3-tasche-fur-sansa-clip.jpg;;;2;;False;;;;;False;False;False;;;;;False;;;;;; -5;0;True;Apple iPod Nano 16 GB silber;Apple ipod nano 16 GB silber mit Kamera;"
    Apple ipod nano 16 GB silber mit Kamera
     
    Der neue iPod nano. Jetzt mit Videokamera, Gehäuse aus poliertem Aluminium und einem größeren Display und dem neuen FM Radio mit Live-Pause.
     
    Neues gebogenes Design, der dünnste iPod, den es je gab mit neun Farben zu Auswahl
    Die Bedieung optimiert: ein einziges Handschütteln und ein anderes Lied wird gespielt
    Die neue Funktion ""Genius"" findet die Songs in Ihrer Mediathek, die besonders gut zusammenpassen, und erstellt daraus eine Genius Wiedergabeliste.
    Viele Abspielformate: z.B. MP3, AAC, Apple Lossless, AIFF, WAV, H.264, MPEG-4
    Lieferumfang: iPod Nano, Ohrhörer, USB 2.0 Kabel, Dock-Adapter, Dokumentation, iTunes 9.0
     
    Vom beliebtesten Musikplayer der Welt gibt es jetzt noch mehr zu sehen.Vom beliebtesten Musikplayer der Welt gibt es jetzt noch mehr zu sehen.Ein Wettrennen mit Einkaufswagen. Der große Food Fight um das Essen in der Mensa. Jetzt kannst du all das mit der iPod nano Videokamera festhalten. Nimm hochwertige Videos im Hoch- oder Querformat auf, die du ganz einfach ins Web stellen oder an Freunde mailen kannst. Über das im iPod nano integrierte Mikrofon wird das Audiomaterial aufgenommen, das du dann beim Abspielen über die integrierten Lautsprecher hörst.
     
    nano macht video
    Der neue iPod nano. Jetzt mit Videokamera, Gehäuse aus poliertem Aluminium und einem größeren Display. Und dem neuen FM Radio mit Live-Pause.
     
    Mach überall zur Filmkulisse
    Den iPod nano gibt's jetzt mit integrierter Videokamera, mit der Sie überall alles spontan festhalten und dann mit deinen Freunden im Internet teilen können. Diese Videokamera ist so klein, dass Sie sie überallhin mitnehmen können.
     
    Videoaufnahme. So nano kann Video sein
    Blättern Sie durch das Menü zur Videokamera und schon können Sie Videos im Hoch- oder Querformat aufnehmen - ideal zum Mailen oder Posten auf Facebook oder MobileMe. Mit dem integrierten Mikro können Sie auch Ton aufnehmen. Wenn Sie dann Ihr Video auf dem iPod nano abspielen, hören Sie den Ton gleich dazu. Damit wird Ihr Immer-dabei-Musikplayer zur Immer-dabei-Videokamera.
     
    Special Effects Abteilung inklusive
    15 tolle Videoeffekte geben Ihren Videos richtigen Hollywood-Touch. Blättern Sie durch die Effekte, wählen Sie den passenden aus, z. B. Filmkörnung oder Bewegungsunschärfe, und dann Kamera ab! Wenn Sie fertig sind, synchronisieren Sie den iPod nano mit Ihrem Computer und iPhoto (oder eine andere Foto-Software) wird geöffnet. Jetzt brauchen Sie Ihren Videohit nur noch zu mailen oder auf YouTube oder Facebook zu posten.
     
    Synchronisieren - Teilen - Und noch mehr Videos auf YouTube laden
    Wenn Sie den iPod nano an Ihren Mac anschließen, wird iPhoto geöffnet und alle mit dem iPod nano gemachten Videos werden mit Ihrem Computer synchronisiert. Auf dem PC geht das mit Ihrer Fotosoftware genauso einfach. Auf einem Mac können Sie Ihre Videos dann direkt in iPhoto durchsuchen und bearbeiten. Die Dateigrößen der Videos sind perfekt geeignet, um sie auf YouTube hochzuladen oder an Freunde zu mailen.
     
    Das ist Genius
    Steuern Sie Genius selbst. Oder Sie lassen ihm einfach freien Lauf. Egal, wofür Sie sich entscheident, Genius durchsucht Ihr Musikarchiv nach Songs, die gut zusammenpassen.
     
    Genius Wiedergabelisten
    Angenommen Sie haben einen Lieblingssong und möchten weitere Titel hören, die gut dazu passen. Ein paar Klicks auf den iPod nano und Genius sucht anhand dieses Songs weitere Titel in Ihrem Musikarchiv und erstellt eine Genius Wiedergabeliste für Sie. Sie können sie sich sofort anhören, für später speichern oder aktualisieren und nochmal gucken, was dabei rauskommt. Wenn Sie Songmixes suchen, an die Sie selbst nie gedacht hätten, dann überlassen Sie das ruhig Genius.
     
    Genius Mixe
    Und es gibt noch eine tolle Möglichkeit, eine ganz persönliche Songsammlung auf den iPod nano zu bekommen und Genius alles für Sie erledigen zu lassen: Die Genius Mixe. Sie müssen dafür nur den iPod nano mit iTunes synchronisieren. Genius durchsucht dann automatisch Ihr Musikarchiv nach Songs, die gut zusammenpassen und erstellt bis zu 12 Genius Mixe. Diese genrebasierten Mixe sind wie Radiosender, die nur Ihre Musik spielen. So entdecken Sie Songs wieder, die Sie schon ewig nicht mehr gehört haben oder welche, die Sie schon ganz vergessen hatten.
     
    Das ist so Cover Flow
    Blättern Sie mit Cover Flow durch Ihre Alben, um ganz schnell den richtigen Song zu finden. Oder halten Sie die Mitteltaste gedrückt, um das Albumcover umzudrehen und die Songs zu sehen. Wenn Sie den gewünschten Song gefunden haben, drücken Sie auf die Mitteltaste, um ihn zu Ihrer On-the-Go-Wiedergabeliste hinzuzufügen.
     
    Zum Mischen schütteln
    Hören Sie Songs einfach mal nach dem Zufallsprinzip. Einfach die Schüttelfunktion aktivieren, den iPod nano kurz schütteln und schon springt er zu irgendeinem anderen Song. Lassen Sie sich überraschen, was der iPod nano als nächstes für Sie auflegt.
     
    Radio hören - Radio anhalten. Radio weiterhören
    Der neue FM Tuner zeigt Ihnen die Namen von Songs und Interpreten. Und mit der fantastischen neuen Live-Pause Funktion ist Radio hören noch besser als Radio hören.
     
    FM Radio. Noch eine Möglichkeiten zu rocken
    Im Radio läuft immer gute Musik. Und mit dem FM Tuner können Sie Ihre Lieblingssendungen jetzt auf dem Weg zur Arbeit hören oder neue Musik entdecken, während Sie im Fitnessstudio rocken. Sie sehen sogar was und wen Sie gerade hören.
     
    Mit Live-Pause nie mehr einen Beat verpassen
    Angenommen Sie müssen Ihre Lieblingssendung im Radio einmal kurz unterbrechen. Ein Klick auf den iPod nano und schon ist Pause. Noch ein Klick und Sie hören die Sendung weiter. Sie können sogar bis zu 15 Minuten zurückspulen und dann vorspulen, um wieder live dabei zu sein.
     
    VoiceOver. Spricht jeden an
    VoiceOver sagt Ihnen die Namen von Titel und Interpreten der Songs, die Sie gerade hören. Und zwar so gut, dass Sie überrascht sein werden.
     
    Lass mal VoiceOver reden
    Sie hören einen Song und wollen wissen, wie er heißt oder von wem er ist? Benutzen Sie einfach das Click Wheel oder die Steuerung an den optionalen Apple Earphones mit Fernbedienung und Mikro, damit VoiceOver Ihnen Songtitel und Interpreten sagt, ohne dabei die Musik zu unterbrechen. Sie müssen nicht mehr auf das Display schauen, sondern können sich aufs Joggen oder Radfahren konzentrieren.
     
    So funktioniert's
    VoiceOver funktioniert ganz einfach. Wir haben hart daran gearbeitet, damit der iPod nano nicht nur spricht, sondern auch genau das Richtige sagt. Alles beginnt mit iTunes und der engen Zusammenarbeit mit dem iPod nano. iTunes liest zunächst die Songinformationen, und verwendet dann das VoiceOver Kit, um Ansagen für Songs, Interpreten und Wiedergabelisten zu erstellen. Sie müssen einfach nur deinen iPod nano mit deinem Computer synchronisieren und schon spricht er mit Ihnen.
     
    Das Sprachtalent
    Dein Musikarchiv enthält Musik aus allen Ländern der Welt: Chansons aus Frankreich, Sambarhythmen aus Brasilien und Popmusik aus Japan. Zum Glück spricht VoiceOver fließend Songisch.
    iTunes wählt automatisch die Sprache und die beste Stimme für die Songtitel und Interpreten aus. Die Software analysiert Songdaten wie Titel, Interpreten und Albuminfos und nutzt dann intelligente Algorithmen, um die richtige Sprache auszuwählen. ""Ya Viene el Sol"" von Ozomatli erkennt iTunes zum Beispiel als spanischen Song - und schon spricht der iPod den Songtitel und Interpreten automatisch auf Spanisch aus. Sie wollen es lieber in einer anderen Sprache hören? Dann können Sie die VoiceOver Sprache für diesen Song natürlich in iTunes ändern.
     
    Geht sofort los
    Mit dem Nike + iPod Sport Kit und einem integrierten Schrittzähler, das Ihre Fortschritte verfolgt und Sie motiviert, wird das Training mit dem iPod nano nie zur Routine.
     
    Der erste Schritt in Richtung Fitness
    Der iPod nano ist sowieso schon Ihr ständiger Begleiter, warum sollten Sie ihn also nicht auch als Fitnesstrainer nutzen? Denn jetzt wird er auch zum Schrittzähler. Mit dem integrierten Beschleunigungssensor zählt er Ihre Schritte, damit Sie Ihr Fitnessziel nie aus den Augen verlieren. Sie können eine tägliche Schrittvorgabe festlegen oder ""Immer eingeschaltet"" wählen, damit er jeden Ihrer Schritte zählt. Das macht den iPod nano zum idealen Trainingspartner.
     
    Rock'n'Run
    Mit dem iPod nano und Ihren Laufschuhen holen Sie alles aus Sich raus. Sehen Sie wie die Minuten verfliegen und Sie Kilometer für Kilometer zurücklegen. Sie bekommen Sprachfeedback in Echtzeit und hören dabei Ihren Lieblingsmusik und den PowerSong, der Sie jedes Mal wieder antreibt, Ihr Bestes zu geben.
     
    Rock das Training
    Nehmen Sie Nike + iPod mit ins Fitnessstudio und Sie werden Minute für Minute, Kilometer für Kilometer durch mehr als nur Musik motiviert. Schließen Sie den iPod nano an ein Fitnessgerät an, das mit Nike + iPod kompatibel ist. Halten Sie die Geschwindigkeit, die Dauer und die Laufstrecke deines Trainings fest. Mit dem iPod nano wird jeder Besuch im Fitnessstudio zur neuen Herausforderung.
     
    Synchronisieren
    Wenn Sie fertig sind, schließen Sie den iPod nano an Ihren Mac oder PC an. Ihre Workout-Daten werden dann automatisch von iTunes an nikeplus.com gesendet. Dort können Sie dann alle Ihre Workouts und Läufe überprüfen. Holen Sie außerdem neue Motivation für den nächsten Lauf mit empfohlenen Zielvorgaben, persönlichen Trainingsprogrammen und Karten mit neuen Strecken, die Sie ausprobieren können. Oder tauschen Sie sich mit Läufern aus aller Welt aus.
    ";2;False;0;;;Apple ipod nano 16 GB schwarz;apple-ipod-nano-16-gb-silber;True;True;P-1380;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;159.9000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;39876,6815625;48;1;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000087-apple-ipod-nano-8-gb-verschiedene-farben.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000076-apple-ipod-nano-8-gb-verschiedene-farben.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000077-apple-ipod-nano-8-gb-verschiedene-farben.jpg;2;;False;;;;;False;False;False;;;;;False;;;;;; -5;0;True;"Griffin Sports Tempo Armband für iPod nano ";"Griffin Sports Tempo Armband für iPod nano ";"

    Griffin Sports Tempo Armband für iPod nano  

     
    Mit dem Tempo Armband von Griffin ist der iPod Nano sicher geschützt und doch immer erreichbar
    Egal, ob Sie wandern, joggen, reiten, Kanu fahren, Fallschirm springen, im Garten werkeln oder sich einfach nur zu Hause entspannen.

    Das formschöne, unauffällige Design mit Reflektorstreifen sorgt für hohe Sichtbarkeit. 
    Eine Aufwicklung für das Kopfhörerkabel sorgt dafür, dass Kabelsalat vermieden wird. 
    Tempo ist mit einer Abdeckung zum Schutz des iPod Displays und einem weichen Innenfutter ausgestattet.
    Das Armband ist für alle Größen gut geeignet und in der Waschmaschine waschbar.
    ";2;False;0;;;"Griffin Tempo Sports Armband ";griffin-sports-tempo-armband-fuer-ipod-nano;True;True;P-1530;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;35.9000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;39876,600787037;51;28;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000195-griffin-sports-tempo-armband-fur-ipod-nano.jpg;;;2;;False;;;;;False;False;False;;;;;False;;;;;; -5;0;True;Artwizz SeeJacket Crystal Case für iPod Nano 4G;Artwizz SeeJacket Crystal Case für iPod Nano 4G transparent;"

    Artwizz SeeJacket Crystal Case für iPod Nano 4G transparent

     
    Funktionale Schutzhülle aus Polycarbonat - Kristallklare Schutzhülle, speziell für iPod nano 4G
    Hochwertige, robuste und transparente Schutzhülle
    Komplettschutz für Vorder- und Rückseite (inkl. Display)
    Anschlüsse sind ausgespart
    Keine Beeinträchtigung der Bedienbarkeit des iPod nano 4G.
    ";2;False;0;;;Artwizz SeeJacket Crystal Case für iPod Nano 4G;artwizz-seejacket-crystal-case-fuer-ipod-nano-4g;True;True;P-1440;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;19.9000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;39860,7781828704;51;30;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000194-artwizz-seejacket-crystal-case-fur-ipod-nano-4g.jpg;;;2;;False;;;;;False;False;False;;;;;False;;;;;; -5;0;True;"Belkin F8Z 409 Silikonhülle für Apple iPod Classic ";"Belkin F8Z 409 Silikonhülle für Apple iPod Classic ";"

    Belkin F8Z 400 Silikonhülle für Apple iPod Classic

    schwarz/blau/rosa 3er-Pack

    iPod Classic SILICON SLEEVE 3-PACK Schwarz & Blau & Pink
    ";2;False;0;;;;belkin-f8z-409-silikonhuelle-fuer-apple-ipod-classic;True;True;P-1430;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;14.9000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;39860,7754166667;51;;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000193-belkin-f8z-409-silikonhulle-fur-apple-ipod-classic.jpg;;;2;;False;;;;;False;False;False;;;;;False;;;;;; -5;0;True;Garmin DVD City Navigator Europa NT Update 2010;Garmin DVD City Navigator Europa NT Update 2010;"

    Garmin DVD City Navigator Europa NT Update 2010

    Der City Navigator Europa NT 2010 bietet einen erhöhten Detailgrad
    mit über 8 Millionen km Straßenabdeckung in Europa
     
    Volle Länderabdeckung für die Baltischen Staaten + erweiterte Straßenabdeckung
    von Griechenland, Kroatien, Tschechien, Ungarn, Polen, Slowakei
     
    1,2 Millionen POIs und 1 Millionen Städte, Orte und Dörfer,
    über 8.000 Campingplätze in West-Europa
    Update der zulässigen Höchstgeschwindigkeiten
    Lieferumfang: DVD mit City Navigator Europa NT
    ";2;False;0;;;Garmin DVD City Navigator Europa NT Update 2009;garmin-dvd-city-navigator-europa-nt-update-2010;True;True;P-2020;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;99.0000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;39856,6709722222;67;44;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000192-garmin-dvd-city-navigator-europa-nt-update-2010.jpg;;;2;;False;;;;;False;False;False;;;;;False;;;;;; -5;0;True;"Sony MDR EX 35 LPB.AE Stereo-In-Ear-Kopfhörer schwarz ";"Sony MDR EX 35 LPB.AE Stereo-In-Ear-Kopfhörer schwarz ";"

    Sony MDR EX 35 LPB.AE Stereo-In-Ear-Kopfhörer schwarz

     
    Leistungsstarke Kopfhörer, hervorragend geeignet als Ersatz für mp3-Player-Kopfhörer der Einstiegsklasse.>Leistungsmerkmale
    Hybrid-Silikon-Ohrpolster für sicheren Halt und Langzeit-Tragekomfort
    Y-förmiges Kabel mit praktischem Kabel- Reiter zur Vermeidung von Kabelsalat
    Frequenzgang: 6-23,000Hz
    3,5mm Klinkenanschluss
    Kabel: 1,2Y-förmig
     
    Zubehör: Ohrpolster, Kabel-Reiter
    ";2;False;0;;;"Sony MDR EX 35 LPB.AE Stereo-In-Ear-Kopfhörer schwarz ";sony-mdr-ex-35-lpbae-stereo-in-ear-kopfhoerer-schwarz;True;True;P-1500;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;24.9000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;39816,7113541667;51;10;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000187-sony-mdr-ex-35-lpbae-stereo-in-ear-kopfhorer-schwarz.jpg;;;2;;False;;;;;False;False;False;;;;;False;;;;;; -5;0;True;"Creative EP 630 Ohrhörer schwarz ";"Creative EP 630 Ohrhörer schwarz ";"

    Creative EP 630 Ohrhörer schwarz

     
    Silikon-Ohrpolster schirmen Umgebungsgeräusche effektiv ab und verbessern die Basswiedergabe
    Leicht und komfortabel - für maximalen Musikgenuss unterwegs
    Sauerstofffreie Kupferkabel für verlustfreie Signalübertragung
    Lieferumfang: 1 Paar In-Ear-Ohrhörer mit Silikon-Ohrpolstern,
    2 Paar zusätzliche Silikon-Ohrpolster in verschiedenen Größen
    ";2;False;0;;;"Creative EP 630 Ohrhörer ";creative-ep-630-ohrhoerer-schwarz;True;True;P-1470;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;19.9000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;39816,7078009259;51;22;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000186-creative-ep-630-ohrhorer-schwarz.jpg;;;2;;False;;;;;False;False;False;;;;;False;;;;;; -5;0;True;Sandisk Sansa Fuze 4 GB;"Sandisk Sansa Fuze MP3-/Video-Player 4 GB mit Radio ";"

    Sandisk Sansa Fuze MP3-/Video-Player 4 GB mit Radio

     
     
    Mit der verfügbaren Akkuleistung können Sie 24 Stunden lang Musik hören, Bilder anschauen oder spielen.
    Der neue Sansa Fuze von SanDisk ist der ideale tragbare Musikplayer für Sie.
    Er steht mit einer Speicherkapazität 4 GB in schwarz,rot,pink zur Verfügung.
    Sehen Sie sich Ihre Lieblingsvideoclips auf dem 1,9""-Farbdisplay des Sansa Fuze an.
    Lauschen Sie dem FM-Radio mit 40 voreingestellten Sendern oder probieren Sie den integrierten Sprachrekorder aus. Mit einer unglaublich starken Akkuleistung in einem 0,3"" schmalen Gerät setzt der Sansa Fuze Zeichen.
    ";2;False;0;;;Sandisk Sansa Fuze MP3-/Video-Player 4 GB mit Radio;sandisk-sansa-fuze-4-gb;True;True;P-1560;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;89.9000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;39789,5565625;52;8;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000180-sandisk-sansa-fuze-4-gb.jpg;;;2;;False;;;;;False;False;False;;;;;False;;;;;; -5;0;True;Sandisk Sansa Clip 2 GB schwarz;Sandisk Sansa Clip 2 GB mit integriertem FM-Tuner;"

    Sandisk Sansa Clip 2 GB mit integriertem FM-Tuner blau, rot, schwarz, pink

    digitaler SanDisk Player für MP3, WMA, Secure WMA und FM Radio
    kleines, kompaktes Design, kaum größer als eine Streichholzschachtel
    FM-Radio mit 40 Stationsspeicherplätzen
    Diktiergerät-Funktion über integriertes Mikrofon
    4-zeiliges OLED-Display
    Sortierung der Titel nach versch. Kriterien möglich, wie z.B. Künstler, Album, Genre, u.a.
    bis zu 15-h-Wiedergabe mittels internem, wiederaufladbaren Akku
    inkl. abnehmbarem Trageclip, Ohrhörer, USB 2.0 Kabel, Installations-CD mit Bedienungsanleitung
    unterstützt Win 2000 / XP / Vista
     
    Lieferumfang:
    Player inkl. abnehmbarem Trageclip, Ohrhörer, USB 2.0 Kabel, Installations-CD mit Bedienungsanleitung
    ";2;False;0;;;"Sandisk Sansa Clip 2 GB mit integriertem FM-Tuner ";sandisk-sansa-clip-2-gb-schwarz;True;True;P-1550;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;49.9000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;39789,5530092593;52;8;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000163-sandisk-sansa-clip-8-gb-schwarz.jpg;;;2;;False;;;;;False;False;False;;;;;False;;;;;; -5;0;True;Sandisk Sansa Clip 8 GB schwarz;"Sandisk Sansa Clip 8 GB mit integriertem FM-Tuner ";"

    Sandisk Sansa Clip 8 GB mit integriertem FM-Tuner schwarz

     
    digitaler SanDisk Player für MP3, WMA, Secure WMA und FM Radio
    kleines, kompaktes Design, kaum größer als eine Streichholzschachtel
    FM-Radio mit 40 Stationsspeicherplätzen
    Diktiergerät-Funktion über integriertes Mikrofon
    4-zeiliges OLED-Display
    Sortierung der Titel nach versch. Kriterien möglich, wie z.B. Künstler, Album, Genre, u.a.
    bis zu 15-h-Wiedergabe mittels internem, wiederaufladbaren Akku
    inkl. abnehmbarem Trageclip, Ohrhörer, USB 2.0 Kabel, Installations-CD mit Bedienungsanleitung
    unterstützt Win 2000 / XP / Vista
     
    Lieferumfang:
    Player inkl. abnehmbarem Trageclip, Ohrhörer, USB 2.0 Kabel, Installations-CD mit Bedienungsanleitung
    ";2;False;0;;;"Sandisk Sansa Clip 8 GB mit integriertem FM-Tuner ";sandisk-sansa-clip-8-gb-schwarz;True;True;P-1570;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;69.9000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;39789,5485648148;52;8;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000163-sandisk-sansa-clip-8-gb-schwarz.jpg;;;2;;False;;;;;False;False;False;;;;;False;;;;;; -5;0;True;Canon PIXMA MP550 Multifunktionsgerät;Canon PIXMA MP550 Multifunktionsgerät;"
    Canon PIXMA MP550  Multifunktionsgerät
     
     
    3 in 1, Drucken, Kopieren, Scannen
     
     
    Der PIXMA MP550 überzeugt als exzellentes Multifunktionssystem für zu Hause mit starkem Preis-Leistungs-Verhältnis.
    Er kombiniert Komfort mit Klasse beim Dokumenten- und Fotodruck; hohes Tempo bei Druck, Scan und Kopie sind selbstverständlicher Standard.
     
    Drucken, Kopieren und Scannen
    Druckgeschwindigkeit: bis zu 9,2/6,0 ISO-Seiten pro Minute (SW/Farbe)
    Bis zu 9.600 x 2.400 dpi Auflösung, 1 Picoliter feine Tintentröpfchen; 10 x 15 cm Randlosprint in ca. 39 Sek.
    5-Tintensystem
    5,0 cm großes TFT-Farbdisplay und Easy-Scroll-Bedienrad
    Scanner mit bis zu 2.400 dpi
    PictBridge und Speicherkarte
    ChromaLife100+
    Auto Photo Fix II
    ";2;False;0;;;Canon PIXMA MP540 Multifunktionsgerät - All in One Drucker - Drucken - Scannen - Kopieren - Faxen;canon-pixma-mp550-multifunktionsgeraet;True;True;P-2200;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;2,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;109.0000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;39784,3258333333;"22;2095";25;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000161-canon-pixma-mp550-multifunktionsgerat.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000162-canon-pixma-mp550-multifunktionsgerat.jpg;;2;;False;;;;;False;False;False;;;;;False;;;;;; -5;0;True;AVM Fritz! WLAN Repeater;AVM Fritz! WLAN Repeater N/G zur Erhöhung der Reichweite von W-LAN Netzen;"
    AVM Fritz!WLAN Repeater N/G 

    zur Erhöhung der Reichweite von W-LAN Netzen

    Erhöht schnell und einfach die Reichweite von WLAN-Netzen
    Funktioniert in allen WLAN-Funknetzen: 802.11n Draft 2.0 (300 MBit/s), 802.11g/a (54 MBit/s)
    und 802.11b (11 MBit/s)
     
    Sichere Funkverbindungen dank WPA2-, WPA- und WEP-Verschlüsselung
    Integrierter UKW-Minisender (FM-Transmitter 87,5-108 Mhz)
    Perfekt abgestimmt auf WLAN-Produkte der FRITZ!Box-Familie
    .
    ";2;False;0;;;AVM Fritz!WLAN Repeater N/G zur Erhöhung der Reichweite von W-LAN Netzen;avm-fritz-wlan-repeater;True;True;P-2730;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;89.0000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;39775,5815509259;19;34;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000157-avm-fritz-wlan-repeater.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000158-avm-fritz-wlan-repeater.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000159-avm-fritz-wlan-repeater.jpg;2;;False;;;;;False;False;False;;;;;False;;;;;; -5;0;True;Adobe Photoshop Elements 7;Adobe Photoshop Elements 7 deutsch WIN.;"
    Adobe Photoshop Elements 7 deutsch WIN

    Adobe Photoshop Elements 7 kombiniert Leistungsfähigkeit mit einfacher Bedienung,
    sodass Ihnen bei der Bearbeitung von Fotos keine Grenzen gesetzt sind.
    Machen Sie aus alltäglichen Motiven eindrucksvolle Kunstwerke. Innovative Werkzeuge und Funktionen ermöglichen es Ihnen zum Beispiel,
    unerwünschte Objekte mühelos aus einem Foto zu entfernen, mit einer einzigen Mausbewegung gleichzeitig einen Bildbereich auszuwählen und mit Effekten zu versehen,
    Zähne aufzuhellen oder einen Himmel noch intensiver wirken zu lassen. Professionell gestaltete Layouts erleichtern Ihnen die Erstellung von Bildbänden,
    Fotoalben und interaktiven Online-Galerien, und dank der durchdachten Verwaltung finden Sie jedes Foto im Handumdrehen.
    Die wichtigsten Merkmale:
    Intuitive Bearbeitungswerkzeuge zur Gestaltung eindrucksvoller Fotoprojekte
    Einfache Erstellung unverwechselbarer Kreationen für Print und Web
    Effizientes Suchen und Aufrufen von Fotos
    ";2;False;0;;;Adobe Photoshop Elements 7;adobe-photoshop-elements-7;True;False;P-3010;;;False;0;False;;False;False;0;False;0;1;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;1;0;True;False;10;0;1;1;False;1;10000;;False;True;False;False;109.5000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;39774,9070023148;31;20;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000155-adobe-photoshop-elements-7.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000156-adobe-photoshop-elements-7.jpg;;2;;False;ounce;;;;False;False;False;;;;;False;;;;;; -5;0;True;"NAVIGON 1300 Navigationssystem D-A-CH ";"NAVIGON 1300 Navigationssystem D-A-CH ";"

    NAVIGON 1300 Navigationssystem D-A-CH

     
    NAVIGON MyRoutes, Clever Parking , POI Klick, Fahrspurassistent Pro, Reality View Light
     
     
    NAVIGON 1300 Besonders klein und trotzdem voll mit Features.
    Die NAVIGON 13er-Serie kann viel mehr, als Sie vielleicht im ersten Moment denken.
    Denn in dem kleinen smarten Gehäuse stecken überaus nützliche Funktionen.
    Zum Beispiel NAVIGON MyRoutes, das Ihnen jederzeit genau die Route empfiehlt, die zu Ihnen und Ihrem Fahrstil passt.
    Für eine schnelle und sichere Navigation sorgen zudem ein verbesserter Fahrspurassistent Pro, Reality View Light und viele weitere Helfer.
     
    NAVIGON MyRoutes
    Je nachdem, welcher Fahrertyp Sie sind, empfiehlt Ihnen NAVIGON MyRoutes die beste Route – zugeschnitten auf Ihren persönlichen Fahrstil,
    den Wochentag und die Tageszeit. Darüber hinaus zeigt Ihnen Ihr NAVIGON bis zu zwei weitere Routen.
    Das schafft Transparenz. Sie entscheiden, ob Sie unserer Empfehlung folgen oder eine der Alternativen wählen.
     
    Clever Parking
    hilft Ihnen bei der Parkplatzsuche. Kurz vor Ihrem Ziel zeigt Ihnen Clever Parking Parkplätze in der näheren Umgebung an.
    In Deutschland werden Sie sogar über Parkgebühren informiert. So vermeiden Sie langes Suchen und sparen dabei Geld.
     
    Fahrspurassistent Pro
    hilft Ihnen selbst durch den hektischsten Straßenverkehr hindurch.
    Vorausschauend und übersichtlich zeigt er Ihnen an, auf welche Fahrspur Sie für Ihren nächsten und übernächsten Abbiegepunkt wechseln müssen.
     
    POI-Klick
    ermöglicht durch Anklicken die Auswahl eines auf der Karte angezeigten Sonderziels wie zum Beispiel Rastplätze oder Sehenswürdigkeiten.
    Inklusive wissenswerter Informationen wie Adresse, Öffnungszeiten und Telefonnummern. Und auf Wunsch können Sie sich direkt dorthin navigieren lassen.
     
    Lieferumfang:
    PNA  1300 (3,5"" im 4:3 Format) | Kurzanleitung | Kfz-Ladekabel | Halterung | Vorinstalliertes Kartenmaterial | USB-Kabel
    ";2;False;0;;;;navigon-1300-navigationssystem-d-a-ch;True;True;P-2130;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;149.0000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;39760,6629166667;"68;2095";14;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000154-navigon-1300-navigationssystem-d-a-ch.jpg;;;2;;False;;;;;False;False;False;;;;;False;;;;;; -5;0;True;Digitus USB2.0 Hub 7-port;Digitus USB2.0 Hub 7-port;

    Digitus USB2.0 Hub 7-port

    USB 2.0 und USB 1.1 kompatibel 7 x USB A Buchse (USB 1.1 und 2.0 Endgeräte
    Maximale Datenübertragungsrate 480 Mbps
    Überspannungsschutz an allen Ausgängen
    Kompatibel mit PC und MAC
    Lieferung inklusive USB Anschlusskabel und Netzteil
    ;2;False;0;;;Digitus USB2.0 Hub 7-port;digitus-usb20-hub-7-port;True;True;P-0045;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;20.9000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;39757,6835532407;26;;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000153-digitus-usb20-hub-7-port.jpg;;;2;;False;;;;;False;False;False;;;;;False;;;;;; -5;0;True;Logitech USB Hub 4-Port USB;Logitech USB Hub 4-Port USB;"

    Logitech USB Hub 4-Port USB

    Lieferumfang: Logitech Premium 4-Port USB Hub for Notebooks,
    USB-Kabel, Schnellstartanleitung, Etui, Netzteil
     
    Systemvoraussetzungen PC: Windows 2000, Windows XP, Windows Vista:
     
    USB-Anschluss Mac: Mac OS X (10.1 oder höher) USB-Anschluss
    ";2;False;0;;;Logitech USB Hub 4-Port USB;logitech-usb-hub-4-port-usb;True;True;P-0072;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;22.9000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;39757,6788425926;26;11;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000152-logitech-usb-hub-4-port-usb.jpg;;;2;;False;;;;;False;False;False;;;;;False;;;;;; -5;0;True;LogiLink USB HUB mit Netzteil;"LogiLink USB 2.0 Hub 7-Port mit Netzteil ";"

    LogiLink USB 2.0 Hub 7-Port mit Netzteil

     
    Der schnelle Hub von LogiLink unterstützt den modernen USB 2.0-Standard mit bis zu 480 MBit/s
    und erweitert Ihren Anschluss um weitere 7 Ports.
    ";2;False;0;;;LogiLink USB HUB mit Netzteil;logilink-usb-hub-mit-netzteil;True;True;P-0070;;;False;0;False;;False;False;0;False;0;1;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;17.9000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;39757,6744907407;"26;2095";31;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000151-logilink-usb-hub-mit-netzteil.jpg;;;2;;False;;;;;False;False;False;;;;;False;;;;;; -5;0;True;"Artwizz SeeJacket Crystal Hülle für iPod classic ";"Artwizz SeeJacket Crystal Hülle für iPod classic Vers.2009 ";"

    Artwizz SeeJacket Crystal Hülle für iPod classic

    80, 120 und 160 GB (2009 & 2010 Version)

     Das SeeJacket Crystal besteht aus robustem, transparentem Kunststoff und schuetzt zuverlaessig
    vor Stoessen, Erschuetterung und Abnutzung.
    Zugriff auf alle Bedienelemente bleibt natuerlich bestehen.
    Eine Befestigungsmoeglichkeit fuer ein Umhaengeband ermoeglicht bequemes Tragen um den Hals.
    Das optional einsetzbares Silikon-Pad schuetzt das Click Wheel und laesst weiterhin bequemes Bedienen zu.
    ";2;False;0;;;Artwizz SeeJacket Crystal Hülle für iPod classic;artwizz-seejacket-crystal-huelle-fuer-ipod-classic;True;True;P-1450;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;29.9000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;39754,7778009259;51;30;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000150-artwizz-seejacket-crystal-hulle-fur-ipod-classic.jpg;;;2;;False;;;;;False;False;False;;;;;False;;;;;; -5;0;True;Artwizz PowerPlug Steckdose;"Artwizz PowerPlug Steckdose auf USB-Ladegerät ";"

    Artwizz PowerPlug Steckdose

     
    auf USB-Ladegerät für iPods und USB aufladbare MP3-Player Mit diesem USB-Ladegerät kann man den iPod shuffle oder andere MP3 Player,

    beziehungsweise andere USB Geräte, einfach an der Steckdose ohne Computer aufladen
    (das Gerät besitzt einen Steckdosenstecker und einen USB-Schnittstelle).
    In Verbindung mit dem iPod Dock Connector-auf-USB Kabel
    kann man alle iPod Modelle an der Steckdose aufladen.

    Technische Daten: Europäischer Netzstecker
    Eingang: 100-240V AC, 0,15A, 47-63Hz
    Ausgang: 5V DC, 1,0A Lieferumfang: Artwizz PowerPlug Steckdose
    ";2;False;0;;;Artwizz PowerPlug Steckdose;artwizz-powerplug-steckdose;True;True;P-1460;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;17.9000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;39754,709837963;51;30;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000149-artwizz-powerplug-steckdose.jpg;;;2;;False;;;;;False;False;False;;;;;False;;;;;; -5;0;True;Sennheiser CX 300 Ohrkanalhörer schwarz;"Sennheiser CX 300 Ohrkanalhörer ";"

    Sennheiser CX 300 Ohrkanalhörer

    Sennheiser CX 300 Ohrhörer, Kraftvoller, bassbetonter Stereo-Sound
    Optimaler Sitz im Ohrkanal durch Ohradapter
    in unterschiedlichen Größen (im Lieferumfang enthalten)
    Sehr gute Abschirmung von Außengeräuschen
    Ideal für MP3-, CD-, DVD- und MD-Player
    sowie portable Spielekonsolen mit 3,5-mm-Kopfhörerausgang
     
    ";2;False;0;;;;sennheiser-cx-300-ohrkanalhoerer-schwarz;True;True;P-1490;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;29.9000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;39754,705462963;51;29;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000148-sennheiser-cx-300-ohrkanalhorer-schwarz.jpg;;;2;;False;;;;;False;False;False;;;;;False;;;;;; -5;0;True;Gear4 IceBox transparent;Gear4 IceBox für iPod nano 4G, transparent;"
    Gear4 IceBox für iPod nano 4G, transparent
     
     
    Gear4 IceBox für iPod nano 4G, transparent
    Transparente Hülle für iPod nano 4G
    ";2;False;0;;;Gear4 IceBox transparent;gear4-icebox-transparent;True;True;P-1480;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;24.9000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;39754,6834143519;"51;2095";28;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000147-gear4-icebox-transparent.jpg;;;2;;False;;;;;False;False;False;;;;;False;;;;;; -5;0;True;Apple iPod Touch 16 GB schwarz;"Apple iPod Touch 16GB schwarz ";"
    Apple iPod Touch 32 GB schwarz mit integrierter WiFi Funktion

    Der iPod touch kann alles, was du am iPod toll findest. Und noch vielmehr. Schlankes neues Design. Mit seinem fantastisch flachen Edelstahl-Design liegt der iPod touch mit dem 3.5 Zoll Touch-Display jetzt noch besser in der Hand. Mobil im Spiel. Durch revolutionäre Technologien wie das Multi-Touch-Display, der Beschleunigungssensor und 3D-Grafiken macht das Spielen auf dem iPod touch besonders viel Spaß. Schlaue Musik Mit der neuen Funktion ""Genius"" wird der iPod touch zu Deinem superintelligenten, persönlichen DJ.
    Nur ein paar Fingertipps, und Genius erzeugt eine Wiedergabeliste mit Songs Deiner Mediathek, die gut zusammenpassen. Internet überall Internetzugang überall, wo ein drahtloses Netzwerk zur Verfügung steht, damit Sie immer mit dabei sind. Multitouch-Oberfläche: Die revolutionäre Technologie des iPhone und die Software Version 3.1 stecken in diesem genialen iPod. Das brillante Breitformat-Display rückt Ihre Videos und Spiele ins beste Licht und dank OpenGL sehen die Spiele jetzt noch besser aus Surfen Sie mit Safari im Web und sehen Sie YouTube Videos auf dem iPod mit integrierter Wi-Fi Funktionalität an. Mit Ihrem iPod touch können Sie im iTunes Wi-Fi Music Store nach Songs suchen, Hörproben abspielen und Titel kaufen.
    Lieferumfang: iPod touch, Ohrhörer, USB 2.0 Kabel, Kurzanleitung
     
    Schlankes neues Design
    Mit seinem fantastisch flachen Edelstahl-Design liegt der iPod touch so gut in der Hand wie nie zuvor. Ebenfalls Eindruck machen der neue Lautstärkeregler und der integrierte Lautsprecher.

    Spiele
    Speziell auf die iPod touch Technologie zugeschnittene Spiele sind nur noch einen Fingertipp entfernt. Stöbere in hunderten von Spielen im App Store direkt auf Deinem iPod touch, und wenn Du gefunden hast, was Du suchst, kannst Du es einfach laden und dann kann es losgehen.
     
    Steuerung per Fingertipp
    Viele Spiele auf dem iPod touch nutzen die Multi-Touch-Technologie für besonders exakte Fingertipp-Steuerung der verschiedenen Spielelemente. Beim Schach ziehst Du mit dem Finger die Figuren, bei Würfelspielen bewegst Du die Würfel. Durch Ziehen mit zwei Fingern kannst Du die Anzeige vergrößern und verkleinern, Deine Figur nach links oder rechts drehen, und durch einfaches Antippen triffst Du eine Auswahl.
     
    Musik
    Blättere in den Albumcovern Deiner Musiksammlung. Erstelle immer wieder neue Genius Wiedergabelisten und erweitere Deine Sammlung aus dem iTunes Wi-Fi Music Store überall, wo ein Wi-Fi-Hotspot in der Nähe ist.
    Mit Cover Flow lebt das Flair einer CD- oder Plattensammlung wieder auf. Wer erinnerst sich nicht an das Gefühl beim Durchblättern der Sammlung? Das gibt es jetzt auch auf dem iPod touch: einfach iPod drehen, durch die Cover blättern, ein Album auswählen, fertig. Ein Fingertipp aufs Cover, und schon siehst Du die Titelliste, ein weiterer Tipp spielt die Musik ab, und dabei kannst Du sogar die Songtexte anzeigen.
     
    Ein Musikgenie
    Stell Dir vor, Du hörst einen Song. Toll wären jetzt andere Titel, die gut dazu passen. Was machst du? Ganz einfach: Du verwendest die neue Funktion ""Genius"". Diese findet die Songs in Deiner Mediathek, die gut zusammenpassen. Du erhältst eine Genius Wiedergabeliste, die Du sofort anhören, sichern oder sogar aktualisieren kannst. Verlass Dich also auf den Genius von iTunes, wenn Du einen Mix willst, auf den Du selbst nicht gekommen wärst.
     
    Lautsprecher integriert
    Mit dem integrierten Lautsprecher kannst Du Musik und Gespräche ohne Kopfhörer hören – perfekt für zwangloses Hörvergnügen.

    Längere Batterielaufzeit
    Jetzt kannst Du noch länger rocken (und ansehen und spielen). Der iPod touch hält bis zu 36 Stunden bei Musik oder bis zu 6 Stunden bei Videos durch. Das reicht für drei oder vier Filme zwischen den Ladevorgängen.
     
    Internet
    Surfe im Internet mit Wi-Fi. Du kannst detailgenaue HTML-E-Mails mit Anlagen empfangen und Wegbeschreibungen und aktuelle Verkehrsinformationen abrufen. Auch als YouTube-Fan entgeht Dir nichts.
     
    Überall ins Internet
    Der iPod touch ist der einzige iPod mit kabellosem 802.11b/g Internetzugriff. Bei bestehender Wi-Fi-Verbindung kannst Du im Internet surfen und Nachrichten lesen, Sportergebnisse sehen, Rechnungen bezahlen und online einkaufen.
     
    Wer suchet, der findet
    Der iPod touch synchronisiert Deine Lesezeichen vom PC oder Mac, sodass Du ruck zuck auf Deine Lieblingsseiten zugreifen kannst. Die Google- und Yahoo!-Suche ist schon integriert, sodass Du im Web schnell findest, was Du suchst.
     
    Zoom mit Aussicht
    Jeden beliebigen Ausschnitt einer Webseite kannst Du vergrößern, indem Du mit dem Finger darauf tippst oder mit zwei Fingern die Anzeige aufziehst. Websites lassen sich im Hoch- oder Querformat anzeigen: einfach den iPod touch um 90 Grad drehen, und schon wird auch die Darstellung der Website gedreht.
     
    Eigene Weblinks
    Für häufig besuchte Websites, etwa die einer Zeitung, eines Blogs oder eine Sport-Website, kannst Du einfach ein Symbol auf dem Home-Bildschirm erstellen. Deine Lieblingsseiten sind über mit Safari erstellte Weblinks nur einen Fingertipp entfernt.
     
    Rock 'n' Run mit Nike+
    Im iPod touch ist kabellose Unterstützung für Nike + iPod integriert. Du brauchst nur einen Nike + iPod Sensor in Deinem Schuh, und schon kann's losgehen.
     
    Das optimale Lauftraining
    Im iPod touch ist jetzt Unterstützung für Nike + iPod integriert. Einfach den Nike + iPod Sensor (separat erhältlich) in den Nike+ Laufschuh einsetzen, und es kann losgehen. Der Sensor überträgt die Laufdaten drahtlos an den iPod touch – er erfasst die gelaufene Zeit, die zurückgelegte Strecke und die verbrauchten Kalorien. Außerdem gibt er Dir gesprochenes Feedback zu Deinen Trainingsfortschritten.
     
    Das optimale Fitnesstraining
    Diese Funktion kann auch zusammen mit neuen, in vielen Fitnessstudios vorhandenen Geräten für das Ausdauertraining gekoppelt werden. Suche einfach nach mit Nike + iPod kompatiblen Laufbändern, Elliptical Trainern, Steppern und Hometrainern.
    ";2;False;0;;;Apple iPod Touch 16 GB;apple-ipod-touch-16-gb-schwarz;True;True;P-1250;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;229.9000;229.9000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;39754,6690972222;43;1;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000141-apple-ipod-touch-16-gb-schwarz.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000142-apple-ipod-touch-16-gb-schwarz.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000143-apple-ipod-touch-16-gb-schwarz.jpg;2;;False;;;;;False;False;False;;;;;False;;;;;; -5;0;True;Hannspree HL231DPB 58,4 cm (23 Zoll);Hannspree HL231DPB 58,4 cm (23 Zoll) Widescreen LCD Monitor DVI, VGA (Kontrast dyn. 1000:1, 5ms Reaktionszeit) schwarz;Marke: HANNSPREE
    Farbe: schwarz (hochglanz)
    Produkthöhe: 18.8 cm
    Produktbreite: 54.6 cm
    Bildschirm Größe: 23 inches
    Bildschirm Auflösung: 1920x1080 Pixel
    Max. Bildschirmauflösung: 1920 x 1080 pixels
    Weitere Spezifikationen
    Leistung: 27 Watt
    ;2;False;0;;;Hannspree HL231DPB 58,4 cm (23 Zoll);hannspree-hl231dpb-584-cm-23-zoll;True;True;P-2540;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;2,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;149.0000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;39741,7897800926;"12;2095";26;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000137-hannspree-hl231dpb-584-cm-23-zoll.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000138-hannspree-hl231dpb-584-cm-23-zoll.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000139-hannspree-hl231dpb-584-cm-23-zoll.jpg;2;;False;;;;;False;False;False;;;;;False;;;;;; -5;0;True;Canon PIXMA MP270 Multifunktionsgerät;"Canon PIXMA MP270 Multifunktionsgerät ";"
    Canon PIXMA MP270 Multifunktionsgerät
     
     
    3 in 1, Drucken, Kopieren, Scannen
     
     
    Der PIXMA MP270 ist ein kompaktes, günstiges Multifunktionssystem.
    Seine Stärken sind der schnelle Dokumentendruck und der Fotodirektdruck in Laborqualität von PictBridge-kompatiblen Kameras und Fotohandys.
     
    Drucken, Kopieren und Scannen
    Druckgeschwindigkeit: bis zu 8,4/4,8 ISO-Seiten pro Minute (SW/Farbe)
    Bis zu 4.800 dpi Auflösung und 2 Picoliter feine Tintentröpfchen
    10 x 15 cm Randlosprint in ca. 45 Sek.
    Easy-WebPrint EX
    Scanner mit bis zu 1.200 dpi und Auto-Scan-Modus
    PictBridge
    Selbst öffnendes Papierausgabefach
    ChromaLife100+
    ";2;False;0;;;Canon Pixma MX310 - All in One Drucker - Drucken - Scannen - Kopieren - Faxen;canon-pixma-mp270-multifunktionsgeraet;True;True;P-2210;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;2,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;89.0000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;39741,6931365741;22;25;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000132-canon-pixma-mp270-multifunktionsgerat.jpg;;;2;;False;;;;;False;False;False;;;;;False;;;;;; -5;0;True;"TomTom XL Black Edition Europe Traffic ";"TomTom XL Black Edition Europe Traffic ";"

    TomTom XL Black Edition Europe Traffic

    TMC ,4,3"" Display, 42 Länderkarten

     
    TomTom Navigationsgerät XL Classic Black Edition mit 4,3 Zoll Farb-Touchscreen,
    RDS/TMC, 42 vorinstallierten Karten europäischer Länder sowie vielen Innovationen für eine verbesserte und komfortable Navigation
    TMC-Empfänger für einen einfachen Zugriff auf Verkehrsinformationen und verschiedene Routenoptionen für die schnellste oder kürzeste Strecke
    Mit TomTom HOME und TomTom Map Share das Navi auf dem neusten Stand halten und weitere Features am PC/Mac nutzen
    TomTom XL Classic Black Edition in einem edlen schwarzen Gehäuse mit passender EasyPort Halterung für eine einfache Frontscheibenmontage
     
    Lieferumfang:
    TomTom XL Classic Black Edition, EasyPort-Halterung, USB-Kabel, Autoladegerät, Dokumentation, RDS/TMC-Verkehrsinfo-Empfänger
    ";2;False;0;;;;tomtom-xl-black-edition-europe-traffic;True;True;P-2000;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;182.9000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;39724,7946643519;66;4;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000131-tomtom-xl-black-edition-europe-traffic.jpg;;;2;;False;;;;;False;False;False;;;;;False;;;;;; -5;0;True;Western Digital My Passport 320 GB;"Western Digital BAAA3200ABK My Passport Essential 320GB ";"

    Western Digital BAAA3200ABK My Passport Essential 320GB  

     
    Schnittstellen:1 x Hi-Speed USB, Schnittstellen Typ:Hi-Speed USB, Kapazität:320 GB, Merkmale:
    Kennwortauthentifizierung, Details zu Service & Support
    Übertragungsrate Schnittstelle:480 Mbit/s, Software inbegriffen:Smartware,
    Erforderliches Betriebssystem:Microsoft Windows XP, Microsoft Windows 7, Apple MacOS X 10.4,
    Microsoft Windows Vista, Apple MacOS X 10.6, Apple MacOS X 10.5, Stromversorgung:USB-Bus,.
    Enthaltene Kabel:1 x USB-Kabel - extern
    ";2;False;0;;;"Western Digital My Passport 320 GB externe Festplatte ";western-digital-my-passport-320-gb;True;True;P-2590;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;99.0000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;39724,7845023148;14;21;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000130-western-digital-my-passport-320-gb.jpg;;;2;;False;;;;;False;False;False;;;;;False;;;;;; -5;0;True;"Trekstor DataStation maxi g.u 1TB ";"Trekstor DataStation maxi g.u externe Festplatte 1TB ";"

    Trekstor DataStation maxi g.u Externe Festplatte 1 TB

     
    USB 2.0 inkl. Nero BackItUp 2 Essentials
     
     
    Optimale Speicherplatzerweiterung
    Die DataStation maxi g.u ist die perfekte Lösung für das
    tägliche Backup oder die Speicherplatzerweiterung Ihres PCs.
    Die externe 3,5“ Festplatte bietet ausreichend Platz
    zum Speichern und Archivieren der heimischen Musik-
    und Videosammlung, digitaler Fotos oder anderer Dateien. 
     Schnell und bedienungsfreundlich
    Mit dem Hi-Speed USB 2.0 Anschluss bietet die
    DataStation maxi g.u einen schnellen Datentransfer.
    Die Festplatte ist zudem bereits vorformatiert und
    ohne Treiber sofort betriebsbereit.
    Unterstützt werden alle gängigen
    Dateisysteme von Windows®, Linux® und Mac® OS X,
    sowie die Betriebssysteme Microsoft
    Windows® 2000 / XP/ Vista, Mac® OS X ab 10.3 und Linux® ab Kernel 2.6.x.
    Die Festplatte wird über das mitgelieferte Netzteil mit Strom versorgt. 
    Der Ein-/Ausschalter am Festplattengehäuse verhindert überflüssigen Stromverbrauch. 
    Exklusives Aluminiumgehäuse
    Das exklusive Aluminiumgehäuse der DataStation maxi g.u
    sorgt für die optimale Kühlung der Festplatte,
    so kommt die externe Festplatte
    ohne Lüfter aus und ist leise während des Betriebs 
    Inklusive Nero Software „BackItUp2 Essentials“
    Die ebenfalls im Lieferumfang enthaltene
    Nero Software rundet das Bild der mobilen, externen Festplatte perfekt ab.
    Mit Nero BackItUp2 Essentials können Sie Backups Ihrer Daten sehr einfach planen.
    So können einzelne Dateien oder ganze Laufwerke gesichert werden.
    Um die Datenmenge gering zu halten, komprimiert die Software die Backups direkt „on the fly“.
    Auf Wunsch lassen sich die gesicherten Daten auch per Passwortschutz vor unbefugtem Zugriff schützen.
    ";2;False;0;;;"Trekstor DataStation maxi g.u-externe Festplatte 1 TB ";trekstor-datastation-maxi-gu-1tb;True;True;P-2620;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;129.0000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;39720,7329166667;15;2;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000129-trekstor-datastation-maxi-gu-1tb.jpg;;;2;;False;;;;;False;False;False;;;;;False;;;;;; -5;0;True;"Western Digital My Passport 250 GB ";Western Digital My Passport Essential 250GB;"

    Western Digital My Passport Essential 250GB Schwarz

     
    Mobiler Hochleistungsspeicher für Ihren Mac® oder PC.
    Es ist leicht und robust, einfach zu transportieren und erfordert kein externes Netzteil.
    Im Lieferumfang sind eine Software zur Synchronisierung und Verschlüsselung sowie
    Google™-Software enthalten.
    USB-gesteuert Software zur Synchronisation und Verschlüsselung
    Besonders gut tragbare Form
    Zum Transportieren von wichtigen Dateien und E-Mails zwischen Büro und Wohnung sowie unterwegs
    Gemeinsame Nutzung von großen Dateien zwischen Büro und Wohnung, zwischen PC und Mac.
    Kapazität: 250 GB (GigaByte)
    maximale Transferrate: 480 Mb/s über USB 2.0
    USB 2.0 Anschluss
    für PC oder Macintosh Computer
     
    Lieferumfang:
    Tragbares Festplattenlaufwerk, USB 2.0-Kabel, Schnellinstallationsanleitung
    ";2;False;0;;;Western Digital My Passport 250 GB 2,5 Zoll Schwarz;western-digital-my-passport-250-gb;True;True;P-2580;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;89.0000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;39707,7523263889;14;21;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000128-western-digital-my-passport-250-gb.jpg;;;2;;False;;;;;False;False;False;;;;;False;;;;;; -5;0;True;"NAVIGON 4310 max Navigationssystem Europa ";"NAVIGON 4310max Navigationssystem Europa ";"

    NAVIGON 4310max Navigationssystem Europa

     
     
    40 Länder, inklusive TMC, NAVIGON MyRoutes
     
     
    NAVIGON 4310 max Ist nicht nur schön,sondern auch intelligent.
    Egal, wo es gerade langgeht, jetzt haben Sie immer eine gute Aussicht: auf die NAVIGON 43 max Serie mit ihrem edlen Design.
    Doch die Routenplaner glänzen auch durch innere Werte.
    Zum Beispiel empfiehlt Ihnen NAVIGON MyRoutes jederzeit die beste Strecke, zugeschnitten auf Ihren persönlichen Fahrstil, den Wochentag und die Tageszeit.
    Für weiteren Komfort sorgen Features wie Reality View Pro, Clever Parking und die TMC-Routeninfo.
     
    NAVIGON MyRoutes
    Je nachdem, welcher Fahrertyp Sie sind, empfiehlt Ihnen NAVIGON MyRoutes die beste Route – zugeschnitten auf Ihren persönlichen Fahrstil, den Wochentag und die Tageszeit.
    Darüber hinaus zeigt Ihnen Ihr NAVIGON bis zu zwei weitere Routen. Das schafft Transparenz. Sie entscheiden, ob Sie unserer Empfehlung folgen oder eine der Alternativen wählen.
     
    TMC-Routeninfo
    zeigt ihnen im Fall einer Staumeldung eine Alternativroute mit aktualisierter Entfernung und Ankunftszeit.
    Sie entscheiden, ob eine Umfahrung in Ihrem Fall sinnvoll ist oder ob Sie die ursprüngliche Route beibehalten wollen.
     
    Reality View Pro
    zeigt Straßen nicht als Linien, sondern realistisch aus Asphalt und mit Mittelstreifen. So behalten Sie an Autobahnkreuzen und Ausfahrten leichter den Überblick.
     
    Clever Parking
    hilft Ihnen bei der Parkplatzsuche. Kurz vor Ihrem Ziel zeigt Ihnen Clever Parking Parkplätze in der näheren Umgebung an.
    In Deutschland werden Sie sogar über Parkgebühren informiert. So vermeiden Sie langes Suchen und sparen dabei Geld.
     
    Lieferumfang:
    PNA 4310 max (4,3"" im 16:9 Format) | Kurzanleitung | Halterung Kfz-Ladekabel mit integrierter TMC-Antenne |Vorinstalliertes Kartenmaterial für 40 Länder | USB-Kabel
    ";2;False;0;;;;navigon-4310-max-navigationssystem-europa;True;True;P-2120;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;199.0000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;39661,6380787037;68;14;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000127-navigon-4310-max-navigationssystem-europa.jpg;;;2;;False;;;;;False;False;False;;;;;False;;;;;; -5;0;True;Logitech G5 Laser Mouse refresh;"Logitech G5 Laser Mouse refresh ";"
    Logitech G5 Laser Mouse refresh
     
     
    Kabelgebundene 7-Tasten Tuningmaus mit Laser-Engine
     
     
    Spieletaugliche Laser Engine mit 2000 dpi
    1.000 Meldungen/Sekunde ermöglichen Präzision bei jeder Geschwindigkeit
    Gewichtstuning mit bis zu 38 Gramm
    Die Oberfläche mit DryGrip-Technologie beugt müden, verschwitzten Händen vor
    Füße aus Polytetrafluorethylen bieten eine besonders gute Gleitfähigkeit der Maus
    ";2;False;0;;;Logitech G5 Laser Mouse Neu;logitech-g5-laser-mouse-refresh;True;True;P-2770;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;59.0000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;39656,6560300926;21;11;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000124-logitech-g5-laser-mouse-refresh.jpg;;;2;;False;;;;;False;False;False;;;;;False;;;;;; -5;0;True;"Microsoft Bluetooth Mouse 5000 ";"Microsoft Bluetooth Notebook Mouse 5000 ";"
    Microsoft Bluetooth Notebook Mouse 5000
     
    Bluetooth- und Lasertechnik in Microsoft-Qualität 
     
    Mehr Komfort und Sicherheit mit modernen Bluetooth-Notebooks:
    Das lästige Empfängermodul für die USB-Schnittstelle entfällt,
    die Maus nimmt direkt Kontakt auf mit dem fest eingebauten Bluetooth-Empfänger des Notebooks
    Stets informiert: Batteriestandsanzeige auf der Oberseite des Gehäuses (Grün/Rot für Batteriestand OK und niedrig)
    Geringe Abmessungen und niedriges Gewicht machen die Maus zum idealen Reisebegleiter.
    Bei Nichtverwendung wird die Maus sicher im formschönen Transportcase aufbewahrt
    Für Rechts- und Linkshänder geeignetes Gehäuse mit 4 leichtgängigen Maustasten inklusive Scrollrad
    Microsoft High Defi nition Laser Technologie für maximale Präzision auch Unterwegs
    ";2;False;0;;;Microsoft Bluetooth Notebook Mouse 5000;microsoft-bluetooth-mouse-5000;True;True;P-2780;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;49.0000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;39656,6470949074;"21;2095";3;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000123-microsoft-bluetooth-mouse-5000.jpg;;;2;;False;;;;;False;False;False;;;;;False;;;;;; -5;0;True;Apple iPod shuffle 2 GB pink;Apple iPod shuffle 2 GB pink;"

    Apple iPod shuffle 2GB pink
     

     
    Wie seine größeren Geschwister besitzt auch der iPod shuffle kreisförmig
    angeordnete, ergonomische Bedienelemente.
    Der Kopfhöreranschluss am iPod shuffle dient gleichzeitig als Dock-Anschluss.
    Drehen Sie den iPod shuffle auf die Seite und setzen Sie ihn in das mitgelieferte Dock ein.
    Dank eines stabilen, integrierten Clips lässt sich der iPod shuffle fast überall befestigen.
    Klemmen Sie ihn am T-Shirt, am Hemdkragen oder am Trageriemen von Rucksack oder Handtasche fest.
    Lassen Sie sich aufs Ungewisse ein: Verwenden Sie den Schalter für die Zufallswiedergabe,
    um den Inhalt Ihres iPod shuffle neu zu mischen.
    verbesserte Kopfhörer und das neue iTunes 8.0
     
    Einfach Musik anhaben mit dem Apple iPOD SHUFFLE 2GB.Tragen Sie bis zu 500 Songs am Ärmel. Oder am Gürtel. Oder am Sportoutfit. Das Erkennungszeichen für Musikfans - den Apple iPOD SHUFFLE. Füllen Sie Ihren Apple iPOD SHUFFLE silber 1GB spielend einfach. iTunes ist der Store für Unterhaltungsinhalte. Ihre super organisierte Musiksammlung und Jukebox. Und die Software, mit der Sie Ihren Apple iPOD SHUFFLE mit einem Mausklick füllen. Das farbige Gehäuse aus eloxiertem Aluminium in silber passt zum genial einfachen Design des Apple iPOD SHUFFLE.
     
    Leistungseigenschaften
     
    2 GB Flash-Memory Speicher
    min. Audio-Datenrate: 8 KBit/s
    max. Audio-Datenrate: 320 KBit/s
    Frequenzgang-Untergrenze: 20 Hz
    Frequenzgang-Obergrenze: 20000 Hz
     
    Formate/Standards
     
    MP3-Standard
    AAC + MP3 Standard
    WAV-Dateiformat kompatibel
    Audible-Format kompatibel
    AIFF-Format kompatibel
     
    Bedienung
     
    Musiktitel-Verwaltung
     
    Leistungsaufnahme/Spannungsversorgung

    Li-Polymer Akku
    12 Std. Spieldauer mit Akku
    Ladezeit für Akku: 4 Std.
     
    Anschlüsse
     
    Kopfhörer-Anschluß
    USB-Schnittstelle
    Anschluß für Docking-Station
     
    Gehäuse-Eigenschaften
     
    Breite: 4.12 cm
    Höhe: 2.73 cm
    Tiefe: 1.05 cm
    Gewicht: 15.5 g

     
    ";2;False;0;;;Apple iPod shuffle 2 GB pink;apple-ipod-shuffle-2-gb-pink;True;True;P-1130;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;64.9000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;39650,6338888889;37;1;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000118-apple-ipod-shuffle-2-gb-pink.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000119-apple-ipod-shuffle-2-gb-pink.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000120-apple-ipod-shuffle-2-gb-pink.jpg;2;;False;;;;;False;False;False;;;;;False;;;;;; -5;0;True;"Me2 ME600HD 500 GB Multimediafestplatte ";"Me2 ME600HD Multimediafestplatte 500 GB ";"

    Me2 ME600HD Multimediafestplatte 500 GB

     
     
    3,5 Zoll USB 2.0 / Scart / HDMI Multimedia
     
     
    Komplett-Lösung für Film- & TV-in Top-Qualität
    Direkter Anschluss an das Fernsehgerät zur sofortigen
    Wiedergabe von Filmen, Musik oder Fotos -
    kein Computer erforderlich 
    Mit der Fernbedienung durch die Medien navigieren
    Das Bild kann bis zu HDTV-Auflösungen von 1080i skaliert werden -
    HDMI, Scart, Component-Video und Digital-Audio Anschlüsse -
    Externe USB 2.0 Multimedia Festplatte - Kapazitäten: bis 1000 GB -
    High-speed USB 2.0 Externe USB 2.0 Multimedia Festplatte -
    Aluminium Gehäuse - Stand-alone Media Player zur Wiedergabe
    von MPEG-1, MPEG-2, DivX/Xvid, JPEG, GMC, Qpel, MP3 (ID3 tag),
    WAW Media Daten - direkte Wiedergabe von DVD Ordnern - Orderner-Navigation - 
    Eigene Playlist benutzen und bearbeiten - einfache Dateiführung, intuitive Bedienung -
    unterstützt Progressive Scan (NTSC-480p, PAL-576p)
    unterstützt NTFS und FAT32 Dateisysteme geeignet für HDTV (skaliert auf 1080i)
     
    Lieferumfang: TV-Infrarotfernbedienung Hi-Speed USB 2.0-Kabel, HDMI-Anschluss
    A/V-Kombikabel Component-Kabel Software-CD Bedienungsanleitung
    AC Netzteil (100-240V) + Netzkabel
    ";2;False;0;Me2 ME600HD 500 GB Multimediafestplatte;Me2 ME600HD 500 GB Multimediafestplatte;"Me2 ME600HD 500 GB Multimediafestplatte ";me2-me600hd-500-gb-multimediafestplatte;True;True;P-2660;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;129.0000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;39650,625474537;"16;2095";;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000117-me2-me600hd-500-gb-multimediafestplatte.jpg;;;2;;False;;;;;False;False;False;;;;;False;;;;;; -5;0;True;Samsung P2450H 24 Zoll HD LCD-Monitor;Samsung P2450H 24 Zoll HD LCD schwarz;"

    Samsung P2450H 24 Zoll HD LCD schwarz


    HDMI ,Kontrastverhältnis 70000:1, Reaktionszeit 2ms
     

     
    Das Modell überzeugt neben dem eleganten ""Touch of Color"" Design auch durch die technischen Features: Neben der VGA- und DVI-D-Schnittstelle bietet das Display auch einen HDMI-Anschluss.
    Das sehr hohe dynamische Kontrastverhältnis von 70.000:1 und die Reaktionszeit von 2 ms (G/G) machen den SyncMaster P2450H ebenfalls für Gamer interessant.
    Hochwertiges 24"" Display mit Full HD Auflösung und HDMI
    Kontrast (dynamisch): 70000:1
    Reaktionszeit: 2 ms (G/G)
    Lieferumfang: Monitor, Signalkabel, Netzkabel, Treiber CD, Handbuch (CD)
    ";2;False;0;;;;samsung-p2450h-24-zoll-hd-lcd-monitor;True;True;P-2460;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;2,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;249.0000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;39650,5278472222;9;5;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000114-samsung-p2450h-24-zoll-hd-lcd-monitor.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000115-samsung-p2450h-24-zoll-hd-lcd-monitor.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000116-samsung-p2450h-24-zoll-hd-lcd-monitor.jpg;2;;False;;;;;False;False;False;;;;;False;;;;;; -5;0;True;Microsoft Windows Vista Home Premium OEM 32 Bit;Microsoft Windows Vista Home Premium OEM 32Bit;"
    Mit Windows Vista erledigen Nutzer sicherer und einfacher ihre täglichen Aufgaben und finden sofort, was sie benötigen. Es bietet neue Möglichkeiten für die digitale Unterhaltung und einfachere Kommunikationswege mit anderen Menschen, sowohl zu Hause als auch unterwegs.
    Sicherheit und Bedienkomfort standen im Zentrum der Entwicklung von Windows Vista. Nutzer können sich auf die neu gestaltete Bedienoberfläche freuen – im neuen Look and Feel. Außerdem kümmert sich Vista noch mehr darum, Ordnung in die Datenflut auf der Festplatte zu bringen. Es wird leichter, Dokumente zu finden oder Multimedia-Daten zu verwalten und zu nutzen.
     
    Neue Benutzeroberfläche
    Windows Vista vereinfacht deutlich das Arbeiten mit dem PC. So sorgt eine benutzerfreundliche Oberfläche dafür, dass der Anwender jederzeit sofort auf die gewünschten Daten zugreifen kann. Integrierte, systemweite Suchfunktionen vereinfachen das Speichern, Auffinden, Verwalten und Organisieren wichtiger Dateien und Programme.
     
    Damit bleiben E-Mails, Dokumente, Bilder, Videos, Musik, Spiele und Websites immer im Griff. Bei der Suche auf dem Desktop-PC braucht der Nutzer nicht mehr den Namen einer Datei zu kennen, es reicht ein Wort im Dokument, der Musikinterpret oder das Datum der Fotografie, um sie zu finden.
     
     
    Das neue Vista Start-Menü mit integrierter Schnellsuche 
     
    Mit „Flip“ lässt sich von einem geöffneten Fenster komfortabel zum nächsten wechseln, wobei für jedes Fenster eine Live-Miniaturansicht angezeigt wird. Mit Hilfe der Miniaturansichten kann der Nutzer das gewünschte Fenster schnell ermitteln, insbesondere wenn mehrere Fenster desselben Typs geöffnet sind. „Flip 3D“ ermöglicht das Verwenden des Bildlaufrads der Maus zum Sichten mehrerer geöffneter Fenster und anschließenden Auswählen des gewünschten Fensters.
     
    Damit Informationen nur einen Mausklick entfernt sind, bietet Windows Vista Minianwendungen. Diese verbinden sich mit Web Services zur Wiedergabe von ständig aktualisierten Informationsdiensten wie Wetterberichte, Nachrichten oder Internet-Radio-Programme. Sie können auch alle Instant-Messaging-Kontakte und Tagesaufgaben anzeigen sowie als Taschenrechner oder Notizzettel fungieren. Alle Minianwendungen werden über die am rechten Bildschirmrand befindliche Windows Sidebar organisiert und aufgerufen.
     
    Windows Aero
    Windows Vista ist das erste Windows-Betriebssystem mit einer Benutzerumgebung, die mühelos an die Hardwaremöglichkeiten des Computers angepasst werden kann, auf dem sie installiert ist. Auf allen Computern, welche die Mindestanforderungen an die Hardware erfüllen, wird die Basisbenutzerumgebung von Windows Vista angezeigt, in der Sie die bereits erwähnten optimierten Oberflächenfunktionen finden.
     
    Windows Aero ist eine Umgebung mit einem zusätzlichen Grad an visueller Ausgereiftheit, die reaktionsschneller und verwaltbarer ist und Windows-Benutzern mehr Übersichtlichkeit und Benutzerfreundlichkeit bietet.
     
     
    Windows Vista Aero bietet spektakuläre visuelle Effekte, wie zum Beispiel transparente Bedienelemente 
     
    Jederzeit verbunden
    Windows Vista-basierte Heimcomputer, Laptops oder Tablet-PCs sind nach dem Einschalten so schnell einsatzbereit wie herkömmliche Elektronikgeräte und lassen sich auch genauso schnell ausschalten. Damit können Privatnutzer sofort auf ihre Anwendungen zugreifen, im Internet surfen oder mit ihren Freunden und Bekannten kommunizieren.
     
    Mit dem neuen „Ruhezustand“ von Windows Vista dauert trotz niedrigen Stromverbrauchs die Reaktivierung des PCs nur zwei bis drei Sekunden. Dadurch braucht der Anwender seinen Computer weniger häufig herunterfahren und neu starten. Außerdem passt das Betriebssystem seine Leistung automatisch an verschiedene Nutzer an, indem es die jeweils am häufigsten genutzten Anwendungen bereits vor dem Aufruf lädt.
     
     
    Die Windows Sidebar bietet schnellen Zugriff auf Minianwendungen, wie etwa Wetterberichte oder Nachrichten 
     
    Über das Windows Synchronisierungscenter gleicht er die Inhalte tragbarer Geräte wie Telefone, PDAs und Musik-Player mit PCs ab. Über das Windows Mobilitätscenter kann er sogar auf Einstellungen mobiler Computer zugreifen und diese ändern.
     
    Plattform für Digitale Unterhaltung
    Windows Vista enthält ein Media Center mit Zugriff per Fernbedienung auf alle wichtigen Unterhaltungsmöglichkeiten wie Musik, Bilder, Filme, TV, aufgezeichnete Sendungen und Services. Da die Software HD TV und HD DVD unterstützt, wurde die Oberfläche für High-Definiton (HD) Breitwand-Bildschirme optimiert und überarbeitet. Sie bietet eine einfache und übersichtliche Suche nach allen digitalen Medien. Das Media Center lässt sich über die Media Center Extender-Funktionalität der Xbox 360 auf das gesamte Heim erweitern.
     
    Microsoft treibt gemeinsam mit Intel und AMD die weitere Entwicklung des digitalen Heims voran. Die Intel Viiv-Technologie bietet eine neue Plattform für digitale Unterhaltung, die leistungsstarke Dual-Core-Prozessoren nutzt. AMD bietet AMD Live! auf Multimedia-Desktop-PCs und -Notebooks an, die rechtzeitig zum Erscheinen von Windows Vista auf den Markt kommen.
     
     
    Mit Flip und Flip 3D navigiert man dank übersichtlicher Miniaturansichten mühelos durch die geöffneten Fenster 
     
    Musik, Bilder und Spiele
    Der in Windows Vista integrierte Media Player 11 enthält eine aufgefrischte Oberfläche mit neuen Navigationsmöglichkeiten. Damit durchsuchen Musikfans noch schneller und effizienter ihre Sammlungen: Während der Eingabe zeigt der Media Player 11 sofort eine aktualisierte Auswahl möglicher Begriffe an.
     
    Mit der Windows Fotogalerie können Nutzer ihre Fotos und Videos von Digitalkameras miteinander tauschen und ansehen. Sie vereinfacht die Verwaltung von Bildern und enthält grundlegende Schneide- und Korrekturfunktionen. Für das Importieren, Schneiden und Organisieren von Videos steht der Windows Movie Maker zur Verfügung.
     
    Die persönlichen Lieblingsspiele lassen sich über den Games Explorer einfacher aufrufen. Die aktuelle Version der Programmier-Schnittstelle DirectX 10 bietet größeren Detailreichtum und mehr Tiefenschärfe bei Spielegrafiken sowie eine fünffach höhere Leistungsfähigkeit. Außerdem stehen viele neue und überarbeitete Games zur Verfügung wie „Halo 2 für Windows Vista“, „Flight Simulator X“ und „Mahjong-Giganten“.
     
     
    Über das Windows Media Center lassen sich Fernsehprogramme, Filme, Musik und Bilder bequem per Fernbedienung steuern 
     
    Sicherheit und Jugendschutz
    Das neue Sicherheitskonzept von Windows Vista hat zu zahlreichen Innovationen geführt. So schützt der Windows Defender den PC vor aktuellen Gefahren wie Würmer, Viren und Spyware. Der integrierte Internet Explorer 7 verhindert unter anderem Schäden durch gefälschte Websites und E-Mails.
     
    Der neue Benutzerkontoschutz unterscheidet Standardaktivitäten von besonders kritischen Aktionen. Standardaktivitäten wie das Surfen im Web, das Senden von E-Mails oder das Verwenden von Office-Programmen sind wenig sicherheitskritisch und erfordern daher keine besonderen Berechtigungen. Wenn der Anwender jedoch eine kritische Aktion durchführen will, zum Beispiel die Installation eines neuen Programms, fordert Windows Vista die Eingabe eines eigenen Kennworts. Dadurch wird es für bösartige Programme schwieriger, den PC zu befallen.
     
    Außerdem verhindert der Benutzerkontoschutz, dass PC-unerfahrene Familienmitglieder unbeabsichtigt sicherheitskritische Aktionen durchführen oder heruntergeladene Programme installieren. Mit speziellen Sicherheitseinstellungen in Windows Vista können Eltern zudem die Computernutzung ihrer Kinder kontrollieren.
     
    Komfortabler Surfen
    Internet Explorer 7 bietet nicht nur wichtige neue Sicherheits- und Datenschutzfeatures, sondern erleichtert auch gängige Aufgaben durch Features wie Registernavigation (Anzeige von Fenstern im Registerkartenformat), Onlinesuche und an die Blattgröße angepasste Druckvorgänge.
     
    Gleichzeitig werden neue Tools bereitgestellt, um einen direkten Zugriff auf die gewünschten Informationen zu ermöglichen, mit integrierter Unterstützung von Webfeeds (auch als RSS oder Really Simple Syndication bezeichnet). RSS ist eine Technologie zum Abonnieren von Informationen, damit Sie nicht nach diesen suchen müssen. Über RSS-Abonnements erhalten Sie automatisch Listen (Feeds) von Überschriften aus Websites.
     
    Internet Explorer erkennt diese Feeds zu Websites und ermöglicht, diese in einer Vorschau anzuzeigen und zu abonnieren. Nach der Abonnierung fasst Internet Explorer 7 Überschriften in jedem Feed automatisch in einer Liste zusammen. Dadurch können Sie neue Informationen auf verschiedenen Websites schnell durchsuchen, ohne die Websites einzeln besuchen zu müssen.
     
    Features:
     
    Ideal für private Anwender, begeisterte Mediennutzer, mobile Anwender und Familien
    Die neue Oberfläche Windows Aero sorgt für mehr Übersichtlichkeit und Benutzerfreundlichkeit
    Leistungsstarke integrierte Desktopsuchfunktionen, mit denen nahezu alles auf dem PC schnell gefunden werden kann
    Unterstützt Minianwendungen, die sich mit Webdiensten verbinden, um Wetterberichte, aktualisierte Nachrichten, Straßenkarten oder Internetradio bereitzustellen
    Schnelles und gezieltes Wechseln zwischen verschiedenen Fenstern mit Hilfe von Windows Flip 3D
    Unterstützung neuester Spiele-Technologie durch DirectX 10
    Windows Media Center bietet Zugriff auf Live- und aufgezeichnete Fernsehprogramme, Filme, Musik und Bilder - über Media Center-Erweiterungen sogar überall im Haus
    Enthält Windows Media Player 11, die digitale Musiksoftware der nächsten Generation
    Windows Defender schützt vor Spyware, Viren und Würmern
    Der neue Benutzerkontoschutz verbindet die Flexibilität eines Administratorkontos mit der Sicherheit eines Benutzerkontos
    Mehr Sicherheit und Komfort beim Surfen mit dem neuen Internet Explorer 7
    Reaktivierung des PCs aus dem Ruhezustand in nur 2 bis 3 Sekunden
    Unterstützt leistungsstarke Dual-Core-Systeme
    ";2;False;0;;;" Windows Vista Home Premium 32 Bit OEM ";microsoft-windows-vista-home-premium-oem-32-bit;True;True;P-2970;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;49.9000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;39650,5243865741;"80;30;2095";3;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000109-microsoft-windows-vista-home-premium-oem-32-bit.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000110-microsoft-windows-vista-home-premium-oem-32-bit.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000111-microsoft-windows-vista-home-premium-oem-32-bit.jpg;2;;False;;;;;False;False;False;;;;;False;;;;;; -5;0;True;"Garmin Topo Österreich V2 ";"Garmin Topo Österreich V2 ";"

    Garmin Topo  Österreich V2

     
    Digitale topographische Vektorkarte-Originallizenz
     
     
    Topo Österreich ist die perfekte Ergänzung für Ihr Garmin GPS!
    Die neueste Version der beliebten Outdoor-Karte ist auf allen kartenfähigen Garmin GPS-Geräten lauffähig.
    Die Topo Österreich bietet eine Vielzahl an Informationen wie Wanderwege, Straßen, Seen, Flüsse, Wälder,
    Berggipfel sowie Höhenlinien im Abstand von 20m und mehr als 800 gespeicherte Positionen von Schutzhütten.
    Die neue Topo Österreich ist mit einem digitalen Höhenmodell hinterlegt und erstmals auch routingfähig!
    Planen Sie Ihre Touren, Routen und Wegpunkte am PC oder direkt am GPS-Gerät -
    die Topo Österreich ist die perfekte Kartengrundlage für Wanderungen und Touren abseits der Straße!Tausende Points of Interest (Gasthäuser, Hotels, Parkplätze, Gemeindeämter ...)
    Suchmöglichkeiten für Geonamen, POIs und Städte/Orte.
    Auch abseits von Straßen auf Wegen und Pfaden routingfähig, sie folgt beim Anlegen von Routen automatisch den auf der Karte verzeichneten Wegen, was die Navigation deutlich vereinfacht
    Dank der mitgelieferten MicroSD-Karte ist die Handhabung der Topo Österreich V2 sehr einfach:
    MicroSD-Karte in Garmin Navigationsgerät einlegen ¿ fertig. Eine Onlinefreischaltung ist für die Nutzung mit MicroSD-Karte nicht erforderlich.
    Höhenlinien im Abstand von 20m, mit anschaulicher Geländedarstellung
    Komfortable Routen- & Wegpunktverwaltung
    Einfache Übertragen von Wegpunkten, Routen & Tracks auf Garmin GPS Geräte
    Gesamtdatenvolumen ca. 175 MB. Die Karte ist in 196 einzelne Kartenabschnitte unterteilt,
    die zwischen 100 kB und 1,6 MB groß sind.
    Lizenz zur Freischaltung eines Gerätes. Registrierung über Internet erforderlich.
    Digitale topographische Vektorkarte Routenplanung: MapSource-Produkt -
    die Kartendaten werden mit der Software MapSource bearbeitet.
    ";2;False;0;;;Garmin Topo CD Österreich;garmin-topo-oesterreich-v2;True;True;P-2030;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;189.0000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;39650,5216550926;"67;2095";44;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000108-garmin-topo-osterreich-v2.jpg;;;2;;False;;;;;False;False;False;;;;;False;;;;;; -5;0;True;"TomTom ONE Europe Classic Edition TMC ";"TomTom ONE Europe Classic Edition TMC ";"

    TomTom ONE Europe Classic Edition TMC 
     

    TomTom ONE Classic Europe 42 Traffic mit RDS/TMC-Empfänger

     

    Der neue ONE Classic Europe 42 Traffic mit EasyPort passt mit Saugnapfhalterung in jede Hemdtasche.
    Ein 3,5-Zoll-Touchscreen, hervorragende Sprachqualität, TMC zur Stauumfahrung, TomTom Map Share, Hilfe!-Menü für Notfälle 
    für die neueste Kartenversion und Kartenmaterial von West- und Osteuropa (42 Länder) machen dieses TomTom ONE Classic so einzigartig.
    TomTom ONE Classic Europe 42 Traffic mit 3,5 Zoll Touchscreen, USB-Heimladegerät, einem RDS/TMC-Empfänger und QuickGPSfix-Funktion für eine sekundenschnelle Navigationsbereitschaft
    vorinstalliertes Kartenmaterial von 32 Ländern aus Ost- und Westeuropa mit Kartenaktualisierung und eigener Kartenanpassung über TomTom HOME und Map Share
    Navigieren von Haustür zu Haustür mit Details zu Adressen, Hausnummern, Tankstellen sowie Orten von besonderem Interesse (Points of Interest, POI), 3D- / 2D-Ansicht mit Tages- und Nachtansichtmodus
    RDS/TMC-Verkehrsinfo-Empfänger für aktuelle Staumeldungen und Verkehrshinweise zum Umfahren schwieriger Verkehrssituationen und alternative Routen
    Lieferumfang: TomTom One Classic Europe 42 Traffic, EasyPort-Halterung, USB-Kabel, Autoladegerät, Dokumentation, RDS/TMC-Empfänger
    ";2;False;0;;;;tomtom-one-europe-classic-edition-tmc;True;True;P-1990;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;130.9000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;39650,5188541667;66;4;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000107-tomtom-one-europe-classic-edition-tmc.jpg;;;2;;False;;;;;False;False;False;;;;;False;;;;;; -5;0;True;"TomTom Go 740 Live Navigationssystem ";"TomTom Go 740 Live Navigationssystem schwarz ";"
    TomTom Go 740 Live Navigationssystem  schwarz
     
    4,3 Zoll Touchscreen, 32+10 Länderkarten, TMC, Bluetooth

    GO 740 LIVE mit 4,3 Zoll Farb-Touchscreen, 42 vorinstallierten Karten europäischer Länder (davon 10 Hauptverkehrsstraßen-Karten), Bluetooth,
    Kfz-Freisprecheinrichtung sowie vielen Innovationen für eine verbesserte und komfortable Navigation
    Sprachsteuerung, LIVE Services mit HD Traffic, Sicherheitswarnungen, Lokale Suche mit Google, Wetter, QuickGPSfix sowie Fahrspurassistent für komplizierte Spurenführungen
    IQ Routes - Intelligente Routenberechnung aus aktuellsten Karten unter Berücksichtigung verschiedener Umweltfaktoren wie Tag, Uhrzeit, Straßenabschnitt, Durchschnittsgeschwindigkeiten etc.
    Text-to-Speech zum Ansagen von Straßennamen und Verkehrshinweisen für einen konzentrierten Blick auf die Fahrbahn und ein entspanntes Fahren
    Lieferumfang: TomTom GO 740 LIVE,Active-Dock Kfz-Halterung, Dockinghalterung für PC/Mac, Autoladegerät, Benutzerhandbuch, CD-ROM (TomTom HOME-Software)
    ";2;False;0;;;;tomtom-go-740-live-navigationssystem;True;True;P-1980;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;249.9000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;39650,5165162037;66;4;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000106-tomtom-go-740-live-navigationssystem.jpg;;;2;;False;;;;;False;False;False;;;;;False;;;;;; -5;210;True;SmartStore Office;;"

    Der Marketing- und Verkaufsmanager für ein erfolgreiches Online-Business

    Kunden gewinnen, Kunden binden, Umsatz steigern


    SmartStore Office ist die leistungsstarke Software-Lösung zur Steuerung Ihrer Online-Verkaufs- und Marketings-Aktivitäten. Auf bahnbrechend einfache und intelligente Weise ermöglicht sie:

     

     

    • Die Planung und Durchführung hocheffektiver Email-Marketing-Kampagnen zur Neukundengewinnung
    • Die Verwaltung und Abwicklung von Bestellungen für störungsfreie Abläufe in Ihrem BackOffice
    • Die rasche Umsetzung von Maßnahmen zur Kundenbindung
    • Eine wirksame Optimierung Ihres Online-Angebotes dank umfangreicher statistischer Auswertungen

    SmartStore Office bietet eine hochmoderne und -intuitive Bedienerführung, die den Aufbau und das Organisieren des "perfekten" Online-Business zu einem Kinderspiel macht. Im SmartStore-typischen Point&Click-Verfahren können Sie auf einfachste Weise:

     

     

    • Professionelle HTML-Newsletter und Serien-Emails erstellen und an tausende Kontakte gleichzeitig versenden
    • Ihre Kunden, Interessenten, Partner und Mitglieder mit den neuesten Informationen rund um Ihr Angebot versorgen
    • Ihre Top-(Produkt)-Angebote mitsamt Abbildungen, Beschreibungen und Preisen mit einem Klick in Ihre Emailings integrieren
    • Den Inhalt Ihrer Emailings personalisieren
    • View- und Klick-Raten Ihrer Emailings auswerten
    • Durch gezielte Nachfassaktionen Folge-Geschäfte generieren
    • Ihre Online-Bestellungen abrufen und bearbeiten
    • Rechnungen, Lieferscheine und sonstige Berichte drucken oder direkt als Emails an Ihren Kunden senden

    SmartStore Office ist die unverzichtbare Ergänzung zu unserer marktführenden und mehrfach ausgezeichneten Ecommerce-Komplettlösung SmartStore.biz. Die einzigartige Interaktion zwischen beiden Anwendungen erhöht die Erfolgsrate Ihres Online-Business erheblich:

    • Kunden, Interessenten und Newsletter-Abonnenten werden in einer zentralen Datenbank gespeichert. Sie verfügen dadurch automatisch über "reiche" Kontaktdaten, die absolut zielgerichtete und hocheffektive Email-Personalisierung ermöglichen.
    • Produkt-Informationen aus einem bestehenden SmartStore.biz Produktkatalog lassen sich automatisch in ein Emailing einfügen. Dabei kann jedes Produkt mit den Produkt-Detail-Informationen in Ihrem Online-Shop verlinkt werden.
    • Aussagefähige Auswertungen zu Newslettern, Kunden, Produkten, Umsätzen etc. geben Ihnen wertvolle Hinweise zur weitergehenden Optimierung Ihres Angebotes. Sie können bspw. das Klick-Verhalten Ihrer Leser auswerten, und so wertvolle Erkentnisse über evtl. geplante Nachfassaktionen gewinnen.
    • Keine Reibungsverluste, keine Insellösungen, keine lästige "Datenschieberei" mehr von Anwendung A nach B!
    ";2;False;0;;;SmartStore Office;smartstore-office;True;True;P-2950;;;False;0;False;;False;False;0;False;0;1;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;2;10000;False;False;5;1;1;0;False;1;10000;;False;False;False;False;99.0000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;38938,5373611111;"2095;81";42;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000095-smartstore-office.gif;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000096-smartstore-office.gif;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000097-smartstore-office.gif;1;;True;kg;2.0000;1;;False;False;False;;;;;False;;;;;; -5;210;True;SmartStore eBay SmartSeller;;"

    Der clevere Verkaufsmanager für eBay!


    eBay SmartSeller ist eine eCommerce-Anwendung, mit der Sie Ihre Produkte auf einfache und bequeme Weise auf dem Online-Marktplatz von eBay anbieten können. Verschiedene Module wie Kundenverwaltung, Fakturierung oder Nachrichten-Manager unterstützen Sie bei der Abwicklung verkaufter Produkte und übernehmen Aufgaben, die Sie sonst manuell erledigen müssten.

    Direkter Zugang

    eBay SmartSeller ermöglicht Ihnen einen direkten Zugang zum größten Online-Marktplatz der Welt, ohne langwieriges Mausklicken oder Suchen. Profitieren Sie von den allerneuesten eBay-Technologien; vereint in einer - durch eBay zertifizierten - Anwendung.

    Kosten minimieren

    Minimieren Sie Ihre Kosten, die Ihnen rund um Ihre eBay-Geschäfte entstehen. Mit eBay SmartSeller ist ein für alle mal Schluss mit versteckten oder zusätzlichen Kosten. Keine Drittanbieter, die an Ihren Umsätzen partizipieren. eBay berechnet Ihnen lediglich die allgemein üblichen Gebühren fürs Einstellen einer Auktion und die Provision, die bei einem erfolgreichen Abschluss anfällt. Über den eBay SmartSeller sind diese Gebühren voll transparent und zu jedem Zeitpunkt durch Sie nachvollziehbar.

    Auktionen verwalten

    Legen Sie beliebig viele Artikel an, wahlweise mit oder ohne Assistenten. Die Ordneransicht hilft Ihnen dabei, die Artikel zu ordnen, um selbst bei einer großen Artikelanzahl nicht den Überblick zu verlieren.

    Starten Sie eine beliebige Anzahl von Auktionen, Festpreisverkäufen oder eBay-Shop-Einträgen. Der Clou dabei: Die Listings erscheinen im Datengitter schräg unterhalb Ihrer Artikel, d.h. Sie können ganz genau den Verlauf Ihrer Artikel über den Lebenszyklus von eBay-Auktionen hinweg mitverfolgen. Zusätzlich gewährleistet der Auktionsstatus, dass Sie stets den Überblick über Ihre eBay-Verkaufsaktivitäten behalten und sofort wissen, wann neue Auktionen gestartet werden müssen.

    Zeitsparend abwickeln

    eBay SmartSeller verfügt über eine umfangreiche Kundenverwaltung, in der Kunden und deren Rechnungen hierarchisch und übersichtlich präsentiert werden. Mit dem Rechnungsassistenten lassen sich komfortabel Rechnungen erstellen, drucken und betrachten. Und mit dem Mahnungsassistenten benachrichtigen Sie mit wenigen Klicks säumige Käufer. Darüber hinaus ermöglicht der Bewertungs-Manager die zügige Bewertungs-Abgabe: wahlweise für ausgewählte oder alle noch nicht bewerteten Transaktionen.

    Professionelle Auktionsvorlagen

    Im eBay SmartSeller integriert ist ein vollwertiger HTML-Editor, mit dem Sie das Aussehen Ihrer Auktionen gestalten können. Oder nutzen Sie einfach die mitgelieferten HTML-Vorlagen, die speziell für die Gestaltung von Auktionen entwickelt und auf das Kategorie-Angebot von eBay abgestimmt wurden. Einer professionellen Präsentation Ihrer Produkte und höherer Erfolgschancen Ihrer Auktionen stehen hier nichts mehr im Wege.

    Beobachten und Bieten

    Zum Beobachten und Bieten von Auktionen steht eine separates Modul zur Verfügung, über das individuelle Suchanfragen erstellt werden können. So filtern Sie gezielt alle für Sie relevanten Angebote aus dem Gesamtangebot bei eBay heraus und behalten die Übersicht über den Online-Marktplatz.

    SmartStore.biz und SmartStore Office enabled

    eBay SmartSeller kommuniziert reibungslos mit dem Shopsystem SmartStore.biz und dem Marketing- und Verkaufs-Manager SmartStore Office: Mit wenigen Klicks lassen sich in SmartStore.biz bereits erfasste Artikel-Daten übernehmen; ebenso einfach lassen sich Kunden und Bestellungen zur weiteren Abwicklung nach SmartStore Office übergeben. ";2;False;0;;;SmartStore eBay SmartSeller;smartstore-ebay-smartseller;True;False;P-2940;;;False;0;False;;False;False;0;False;0;0;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;0;10000;False;False;0;1;1;0;False;1;10000;;False;False;False;False;79.0000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;38938,5365625;"29;2095;81";42;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000090-smartstore-ebay-smartseller.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000091-smartstore-ebay-smartseller.gif;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000092-smartstore-ebay-smartseller.gif;1;;False;;;;;False;False;False;;;;;False;;;;;; -5;210;True;SmartStore.biz 5;;"
    Achtung, Fertig, Klick!
    Das Mega-Update SmartStore.biz 5

    Es ist soweit! Mit SmartStore.biz 5 geht eine Revolution im Bereich Desktop- basierender Online-Shop-Systeme an den Start.

    Alles ist neu, besser, größer, einfacher!

    SmartStore.biz ist in der Version 5 komplett neu entwickelt worden. Dabei wurden bewährte Programmabschnitte ausgebaut, viele bahnbrechend neue Funktionen implementiert und verbesserte Bedienungsabläufe ausgearbeitet. Nie zuvor war es so einfach, einen hochwertigen und modernen Online-Shop zu gestalten und zu organisieren.

    SmartStore.biz 5 bietet für das individuelle Erscheinungsbild eines Online-Shops unzählige Variationen im Bereich Layout & Design, eine schnelle und unkomplizierte Produktverwaltung und darüber hinaus ein herausragendes Content-Management.

    Eines der größten Highlights ist das integrierte WYSIWYG-Redaktionssystem mit nahezu unbegrenzten Möglichkeiten, den eigenen Online-Shop inhaltlich zu gestalten. Hand in Hand mit dem neuen Designer und einer Auswahl mitgelieferter Designvorlagen verleihen Sie Ihrem Shop per Klick ein höchst anspruchsvolles Look & Feel.

    Nahtlos in die inhaltliche Gestaltung eingebunden ist auch der stark ausgebaute Produktmanager. Auf einfachste Weise sorgt das Zusammenspiel beider Bereiche für eine perfekte Produktpräsentation und ist die optimale Voraussetzung für einen erfolgreichen Online-Shop.

    SmartStore.biz 5 ist von Haus bereits optimal für Suchmaschinen optimiert und erstellt für die maximale Präsenz zudem Webpfade aus lesbaren und völlig frei konfigurierbaren Namen für Verzeichnisse und Dateien. Die aussagekräftigen Linkpfade unterstützen dabei auch den Besucher der Seiten bei seiner Navigation durch den Katalog.

    ";2;False;0;;;SmartStore.Biz 5;smartstorebiz-5;True;True;P-2930;;;False;0;False;169;True;False;0;False;0;1;False;;False;;False;0;0;0;True;False;0,0000;False;False;1;1;10000;False;True;1;1;1;0;False;1;10000;;False;False;False;False;149.0000;0.0000;0.0000;;0.0;0.0;False;0.0000;0.0000;0.0000;0.0000;0.0000;0.0000;38938,536400463;"29;81;2095";42;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000088-smartstorebiz-5.jpg;D:\Develop\Git\smartstorenetfull\SmartStoreNET\src\Presentation\SmartStore.Web\Media\Thumbs\0000\0000089-smartstorebiz-5.png;;1;;False;ounce;;;;False;False;False;;;;;False;;;;;; From 8619c2eced34aa26f3c35e327e7634f231b9f74f Mon Sep 17 00:00:00 2001 From: Marcus Gesing Date: Thu, 10 Dec 2015 20:13:29 +0100 Subject: [PATCH 156/707] Editing an import profile --- .../DataExchange/ExportProfileService.cs | 4 + .../Import/ImportProfileService.cs | 12 ++- .../Controllers/ImportController.cs | 88 ++++++++++++++----- .../Models/DataExchange/ImportProfileModel.cs | 2 +- .../Administration/SmartStore.Admin.csproj | 2 + .../Administration/Views/Export/List.cshtml | 7 -- .../Administration/Views/Import/Edit.cshtml | 37 ++++++++ .../Administration/Views/Import/List.cshtml | 8 +- .../Views/Import/_CreateOrUpdate.cshtml | 45 +++++++++- .../Views/Import/_ImportFileList.cshtml | 35 ++++++++ 10 files changed, 207 insertions(+), 33 deletions(-) create mode 100644 src/Presentation/SmartStore.Web/Administration/Views/Import/Edit.cshtml create mode 100644 src/Presentation/SmartStore.Web/Administration/Views/Import/_ImportFileList.cshtml diff --git a/src/Libraries/SmartStore.Services/DataExchange/ExportProfileService.cs b/src/Libraries/SmartStore.Services/DataExchange/ExportProfileService.cs index 53776a31c7..948b1d8ded 100644 --- a/src/Libraries/SmartStore.Services/DataExchange/ExportProfileService.cs +++ b/src/Libraries/SmartStore.Services/DataExchange/ExportProfileService.cs @@ -210,6 +210,10 @@ public virtual void UpdateExportProfile(ExportProfile profile) if (profile == null) throw new ArgumentNullException("profile"); + profile.FolderName = profile.FolderName + .ToValidPath() + .Truncate(_dataExchangeSettings.MaxFileNameLength); + _exportProfileRepository.Update(profile); _eventPublisher.EntityUpdated(profile); diff --git a/src/Libraries/SmartStore.Services/DataExchange/Import/ImportProfileService.cs b/src/Libraries/SmartStore.Services/DataExchange/Import/ImportProfileService.cs index 21bbb22823..dce39f68d6 100644 --- a/src/Libraries/SmartStore.Services/DataExchange/Import/ImportProfileService.cs +++ b/src/Libraries/SmartStore.Services/DataExchange/Import/ImportProfileService.cs @@ -73,6 +73,10 @@ public virtual void UpdateImportProfile(ImportProfile profile) if (profile == null) throw new ArgumentNullException("profile"); + profile.FolderName = profile.FolderName + .ToValidPath() + .Truncate(_dataExchangeSettings.MaxFileNameLength); + _importProfileRepository.Update(profile); _eventPublisher.EntityUpdated(profile); @@ -83,7 +87,8 @@ public virtual void DeleteImportProfile(ImportProfile profile) if (profile == null) throw new ArgumentNullException("profile"); - int scheduleTaskId = profile.SchedulingTaskId; + var scheduleTaskId = profile.SchedulingTaskId; + var folder = profile.GetImportFolder(); _importProfileRepository.Delete(profile); @@ -91,6 +96,11 @@ public virtual void DeleteImportProfile(ImportProfile profile) _scheduleTaskService.DeleteTask(scheduleTask); _eventPublisher.EntityDeleted(profile); + + if (System.IO.Directory.Exists(folder)) + { + FileSystemHelper.ClearDirectory(folder, true); + } } public virtual IQueryable GetImportProfiles(bool? enabled = null) diff --git a/src/Presentation/SmartStore.Web/Administration/Controllers/ImportController.cs b/src/Presentation/SmartStore.Web/Administration/Controllers/ImportController.cs index 4cf43afe3f..57997043c6 100644 --- a/src/Presentation/SmartStore.Web/Administration/Controllers/ImportController.cs +++ b/src/Presentation/SmartStore.Web/Administration/Controllers/ImportController.cs @@ -65,8 +65,13 @@ private void PrepareProfileModel(ImportProfileModel model, ImportProfile profile model.ExistingFileNames = profile.GetImportFiles() .Select(x => Path.GetFileName(x)) + .OrderBy(x => x) .ToList(); } + else + { + model.ExistingFileNames = new List(); + } if (forEdit) { @@ -115,12 +120,14 @@ public ActionResult Create() } [HttpPost, ParameterBasedOnFormName("save-continue", "continueEditing"), FormValueRequired("save", "save-continue")] - public ActionResult Create(ImportProfileModel model, ImportEntityType entityType) + public ActionResult Create(ImportProfileModel model) { if (!_services.Permissions.Authorize(StandardPermissionProvider.ManageImports)) return AccessDeniedView(); - if (!System.IO.File.Exists(model.TempImportFile)) + string[] tempFiles = model.TempImportFiles.SplitSafe("|"); + + if (tempFiles.Length == 0) { ModelState.AddModelError("ImportFiles", T("Admin.DataExchange.Import.MissingImportFile")); } @@ -131,9 +138,12 @@ public ActionResult Create(ImportProfileModel model, ImportEntityType entityType if (profile != null && profile.Id != 0) { var folder = profile.GetImportFolder(true, true); - var destPath = Path.Combine(folder, Path.GetFileName(model.TempImportFile)); + var tempDir = FileSystemHelper.TempDir(); - FileSystemHelper.Copy(model.TempImportFile, destPath, true, true); + foreach (var file in tempFiles) + { + FileSystemHelper.Copy(Path.Combine(tempDir, file), Path.Combine(folder, file), true, true); + } return RedirectToAction("Edit", new { id = profile.Id }); } @@ -178,8 +188,11 @@ public ActionResult Edit(ImportProfileModel model, bool continueEditing) profile.Name = model.Name; profile.FolderName = model.FolderName; + profile.EntityType = model.EntityType; profile.Enabled = model.Enabled; - + profile.Skip = model.Skip; + profile.Take = model.Take; + profile.Cleanup = model.Cleanup; _importService.UpdateImportProfile(profile); @@ -218,8 +231,8 @@ public ActionResult DeleteConfirmed(int id) public JsonResult FileUpload(int id) { var success = false; - string error = null; - string tempFile = null; + string tempFile = ""; + string fileList = ""; if (_services.Permissions.Authorize(StandardPermissionProvider.ManageImports)) { @@ -228,28 +241,44 @@ public JsonResult FileUpload(int id) { if (id == 0) { - tempFile = Path.Combine(FileSystemHelper.TempDir(), postedFile.FileName); - FileSystemHelper.Delete(tempFile); + var path = Path.Combine(FileSystemHelper.TempDir(), postedFile.FileName); + FileSystemHelper.Delete(path); + + success = postedFile.Stream.ToFile(path); + + if (success) + tempFile = postedFile.FileName; } else { + var profile = _importService.GetImportProfileById(id); + if (profile != null) + { + var folder = profile.GetImportFolder(true, true); + var destFile = Path.Combine(folder, Path.GetFileName(postedFile.FileName)); + + success = postedFile.Stream.ToFile(destFile); + + if (success) + { + var model = new ImportProfileModel(); + PrepareProfileModel(model, profile, false); + + fileList = this.RenderPartialViewToString("_ImportFileList", model); + } + } } - - success = postedFile.Stream.ToFile(tempFile); - - if (!success) - error = T("Admin.Common.UploadFileFailed"); } + + if (!success) + NotifyError(T("Admin.Common.UploadFileFailed")); } else { - error = T("Admin.AccessDenied.Description"); + NotifyError(T("Admin.AccessDenied.Description")); } - if (error.HasValue()) - NotifyError(error, true); - - return Json(new { success = success, tempFile = tempFile }); + return Json(new { success = success, tempFile = tempFile, fileList = fileList }); } [HttpPost] @@ -287,7 +316,7 @@ public ActionResult DownloadLogFile(int id) return result; } - public ActionResult DownloadExportFile(int id, string name) + public ActionResult DownloadImportFile(int id, string name) { if (!_services.Permissions.Authorize(StandardPermissionProvider.ManageImports)) return AccessDeniedView(); @@ -308,5 +337,24 @@ public ActionResult DownloadExportFile(int id, string name) return result; } + + public ActionResult DeleteImportFile(int id, string name) + { + if (_services.Permissions.Authorize(StandardPermissionProvider.ManageImports)) + { + var profile = _importService.GetImportProfileById(id); + if (profile != null) + { + var path = Path.Combine(profile.GetImportFolder(true), name); + FileSystemHelper.Delete(path); + + var model = new ImportProfileModel(); + PrepareProfileModel(model, profile, false); + + return PartialView("_ImportFileList", model); + } + } + return new EmptyResult(); + } } } \ No newline at end of file diff --git a/src/Presentation/SmartStore.Web/Administration/Models/DataExchange/ImportProfileModel.cs b/src/Presentation/SmartStore.Web/Administration/Models/DataExchange/ImportProfileModel.cs index 77bb5f64ea..11724f7622 100644 --- a/src/Presentation/SmartStore.Web/Administration/Models/DataExchange/ImportProfileModel.cs +++ b/src/Presentation/SmartStore.Web/Administration/Models/DataExchange/ImportProfileModel.cs @@ -45,7 +45,7 @@ public partial class ImportProfileModel : EntityModelBase public ScheduleTaskModel TaskModel { get; set; } public bool LogFileExists { get; set; } - public string TempImportFile { get; set; } + public string TempImportFiles { get; set; } public string EntityTypeName { get; set; } } } \ No newline at end of file diff --git a/src/Presentation/SmartStore.Web/Administration/SmartStore.Admin.csproj b/src/Presentation/SmartStore.Web/Administration/SmartStore.Admin.csproj index 1cb806ab59..5b9aafc01f 100644 --- a/src/Presentation/SmartStore.Web/Administration/SmartStore.Admin.csproj +++ b/src/Presentation/SmartStore.Web/Administration/SmartStore.Admin.csproj @@ -539,6 +539,8 @@ + + diff --git a/src/Presentation/SmartStore.Web/Administration/Views/Export/List.cshtml b/src/Presentation/SmartStore.Web/Administration/Views/Export/List.cshtml index 9405ee9369..d65ebdf061 100644 --- a/src/Presentation/SmartStore.Web/Administration/Views/Export/List.cshtml +++ b/src/Presentation/SmartStore.Web/Administration/Views/Export/List.cshtml @@ -157,7 +157,6 @@ else url: dialog.attr('data-urldelete'), ask: dialog.find('.modal-ask-delete').text(), callbackSuccess: function (resp) { - refreshGrid(); } }); return false; @@ -233,12 +232,6 @@ else // selected provider changed $(document).on('change', 'select[name="ProviderSystemName"]', toggleProviderDescription); - function refreshGrid() { - setTimeout(function () { - $('#export-profile-list').data('tGrid').ajaxRequest(); - }, 500); - } - function showPrimaryButton(display) { var button = $('#export-profile-dialog').find('.btn-primary').toggle(display); } diff --git a/src/Presentation/SmartStore.Web/Administration/Views/Import/Edit.cshtml b/src/Presentation/SmartStore.Web/Administration/Views/Import/Edit.cshtml new file mode 100644 index 0000000000..79250bb6dd --- /dev/null +++ b/src/Presentation/SmartStore.Web/Administration/Views/Import/Edit.cshtml @@ -0,0 +1,37 @@ +@using SmartStore.Admin.Models.DataExchange; +@model ImportProfileModel +@{ + var title = string.Concat(T("Admin.Common.Edit"), " ", T("Common.Profile")); + ViewBag.Title = title; +} + +@using (Html.BeginForm()) +{ +
    +
    +
    + + @title - @Model.Name @Html.ActionLink("(" + T("Admin.Common.BackToList") + ")", "List") +
    +
    + @if (Model.LogFileExists) + { + +  @T("Admin.Configuration.ActivityLog") + + } + + + +
    +
    + @Html.Partial("_CreateOrUpdate", Model) +
    +} +@Html.DeleteConfirmation("import-profile-delete") \ No newline at end of file diff --git a/src/Presentation/SmartStore.Web/Administration/Views/Import/List.cshtml b/src/Presentation/SmartStore.Web/Administration/Views/Import/List.cshtml index 11ae7b52b0..014eac56c2 100644 --- a/src/Presentation/SmartStore.Web/Administration/Views/Import/List.cshtml +++ b/src/Presentation/SmartStore.Web/Administration/Views/Import/List.cshtml @@ -48,7 +48,13 @@ @profile.EntityTypeName
    - @(string.Join("
    ", profile.ExistingFileNames)) + @foreach (var fileName in profile.ExistingFileNames) + { +
    + @Html.IconForFileExtension(Path.GetExtension(fileName), false) + @fileName +
    + }
    diff --git a/src/Presentation/SmartStore.Web/Administration/Views/Import/_CreateOrUpdate.cshtml b/src/Presentation/SmartStore.Web/Administration/Views/Import/_CreateOrUpdate.cshtml index 15820d8042..fbed22181b 100644 --- a/src/Presentation/SmartStore.Web/Administration/Views/Import/_CreateOrUpdate.cshtml +++ b/src/Presentation/SmartStore.Web/Administration/Views/Import/_CreateOrUpdate.cshtml @@ -7,7 +7,7 @@ @Html.ValidationSummary(false) @Html.HiddenFor(model => model.Id) -@Html.HiddenFor(model => model.TempImportFile) +@Html.HiddenFor(model => model.TempImportFiles) @@ -38,6 +38,28 @@ + + + + + @if (Model.ScheduleTaskId > 0) + { + + + + + } + + +
    +   + + @Html.Partial("_ImportFileList", Model) +
    + @Html.SmartLabelFor(x => x.ScheduleTaskId) + + @Html.Action("MinimalTask", "ScheduleTask", new { taskId = Model.ScheduleTaskId, returnUrl = Request.RawUrl, cancellable = true, area = "admin" }) +
     
    @Html.SmartLabelFor(x => x.Name) @@ -114,8 +136,25 @@ dataType: 'json', acceptFileTypes: /(\.|\/)(csv|xls|xlsx)$/i, done: function (e, data) { - if (data.result.success && data.result.tempFile.length > 0) { - $('input[name=TempImportFile]').val(data.result.tempFile); + if (data.result.success) { + $('#ImportFileListContainer').show(); + + if (!_.isEmpty(data.result.tempFile)) { + var fileInput = $('input[name=TempImportFiles]'), + files = fileInput.val(); + + if (_.isEmpty(files)) + files = data.result.tempFile; + else + files += '|' + data.result.tempFile; + + fileInput.val(files); + $('#ImportFileList').html(files.replace('|', ', ')); + } + + if (!_.isEmpty(data.result.fileList)) { + $('#ImportFileList').html(data.result.fileList); + } } } }); diff --git a/src/Presentation/SmartStore.Web/Administration/Views/Import/_ImportFileList.cshtml b/src/Presentation/SmartStore.Web/Administration/Views/Import/_ImportFileList.cshtml new file mode 100644 index 0000000000..78fc121360 --- /dev/null +++ b/src/Presentation/SmartStore.Web/Administration/Views/Import/_ImportFileList.cshtml @@ -0,0 +1,35 @@ +@using SmartStore.Admin.Models.DataExchange; +@model ImportProfileModel +@foreach (var fileName in Model.ExistingFileNames) +{ +

    + @Html.IconForFileExtension(Path.GetExtension(fileName), false) + @fileName + +   + +

    +} + \ No newline at end of file From dc7d4e41d73f3a7833f61bfb741e349dfe466c23 Mon Sep 17 00:00:00 2001 From: Marcus Gesing Date: Fri, 11 Dec 2015 13:14:10 +0100 Subject: [PATCH 157/707] An import file is mandatory for creating an import profile (to specify the file format). Allow to upload further import files while editing a profile (because we allow to export data in multiple files). --- .../Domain/DataExchange/ImportProfile.cs | 10 +- .../Mapping/DataExchange/ImportProfileMap.cs | 1 + .../201512101150534_ImportFramework.resx | 126 ------------------ ...1512111134591_ImportFramework.Designer.cs} | 2 +- ....cs => 201512111134591_ImportFramework.cs} | 14 +- .../201512111134591_ImportFramework.resx | 126 ++++++++++++++++++ .../SmartStore.Data/SmartStore.Data.csproj | 10 +- .../Import/IImportProfileService.cs | 3 +- .../DataExchange/Import/ImportExtensions.cs | 12 +- .../Import/ImportProfileService.cs | 8 +- .../Controllers/ImportController.cs | 45 +++---- .../Models/DataExchange/ImportProfileModel.cs | 22 +-- .../Administration/Views/Export/List.cshtml | 15 +-- .../Administration/Views/Import/List.cshtml | 26 ---- .../Views/Import/_CreateOrUpdate.cshtml | 53 ++++---- .../Views/Import/_ImportFileList.cshtml | 33 +---- .../Content/bootstrap/custom/custom.less | 3 + 17 files changed, 217 insertions(+), 292 deletions(-) delete mode 100644 src/Libraries/SmartStore.Data/Migrations/201512101150534_ImportFramework.resx rename src/Libraries/SmartStore.Data/Migrations/{201512101150534_ImportFramework.Designer.cs => 201512111134591_ImportFramework.Designer.cs} (92%) rename src/Libraries/SmartStore.Data/Migrations/{201512101150534_ImportFramework.cs => 201512111134591_ImportFramework.cs} (86%) create mode 100644 src/Libraries/SmartStore.Data/Migrations/201512111134591_ImportFramework.resx diff --git a/src/Libraries/SmartStore.Core/Domain/DataExchange/ImportProfile.cs b/src/Libraries/SmartStore.Core/Domain/DataExchange/ImportProfile.cs index ccff94629c..2654192757 100644 --- a/src/Libraries/SmartStore.Core/Domain/DataExchange/ImportProfile.cs +++ b/src/Libraries/SmartStore.Core/Domain/DataExchange/ImportProfile.cs @@ -15,6 +15,11 @@ public class ImportProfile : BaseEntity /// public string FolderName { get; set; } + /// + /// The name of the initially uploaded import file + /// + public string FileName { get; set; } + /// /// The identifier of the entity type /// @@ -60,11 +65,6 @@ public ImportEntityType EntityType /// public string ColumnMapping { get; set; } - /// - /// Whether to delete import files after import - /// - public bool Cleanup { get; set; } - /// /// The scheduling task identifier /// diff --git a/src/Libraries/SmartStore.Data/Mapping/DataExchange/ImportProfileMap.cs b/src/Libraries/SmartStore.Data/Mapping/DataExchange/ImportProfileMap.cs index c390eff79d..9b0efcac9d 100644 --- a/src/Libraries/SmartStore.Data/Mapping/DataExchange/ImportProfileMap.cs +++ b/src/Libraries/SmartStore.Data/Mapping/DataExchange/ImportProfileMap.cs @@ -12,6 +12,7 @@ public ImportProfileMap() this.Property(x => x.Name).IsRequired().HasMaxLength(100); this.Property(x => x.FolderName).IsRequired().HasMaxLength(100); + this.Property(x => x.FileName).IsRequired().HasMaxLength(400); this.Property(x => x.FileTypeConfiguration).IsMaxLength(); this.Property(x => x.ColumnMapping).IsMaxLength(); diff --git a/src/Libraries/SmartStore.Data/Migrations/201512101150534_ImportFramework.resx b/src/Libraries/SmartStore.Data/Migrations/201512101150534_ImportFramework.resx deleted file mode 100644 index 641f298bd8..0000000000 --- a/src/Libraries/SmartStore.Data/Migrations/201512101150534_ImportFramework.resx +++ /dev/null @@ -1,126 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - text/microsoft-resx - - - 2.0 - - - System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - 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 - - - dbo - - \ No newline at end of file diff --git a/src/Libraries/SmartStore.Data/Migrations/201512101150534_ImportFramework.Designer.cs b/src/Libraries/SmartStore.Data/Migrations/201512111134591_ImportFramework.Designer.cs similarity index 92% rename from src/Libraries/SmartStore.Data/Migrations/201512101150534_ImportFramework.Designer.cs rename to src/Libraries/SmartStore.Data/Migrations/201512111134591_ImportFramework.Designer.cs index 8f8b2e1554..1d43defd3f 100644 --- a/src/Libraries/SmartStore.Data/Migrations/201512101150534_ImportFramework.Designer.cs +++ b/src/Libraries/SmartStore.Data/Migrations/201512111134591_ImportFramework.Designer.cs @@ -13,7 +13,7 @@ public sealed partial class ImportFramework : IMigrationMetadata string IMigrationMetadata.Id { - get { return "201512101150534_ImportFramework"; } + get { return "201512111134591_ImportFramework"; } } string IMigrationMetadata.Source diff --git a/src/Libraries/SmartStore.Data/Migrations/201512101150534_ImportFramework.cs b/src/Libraries/SmartStore.Data/Migrations/201512111134591_ImportFramework.cs similarity index 86% rename from src/Libraries/SmartStore.Data/Migrations/201512101150534_ImportFramework.cs rename to src/Libraries/SmartStore.Data/Migrations/201512111134591_ImportFramework.cs index dda44fb555..9e3be78b89 100644 --- a/src/Libraries/SmartStore.Data/Migrations/201512101150534_ImportFramework.cs +++ b/src/Libraries/SmartStore.Data/Migrations/201512111134591_ImportFramework.cs @@ -16,13 +16,13 @@ public override void Up() Id = c.Int(nullable: false, identity: true), Name = c.String(nullable: false, maxLength: 100), FolderName = c.String(nullable: false, maxLength: 100), + FileName = c.String(nullable: false, maxLength: 400), EntityTypeId = c.Int(nullable: false), Enabled = c.Boolean(nullable: false), Skip = c.Int(nullable: false), Take = c.Int(nullable: false), FileTypeConfiguration = c.String(), ColumnMapping = c.String(), - Cleanup = c.Boolean(nullable: false), SchedulingTaskId = c.Int(nullable: false), }) .PrimaryKey(t => t.Id) @@ -84,18 +84,6 @@ public void MigrateLocaleResources(LocaleResourcesBuilder builder) "Specifies the name of the import profile.", "Legt den Namen des Importprofils fest."); - builder.AddOrUpdate("Admin.DataExchange.Import.FolderName", - "Folder name", - "Ordnername", - "Specifies the name of the folder where the import files are saved.", - "Legt den Namen des Ordners fest, in den die Importdateien gespeichert werden."); - - builder.AddOrUpdate("Admin.DataExchange.Import.Cleanup", - "Clean up at the end", - "Zum Schluss aufrumen", - "Specifies whether to delete import files after an import.", - "Legt fest, ob die Importdateien nach einem Import gelscht werden sollen."); - builder.AddOrUpdate("Enums.SmartStore.Core.Domain.DataExchange.ImportEntityType.Product", "Product", "Produkt"); builder.AddOrUpdate("Enums.SmartStore.Core.Domain.DataExchange.ImportEntityType.Customer", "Customer", "Kunde"); builder.AddOrUpdate("Enums.SmartStore.Core.Domain.DataExchange.ImportEntityType.NewsLetterSubscription", "Newsletter Subscribers", "Newsletter Abonnenten"); diff --git a/src/Libraries/SmartStore.Data/Migrations/201512111134591_ImportFramework.resx b/src/Libraries/SmartStore.Data/Migrations/201512111134591_ImportFramework.resx new file mode 100644 index 0000000000..1fea63c233 --- /dev/null +++ b/src/Libraries/SmartStore.Data/Migrations/201512111134591_ImportFramework.resx @@ -0,0 +1,126 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 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 + + + dbo + + \ No newline at end of file diff --git a/src/Libraries/SmartStore.Data/SmartStore.Data.csproj b/src/Libraries/SmartStore.Data/SmartStore.Data.csproj index 8272d36d87..f58765ce75 100644 --- a/src/Libraries/SmartStore.Data/SmartStore.Data.csproj +++ b/src/Libraries/SmartStore.Data/SmartStore.Data.csproj @@ -372,9 +372,9 @@ 201511271019577_ExportFramework3.cs - - - 201512101150534_ImportFramework.cs + + + 201512111134591_ImportFramework.cs @@ -699,8 +699,8 @@ 201511271019577_ExportFramework3.cs - - 201512101150534_ImportFramework.cs + + 201512111134591_ImportFramework.cs diff --git a/src/Libraries/SmartStore.Services/DataExchange/Import/IImportProfileService.cs b/src/Libraries/SmartStore.Services/DataExchange/Import/IImportProfileService.cs index 366cb9d5bb..ceb9c751c1 100644 --- a/src/Libraries/SmartStore.Services/DataExchange/Import/IImportProfileService.cs +++ b/src/Libraries/SmartStore.Services/DataExchange/Import/IImportProfileService.cs @@ -9,10 +9,11 @@ public interface IImportProfileService /// /// Inserts an import profile /// + /// Name of the import file /// Profile name /// /// Inserted import profile - ImportProfile InsertImportProfile(string name, ImportEntityType entityType); + ImportProfile InsertImportProfile(string fileName, string name, ImportEntityType entityType); /// /// Updates an import profile diff --git a/src/Libraries/SmartStore.Services/DataExchange/Import/ImportExtensions.cs b/src/Libraries/SmartStore.Services/DataExchange/Import/ImportExtensions.cs index 078a04a460..6e96b65fe1 100644 --- a/src/Libraries/SmartStore.Services/DataExchange/Import/ImportExtensions.cs +++ b/src/Libraries/SmartStore.Services/DataExchange/Import/ImportExtensions.cs @@ -30,16 +30,22 @@ public static string GetImportFolder(this ImportProfile profile, bool content = /// List of file paths public static List GetImportFiles(this ImportProfile profile) { + var result = new List(); var folder = profile.GetImportFolder(true); if (System.IO.Directory.Exists(folder)) { - return System.IO.Directory.EnumerateFiles(folder, "*", SearchOption.TopDirectoryOnly) + var initialImportFile = Path.Combine(folder, profile.FileName); + + result.Add(initialImportFile); + + result.AddRange(System.IO.Directory.EnumerateFiles(folder, "*", SearchOption.TopDirectoryOnly) + .Where(x => !x.IsCaseInsensitiveEqual(initialImportFile)) .OrderBy(x => x) - .ToList(); + .ToList()); } - return new List(); + return result; } /// diff --git a/src/Libraries/SmartStore.Services/DataExchange/Import/ImportProfileService.cs b/src/Libraries/SmartStore.Services/DataExchange/Import/ImportProfileService.cs index dce39f68d6..7b4cb63697 100644 --- a/src/Libraries/SmartStore.Services/DataExchange/Import/ImportProfileService.cs +++ b/src/Libraries/SmartStore.Services/DataExchange/Import/ImportProfileService.cs @@ -29,8 +29,9 @@ public ImportProfileService( _dataExchangeSettings = dataExchangeSettings; } - public virtual ImportProfile InsertImportProfile(string name, ImportEntityType entityType) + public virtual ImportProfile InsertImportProfile(string fileName, string name, ImportEntityType entityType) { + Guard.ArgumentNotEmpty(() => fileName); Guard.ArgumentNotEmpty(() => name); var task = new ScheduleTask @@ -49,6 +50,7 @@ public virtual ImportProfile InsertImportProfile(string name, ImportEntityType e var profile = new ImportProfile { Name = name, + FileName = fileName, EntityType = entityType, Enabled = true, SchedulingTaskId = task.Id @@ -73,10 +75,6 @@ public virtual void UpdateImportProfile(ImportProfile profile) if (profile == null) throw new ArgumentNullException("profile"); - profile.FolderName = profile.FolderName - .ToValidPath() - .Truncate(_dataExchangeSettings.MaxFileNameLength); - _importProfileRepository.Update(profile); _eventPublisher.EntityUpdated(profile); diff --git a/src/Presentation/SmartStore.Web/Administration/Controllers/ImportController.cs b/src/Presentation/SmartStore.Web/Administration/Controllers/ImportController.cs index 57997043c6..9727cce98e 100644 --- a/src/Presentation/SmartStore.Web/Administration/Controllers/ImportController.cs +++ b/src/Presentation/SmartStore.Web/Administration/Controllers/ImportController.cs @@ -50,12 +50,11 @@ private void PrepareProfileModel(ImportProfileModel model, ImportProfile profile { model.Id = profile.Id; model.Name = profile.Name; - model.FolderName = profile.FolderName; + model.FileName = profile.FileName; model.EntityType = profile.EntityType; model.Enabled = profile.Enabled; model.Skip = profile.Skip; model.Take = profile.Take; - model.Cleanup = profile.Cleanup; model.ScheduleTaskId = profile.SchedulingTaskId; model.ScheduleTaskName = profile.ScheduleTask.Name.NaIfEmpty(); model.IsTaskRunning = profile.ScheduleTask.IsRunning; @@ -65,7 +64,6 @@ private void PrepareProfileModel(ImportProfileModel model, ImportProfile profile model.ExistingFileNames = profile.GetImportFiles() .Select(x => Path.GetFileName(x)) - .OrderBy(x => x) .ToList(); } else @@ -116,6 +114,8 @@ public ActionResult Create() var model = new ImportProfileModel(); PrepareProfileModel(model, null, true); + model.Name = T("Common.Import"); + return View(model); } @@ -125,25 +125,21 @@ public ActionResult Create(ImportProfileModel model) if (!_services.Permissions.Authorize(StandardPermissionProvider.ManageImports)) return AccessDeniedView(); - string[] tempFiles = model.TempImportFiles.SplitSafe("|"); + var importFile = Path.Combine(FileSystemHelper.TempDir(), model.FileName); - if (tempFiles.Length == 0) + if (model.FileName.IsEmpty() || !System.IO.File.Exists(importFile)) { - ModelState.AddModelError("ImportFiles", T("Admin.DataExchange.Import.MissingImportFile")); + ModelState.AddModelError("", T("Admin.DataExchange.Import.MissingImportFile")); } else if (ModelState.IsValid) { - var profile = _importService.InsertImportProfile(model.Name, model.EntityType); + var profile = _importService.InsertImportProfile(model.FileName, model.Name, model.EntityType); if (profile != null && profile.Id != 0) { - var folder = profile.GetImportFolder(true, true); - var tempDir = FileSystemHelper.TempDir(); + var importFileDestination = Path.Combine(profile.GetImportFolder(true, true), model.FileName); - foreach (var file in tempFiles) - { - FileSystemHelper.Copy(Path.Combine(tempDir, file), Path.Combine(folder, file), true, true); - } + FileSystemHelper.Copy(importFile, importFileDestination, true, true); return RedirectToAction("Edit", new { id = profile.Id }); } @@ -180,23 +176,18 @@ public ActionResult Edit(ImportProfileModel model, bool continueEditing) if (profile == null) return RedirectToAction("List"); - if (!ModelState.IsValid) + if (ModelState.IsValid) { - PrepareProfileModel(model, profile, true); - return View(model); - } - - profile.Name = model.Name; - profile.FolderName = model.FolderName; - profile.EntityType = model.EntityType; - profile.Enabled = model.Enabled; - profile.Skip = model.Skip; - profile.Take = model.Take; - profile.Cleanup = model.Cleanup; + profile.Name = model.Name; + profile.EntityType = model.EntityType; + profile.Enabled = model.Enabled; + profile.Skip = model.Skip; + profile.Take = model.Take; - _importService.UpdateImportProfile(profile); + _importService.UpdateImportProfile(profile); - NotifySuccess(T("Admin.Common.DataSuccessfullySaved")); + NotifySuccess(T("Admin.Common.DataSuccessfullySaved")); + } return (continueEditing ? RedirectToAction("Edit", new { id = profile.Id }) : RedirectToAction("List")); } diff --git a/src/Presentation/SmartStore.Web/Administration/Models/DataExchange/ImportProfileModel.cs b/src/Presentation/SmartStore.Web/Administration/Models/DataExchange/ImportProfileModel.cs index 11724f7622..ecf64bc593 100644 --- a/src/Presentation/SmartStore.Web/Administration/Models/DataExchange/ImportProfileModel.cs +++ b/src/Presentation/SmartStore.Web/Administration/Models/DataExchange/ImportProfileModel.cs @@ -1,4 +1,6 @@ using System.Collections.Generic; +using System.IO; +using System.Linq; using System.Web.Mvc; using FluentValidation.Attributes; using SmartStore.Admin.Models.Tasks; @@ -12,17 +14,22 @@ namespace SmartStore.Admin.Models.DataExchange [Validator(typeof(ImportProfileValidator))] public partial class ImportProfileModel : EntityModelBase { - [SmartResourceDisplayName("Admin.Common.ImportFiles")] - public List ExistingFileNames { get; set; } - [SmartResourceDisplayName("Admin.DataExchange.Import.Name")] public string Name { get; set; } - [SmartResourceDisplayName("Admin.DataExchange.Import.FolderName")] - public string FolderName { get; set; } + public string FileName { get; set; } + + public string FileExtension + { + get { return Path.GetExtension(FileName); } + } + + [SmartResourceDisplayName("Admin.Common.ImportFiles")] + public List ExistingFileNames { get; set; } [SmartResourceDisplayName("Admin.Common.Entity")] public ImportEntityType EntityType { get; set; } + public string EntityTypeName { get; set; } public List AvailableEntityTypes { get; set; } [SmartResourceDisplayName("Common.Enabled")] @@ -34,9 +41,6 @@ public partial class ImportProfileModel : EntityModelBase [SmartResourceDisplayName("Admin.Common.RecordsTake")] public int Take { get; set; } - [SmartResourceDisplayName("Admin.DataExchange.Import.Cleanup")] - public bool Cleanup { get; set; } - [SmartResourceDisplayName("Common.Execution")] public int ScheduleTaskId { get; set; } public string ScheduleTaskName { get; set; } @@ -45,7 +49,5 @@ public partial class ImportProfileModel : EntityModelBase public ScheduleTaskModel TaskModel { get; set; } public bool LogFileExists { get; set; } - public string TempImportFiles { get; set; } - public string EntityTypeName { get; set; } } } \ No newline at end of file diff --git a/src/Presentation/SmartStore.Web/Administration/Views/Export/List.cshtml b/src/Presentation/SmartStore.Web/Administration/Views/Export/List.cshtml index d65ebdf061..520d95b0a1 100644 --- a/src/Presentation/SmartStore.Web/Administration/Views/Export/List.cshtml +++ b/src/Presentation/SmartStore.Web/Administration/Views/Export/List.cshtml @@ -118,13 +118,12 @@ else } -
    +@if (Model.CsvConfiguration != null) +{ + var viewData = new ViewDataDictionary(); + viewData.Add("ShowGroupCaption", true); + viewData.TemplateInfo.HtmlFieldPrefix = "CsvConfiguration"; + viewData.ModelState.Merge(ViewData.ModelState); + @Html.Partial("CsvConfiguration", Model.CsvConfiguration, viewData) +} + - -@*import emails form*@ -@{Html.SmartStore().Window() - .Name("importcsv-window") - .Title(T("Admin.Common.ImportFromCsv").Text) - .Content(@ - @using (Html.BeginForm("ImportCsv", "NewsLetterSubscription", FormMethod.Post, new { enctype = "multipart/form-data" })) - { -
    - @T("Admin.Common.CsvFile"): -
    - } -
    ) - .FooterContent(@ - - ) - .Width(400) - .Modal(true) - .Visible(false) - .Render(); -} - - + \ No newline at end of file diff --git a/src/Tests/SmartStore.Services.Tests/Messages/NewsLetterSubscriptionServiceTests.cs b/src/Tests/SmartStore.Services.Tests/Messages/NewsLetterSubscriptionServiceTests.cs index 843e2c60ca..bce6703f67 100644 --- a/src/Tests/SmartStore.Services.Tests/Messages/NewsLetterSubscriptionServiceTests.cs +++ b/src/Tests/SmartStore.Services.Tests/Messages/NewsLetterSubscriptionServiceTests.cs @@ -1,20 +1,18 @@ -using SmartStore.Core.Data; +using NUnit.Framework; +using Rhino.Mocks; +using SmartStore.Core.Data; using SmartStore.Core.Domain.Messages; using SmartStore.Core.Events; using SmartStore.Services.Messages; -using NUnit.Framework; -using Rhino.Mocks; -using SmartStore.Services.Stores; namespace SmartStore.Services.Tests.Messages { - [TestFixture] + [TestFixture] public class NewsLetterSubscriptionServiceTests : ServiceTest { IEventPublisher _eventPublisher; IRepository _subscriptionRepository; IDbContext _dbContext; - IStoreService _storeService; NewsLetterSubscriptionService _newsLetterSubscriptionService; [SetUp] @@ -23,9 +21,8 @@ public class NewsLetterSubscriptionServiceTests : ServiceTest _eventPublisher = MockRepository.GenerateStub(); _subscriptionRepository = MockRepository.GenerateStub>(); _dbContext = MockRepository.GenerateStub(); - _storeService = MockRepository.GenerateStub(); - _newsLetterSubscriptionService = new NewsLetterSubscriptionService(_dbContext, _subscriptionRepository, _eventPublisher, _storeService); + _newsLetterSubscriptionService = new NewsLetterSubscriptionService(_dbContext, _subscriptionRepository, _eventPublisher); } /// From 2276ea63b9e650f11229c87caeaaea10017d8300 Mon Sep 17 00:00:00 2001 From: Marcus Gesing Date: Mon, 14 Dec 2015 12:18:01 +0100 Subject: [PATCH 166/707] Export framework should check permission for export entity --- .../DataExchange/DataExportTask.cs | 1 + .../DataExchange/DataExporter.cs | 46 ++++++++++++++++--- .../DataExchange/IDataExporter.cs | 2 + .../DataExchange/Import/DataImporter.cs | 3 ++ .../Controllers/ExportController.cs | 10 ++-- 5 files changed, 50 insertions(+), 12 deletions(-) diff --git a/src/Libraries/SmartStore.Services/DataExchange/DataExportTask.cs b/src/Libraries/SmartStore.Services/DataExchange/DataExportTask.cs index 8d8aa30923..ba4356de43 100644 --- a/src/Libraries/SmartStore.Services/DataExchange/DataExportTask.cs +++ b/src/Libraries/SmartStore.Services/DataExchange/DataExportTask.cs @@ -32,6 +32,7 @@ public void Execute(TaskExecutionContext ctx) // build export request var request = new DataExportRequest(profile, provider); + request.CustomerId = ctx.Parameters["CurrentCustomerId"].ToInt(); // do not use built-in background tasks customer request.ProgressValueSetter = delegate(int val, int max, string msg) { diff --git a/src/Libraries/SmartStore.Services/DataExchange/DataExporter.cs b/src/Libraries/SmartStore.Services/DataExchange/DataExporter.cs index f9bc604ab3..1b56c39d1c 100644 --- a/src/Libraries/SmartStore.Services/DataExchange/DataExporter.cs +++ b/src/Libraries/SmartStore.Services/DataExchange/DataExporter.cs @@ -30,6 +30,7 @@ using SmartStore.Services.Media; using SmartStore.Services.Messages; using SmartStore.Services.Orders; +using SmartStore.Services.Security; using SmartStore.Services.Seo; using SmartStore.Services.Shipping; using SmartStore.Services.Tax; @@ -63,7 +64,7 @@ public partial class DataExporter : IDataExporter private readonly Lazy _productService; private readonly Lazy _orderService; private readonly Lazy _manufacturerService; - private readonly Lazy _customerService; + private readonly ICustomerService _customerService; private readonly Lazy _addressService; private readonly Lazy _countryService; private readonly Lazy _shipmentService; @@ -102,7 +103,7 @@ public DataExporter( Lazy productService, Lazy orderService, Lazy manufacturerService, - Lazy customerService, + ICustomerService customerService, Lazy addressService, Lazy countryService, Lazy shipmentService, @@ -199,6 +200,30 @@ private void SetProgress(DataExporterContext ctx, string message) catch { } } + private bool HasPermission(DataExporterContext ctx) + { + if (ctx.Request.CustomerId == 0) + ctx.Request.CustomerId = _services.WorkContext.CurrentCustomer.Id; + + var customer = _customerService.GetCustomerById(ctx.Request.CustomerId); + + if (ctx.Request.Provider.Value.EntityType == ExportEntityType.Product || + ctx.Request.Provider.Value.EntityType == ExportEntityType.Category || + ctx.Request.Provider.Value.EntityType == ExportEntityType.Manufacturer) + return _services.Permissions.Authorize(StandardPermissionProvider.ManageCatalog, customer); + + if (ctx.Request.Provider.Value.EntityType == ExportEntityType.Customer) + return _services.Permissions.Authorize(StandardPermissionProvider.ManageCustomers, customer); + + if (ctx.Request.Provider.Value.EntityType == ExportEntityType.Order) + return _services.Permissions.Authorize(StandardPermissionProvider.ManageOrders, customer); + + if (ctx.Request.Provider.Value.EntityType == ExportEntityType.NewsLetterSubscription) + return _services.Permissions.Authorize(StandardPermissionProvider.ManageNewsletterSubscribers, customer); + + return true; + } + private void DetachAllEntitiesAndClear(DataExporterContext ctx) { try @@ -285,8 +310,8 @@ private IExportDataSegmenterProvider CreateSegmenter(DataExporterContext ctx, in entities => { ctx.OrderExportContext = new OrderExportContext(entities, - x => _customerService.Value.GetCustomersByIds(x), - x => _customerService.Value.GetRewardPointsHistoriesByCustomerIds(x), + x => _customerService.GetCustomersByIds(x), + x => _customerService.GetRewardPointsHistoriesByCustomerIds(x), x => _addressService.Value.GetAddressByIds(x), x => _orderService.Value.GetOrderItemsByOrderIds(x), x => _shipmentService.Value.GetShipmentsByOrderIds(x) @@ -839,13 +864,16 @@ private List Init(DataExporterContext ctx, int? totalRecords = null) // Init base things that are even required for preview. Init all other things (regular export) in ExportCoreOuter. List result = null; + if (ctx.Request.CustomerId == 0) + ctx.Request.CustomerId = _services.WorkContext.CurrentCustomer.Id; + if (ctx.Projection.CurrencyId.HasValue) ctx.ContextCurrency = _currencyService.Value.GetCurrencyById(ctx.Projection.CurrencyId.Value); else ctx.ContextCurrency = _services.WorkContext.WorkingCurrency; if (ctx.Projection.CustomerId.HasValue) - ctx.ContextCustomer = _customerService.Value.GetCustomerById(ctx.Projection.CustomerId.Value); + ctx.ContextCustomer = _customerService.GetCustomerById(ctx.Projection.CustomerId.Value); else ctx.ContextCustomer = _services.WorkContext.CurrentCustomer; @@ -1045,9 +1073,10 @@ private void ExportCoreOuter(DataExporterContext ctx) try { if (!ctx.Request.Provider.IsValid()) - { throw new SmartException("Export aborted because the export provider is not valid"); - } + + if (!HasPermission(ctx)) + throw new SmartException("You do not have permission to perform the selected export"); foreach (var item in ctx.Request.CustomData) { @@ -1298,6 +1327,9 @@ public IList Preview(DataExportRequest request, int pageIndex, int? tot var unused = Init(ctx, totalRecords); + if (!HasPermission(ctx)) + throw new SmartException("You do not have permission to perform the selected export"); + using (var segmenter = CreateSegmenter(ctx, pageIndex)) { if (segmenter == null) diff --git a/src/Libraries/SmartStore.Services/DataExchange/IDataExporter.cs b/src/Libraries/SmartStore.Services/DataExchange/IDataExporter.cs index b1c2dacf7d..8e30fa9974 100644 --- a/src/Libraries/SmartStore.Services/DataExchange/IDataExporter.cs +++ b/src/Libraries/SmartStore.Services/DataExchange/IDataExporter.cs @@ -42,6 +42,8 @@ public DataExportRequest(ExportProfile profile, Provider provid public ProgressValueSetter ProgressValueSetter { get; set; } + public int CustomerId { get; set; } + public IList EntitiesToExport { get; set; } public IDictionary CustomData { get; private set; } diff --git a/src/Libraries/SmartStore.Services/DataExchange/Import/DataImporter.cs b/src/Libraries/SmartStore.Services/DataExchange/Import/DataImporter.cs index 1e0153c2b1..b2ff901499 100644 --- a/src/Libraries/SmartStore.Services/DataExchange/Import/DataImporter.cs +++ b/src/Libraries/SmartStore.Services/DataExchange/Import/DataImporter.cs @@ -110,6 +110,9 @@ private void ImportCoreOuter(DataImporterContext ctx) if (ctx.Request.Profile == null || !ctx.Request.Profile.Enabled) return; + if (ctx.Request.CustomerId == 0) + ctx.Request.CustomerId = _services.WorkContext.CurrentCustomer.Id; + var logPath = ctx.Request.Profile.GetImportLogPath(); FileSystemHelper.Delete(logPath); diff --git a/src/Presentation/SmartStore.Web/Administration/Controllers/ExportController.cs b/src/Presentation/SmartStore.Web/Administration/Controllers/ExportController.cs index 904d8a4089..1a7a72e057 100644 --- a/src/Presentation/SmartStore.Web/Administration/Controllers/ExportController.cs +++ b/src/Presentation/SmartStore.Web/Administration/Controllers/ExportController.cs @@ -975,20 +975,20 @@ public ActionResult PreviewList(GridCommand command, int id, int totalRecords) [HttpPost] public ActionResult Execute(int id, string selectedIds) { - if (!_services.Permissions.Authorize(StandardPermissionProvider.ManageExports)) + var customer = _services.WorkContext.CurrentCustomer; + + if (!_services.Permissions.Authorize(StandardPermissionProvider.ManageExports, customer)) return AccessDeniedView(); var profile = _exportService.GetExportProfileById(id); if (profile == null) return RedirectToAction("List"); - Dictionary taskParams = null; + var taskParams = new Dictionary(); + taskParams.Add("CurrentCustomerId", customer.Id.ToString()); if (selectedIds.HasValue()) - { - taskParams = new Dictionary(); taskParams.Add("SelectedIds", selectedIds); - } _taskScheduler.RunSingleTask(profile.SchedulingTaskId, taskParams); From f6d434a30ca03072345ddf5e07d3cf48582ae98e Mon Sep 17 00:00:00 2001 From: Marcus Gesing Date: Tue, 15 Dec 2015 14:00:32 +0100 Subject: [PATCH 167/707] Getting started to support import framework for product import --- .../Catalog/Importer/ProductImporter.cs | 658 ++++++++++++++++++ .../DataExchange/DataExportTask.cs | 8 +- .../DataExchange/DataExporter.cs | 32 +- .../DataExchange/Import/DataImportTask.cs | 6 +- .../DataExchange/Import/DataImporter.cs | 159 ++++- .../DataExchange/Import/IEntityImporter.cs | 26 +- .../DataExchange/Import/ImportResult.cs | 22 +- .../Internal/DataExporterContext.cs | 4 + .../NewsLetterSubscriptionImporter.cs | 19 +- .../SmartStore.Services.csproj | 1 + .../Controllers/ExportController.cs | 7 +- .../Controllers/ImportController.cs | 7 +- 12 files changed, 867 insertions(+), 82 deletions(-) create mode 100644 src/Libraries/SmartStore.Services/Catalog/Importer/ProductImporter.cs diff --git a/src/Libraries/SmartStore.Services/Catalog/Importer/ProductImporter.cs b/src/Libraries/SmartStore.Services/Catalog/Importer/ProductImporter.cs new file mode 100644 index 0000000000..bfd2d5d27d --- /dev/null +++ b/src/Libraries/SmartStore.Services/Catalog/Importer/ProductImporter.cs @@ -0,0 +1,658 @@ +using System; +using System.Collections.Generic; +using System.Globalization; +using System.IO; +using System.Linq; +using SmartStore.Core.Data; +using SmartStore.Core.Domain.Catalog; +using SmartStore.Core.Domain.DataExchange; +using SmartStore.Core.Domain.Seo; +using SmartStore.Core.Events; +using SmartStore.Services.DataExchange.Import; +using SmartStore.Services.Localization; +using SmartStore.Services.Media; +using SmartStore.Services.Seo; +using SmartStore.Services.Stores; +using SmartStore.Utilities; + +namespace SmartStore.Services.Catalog.Importer +{ + public class ProductImporter : IEntityImporter + { + private readonly IRepository _rsProductPicture; + private readonly IRepository _rsProductManufacturer; + private readonly IRepository _rsProductCategory; + private readonly IRepository _rsUrlRecord; + private readonly IRepository _rsProduct; + private readonly ICommonServices _services; + private readonly ILanguageService _languageService; + private readonly ILocalizedEntityService _localizedEntityService; + private readonly IPictureService _pictureService; + private readonly IManufacturerService _manufacturerService; + private readonly ICategoryService _categoryService; + private readonly IProductService _productService; + private readonly IUrlRecordService _urlRecordService; + private readonly IStoreMappingService _storeMappingService; + private readonly SeoSettings _seoSettings; + + public ProductImporter( + IRepository rsProductPicture, + IRepository rsProductManufacturer, + IRepository rsProductCategory, + IRepository rsUrlRecord, + IRepository rsProduct, + ICommonServices services, + ILanguageService languageService, + ILocalizedEntityService localizedEntityService, + IPictureService pictureService, + IManufacturerService manufacturerService, + ICategoryService categoryService, + IProductService productService, + IUrlRecordService urlRecordService, + IStoreMappingService storeMappingService, + SeoSettings seoSettings) + { + _rsProductPicture = rsProductPicture; + _rsProductManufacturer = rsProductManufacturer; + _rsProductCategory = rsProductCategory; + _rsUrlRecord = rsUrlRecord; + _rsProduct = rsProduct; + _services = services; + _languageService = languageService; + _localizedEntityService = localizedEntityService; + _pictureService = pictureService; + _manufacturerService = manufacturerService; + _categoryService = categoryService; + _productService = productService; + _urlRecordService = urlRecordService; + _storeMappingService = storeMappingService; + _seoSettings = seoSettings; + } + + private int? ZeroToNull(object value, CultureInfo culture) + { + int result; + if (CommonHelper.TryConvert(value, culture, out result) && result > 0) + { + return result; + } + + return (int?)null; + } + + private void ProcessProductPictures(ImportExecuteContext context, ImportRow[] batch) + { + // true, cause pictures must be saved and assigned an id + // prior adding a mapping. + _rsProductPicture.AutoCommitEnabled = true; + + ProductPicture lastInserted = null; + int equalPictureId = 0; + + foreach (var row in batch) + { + var pictures = new string[] + { + row.GetDataValue("Picture1"), + row.GetDataValue("Picture2"), + row.GetDataValue("Picture3") + }; + + int i = 0; + try + { + for (i = 0; i < pictures.Length; i++) + { + var picture = pictures[i]; + + if (picture.IsEmpty() || !File.Exists(picture)) + continue; + + var currentPictures = _rsProductPicture.TableUntracked.Expand(x => x.Picture).Where(x => x.ProductId == row.Entity.Id).Select(x => x.Picture).ToList(); + var pictureBinary = _pictureService.FindEqualPicture(picture, currentPictures, out equalPictureId); + + if (pictureBinary != null && pictureBinary.Length > 0) + { + // no equal picture found in sequence + var newPicture = _pictureService.InsertPicture(pictureBinary, "image/jpeg", _pictureService.GetPictureSeName(row.EntityDisplayName), true, false, false); + if (newPicture != null) + { + var mapping = new ProductPicture + { + ProductId = row.Entity.Id, + PictureId = newPicture.Id, + DisplayOrder = 1, + }; + _rsProductPicture.Insert(mapping); + lastInserted = mapping; + } + } + else + { + context.Result.AddInfo("Found equal picture in data store. Skipping field.", row.GetRowInfo(), "Picture" + (i + 1).ToString()); + } + } + } + catch (Exception exception) + { + context.Result.AddWarning(exception.Message, row.GetRowInfo(), "Picture" + (i + 1).ToString()); + } + + } + + // Perf: notify only about LAST insertion and update + if (lastInserted != null) + _services.EventPublisher.EntityInserted(lastInserted); + } + + private int ProcessProductManufacturers(ImportExecuteContext context, ImportRow[] batch) + { + _rsProductManufacturer.AutoCommitEnabled = false; + + ProductManufacturer lastInserted = null; + + foreach (var row in batch) + { + var manufacturerIds = row.GetDataValue>("ManufacturerIds"); + if (manufacturerIds != null && manufacturerIds.Any()) + { + try + { + foreach (var id in manufacturerIds) + { + if (_rsProductManufacturer.TableUntracked.Where(x => x.ProductId == row.Entity.Id && x.ManufacturerId == id).FirstOrDefault() == null) + { + // ensure that manufacturer exists + var manufacturer = _manufacturerService.GetManufacturerById(id); + if (manufacturer != null) + { + var productManufacturer = new ProductManufacturer + { + ProductId = row.Entity.Id, + ManufacturerId = manufacturer.Id, + IsFeaturedProduct = false, + DisplayOrder = 1 + }; + _rsProductManufacturer.Insert(productManufacturer); + lastInserted = productManufacturer; + } + } + } + } + catch (Exception exception) + { + context.Result.AddWarning(exception.Message, row.GetRowInfo(), "ManufacturerIds"); + } + } + } + + // commit whole batch at once + var num = _rsProductManufacturer.Context.SaveChanges(); + + // Perf: notify only about LAST insertion and update + if (lastInserted != null) + _services.EventPublisher.EntityInserted(lastInserted); + + return num; + } + + private int ProcessProductCategories(ImportExecuteContext context, ImportRow[] batch) + { + _rsProductCategory.AutoCommitEnabled = false; + + ProductCategory lastInserted = null; + + foreach (var row in batch) + { + var categoryIds = row.GetDataValue>("CategoryIds"); + if (categoryIds != null && categoryIds.Any()) + { + try + { + foreach (var id in categoryIds) + { + if (_rsProductCategory.TableUntracked.Where(x => x.ProductId == row.Entity.Id && x.CategoryId == id).FirstOrDefault() == null) + { + // ensure that category exists + var category = _categoryService.GetCategoryById(id); + if (category != null) + { + var productCategory = new ProductCategory + { + ProductId = row.Entity.Id, + CategoryId = category.Id, + IsFeaturedProduct = false, + DisplayOrder = 1 + }; + _rsProductCategory.Insert(productCategory); + lastInserted = productCategory; + } + } + } + } + catch (Exception exception) + { + context.Result.AddWarning(exception.Message, row.GetRowInfo(), "CategoryIds"); + } + } + } + + // commit whole batch at once + var num = _rsProductCategory.Context.SaveChanges(); + + // Perf: notify only about LAST insertion and update + if (lastInserted != null) + _services.EventPublisher.EntityInserted(lastInserted); + + return num; + } + + private int ProcessLocalizations(ImportExecuteContext context, ImportRow[] batch) + { + //_rsProductManufacturer.AutoCommitEnabled = false; + + //string lastInserted = null; + + var languages = _languageService.GetAllLanguages(true); + + foreach (var row in batch) + { + + Product product = null; + + //get product + try + { + product = _productService.GetProductById(row.Entity.Id); + } + catch (Exception exception) + { + context.Result.AddWarning(exception.Message, row.GetRowInfo(), "ProcessLocalizations Product"); + } + + foreach (var lang in languages) + { + string localizedName = row.GetDataValue("Name", lang.UniqueSeoCode); + string localizedShortDescription = row.GetDataValue("ShortDescription", lang.UniqueSeoCode); + string localizedFullDescription = row.GetDataValue("FullDescription", lang.UniqueSeoCode); + + if (localizedName.HasValue()) + { + _localizedEntityService.SaveLocalizedValue(product, x => x.Name, localizedName, lang.Id); + } + if (localizedShortDescription.HasValue()) + { + _localizedEntityService.SaveLocalizedValue(product, x => x.ShortDescription, localizedShortDescription, lang.Id); + } + if (localizedFullDescription.HasValue()) + { + _localizedEntityService.SaveLocalizedValue(product, x => x.FullDescription, localizedFullDescription, lang.Id); + } + } + } + + // commit whole batch at once + var num = _rsProductManufacturer.Context.SaveChanges(); + + // Perf: notify only about LAST insertion and update + //if (lastInserted != null) + // _eventPublisher.EntityInserted(lastInserted); + + return num; + } + + private int ProcessSlugs(ImportExecuteContext context, ImportRow[] batch) + { + var slugMap = new Dictionary(100); + Func slugLookup = ((s) => + { + if (slugMap.ContainsKey(s)) + { + return slugMap[s]; + } + return (UrlRecord)null; + }); + + var entityName = typeof(Product).Name; + + foreach (var row in batch) + { + if (row.IsNew || row.NameChanged || row.Segmenter.HasDataColumn("SeName")) + { + try + { + string seName = row.GetDataValue("SeName"); + seName = row.Entity.ValidateSeName(seName, row.Entity.Name, true, _urlRecordService, _seoSettings, extraSlugLookup: slugLookup); + + UrlRecord urlRecord = null; + + if (row.IsNew) + { + // dont't bother validating SeName for new entities. + urlRecord = new UrlRecord + { + EntityId = row.Entity.Id, + EntityName = entityName, + Slug = seName, + LanguageId = 0, + IsActive = true, + }; + _rsUrlRecord.Insert(urlRecord); + } + else + { + urlRecord = _urlRecordService.SaveSlug(row.Entity, seName, 0); + } + + if (urlRecord != null) + { + // a new record was inserted to the store: keep track of it for this batch. + slugMap[seName] = urlRecord; + } + } + catch (Exception exception) + { + context.Result.AddWarning(exception.Message, row.GetRowInfo(), "SeName"); + } + } + } + + // commit whole batch at once + return _rsUrlRecord.Context.SaveChanges(); + } + + private int ProcessProducts(ImportExecuteContext context, ImportRow[] batch) + { + _rsProduct.AutoCommitEnabled = true; + + Product lastInserted = null; + Product lastUpdated = null; + + foreach (var row in batch) + { + Product product = null; + + object key; + var dataRow = row.DataRow; + + // try get by int ID + if (dataRow.TryGetValue("Id", out key) && key.ToString().ToInt() > 0) + { + product = _productService.GetProductById(key.ToString().ToInt()); + } + + // try get by SKU + if (product == null && dataRow.TryGetValue("SKU", out key)) + { + product = _productService.GetProductBySku(key.ToString()); + } + + // try get by GTIN + if (product == null && dataRow.TryGetValue("Gtin", out key)) + { + product = _productService.GetProductByGtin(key.ToString()); + } + + if (product == null) + { + // a Name is required with new products. + if (!row.Segmenter.HasDataColumn("Name")) + { + context.Result.AddError("The 'Name' field is required for new products. Skipping row.", row.GetRowInfo(), "Name"); + continue; + } + product = new Product(); + } + + string name = row.GetDataValue("Name"); + + row.Initialize(product, name); + + if (!row.IsNew) + { + if (!product.Name.Equals(name, StringComparison.OrdinalIgnoreCase)) + { + // Perf: use this later for SeName updates. + row.NameChanged = true; + } + } + + row.SetProperty(context.Result, product, (x) => x.Sku); + row.SetProperty(context.Result, product, (x) => x.Gtin); + row.SetProperty(context.Result, product, (x) => x.ManufacturerPartNumber); + row.SetProperty(context.Result, product, (x) => x.ProductTypeId, (int)ProductType.SimpleProduct); + row.SetProperty(context.Result, product, (x) => x.ParentGroupedProductId); + row.SetProperty(context.Result, product, (x) => x.VisibleIndividually, true); + row.SetProperty(context.Result, product, (x) => x.Name); + row.SetProperty(context.Result, product, (x) => x.ShortDescription); + row.SetProperty(context.Result, product, (x) => x.FullDescription); + row.SetProperty(context.Result, product, (x) => x.ProductTemplateId); + row.SetProperty(context.Result, product, (x) => x.ShowOnHomePage); + row.SetProperty(context.Result, product, (x) => x.HomePageDisplayOrder); + row.SetProperty(context.Result, product, (x) => x.MetaKeywords); + row.SetProperty(context.Result, product, (x) => x.MetaDescription); + row.SetProperty(context.Result, product, (x) => x.MetaTitle); + row.SetProperty(context.Result, product, (x) => x.AllowCustomerReviews, true); + row.SetProperty(context.Result, product, (x) => x.Published, true); + row.SetProperty(context.Result, product, (x) => x.IsGiftCard); + row.SetProperty(context.Result, product, (x) => x.GiftCardTypeId); + row.SetProperty(context.Result, product, (x) => x.RequireOtherProducts); + row.SetProperty(context.Result, product, (x) => x.RequiredProductIds); + row.SetProperty(context.Result, product, (x) => x.AutomaticallyAddRequiredProducts); + row.SetProperty(context.Result, product, (x) => x.IsDownload); + row.SetProperty(context.Result, product, (x) => x.DownloadId); + row.SetProperty(context.Result, product, (x) => x.UnlimitedDownloads, true); + row.SetProperty(context.Result, product, (x) => x.MaxNumberOfDownloads, 10); + row.SetProperty(context.Result, product, (x) => x.DownloadActivationTypeId, 1); + row.SetProperty(context.Result, product, (x) => x.HasSampleDownload); + row.SetProperty(context.Result, product, (x) => x.SampleDownloadId, (int?)null, ZeroToNull); + row.SetProperty(context.Result, product, (x) => x.HasUserAgreement); + row.SetProperty(context.Result, product, (x) => x.UserAgreementText); + row.SetProperty(context.Result, product, (x) => x.IsRecurring); + row.SetProperty(context.Result, product, (x) => x.RecurringCycleLength, 100); + row.SetProperty(context.Result, product, (x) => x.RecurringCyclePeriodId); + row.SetProperty(context.Result, product, (x) => x.RecurringTotalCycles, 10); + row.SetProperty(context.Result, product, (x) => x.IsShipEnabled, true); + row.SetProperty(context.Result, product, (x) => x.IsFreeShipping); + row.SetProperty(context.Result, product, (x) => x.AdditionalShippingCharge); + row.SetProperty(context.Result, product, (x) => x.IsEsd); + row.SetProperty(context.Result, product, (x) => x.IsTaxExempt); + row.SetProperty(context.Result, product, (x) => x.TaxCategoryId, 1); + row.SetProperty(context.Result, product, (x) => x.ManageInventoryMethodId); + row.SetProperty(context.Result, product, (x) => x.StockQuantity, 10000); + row.SetProperty(context.Result, product, (x) => x.DisplayStockAvailability); + row.SetProperty(context.Result, product, (x) => x.DisplayStockQuantity); + row.SetProperty(context.Result, product, (x) => x.MinStockQuantity); + row.SetProperty(context.Result, product, (x) => x.LowStockActivityId); + row.SetProperty(context.Result, product, (x) => x.NotifyAdminForQuantityBelow, 1); + row.SetProperty(context.Result, product, (x) => x.BackorderModeId); + row.SetProperty(context.Result, product, (x) => x.AllowBackInStockSubscriptions); + row.SetProperty(context.Result, product, (x) => x.OrderMinimumQuantity, 1); + row.SetProperty(context.Result, product, (x) => x.OrderMaximumQuantity, 10000); + row.SetProperty(context.Result, product, (x) => x.AllowedQuantities); + row.SetProperty(context.Result, product, (x) => x.DisableBuyButton); + row.SetProperty(context.Result, product, (x) => x.DisableWishlistButton); + row.SetProperty(context.Result, product, (x) => x.AvailableForPreOrder); + row.SetProperty(context.Result, product, (x) => x.CallForPrice); + row.SetProperty(context.Result, product, (x) => x.Price); + row.SetProperty(context.Result, product, (x) => x.OldPrice); + row.SetProperty(context.Result, product, (x) => x.ProductCost); + row.SetProperty(context.Result, product, (x) => x.SpecialPrice); + row.SetProperty(context.Result, product, (x) => x.SpecialPriceStartDateTimeUtc); + row.SetProperty(context.Result, product, (x) => x.SpecialPriceEndDateTimeUtc); + row.SetProperty(context.Result, product, (x) => x.CustomerEntersPrice); + row.SetProperty(context.Result, product, (x) => x.MinimumCustomerEnteredPrice); + row.SetProperty(context.Result, product, (x) => x.MaximumCustomerEnteredPrice, 1000); + row.SetProperty(context.Result, product, (x) => x.Weight); + row.SetProperty(context.Result, product, (x) => x.Length); + row.SetProperty(context.Result, product, (x) => x.Width); + row.SetProperty(context.Result, product, (x) => x.Height); + row.SetProperty(context.Result, product, (x) => x.DeliveryTimeId); + row.SetProperty(context.Result, product, (x) => x.QuantityUnitId); + row.SetProperty(context.Result, product, (x) => x.BasePriceEnabled); + row.SetProperty(context.Result, product, (x) => x.BasePriceMeasureUnit); + row.SetProperty(context.Result, product, (x) => x.BasePriceAmount); + row.SetProperty(context.Result, product, (x) => x.BasePriceBaseAmount); + row.SetProperty(context.Result, product, (x) => x.BundlePerItemPricing); + row.SetProperty(context.Result, product, (x) => x.BundlePerItemShipping); + row.SetProperty(context.Result, product, (x) => x.BundlePerItemShoppingCart); + row.SetProperty(context.Result, product, (x) => x.BundleTitleText); + row.SetProperty(context.Result, product, (x) => x.AvailableStartDateTimeUtc); + row.SetProperty(context.Result, product, (x) => x.AvailableEndDateTimeUtc); + row.SetProperty(context.Result, product, (x) => x.LimitedToStores); + + var storeIds = row.GetDataValue>("StoreIds"); + if (storeIds != null && storeIds.Any()) + { + _storeMappingService.SaveStoreMappings(product, storeIds.ToArray()); + } + + row.SetProperty(context.Result, product, (x) => x.CreatedOnUtc, DateTime.UtcNow); + + product.UpdatedOnUtc = DateTime.UtcNow; + + if (row.IsTransient) + { + _rsProduct.Insert(product); + lastInserted = product; + } + else + { + _rsProduct.Update(product); + lastUpdated = product; + } + } + + // commit whole batch at once + var num = _rsProduct.Context.SaveChanges(); + + // Perf: notify only about LAST insertion and update + if (lastInserted != null) + _services.EventPublisher.EntityInserted(lastInserted); + if (lastUpdated != null) + _services.EventPublisher.EntityUpdated(lastUpdated); + + return num; + } + + public void Execute(ImportExecuteContext context) + { + using (var scope = new DbContextScope(ctx: _rsProduct.Context, autoDetectChanges: false, proxyCreation: false, validateOnSave: false)) + { + var segmenter = new ImportDataSegmenter(context.DataTable); + segmenter.Culture = CultureInfo.CurrentUICulture; + + context.Result.TotalRecords = segmenter.TotalRows; + + while (context.Abort == DataExchangeAbortion.None && segmenter.ReadNextBatch()) + { + var batch = segmenter.CurrentBatch; + + // Perf: detach all entities + _rsProduct.Context.DetachAll(false); + + context.SetProgress(segmenter.CurrentSegmentFirstRowIndex - 1, segmenter.TotalRows); + + // =========================================================================== + // 1.) Import products + // =========================================================================== + try + { + ProcessProducts(context, batch); + } + catch (Exception exception) + { + context.Result.AddError(exception, segmenter.CurrentSegment, "ProcessProducts"); + } + + // reduce batch to saved (valid) products. + // No need to perform import operations on errored products. + batch = batch.Where(x => x.Entity != null && !x.IsTransient).ToArray(); + + // update result object + context.Result.NewRecords += batch.Count(x => x.IsNew && !x.IsTransient); + context.Result.ModifiedRecords += batch.Count(x => !x.IsNew && !x.IsTransient); + + // =========================================================================== + // 2.) Import SEO Slugs + // IMPORTANT: Unlike with Products AutoCommitEnabled must be TRUE, + // as Slugs are going to be validated against existing ones in DB. + // =========================================================================== + if (context.DataTable.HasColumn("SeName") || batch.Any(x => x.IsNew || x.NameChanged)) + { + try + { + _rsProduct.Context.AutoDetectChangesEnabled = true; + ProcessSlugs(context, batch); + } + catch (Exception exception) + { + context.Result.AddError(exception, segmenter.CurrentSegment, "ProcessSeoSlugs"); + } + finally + { + _rsProduct.Context.AutoDetectChangesEnabled = false; + } + } + + // =========================================================================== + // 3.) Import Localizations + // =========================================================================== + try + { + ProcessLocalizations(context, batch); + } + catch (Exception exception) + { + context.Result.AddError(exception, segmenter.CurrentSegment, "ProcessLocalizations"); + } + + // =========================================================================== + // 4.) Import product category mappings + // =========================================================================== + if (context.DataTable.HasColumn("CategoryIds")) + { + try + { + ProcessProductCategories(context, batch); + } + catch (Exception exception) + { + context.Result.AddError(exception, segmenter.CurrentSegment, "ProcessProductCategories"); + } + } + + // =========================================================================== + // 5.) Import product manufacturer mappings + // =========================================================================== + if (context.DataTable.HasColumn("ManufacturerIds")) + { + try + { + ProcessProductManufacturers(context, batch); + } + catch (Exception exception) + { + context.Result.AddError(exception, segmenter.CurrentSegment, "ProcessProductManufacturers"); + } + } + + // =========================================================================== + // 6.) Import product picture mappings + // =========================================================================== + if (context.DataTable.HasColumn("Picture1") || context.DataTable.HasColumn("Picture2") || context.DataTable.HasColumn("Picture3")) + { + try + { + ProcessProductPictures(context, batch); + } + catch (Exception exception) + { + context.Result.AddError(exception, segmenter.CurrentSegment, "ProcessProductPictures"); + } + } + } + } + } + } +} diff --git a/src/Libraries/SmartStore.Services/DataExchange/DataExportTask.cs b/src/Libraries/SmartStore.Services/DataExchange/DataExportTask.cs index ba4356de43..213d23f387 100644 --- a/src/Libraries/SmartStore.Services/DataExchange/DataExportTask.cs +++ b/src/Libraries/SmartStore.Services/DataExchange/DataExportTask.cs @@ -32,13 +32,17 @@ public void Execute(TaskExecutionContext ctx) // build export request var request = new DataExportRequest(profile, provider); - request.CustomerId = ctx.Parameters["CurrentCustomerId"].ToInt(); // do not use built-in background tasks customer - request.ProgressValueSetter = delegate(int val, int max, string msg) + request.ProgressValueSetter = delegate (int val, int max, string msg) { ctx.SetProgress(val, max, msg, true); }; + if (ctx.Parameters.ContainsKey("CurrentCustomerId")) + { + request.CustomerId = ctx.Parameters["CurrentCustomerId"].ToInt(); // do not use built-in background tasks customer + } + if (ctx.Parameters.ContainsKey("SelectedIds")) { request.EntitiesToExport = ctx.Parameters["SelectedIds"] diff --git a/src/Libraries/SmartStore.Services/DataExchange/DataExporter.cs b/src/Libraries/SmartStore.Services/DataExchange/DataExporter.cs index 1b56c39d1c..d8d3006017 100644 --- a/src/Libraries/SmartStore.Services/DataExchange/DataExporter.cs +++ b/src/Libraries/SmartStore.Services/DataExchange/DataExporter.cs @@ -203,7 +203,7 @@ private void SetProgress(DataExporterContext ctx, string message) private bool HasPermission(DataExporterContext ctx) { if (ctx.Request.CustomerId == 0) - ctx.Request.CustomerId = _services.WorkContext.CurrentCustomer.Id; + ctx.Request.CustomerId = _services.WorkContext.CurrentCustomer.Id; // fallback to background task system customer var customer = _customerService.GetCustomerById(ctx.Request.CustomerId); @@ -390,7 +390,7 @@ private IExportDataSegmenterProvider CreateSegmenter(DataExporterContext ctx, in private bool CallProvider(DataExporterContext ctx, string streamId, string method, string path) { if (method != "Execute" && method != "OnExecuted") - throw new SmartException("Unknown export method {0}".FormatInvariant(method.NaIfEmpty())); + throw new SmartException("Unknown export method {0}.".FormatInvariant(method.NaIfEmpty())); try { @@ -417,7 +417,7 @@ private bool CallProvider(DataExporterContext ctx, string streamId, string metho using (_rwLock.GetWriteLock()) using (var fileStream = new FileStream(path, FileMode.Create, FileAccess.Write, FileShare.ReadWrite)) { - ctx.Log.Information("Creating file " + path); + ctx.Log.Information("Creating file {0}.".FormatInvariant(path)); ctx.ExecuteContext.DataStream.CopyTo(fileStream); } @@ -427,7 +427,7 @@ private bool CallProvider(DataExporterContext ctx, string streamId, string metho catch (Exception exception) { ctx.ExecuteContext.Abort = DataExchangeAbortion.Hard; - ctx.Log.Error("The provider failed at the {0} method: {1}".FormatInvariant(method, exception.ToAllMessages()), exception); + ctx.Log.Error("The provider failed at the {0} method: {1}.".FormatInvariant(method, exception.ToAllMessages()), exception); ctx.Result.LastError = exception.ToString(); } finally @@ -986,12 +986,12 @@ private void ExportCoreInner(DataExporterContext ctx, Store store) { if (segmenter == null) { - throw new SmartException("Unsupported entity type '{0}'".FormatInvariant(ctx.Request.Provider.Value.EntityType.ToString())); + throw new SmartException("Unsupported entity type '{0}'.".FormatInvariant(ctx.Request.Provider.Value.EntityType.ToString())); } if (segmenter.TotalRecords <= 0) { - ctx.Log.Information("There are no records to export"); + ctx.Log.Information("There are no records to export."); } while (ctx.ExecuteContext.Abort == DataExchangeAbortion.None && segmenter.HasData) @@ -1014,7 +1014,7 @@ private void ExportCoreInner(DataExporterContext ctx, Store store) if (CallProvider(ctx, null, "Execute", path)) { - ctx.Log.Information("Provider reports {0} successfully exported record(s)".FormatInvariant(ctx.ExecuteContext.RecordsSucceeded)); + ctx.Log.Information("Provider reports {0} successfully exported record(s).".FormatInvariant(ctx.ExecuteContext.RecordsSucceeded)); // create info for deployment list in profile edit if (ctx.IsFileBasedExport) @@ -1030,10 +1030,10 @@ private void ExportCoreInner(DataExporterContext ctx, Store store) ctx.EntityIdsPerSegment.Clear(); if (ctx.ExecuteContext.IsMaxFailures) - ctx.Log.Warning("Export aborted. The maximum number of failures has been reached"); + ctx.Log.Warning("Export aborted. The maximum number of failures has been reached."); if (ctx.CancellationToken.IsCancellationRequested) - ctx.Log.Warning("Export aborted. A cancellation has been requested"); + ctx.Log.Warning("Export aborted. A cancellation has been requested."); DetachAllEntitiesAndClear(ctx); } @@ -1072,21 +1072,21 @@ private void ExportCoreOuter(DataExporterContext ctx) { try { + ctx.Log = logger; + ctx.ExecuteContext.Log = logger; + ctx.ProgressInfo = T("Admin.DataExchange.Export.ProgressInfo"); + if (!ctx.Request.Provider.IsValid()) - throw new SmartException("Export aborted because the export provider is not valid"); + throw new SmartException("Export aborted because the export provider is not valid."); if (!HasPermission(ctx)) - throw new SmartException("You do not have permission to perform the selected export"); + throw new SmartException("You do not have permission to perform the selected export."); foreach (var item in ctx.Request.CustomData) { ctx.ExecuteContext.CustomProperties.Add(item.Key, item.Value); } - ctx.Log = logger; - ctx.ExecuteContext.Log = logger; - ctx.ProgressInfo = T("Admin.DataExchange.Export.ProgressInfo"); - if (ctx.Request.Profile.ProviderConfigData.HasValue()) { var configInfo = ctx.Request.Provider.Value.ConfigurationInfo; @@ -1203,11 +1203,11 @@ private void ExportCoreOuter(DataExporterContext ctx) ctx.ProductTemplates.Clear(); ctx.Countries.Clear(); ctx.Languages.Clear(); - ctx.Stores.Clear(); ctx.QuantityUnits.Clear(); ctx.DeliveryTimes.Clear(); ctx.CategoryPathes.Clear(); ctx.Categories.Clear(); + ctx.Stores.Clear(); ctx.Request.CustomData.Clear(); diff --git a/src/Libraries/SmartStore.Services/DataExchange/Import/DataImportTask.cs b/src/Libraries/SmartStore.Services/DataExchange/Import/DataImportTask.cs index 51afd08d85..253bd10b6f 100644 --- a/src/Libraries/SmartStore.Services/DataExchange/Import/DataImportTask.cs +++ b/src/Libraries/SmartStore.Services/DataExchange/Import/DataImportTask.cs @@ -22,13 +22,17 @@ public void Execute(TaskExecutionContext ctx) var profile = _importProfileService.GetImportProfileById(profileId); var request = new DataImportRequest(profile); - request.CustomerId = ctx.Parameters["CurrentCustomerId"].ToInt(); // do not use built-in background tasks customer request.ProgressValueSetter = delegate (int val, int max, string msg) { ctx.SetProgress(val, max, msg, true); }; + if (ctx.Parameters.ContainsKey("CurrentCustomerId")) + { + request.CustomerId = ctx.Parameters["CurrentCustomerId"].ToInt(); // do not use built-in background tasks customer + } + _importer.Import(request, ctx.CancellationToken); } } diff --git a/src/Libraries/SmartStore.Services/DataExchange/Import/DataImporter.cs b/src/Libraries/SmartStore.Services/DataExchange/Import/DataImporter.cs index b2ff901499..52aaf0b992 100644 --- a/src/Libraries/SmartStore.Services/DataExchange/Import/DataImporter.cs +++ b/src/Libraries/SmartStore.Services/DataExchange/Import/DataImporter.cs @@ -1,44 +1,105 @@ using System; using System.IO; +using System.Linq; using System.Text; using System.Threading; using SmartStore.Core; using SmartStore.Core.Data; +using SmartStore.Core.Domain.Catalog; using SmartStore.Core.Domain.DataExchange; using SmartStore.Core.Domain.Messages; +using SmartStore.Core.Domain.Seo; using SmartStore.Core.Localization; using SmartStore.Core.Logging; +using SmartStore.Services.Catalog; +using SmartStore.Services.Catalog.Importer; using SmartStore.Services.Customers; using SmartStore.Services.DataExchange.Csv; using SmartStore.Services.DataExchange.Import.Internal; +using SmartStore.Services.Localization; +using SmartStore.Services.Media; using SmartStore.Services.Messages.Importer; using SmartStore.Services.Security; +using SmartStore.Services.Seo; +using SmartStore.Services.Stores; using SmartStore.Utilities; namespace SmartStore.Services.DataExchange.Import { public partial class DataImporter : IDataImporter { + #region Dependencies + private readonly ICommonServices _services; private readonly ICustomerService _customerService; + private readonly Lazy> _subscriptionRepository; + private readonly Lazy> _productPictureRepository; + private readonly Lazy> _productManufacturerRepository; + private readonly Lazy> _productCategoryRepository; + private readonly Lazy> _urlRecordRepository; + private readonly Lazy> _productRepository; + + private readonly Lazy _languageService; + private readonly Lazy _localizedEntityService; + private readonly Lazy _pictureService; + private readonly Lazy _manufacturerService; + private readonly Lazy _categoryService; + private readonly Lazy _productService; + private readonly Lazy _urlRecordService; + private readonly Lazy _storeMappingService; + + private readonly Lazy _seoSettings; public DataImporter( ICommonServices services, ICustomerService customerService, - Lazy> subscriptionRepository) + Lazy> subscriptionRepository, + Lazy> productPictureRepository, + Lazy> productManufacturerRepository, + Lazy> productCategoryRepository, + Lazy> urlRecordRepository, + Lazy> productRepository, + Lazy languageService, + Lazy localizedEntityService, + Lazy pictureService, + Lazy manufacturerService, + Lazy categoryService, + Lazy productService, + Lazy urlRecordService, + Lazy storeMappingService, + Lazy seoSettings) { _services = services; _customerService = customerService; _subscriptionRepository = subscriptionRepository; + _productPictureRepository = productPictureRepository; + _productManufacturerRepository = productManufacturerRepository; + _productCategoryRepository = productCategoryRepository; + _urlRecordRepository = urlRecordRepository; + _productRepository = productRepository; + _languageService = languageService; + _localizedEntityService = localizedEntityService; + _pictureService = pictureService; + _manufacturerService = manufacturerService; + _categoryService = categoryService; + _productService = productService; + _urlRecordService = urlRecordService; + _storeMappingService = storeMappingService; + _seoSettings = seoSettings; T = NullLocalizer.Instance; } + #endregion + public Localizer T { get; set; } private bool HasPermission(DataImporterContext ctx) { + if (ctx.Request.CustomerId == 0) + ctx.Request.CustomerId = _services.WorkContext.CurrentCustomer.Id; // fallback to background task system customer + var customer = _customerService.GetCustomerById(ctx.Request.CustomerId); if (ctx.Request.Profile.EntityType == ImportEntityType.Product) @@ -53,8 +114,52 @@ private bool HasPermission(DataImporterContext ctx) return true; } + private void LogResult(DataImporterContext ctx) + { + var result = ctx.ExecuteContext.Result; + var sb = new StringBuilder(); + + sb.AppendLine(); + sb.AppendFormat("Started:\t\t\t{0}\r\n", result.StartDateUtc.ToLocalTime()); + sb.AppendFormat("Finished:\t\t\t{0}\r\n", result.EndDateUtc.ToLocalTime()); + sb.AppendFormat("Duration:\t\t\t{0}\r\n", (result.EndDateUtc - result.StartDateUtc).ToString("g")); + sb.AppendLine(); + sb.AppendFormat("Total rows:\t\t\t{0}\r\n", result.TotalRecords); + sb.AppendFormat("Rows processed:\t\t{0}\r\n", result.AffectedRecords); + sb.AppendFormat("Records imported:\t{0}\r\n", result.NewRecords); + sb.AppendFormat("Records updated:\t{0}\r\n", result.ModifiedRecords); + sb.AppendLine(); + sb.AppendFormat("Warnings:\t\t\t{0}\r\n", result.Messages.Count(x => x.MessageType == ImportMessageType.Warning)); + sb.AppendFormat("Errors:\t\t\t\t{0}", result.Messages.Count(x => x.MessageType == ImportMessageType.Error)); + + ctx.Log.Information(sb.ToString()); + + foreach (var message in result.Messages) + { + string prefix = null; + + if (message.AffectedItem != null) + prefix.Grow("Pos: " + (message.AffectedItem.Position + 1).ToString(), ", "); + + if (message.AffectedField.HasValue()) + prefix.Grow("Field: " + message.AffectedField, ", "); + + if (prefix.HasValue()) + message.Message = "[{0}] {1}".FormatInvariant(prefix, message.Message); + + if (message.MessageType == ImportMessageType.Error) + ctx.Log.Error(message.Message); + else if (message.MessageType == ImportMessageType.Warning) + ctx.Log.Warning(message.Message); + else + ctx.Log.Information(message.Message); + } + } + private void ImportCoreInner(DataImporterContext ctx, string filePath) { + ctx.ExecuteContext.Result.Clear(); + { var logHead = new StringBuilder(); logHead.AppendLine(); @@ -71,7 +176,7 @@ private void ImportCoreInner(DataImporterContext ctx, string filePath) if (!File.Exists(filePath)) { - throw new SmartException("File does not exist {0}".FormatInvariant(filePath)); + throw new SmartException("File does not exist {0}.".FormatInvariant(filePath)); } CsvConfiguration csvConfiguration = null; @@ -86,22 +191,33 @@ private void ImportCoreInner(DataImporterContext ctx, string filePath) if (csvConfiguration == null) { - csvConfiguration = new CsvConfiguration(); + csvConfiguration = CsvConfiguration.ExcelFriendlyConfiguration; + ctx.Log.Warning("No CSV configuration provided for import profile. Fallback to Excel friendly configuration."); } using (var stream = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.Read)) { ctx.ExecuteContext.DataTable = LightweightDataTable.FromFile(Path.GetFileName(filePath), stream, stream.Length, csvConfiguration, ctx.Request.Profile.Skip, take); - ctx.Importer.Execute(ctx.ExecuteContext); + try + { + ctx.Importer.Execute(ctx.ExecuteContext); + } + catch (Exception exception) + { + ctx.ExecuteContext.Abort = DataExchangeAbortion.Hard; + ctx.Log.Error("The importer failed: {0}.".FormatInvariant(exception.ToAllMessages()), exception); + } - ctx.Log.Information("Importer reports {0} added and {1} updated record(s)".FormatInvariant(ctx.ExecuteContext.RecordsAdded, ctx.ExecuteContext.RecordsUpdated)); + ctx.ExecuteContext.Result.EndDateUtc = DateTime.UtcNow; if (ctx.ExecuteContext.IsMaxFailures) - ctx.Log.Warning("Export aborted. The maximum number of failures has been reached"); + ctx.Log.Warning("Import aborted. The maximum number of failures has been reached."); if (ctx.CancellationToken.IsCancellationRequested) - ctx.Log.Warning("Import aborted. A cancellation has been requested"); + ctx.Log.Warning("Import aborted. A cancellation has been requested."); + + LogResult(ctx); } } @@ -122,29 +238,46 @@ private void ImportCoreOuter(DataImporterContext ctx) try { ctx.Log = logger; - ctx.ExecuteContext.Log = logger; var files = ctx.Request.Profile.GetImportFiles(); if (files.Count == 0) - throw new SmartException("No files to import found"); + throw new SmartException("No files to import found."); if (!HasPermission(ctx)) - throw new SmartException("You do not have permission to perform the selected import"); + throw new SmartException("You do not have permission to perform the selected import."); if (ctx.Request.Profile.EntityType == ImportEntityType.Product) - { + { + ctx.Importer = new ProductImporter( + _productPictureRepository.Value, + _productManufacturerRepository.Value, + _productCategoryRepository.Value, + _urlRecordRepository.Value, + _productRepository.Value, + _services, + _languageService.Value, + _localizedEntityService.Value, + _pictureService.Value, + _manufacturerService.Value, + _categoryService.Value, + _productService.Value, + _urlRecordService.Value, + _storeMappingService.Value, + _seoSettings.Value); } else if (ctx.Request.Profile.EntityType == ImportEntityType.Customer) { } else if (ctx.Request.Profile.EntityType == ImportEntityType.NewsLetterSubscription) { - ctx.Importer = new NewsLetterSubscriptionImporter(_services, _subscriptionRepository.Value); + ctx.Importer = new NewsLetterSubscriptionImporter( + _services, + _subscriptionRepository.Value); } else { - throw new SmartException("Unsupported entity type {0}".FormatInvariant(ctx.Request.Profile.EntityType.ToString())); + throw new SmartException("Unsupported entity type {0}.".FormatInvariant(ctx.Request.Profile.EntityType.ToString())); } files.ForEach(x => ImportCoreInner(ctx, x)); diff --git a/src/Libraries/SmartStore.Services/DataExchange/Import/IEntityImporter.cs b/src/Libraries/SmartStore.Services/DataExchange/Import/IEntityImporter.cs index 2d0bb6a082..051a95132d 100644 --- a/src/Libraries/SmartStore.Services/DataExchange/Import/IEntityImporter.cs +++ b/src/Libraries/SmartStore.Services/DataExchange/Import/IEntityImporter.cs @@ -1,9 +1,8 @@ using System; +using System.Linq; using System.Collections.Generic; using System.Threading; -using SmartStore.Core.Domain.Customers; using SmartStore.Core.Domain.DataExchange; -using SmartStore.Core.Logging; namespace SmartStore.Services.DataExchange.Import { @@ -32,10 +31,9 @@ public ImportExecuteContext( CustomerId = customerId; CustomProperties = new Dictionary(); + Result = new ImportResult(); } - public ILogger Log { get; internal set; } - public IDataTable DataTable { get; internal set; } public int CustomerId { get; private set; } @@ -45,9 +43,7 @@ public ImportExecuteContext( /// public Dictionary CustomProperties { get; private set; } - public int RecordsAdded { get; set; } - public int RecordsUpdated { get; set; } - public int RecordsFailed { get; set; } + public ImportResult Result { get; set; } public DataExchangeAbortion Abort { @@ -66,18 +62,10 @@ public DataExchangeAbortion Abort public bool IsMaxFailures { - get { return RecordsFailed > 11; } - } - - /// - /// Processes an exception that occurred while importing a record - /// - /// Exception - public void RecordException(Exception exception, string id) - { - ++RecordsFailed; - - Log.Error("Error while processing record with id {0}: {1}".FormatInvariant(id, exception.ToAllMessages()), exception); + get + { + return Result.Messages.Count(x => x.MessageType == ImportMessageType.Error) > 11; + } } public void SetProgress(int value, int maximum) diff --git a/src/Libraries/SmartStore.Services/DataExchange/Import/ImportResult.cs b/src/Libraries/SmartStore.Services/DataExchange/Import/ImportResult.cs index 731a12861b..7e52d3948e 100644 --- a/src/Libraries/SmartStore.Services/DataExchange/Import/ImportResult.cs +++ b/src/Libraries/SmartStore.Services/DataExchange/Import/ImportResult.cs @@ -11,7 +11,17 @@ public class ImportResult public ImportResult() { this.Messages = new List(); - this.StartDateUtc = DateTime.UtcNow; + Clear(); + } + + public void Clear() + { + Messages.Clear(); + StartDateUtc = EndDateUtc = DateTime.UtcNow; + TotalRecords = 0; + NewRecords = 0; + ModifiedRecords = 0; + Cancelled = false; } public DateTime StartDateUtc @@ -72,14 +82,6 @@ public ImportMessage AddError(string message, ImportRowInfo affectedRow = null, public ImportMessage AddError(Exception exception, int? affectedBatch = null, string stage = null) { - var ex = exception; - while (true) - { - if (ex.InnerException == null) - break; - ex = ex.InnerException; - } - var prefix = new List(); if (affectedBatch.HasValue) { @@ -96,7 +98,7 @@ public ImportMessage AddError(Exception exception, int? affectedBatch = null, st msg = "[{0}] ".FormatCurrent(String.Join(", ", prefix)); } - msg += ex.Message; + msg += exception.ToAllMessages(); return this.AddMessage(msg, ImportMessageType.Error); } diff --git a/src/Libraries/SmartStore.Services/DataExchange/Internal/DataExporterContext.cs b/src/Libraries/SmartStore.Services/DataExchange/Internal/DataExporterContext.cs index c3960e8bd0..f909b93678 100644 --- a/src/Libraries/SmartStore.Services/DataExchange/Internal/DataExporterContext.cs +++ b/src/Libraries/SmartStore.Services/DataExchange/Internal/DataExporterContext.cs @@ -29,6 +29,10 @@ public DataExporterContext( Categories = new Dictionary(); CategoryPathes = new Dictionary(); + DeliveryTimes = new Dictionary(); + QuantityUnits = new Dictionary(); + Stores = new Dictionary(); + Languages = new Dictionary(); Countries = new Dictionary(); ProductTemplates = new Dictionary(); NewsletterSubscriptions = new HashSet(); diff --git a/src/Libraries/SmartStore.Services/Messages/Importer/NewsLetterSubscriptionImporter.cs b/src/Libraries/SmartStore.Services/Messages/Importer/NewsLetterSubscriptionImporter.cs index 8c0b0abdf2..9cf6be74ac 100644 --- a/src/Libraries/SmartStore.Services/Messages/Importer/NewsLetterSubscriptionImporter.cs +++ b/src/Libraries/SmartStore.Services/Messages/Importer/NewsLetterSubscriptionImporter.cs @@ -5,7 +5,6 @@ using SmartStore.Core.Data; using SmartStore.Core.Domain.DataExchange; using SmartStore.Core.Domain.Messages; -using SmartStore.Core.Logging; using SmartStore.Services.DataExchange.Import; namespace SmartStore.Services.Messages.Importer @@ -36,6 +35,8 @@ public void Execute(ImportExecuteContext context) var segmenter = new ImportDataSegmenter(context.DataTable); segmenter.Culture = CultureInfo.CurrentCulture; + context.Result.TotalRecords = segmenter.TotalRows; + while (context.Abort == DataExchangeAbortion.None && segmenter.ReadNextBatch()) { var batch = segmenter.CurrentBatch; @@ -46,13 +47,9 @@ public void Execute(ImportExecuteContext context) foreach (var row in batch) { - string id = null; - try { var email = row.GetDataValue("Email"); - id = email; - var active = row.GetDataValue("Active"); var storeId = row.GetDataValue("StoreId"); @@ -61,19 +58,19 @@ public void Execute(ImportExecuteContext context) if (email.IsEmpty()) { - context.Log.Warning("Skipped empty email address".FormatInvariant(email)); + context.Result.AddWarning("Skipped empty email address", row.GetRowInfo(), "Email"); continue; } if (email.Length > 255) { - context.Log.Warning("Skipped email address '{0}' because it exceeds the maximum allowed length of 255".FormatInvariant(email)); + context.Result.AddWarning("Skipped email address '{0}'. It exceeds the maximum allowed length of 255".FormatInvariant(email), row.GetRowInfo(), "Email"); continue; } if (!email.IsEmail()) { - context.Log.Warning("Skipped invalid email address '{0}'".FormatInvariant(email)); + context.Result.AddWarning("Skipped invalid email address '{0}'".FormatInvariant(email), row.GetRowInfo(), "Email"); continue; } @@ -93,14 +90,14 @@ public void Execute(ImportExecuteContext context) }; toAdd.Add(subscription); - ++context.RecordsAdded; + ++context.Result.NewRecords; } else { subscription.Active = active; toUpdate.Add(subscription); - ++context.RecordsUpdated; + ++context.Result.ModifiedRecords; } // insert new subscribers @@ -116,7 +113,7 @@ public void Execute(ImportExecuteContext context) } catch (Exception exception) { - context.RecordException(exception, id.NaIfEmpty()); + context.Result.AddError(exception.ToAllMessages(), row.GetRowInfo()); } } } diff --git a/src/Libraries/SmartStore.Services/SmartStore.Services.csproj b/src/Libraries/SmartStore.Services/SmartStore.Services.csproj index 350544f611..a3b6819b57 100644 --- a/src/Libraries/SmartStore.Services/SmartStore.Services.csproj +++ b/src/Libraries/SmartStore.Services/SmartStore.Services.csproj @@ -165,6 +165,7 @@ Properties\AssemblyVersionInfo.cs + diff --git a/src/Presentation/SmartStore.Web/Administration/Controllers/ExportController.cs b/src/Presentation/SmartStore.Web/Administration/Controllers/ExportController.cs index 1a7a72e057..32f84d8afd 100644 --- a/src/Presentation/SmartStore.Web/Administration/Controllers/ExportController.cs +++ b/src/Presentation/SmartStore.Web/Administration/Controllers/ExportController.cs @@ -975,17 +975,14 @@ public ActionResult PreviewList(GridCommand command, int id, int totalRecords) [HttpPost] public ActionResult Execute(int id, string selectedIds) { - var customer = _services.WorkContext.CurrentCustomer; - - if (!_services.Permissions.Authorize(StandardPermissionProvider.ManageExports, customer)) - return AccessDeniedView(); + // permissions checked internally by DataExporter var profile = _exportService.GetExportProfileById(id); if (profile == null) return RedirectToAction("List"); var taskParams = new Dictionary(); - taskParams.Add("CurrentCustomerId", customer.Id.ToString()); + taskParams.Add("CurrentCustomerId", _services.WorkContext.CurrentCustomer.Id.ToString()); if (selectedIds.HasValue()) taskParams.Add("SelectedIds", selectedIds); diff --git a/src/Presentation/SmartStore.Web/Administration/Controllers/ImportController.cs b/src/Presentation/SmartStore.Web/Administration/Controllers/ImportController.cs index 604f0c53b0..4d57685583 100644 --- a/src/Presentation/SmartStore.Web/Administration/Controllers/ImportController.cs +++ b/src/Presentation/SmartStore.Web/Administration/Controllers/ImportController.cs @@ -307,17 +307,14 @@ public JsonResult FileUpload(int id) [HttpPost] public ActionResult Execute(int id) { - var customer = _services.WorkContext.CurrentCustomer; - - if (!_services.Permissions.Authorize(StandardPermissionProvider.ManageImports, customer)) - return AccessDeniedView(); + // permissions checked internally by DataImporter var profile = _importService.GetImportProfileById(id); if (profile == null) return RedirectToAction("List"); var taskParams = new Dictionary(); - taskParams.Add("CurrentCustomerId", customer.Id.ToString()); + taskParams.Add("CurrentCustomerId", _services.WorkContext.CurrentCustomer.Id.ToString()); _taskScheduler.RunSingleTask(profile.SchedulingTaskId, taskParams); From ab58896c4be73c9eaece7abfc3bc9a9a7874ede4 Mon Sep 17 00:00:00 2001 From: Marcus Gesing Date: Tue, 15 Dec 2015 17:34:22 +0100 Subject: [PATCH 168/707] It's better to have a file type field for import profiles --- .../Domain/DataExchange/ImportEnums.cs | 6 + .../Domain/DataExchange/ImportProfile.cs | 19 ++- .../Mapping/DataExchange/ImportProfileMap.cs | 2 +- .../201512111134591_ImportFramework.resx | 126 ------------------ ...1512151526290_ImportFramework.Designer.cs} | 2 +- ....cs => 201512151526290_ImportFramework.cs} | 11 +- .../201512151526290_ImportFramework.resx | 126 ++++++++++++++++++ .../SmartStore.Data/SmartStore.Data.csproj | 10 +- .../DataExchange/Import/ImportExtensions.cs | 16 +-- .../Import/ImportProfileService.cs | 7 +- .../Controllers/ImportController.cs | 61 ++++----- .../Models/DataExchange/ImportProfileModel.cs | 5 +- .../Views/Import/_CreateOrUpdate.cshtml | 13 +- .../Views/Import/_ImportFileList.cshtml | 9 +- 14 files changed, 224 insertions(+), 189 deletions(-) delete mode 100644 src/Libraries/SmartStore.Data/Migrations/201512111134591_ImportFramework.resx rename src/Libraries/SmartStore.Data/Migrations/{201512111134591_ImportFramework.Designer.cs => 201512151526290_ImportFramework.Designer.cs} (92%) rename src/Libraries/SmartStore.Data/Migrations/{201512111134591_ImportFramework.cs => 201512151526290_ImportFramework.cs} (92%) create mode 100644 src/Libraries/SmartStore.Data/Migrations/201512151526290_ImportFramework.resx diff --git a/src/Libraries/SmartStore.Core/Domain/DataExchange/ImportEnums.cs b/src/Libraries/SmartStore.Core/Domain/DataExchange/ImportEnums.cs index 498c39b3d2..eb993124dc 100644 --- a/src/Libraries/SmartStore.Core/Domain/DataExchange/ImportEnums.cs +++ b/src/Libraries/SmartStore.Core/Domain/DataExchange/ImportEnums.cs @@ -9,4 +9,10 @@ public enum ImportEntityType Customer, NewsLetterSubscription } + + public enum ImportFileType + { + CSV = 0, + XLSX + } } diff --git a/src/Libraries/SmartStore.Core/Domain/DataExchange/ImportProfile.cs b/src/Libraries/SmartStore.Core/Domain/DataExchange/ImportProfile.cs index 2654192757..73e94b5c72 100644 --- a/src/Libraries/SmartStore.Core/Domain/DataExchange/ImportProfile.cs +++ b/src/Libraries/SmartStore.Core/Domain/DataExchange/ImportProfile.cs @@ -16,9 +16,24 @@ public class ImportProfile : BaseEntity public string FolderName { get; set; } /// - /// The name of the initially uploaded import file + /// The identifier of the file type /// - public string FileName { get; set; } + public int FileTypeId { get; set; } + + /// + /// The file type + /// + public ImportFileType FileType + { + get + { + return (ImportFileType)FileTypeId; + } + set + { + FileTypeId = (int)value; + } + } /// /// The identifier of the entity type diff --git a/src/Libraries/SmartStore.Data/Mapping/DataExchange/ImportProfileMap.cs b/src/Libraries/SmartStore.Data/Mapping/DataExchange/ImportProfileMap.cs index 9b0efcac9d..4cb2485f9e 100644 --- a/src/Libraries/SmartStore.Data/Mapping/DataExchange/ImportProfileMap.cs +++ b/src/Libraries/SmartStore.Data/Mapping/DataExchange/ImportProfileMap.cs @@ -12,10 +12,10 @@ public ImportProfileMap() this.Property(x => x.Name).IsRequired().HasMaxLength(100); this.Property(x => x.FolderName).IsRequired().HasMaxLength(100); - this.Property(x => x.FileName).IsRequired().HasMaxLength(400); this.Property(x => x.FileTypeConfiguration).IsMaxLength(); this.Property(x => x.ColumnMapping).IsMaxLength(); + this.Ignore(x => x.FileType); this.Ignore(x => x.EntityType); this.HasRequired(x => x.ScheduleTask) diff --git a/src/Libraries/SmartStore.Data/Migrations/201512111134591_ImportFramework.resx b/src/Libraries/SmartStore.Data/Migrations/201512111134591_ImportFramework.resx deleted file mode 100644 index 1fea63c233..0000000000 --- a/src/Libraries/SmartStore.Data/Migrations/201512111134591_ImportFramework.resx +++ /dev/null @@ -1,126 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - text/microsoft-resx - - - 2.0 - - - System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - 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 - - - dbo - - \ No newline at end of file diff --git a/src/Libraries/SmartStore.Data/Migrations/201512111134591_ImportFramework.Designer.cs b/src/Libraries/SmartStore.Data/Migrations/201512151526290_ImportFramework.Designer.cs similarity index 92% rename from src/Libraries/SmartStore.Data/Migrations/201512111134591_ImportFramework.Designer.cs rename to src/Libraries/SmartStore.Data/Migrations/201512151526290_ImportFramework.Designer.cs index 1d43defd3f..a112acac53 100644 --- a/src/Libraries/SmartStore.Data/Migrations/201512111134591_ImportFramework.Designer.cs +++ b/src/Libraries/SmartStore.Data/Migrations/201512151526290_ImportFramework.Designer.cs @@ -13,7 +13,7 @@ public sealed partial class ImportFramework : IMigrationMetadata string IMigrationMetadata.Id { - get { return "201512111134591_ImportFramework"; } + get { return "201512151526290_ImportFramework"; } } string IMigrationMetadata.Source diff --git a/src/Libraries/SmartStore.Data/Migrations/201512111134591_ImportFramework.cs b/src/Libraries/SmartStore.Data/Migrations/201512151526290_ImportFramework.cs similarity index 92% rename from src/Libraries/SmartStore.Data/Migrations/201512111134591_ImportFramework.cs rename to src/Libraries/SmartStore.Data/Migrations/201512151526290_ImportFramework.cs index f31939779d..b2b7a42d00 100644 --- a/src/Libraries/SmartStore.Data/Migrations/201512111134591_ImportFramework.cs +++ b/src/Libraries/SmartStore.Data/Migrations/201512151526290_ImportFramework.cs @@ -16,7 +16,7 @@ public override void Up() Id = c.Int(nullable: false, identity: true), Name = c.String(nullable: false, maxLength: 100), FolderName = c.String(nullable: false, maxLength: 100), - FileName = c.String(nullable: false, maxLength: 400), + FileTypeId = c.Int(nullable: false), EntityTypeId = c.Int(nullable: false), Enabled = c.Boolean(nullable: false), Skip = c.Int(nullable: false), @@ -89,6 +89,12 @@ public void MigrateLocaleResources(LocaleResourcesBuilder builder) "Specifies the name of the import profile.", "Legt den Namen des Importprofils fest."); + builder.AddOrUpdate("Admin.DataExchange.Import.FileType", + "File type", + "Dateityp", + "The file type of the import file(s).", + "Der Dateityp der Importdatei(en)."); + builder.AddOrUpdate("Admin.DataExchange.Import.ProgressInfo", "{0} of {1} records processed", "{0} von {1} Datenstzen verarbeitet"); @@ -98,6 +104,9 @@ public void MigrateLocaleResources(LocaleResourcesBuilder builder) builder.AddOrUpdate("Enums.SmartStore.Core.Domain.DataExchange.ImportEntityType.Customer", "Customer", "Kunde"); builder.AddOrUpdate("Enums.SmartStore.Core.Domain.DataExchange.ImportEntityType.NewsLetterSubscription", "Newsletter Subscribers", "Newsletter Abonnenten"); + builder.AddOrUpdate("Enums.SmartStore.Core.Domain.DataExchange.ImportFileType.CSV", "Delimiter separated values (.csv)", "Trennzeichen getrennte Werte (.csv)"); + builder.AddOrUpdate("Enums.SmartStore.Core.Domain.DataExchange.ImportFileType.XLSX", "Excel (.xlsx)", "Excel (.xlsx)"); + builder.AddOrUpdate("Admin.DataExchange.Import.FileUpload", "Upload import file...", "Importdatei hochladen..."); diff --git a/src/Libraries/SmartStore.Data/Migrations/201512151526290_ImportFramework.resx b/src/Libraries/SmartStore.Data/Migrations/201512151526290_ImportFramework.resx new file mode 100644 index 0000000000..fa9e8cc53c --- /dev/null +++ b/src/Libraries/SmartStore.Data/Migrations/201512151526290_ImportFramework.resx @@ -0,0 +1,126 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 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 + + + dbo + + \ No newline at end of file diff --git a/src/Libraries/SmartStore.Data/SmartStore.Data.csproj b/src/Libraries/SmartStore.Data/SmartStore.Data.csproj index f58765ce75..afc16698c0 100644 --- a/src/Libraries/SmartStore.Data/SmartStore.Data.csproj +++ b/src/Libraries/SmartStore.Data/SmartStore.Data.csproj @@ -372,9 +372,9 @@ 201511271019577_ExportFramework3.cs - - - 201512111134591_ImportFramework.cs + + + 201512151526290_ImportFramework.cs @@ -699,8 +699,8 @@ 201511271019577_ExportFramework3.cs - - 201512111134591_ImportFramework.cs + + 201512151526290_ImportFramework.cs diff --git a/src/Libraries/SmartStore.Services/DataExchange/Import/ImportExtensions.cs b/src/Libraries/SmartStore.Services/DataExchange/Import/ImportExtensions.cs index 6e96b65fe1..89f576e47a 100644 --- a/src/Libraries/SmartStore.Services/DataExchange/Import/ImportExtensions.cs +++ b/src/Libraries/SmartStore.Services/DataExchange/Import/ImportExtensions.cs @@ -30,22 +30,16 @@ public static string GetImportFolder(this ImportProfile profile, bool content = /// List of file paths public static List GetImportFiles(this ImportProfile profile) { - var result = new List(); - var folder = profile.GetImportFolder(true); + var importFolder = profile.GetImportFolder(true); - if (System.IO.Directory.Exists(folder)) + if (System.IO.Directory.Exists(importFolder)) { - var initialImportFile = Path.Combine(folder, profile.FileName); - - result.Add(initialImportFile); - - result.AddRange(System.IO.Directory.EnumerateFiles(folder, "*", SearchOption.TopDirectoryOnly) - .Where(x => !x.IsCaseInsensitiveEqual(initialImportFile)) + return System.IO.Directory.EnumerateFiles(importFolder, "*", SearchOption.TopDirectoryOnly) .OrderBy(x => x) - .ToList()); + .ToList(); } - return result; + return new List(); } /// diff --git a/src/Libraries/SmartStore.Services/DataExchange/Import/ImportProfileService.cs b/src/Libraries/SmartStore.Services/DataExchange/Import/ImportProfileService.cs index 782d9509da..39c0ae708e 100644 --- a/src/Libraries/SmartStore.Services/DataExchange/Import/ImportProfileService.cs +++ b/src/Libraries/SmartStore.Services/DataExchange/Import/ImportProfileService.cs @@ -1,4 +1,5 @@ using System; +using System.IO; using System.Linq; using SmartStore.Core.Data; using SmartStore.Core.Domain; @@ -50,12 +51,16 @@ public virtual ImportProfile InsertImportProfile(string fileName, string name, I var profile = new ImportProfile { Name = name, - FileName = fileName, EntityType = entityType, Enabled = true, SchedulingTaskId = task.Id }; + if (Path.GetExtension(fileName).IsCaseInsensitiveEqual(".xlsx")) + profile.FileType = ImportFileType.XLSX; + else + profile.FileType = ImportFileType.CSV; + profile.FolderName = SeoHelper.GetSeName(name, true, false) .ToValidPath() .Truncate(_dataExchangeSettings.MaxFileNameLength); diff --git a/src/Presentation/SmartStore.Web/Administration/Controllers/ImportController.cs b/src/Presentation/SmartStore.Web/Administration/Controllers/ImportController.cs index 4d57685583..958680a2fa 100644 --- a/src/Presentation/SmartStore.Web/Administration/Controllers/ImportController.cs +++ b/src/Presentation/SmartStore.Web/Administration/Controllers/ImportController.cs @@ -49,11 +49,9 @@ private void PrepareProfileModel(ImportProfileModel model, ImportProfile profile { if (profile != null) { - var extension = Path.GetExtension(profile.FileName); - model.Id = profile.Id; model.Name = profile.Name; - model.FileName = profile.FileName; + model.FileType = profile.FileType; model.EntityType = profile.EntityType; model.Enabled = profile.Enabled; model.Skip = profile.Skip; @@ -69,7 +67,7 @@ private void PrepareProfileModel(ImportProfileModel model, ImportProfile profile .Select(x => Path.GetFileName(x)) .ToList(); - if (extension.IsCaseInsensitiveEqual(".csv")) + if (profile.FileType == ImportFileType.CSV || profile.FileType == ImportFileType.XLSX) { var converter = new CsvConfigurationConverter(); var config = converter.ConvertFrom(profile.FileTypeConfiguration); @@ -86,6 +84,7 @@ private void PrepareProfileModel(ImportProfileModel model, ImportProfile profile if (forEdit) { model.AvailableEntityTypes = ImportEntityType.Product.ToSelectList(false).ToList(); + model.AvailableFileTypes = ImportFileType.CSV.ToSelectList(false).ToList(); } } @@ -135,19 +134,19 @@ public ActionResult Create(ImportProfileModel model) if (!_services.Permissions.Authorize(StandardPermissionProvider.ManageImports)) return AccessDeniedView(); - var importFile = Path.Combine(FileSystemHelper.TempDir(), model.FileName); + var importFile = Path.Combine(FileSystemHelper.TempDir(), model.TempFileName.EmptyNull()); - if (model.FileName.IsEmpty() || !System.IO.File.Exists(importFile)) + if (!System.IO.File.Exists(importFile)) { ModelState.AddModelError("", T("Admin.DataExchange.Import.MissingImportFile")); } else if (ModelState.IsValid) { - var profile = _importService.InsertImportProfile(model.FileName, model.Name, model.EntityType); + var profile = _importService.InsertImportProfile(model.TempFileName, model.Name, model.EntityType); if (profile != null && profile.Id != 0) { - var importFileDestination = Path.Combine(profile.GetImportFolder(true, true), model.FileName); + var importFileDestination = Path.Combine(profile.GetImportFolder(true, true), model.TempFileName); FileSystemHelper.Copy(importFile, importFileDestination, true, true); @@ -187,15 +186,13 @@ public ActionResult Edit(ImportProfileModel model, bool continueEditing, FormCol if (ModelState.IsValid) { - var extension = Path.GetExtension(profile.FileName); - profile.Name = model.Name; profile.EntityType = model.EntityType; profile.Enabled = model.Enabled; profile.Skip = model.Skip; profile.Take = model.Take; - if (extension.IsCaseInsensitiveEqual(".csv") && model.CsvConfiguration != null) + if (profile.FileType == ImportFileType.CSV || profile.FileType == ImportFileType.XLSX) { CsvConfiguration config = model.CsvConfiguration.Clone(); @@ -268,27 +265,27 @@ public JsonResult FileUpload(int id) var profile = _importService.GetImportProfileById(id); if (profile != null) { - var extension = Path.GetExtension(profile.FileName); - - if (postedFile.FileExtension.IsCaseInsensitiveEqual(extension)) - { - var folder = profile.GetImportFolder(true, true); - var destFile = Path.Combine(folder, Path.GetFileName(postedFile.FileName)); - - success = postedFile.Stream.ToFile(destFile); - - if (success) - { - var model = new ImportProfileModel(); - PrepareProfileModel(model, profile, false); - - fileList = this.RenderPartialViewToString("_ImportFileList", model); - } - } - else - { - NotifyError(T("Admin.Common.FileTypeMustEqual", extension.Substring(1).ToUpper())); - } + //var extension = Path.GetExtension(profile.FileType); + + //if (postedFile.FileExtension.IsCaseInsensitiveEqual(extension)) + //{ + // var folder = profile.GetImportFolder(true, true); + // var destFile = Path.Combine(folder, Path.GetFileName(postedFile.FileName)); + + // success = postedFile.Stream.ToFile(destFile); + + // if (success) + // { + // var model = new ImportProfileModel(); + // PrepareProfileModel(model, profile, false); + + // fileList = this.RenderPartialViewToString("_ImportFileList", model); + // } + //} + //else + //{ + // NotifyError(T("Admin.Common.FileTypeMustEqual", extension.Substring(1).ToUpper())); + //} } } } diff --git a/src/Presentation/SmartStore.Web/Administration/Models/DataExchange/ImportProfileModel.cs b/src/Presentation/SmartStore.Web/Administration/Models/DataExchange/ImportProfileModel.cs index 0190256589..76cc11caff 100644 --- a/src/Presentation/SmartStore.Web/Administration/Models/DataExchange/ImportProfileModel.cs +++ b/src/Presentation/SmartStore.Web/Administration/Models/DataExchange/ImportProfileModel.cs @@ -15,7 +15,9 @@ public partial class ImportProfileModel : EntityModelBase [SmartResourceDisplayName("Admin.DataExchange.Import.Name")] public string Name { get; set; } - public string FileName { get; set; } + [SmartResourceDisplayName("Admin.DataExchange.Import.FileType")] + public ImportFileType FileType { get; set; } + public List AvailableFileTypes { get; set; } [SmartResourceDisplayName("Admin.Common.ImportFiles")] public List ExistingFileNames { get; set; } @@ -42,6 +44,7 @@ public partial class ImportProfileModel : EntityModelBase public ScheduleTaskModel TaskModel { get; set; } public bool LogFileExists { get; set; } + public string TempFileName { get; set; } public CsvConfigurationModel CsvConfiguration { get; set; } } diff --git a/src/Presentation/SmartStore.Web/Administration/Views/Import/_CreateOrUpdate.cshtml b/src/Presentation/SmartStore.Web/Administration/Views/Import/_CreateOrUpdate.cshtml index e1bc7577bc..59d92a5c9d 100644 --- a/src/Presentation/SmartStore.Web/Administration/Views/Import/_CreateOrUpdate.cshtml +++ b/src/Presentation/SmartStore.Web/Administration/Views/Import/_CreateOrUpdate.cshtml @@ -7,7 +7,7 @@ @Html.ValidationSummary(false) @Html.HiddenFor(model => model.Id) -@Html.HiddenFor(model => model.FileName) +@Html.HiddenFor(model => model.TempFileName) @@ -80,6 +80,15 @@ @if (Model.Id != 0) { + + + +
    + @Html.SmartLabelFor(x => x.FileType) + + @Html.DropDownListFor(x => x.FileType, Model.AvailableFileTypes) + @Html.ValidationMessageFor(x => x.FileType) +
    @Html.SmartLabelFor(x => x.Enabled) @@ -132,7 +141,7 @@ $('#ImportFileListContainer').show(); if (!_.isEmpty(data.result.tempFile)) { - $('input[name=FileName]').val(data.result.tempFile); + $('input[name=TempFileName]').val(data.result.tempFile); $('#ImportFileList').html(data.result.tempFile); $('#ImportFileUploadContainer').hide(); // just one initial file to specify the file type } diff --git a/src/Presentation/SmartStore.Web/Administration/Views/Import/_ImportFileList.cshtml b/src/Presentation/SmartStore.Web/Administration/Views/Import/_ImportFileList.cshtml index d624b86fdb..be0f5d9703 100644 --- a/src/Presentation/SmartStore.Web/Administration/Views/Import/_ImportFileList.cshtml +++ b/src/Presentation/SmartStore.Web/Administration/Views/Import/_ImportFileList.cshtml @@ -6,11 +6,8 @@ @Html.IconForFileExtension(Path.GetExtension(fileName), false) @fileName - @if(!fileName.IsCaseInsensitiveEqual(Model.FileName)) - { - - } +

    } \ No newline at end of file From 5b4354222c00d1329bcfae9078e96fc380dffaeb Mon Sep 17 00:00:00 2001 From: Marcus Gesing Date: Tue, 15 Dec 2015 17:54:28 +0100 Subject: [PATCH 169/707] Updated web.config. Mime type mapping for woff2 required. --- src/Presentation/SmartStore.Web/Web.config | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Presentation/SmartStore.Web/Web.config b/src/Presentation/SmartStore.Web/Web.config index c1470f69a4..9e60aa9751 100644 --- a/src/Presentation/SmartStore.Web/Web.config +++ b/src/Presentation/SmartStore.Web/Web.config @@ -170,6 +170,7 @@ + From 7971fbc90b91ccd170e88b674639f19ce4921c94 Mon Sep 17 00:00:00 2001 From: Marcus Gesing Date: Tue, 15 Dec 2015 17:54:28 +0100 Subject: [PATCH 170/707] Updated web.config. Mime type mapping for woff2 required. --- src/Presentation/SmartStore.Web/Web.config | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Presentation/SmartStore.Web/Web.config b/src/Presentation/SmartStore.Web/Web.config index c1470f69a4..9e60aa9751 100644 --- a/src/Presentation/SmartStore.Web/Web.config +++ b/src/Presentation/SmartStore.Web/Web.config @@ -170,6 +170,7 @@ + From aa1e6717a394eb63a9ac5ce5d1791c81b6b73399 Mon Sep 17 00:00:00 2001 From: Marcus Gesing Date: Tue, 15 Dec 2015 21:04:18 +0100 Subject: [PATCH 171/707] Removed obsolete Excel import button. Products are now imported through import profiles. --- .../201512151526290_ImportFramework.cs | 15 +- .../Controllers/ProductController.cs | 158 +---------------- .../Administration/Views/Product/List.cshtml | 161 +----------------- 3 files changed, 16 insertions(+), 318 deletions(-) diff --git a/src/Libraries/SmartStore.Data/Migrations/201512151526290_ImportFramework.cs b/src/Libraries/SmartStore.Data/Migrations/201512151526290_ImportFramework.cs index b2b7a42d00..2bc57f326a 100644 --- a/src/Libraries/SmartStore.Data/Migrations/201512151526290_ImportFramework.cs +++ b/src/Libraries/SmartStore.Data/Migrations/201512151526290_ImportFramework.cs @@ -178,7 +178,20 @@ public void MigrateLocaleResources(LocaleResourcesBuilder builder) "Admin.DataExchange.Export.Limit", "Admin.Promotions.NewsLetterSubscriptions.ImportEmailsSuccess", "Admin.Common.ImportFromCsv", - "Admin.Common.CsvFile" + "Admin.Common.CsvFile", + + "Admin.Common.ImportFromExcel", + "Admin.Common.ExcelFile", + "Admin.Common.ImportFromExcel.InProgress", + "Admin.Common.ImportFromExcel.LastResultTitle", + "Admin.Common.ImportFromExcel.ProcessedCount", + "Admin.Common.ImportFromExcel.QuickStats", + "Admin.Common.ImportFromExcel.ActiveSince", + "Admin.Common.ImportFromExcel.CancelPrompt", + "Admin.Common.ImportFromExcel.Cancel", + "Admin.Common.ImportFromExcel.Cancelled", + "Admin.Common.ImportFromExcel.DownloadReport", + "Admin.Common.ImportFromExcel.NoReportAvailable" ); } } diff --git a/src/Presentation/SmartStore.Web/Administration/Controllers/ProductController.cs b/src/Presentation/SmartStore.Web/Administration/Controllers/ProductController.cs index d677730a02..8270ea5cdb 100644 --- a/src/Presentation/SmartStore.Web/Administration/Controllers/ProductController.cs +++ b/src/Presentation/SmartStore.Web/Administration/Controllers/ProductController.cs @@ -3,16 +3,12 @@ using System.ComponentModel; using System.Data; using System.Linq; -using System.Text; -using System.Threading; -using System.Threading.Tasks; using System.Web.Mvc; using Autofac; using Newtonsoft.Json; using SmartStore.Admin.Models.Catalog; using SmartStore.Collections; using SmartStore.Core; -using SmartStore.Core.Async; using SmartStore.Core.Data; using SmartStore.Core.Domain.Catalog; using SmartStore.Core.Domain.Common; @@ -22,7 +18,6 @@ using SmartStore.Core.Domain.Orders; using SmartStore.Core.Domain.Seo; using SmartStore.Core.Events; -using SmartStore.Core.Infrastructure; using SmartStore.Core.Logging; using SmartStore.Services; using SmartStore.Services.Catalog; @@ -41,10 +36,10 @@ using SmartStore.Services.Tax; using SmartStore.Web.Framework; using SmartStore.Web.Framework.Controllers; -using Telerik.Web.Mvc; using SmartStore.Web.Framework.Filters; using SmartStore.Web.Framework.Modelling; using SmartStore.Web.Framework.Security; +using Telerik.Web.Mvc; namespace SmartStore.Admin.Controllers { @@ -2793,157 +2788,6 @@ public ActionResult EditProductTag(string btnId, string formId, ProductTagModel #endregion - #region Import - - [HttpPost] - public ActionResult ImportExcel(FormCollection form) - { - if (!_permissionService.Authorize(StandardPermissionProvider.ManageCatalog)) - return AccessDeniedView(); - - try - { - var file = Request.Files["importfile"]; - if (file != null) - { - IDataTable table = null; - - try - { - table = LightweightDataTable.FromPostedFile(file); - } - catch (Exception ex) - { - NotifyError(ex); - return RedirectToAction("List"); - } - - var options = TaskCreationOptions.LongRunning; - var cts = new CancellationTokenSource(); - var scheduler = TaskScheduler.Default; - - var task = AsyncRunner.Run((c, ct) => - { - var progress = new Progress(p => - { - AsyncState.Current.Set(p); - }); - - try - { - AsyncState.Current.SetCancelTokenSource(cts); - var importManager = c.Resolve(); - var result = importManager.ImportProducts(table, ct, progress); - - // Saving the result enables us to show a report for last import. - AsyncState.Current.Set(result, neverExpires: true); - } - catch (AggregateException ae) - { - foreach (var e in ae.Flatten().InnerExceptions) - { - // TBD: do exactly WHAT now?! Logging? Nothing? - // [...] - } - } - finally - { - AsyncState.Current.Remove(); - } - - }, cts.Token, options, scheduler); - - task.Wait(500); - } - else - { - NotifyError(T("Admin.Common.UploadFile")); - return RedirectToAction("List"); - } - - NotifySuccess(T("Admin.Common.ImportFromExcel.InProgress")); - return RedirectToAction("List"); - } - catch (Exception exc) - { - NotifyError(exc); - return RedirectToAction("List"); - } - } - - [HttpPost] - public ActionResult ImportExcelProgress() - { - var progress = AsyncState.Current.Get(); - - //object lastResult = null; - string lastResultSummary = null; - string lastResultClass = ""; - var result = AsyncState.Current.Get(); - if (result != null) - { - var title = _localizationService.GetResource("Admin.Common.ImportFromExcel.LastResultTitle").FormatCurrent( - result.EndDateUtc.ToLocalTime(), - result.Cancelled ? " (" + _localizationService.GetResource("Common.Cancelled").ToLower() + ")" : ""); - var counts = _localizationService.GetResource("Admin.Common.ImportFromExcel.ProcessedCount").FormatCurrent( - result.AffectedRecords, - result.TotalRecords); - var stats = _localizationService.GetResource("Admin.Common.ImportFromExcel.QuickStats").FormatCurrent( - result.NewRecords, - result.ModifiedRecords, - result.Messages.Count(x => x.MessageType == ImportMessageType.Warning), - result.Messages.Count(x => x.MessageType == ImportMessageType.Error)); - - lastResultSummary = "{0} {1} {2}".FormatInvariant(title, counts, stats); - - if (!result.Cancelled) - { - lastResultClass = result.HasErrors ? "alert-error" : "alert-success"; - } - } - - if (progress == null) - { - return Json(new { NoRunningTask = true, LastResultSummary = lastResultSummary, LastResultClass = lastResultClass }, JsonRequestBehavior.DenyGet); - } - - return Json(new { Progress = progress, LastResultSummary = lastResultSummary, LastResultClass = lastResultClass }, JsonRequestBehavior.DenyGet); - } - - public ActionResult ImportExcelCancel() - { - if (!_permissionService.Authorize(StandardPermissionProvider.ManageCatalog)) - return AccessDeniedView(); - - var tcs = AsyncState.Current.GetCancelTokenSource(); - if (tcs != null) - { - tcs.Cancel(); - NotifySuccess(_localizationService.GetResource("Admin.Common.ImportFromExcel.Cancelled")); - } - - return RedirectToAction("List"); - } - - public ActionResult ImportExcelDownloadReport() - { - if (!_permissionService.Authorize(StandardPermissionProvider.ManageCatalog)) - return AccessDeniedView(); - - var result = AsyncState.Current.Get(); - if (result == null) - { - return Content(_localizationService.GetResource("Admin.Common.ImportFromExcel.NoReportAvailable")); - } - - var importManager = EngineContext.Current.Resolve(); - string report = importManager.CreateTextReport(result); - - return File(Encoding.UTF8.GetBytes(report), "text/plain", "excelimport-report-{0}.txt".FormatInvariant(result.StartDateUtc.ToLocalTime())); - } - - #endregion - #region Low stock reports public ActionResult LowStockReport() diff --git a/src/Presentation/SmartStore.Web/Administration/Views/Product/List.cshtml b/src/Presentation/SmartStore.Web/Administration/Views/Product/List.cshtml index 3c268ef816..feb7fe9c84 100644 --- a/src/Presentation/SmartStore.Web/Administration/Views/Product/List.cshtml +++ b/src/Presentation/SmartStore.Web/Administration/Views/Product/List.cshtml @@ -1,7 +1,6 @@ @model ProductListModel @using Telerik.Web.Mvc.UI @{ - var trueTemplate = "#if (Published) {# #} #"; var allString = T("Admin.Common.All").Text; ViewBag.Title = T("Admin.Catalog.Products.Manage").Text; @@ -24,10 +23,6 @@  @T("Admin.Common.Delete.Selected") - -  @T("Admin.Common.ImportFromExcel") - - @Html.Widget("admin_button_toolbar_after") @@ -311,158 +306,4 @@ $('#mastercheckbox').attr('checked', numChkBoxes == numChkBoxesChecked && numChkBoxes > 0); } -} -@*import products form*@ -@{Html.SmartStore().Window() - .Name("importexcel-window") - .Title(T("Admin.Common.ImportFromExcel").Text) - .Content(@ - @using (Html.BeginForm("ImportExcel", "Product", FormMethod.Post, new { enctype = "multipart/form-data", @class = "form-horizontal" })) - { -
    - -
    - -
    - -
    - -
    -
    - -
    -
    -
    -
    -
    - @Html.Raw(T("Admin.Common.ImportFromExcel.ProcessedCount").ToString().FormatInvariant("0", "0")) - @Html.Raw(T("Admin.Common.ImportFromExcel.ActiveSince").ToString().FormatCurrent("")) -
    -
    - @(Html.Raw(T("Admin.Common.ImportFromExcel.QuickStats").ToString().FormatInvariant( - "0", - "0", - "0", - "0"))) -
    -
    - } - -
    ) - .FooterContent(@ - - @T("Common.Close") - ) - .Modal(true) - .Visible(false) - .Render(); -} - - +} \ No newline at end of file From 5b691da05810e2800bf2f4d4814abf55f7294202 Mon Sep 17 00:00:00 2001 From: Murat Cakir Date: Wed, 16 Dec 2015 17:38:47 +0100 Subject: [PATCH 172/707] A new mime type entry in web.config should be removed first --- src/Presentation/SmartStore.Web/Web.config | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Presentation/SmartStore.Web/Web.config b/src/Presentation/SmartStore.Web/Web.config index 9e60aa9751..cd1115ffa2 100644 --- a/src/Presentation/SmartStore.Web/Web.config +++ b/src/Presentation/SmartStore.Web/Web.config @@ -164,13 +164,14 @@ + - + From 1696f4d00fe425c2997eae15120bac6eea6e66b3 Mon Sep 17 00:00:00 2001 From: Marcus Gesing Date: Wed, 16 Dec 2015 17:43:09 +0100 Subject: [PATCH 173/707] Added customer importer --- changelog.md | 1 + .../Common/GenericAttributeService.cs | 79 +++-- .../Common/IGenericAttributeService.cs | 13 +- .../Customers/Importer/CustomerImporter.cs | 333 ++++++++++++++++++ .../DataExchange/ExportXmlHelper.cs | 2 + .../DataExchange/Import/DataImporter.cs | 57 ++- .../DataExchange/Import/IEntityImporter.cs | 7 +- .../Import/Internal/DataImporterContext.cs | 6 +- .../Directory/IStateProvinceService.cs | 20 +- .../Directory/StateProvinceService.cs | 31 +- .../NewsLetterSubscriptionImporter.cs | 1 - .../SmartStore.Services.csproj | 1 + .../Controllers/ImportController.cs | 53 +-- 13 files changed, 509 insertions(+), 95 deletions(-) create mode 100644 src/Libraries/SmartStore.Services/Customers/Importer/CustomerImporter.cs diff --git a/changelog.md b/changelog.md index 4f370dcf36..1c11d670f2 100644 --- a/changelog.md +++ b/changelog.md @@ -28,6 +28,7 @@ * #722 System > SEO Names: Implement editing of an UrlRecord * Admin > System > System Info shows used application memory (RAM) * Added option to make VATIN mandatory during customer registration +* Customer import ### Improvements * (Perf) Implemented static caches for URL aliases and localized properties. Increases app startup and request speed by up to 30%. diff --git a/src/Libraries/SmartStore.Services/Common/GenericAttributeService.cs b/src/Libraries/SmartStore.Services/Common/GenericAttributeService.cs index 4c73f2e7ed..d57222a18a 100644 --- a/src/Libraries/SmartStore.Services/Common/GenericAttributeService.cs +++ b/src/Libraries/SmartStore.Services/Common/GenericAttributeService.cs @@ -209,49 +209,54 @@ public virtual void SaveAttribute(BaseEntity entity, string key, TPro if (entity == null) throw new ArgumentNullException("entity"); - string keyGroup = entity.GetUnproxiedEntityType().Name; + SaveAttribute(entity.Id, key, entity.GetUnproxiedEntityType().Name, value, storeId); + } + + public virtual void SaveAttribute(int entityId, string key, string keyGroup, TPropType value, int storeId = 0) + { + Guard.ArgumentNotZero(entityId, "entityId"); - var props = GetAttributesForEntity(entity.Id, keyGroup) + var props = GetAttributesForEntity(entityId, keyGroup) .Where(x => x.StoreId == storeId) .ToList(); - var prop = props.FirstOrDefault(ga => - ga.Key.Equals(key, StringComparison.InvariantCultureIgnoreCase)); // should be culture invariant + var prop = props.FirstOrDefault(ga => + ga.Key.Equals(key, StringComparison.InvariantCultureIgnoreCase)); // should be culture invariant - string valueStr = value.Convert(); + string valueStr = value.Convert(); - if (prop != null) - { - if (string.IsNullOrWhiteSpace(valueStr)) - { - //delete - DeleteAttribute(prop); - } - else - { - //update - prop.Value = valueStr; - UpdateAttribute(prop); - } - } - else - { - if (!string.IsNullOrWhiteSpace(valueStr)) - { - //insert - prop = new GenericAttribute() - { - EntityId = entity.Id, - Key = key, - KeyGroup = keyGroup, - Value = valueStr, + if (prop != null) + { + if (string.IsNullOrWhiteSpace(valueStr)) + { + //delete + DeleteAttribute(prop); + } + else + { + //update + prop.Value = valueStr; + UpdateAttribute(prop); + } + } + else + { + if (!string.IsNullOrWhiteSpace(valueStr)) + { + //insert + prop = new GenericAttribute + { + EntityId = entityId, + Key = key, + KeyGroup = keyGroup, + Value = valueStr, StoreId = storeId - }; - InsertAttribute(prop); - } - } - } + }; + InsertAttribute(prop); + } + } + } - #endregion - } + #endregion + } } \ No newline at end of file diff --git a/src/Libraries/SmartStore.Services/Common/IGenericAttributeService.cs b/src/Libraries/SmartStore.Services/Common/IGenericAttributeService.cs index cb837a6f74..c584c4ad4c 100644 --- a/src/Libraries/SmartStore.Services/Common/IGenericAttributeService.cs +++ b/src/Libraries/SmartStore.Services/Common/IGenericAttributeService.cs @@ -69,5 +69,16 @@ public partial interface IGenericAttributeService /// Value /// Store identifier; pass 0 if this attribute will be available for all stores void SaveAttribute(BaseEntity entity, string key, TPropType value, int storeId = 0); - } + + /// + /// Save attribute value + /// + /// Property type + /// Entity identifier + /// The key + /// The key group + /// Property type + /// Store identifier; pass 0 if this attribute will be available for all stores + void SaveAttribute(int entityId, string key, string keyGroup, TPropType value, int storeId = 0); + } } \ No newline at end of file diff --git a/src/Libraries/SmartStore.Services/Customers/Importer/CustomerImporter.cs b/src/Libraries/SmartStore.Services/Customers/Importer/CustomerImporter.cs new file mode 100644 index 0000000000..c5204fe8aa --- /dev/null +++ b/src/Libraries/SmartStore.Services/Customers/Importer/CustomerImporter.cs @@ -0,0 +1,333 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using SmartStore.Core.Data; +using SmartStore.Core.Domain.Customers; +using SmartStore.Core.Domain.DataExchange; +using SmartStore.Core.Domain.Forums; +using SmartStore.Core.Events; +using SmartStore.Services.Affiliates; +using SmartStore.Services.Common; +using SmartStore.Services.DataExchange.Import; +using SmartStore.Services.Directory; +using SmartStore.Services.Helpers; +using SmartStore.Services.Security; + +namespace SmartStore.Services.Customers.Importer +{ + public class CustomerImporter : IEntityImporter + { + private const string _attributeKeyGroup = "Customer"; + + private readonly ICommonServices _services; + private readonly IRepository _customerRepository; + private readonly IGenericAttributeService _genericAttributeService; + private readonly ICustomerService _customerService; + private readonly IAffiliateService _affiliateService; + private readonly ICountryService _countryService; + private readonly IStateProvinceService _stateProvinceService; + private readonly CustomerSettings _customerSettings; + private readonly DateTimeSettings _dateTimeSettings; + private readonly ForumSettings _forumSettings; + + public CustomerImporter( + ICommonServices services, + IRepository customerRepository, + IGenericAttributeService genericAttributeService, + ICustomerService customerService, + IAffiliateService affiliateService, + ICountryService countryService, + IStateProvinceService stateProvinceService, + CustomerSettings customerSettings, + DateTimeSettings dateTimeSettings, + ForumSettings forumSettings) + { + _services = services; + _customerRepository = customerRepository; + _genericAttributeService = genericAttributeService; + _customerService = customerService; + _affiliateService = affiliateService; + _countryService = countryService; + _stateProvinceService = stateProvinceService; + _customerSettings = customerSettings; + _dateTimeSettings = dateTimeSettings; + _forumSettings = forumSettings; + } + + private void SaveAttribute(ImportRow row, string key) + { + _genericAttributeService.SaveAttribute(row.Entity.Id, key, _attributeKeyGroup, row.GetDataValue(key)); + } + + private void UpsertRole(ImportRow row, CustomerRole role, string roleSystemName, bool value) + { + if (role != null) + { + var hasRole = row.Entity.CustomerRoles.Any(x => x.SystemName == roleSystemName); + + if (value && !hasRole) + row.Entity.CustomerRoles.Add(role); + else if (!value && hasRole) + row.Entity.CustomerRoles.Remove(role); + } + } + + private int ProcessGenericAttributes(ImportExecuteContext context, + ImportRow[] batch, + List allCountryIds, + List allStateProvinceIds, + List allCustomerNumbers) + { + foreach (var row in batch) + { + SaveAttribute(row, SystemCustomerAttributeNames.FirstName); + SaveAttribute(row, SystemCustomerAttributeNames.LastName); + + if (_dateTimeSettings.AllowCustomersToSetTimeZone) + SaveAttribute(row, SystemCustomerAttributeNames.TimeZoneId); + + if (_customerSettings.GenderEnabled) + SaveAttribute(row, SystemCustomerAttributeNames.Gender); + + if (_customerSettings.DateOfBirthEnabled) + SaveAttribute(row, SystemCustomerAttributeNames.DateOfBirth); + + if (_customerSettings.CompanyEnabled) + SaveAttribute(row, SystemCustomerAttributeNames.Company); + + if (_customerSettings.StreetAddressEnabled) + SaveAttribute(row, SystemCustomerAttributeNames.StreetAddress); + + if (_customerSettings.StreetAddress2Enabled) + SaveAttribute(row, SystemCustomerAttributeNames.StreetAddress2); + + if (_customerSettings.ZipPostalCodeEnabled) + SaveAttribute(row, SystemCustomerAttributeNames.ZipPostalCode); + + if (_customerSettings.CityEnabled) + SaveAttribute(row, SystemCustomerAttributeNames.City); + + if (_customerSettings.CountryEnabled) + SaveAttribute(row, SystemCustomerAttributeNames.CountryId); + + if (_customerSettings.CountryEnabled && _customerSettings.StateProvinceEnabled) + SaveAttribute(row, SystemCustomerAttributeNames.StateProvinceId); + + if (_customerSettings.PhoneEnabled) + SaveAttribute(row, SystemCustomerAttributeNames.Phone); + + if (_customerSettings.FaxEnabled) + SaveAttribute(row, SystemCustomerAttributeNames.Fax); + + if (_customerSettings.AllowCustomersToUploadAvatars) + SaveAttribute(row, SystemCustomerAttributeNames.AvatarPictureId); + + if (_forumSettings.ForumsEnabled) + SaveAttribute(row, SystemCustomerAttributeNames.ForumPostCount); + + if (_forumSettings.SignaturesEnabled) + SaveAttribute(row, SystemCustomerAttributeNames.Signature); + + var countryId = row.GetDataValue("CountryId"); + var stateProvinceId = row.GetDataValue("StateProvinceId"); + + if (countryId != 0 && allCountryIds.Contains(countryId)) + { + _genericAttributeService.SaveAttribute(row.Entity.Id, SystemCustomerAttributeNames.CountryId, _attributeKeyGroup, countryId); + } + + if (stateProvinceId != 0 && allStateProvinceIds.Contains(stateProvinceId)) + { + _genericAttributeService.SaveAttribute(row.Entity.Id, SystemCustomerAttributeNames.StateProvinceId, _attributeKeyGroup, stateProvinceId); + } + + string customerNumber = null; + + if (_customerSettings.CustomerNumberMethod == CustomerNumberMethod.AutomaticallySet) + customerNumber = row.Entity.Id.ToString(); + else + customerNumber = row.GetDataValue("CustomerNumber"); + + if (customerNumber.IsEmpty() || !allCustomerNumbers.Any(x => x.IsCaseInsensitiveEqual(customerNumber))) + { + _genericAttributeService.SaveAttribute(row.Entity.Id, SystemCustomerAttributeNames.CustomerNumber, _attributeKeyGroup, customerNumber); + + if (!customerNumber.IsEmpty()) + allCustomerNumbers.Add(customerNumber); + } + } + + var num = _customerRepository.Context.SaveChanges(); + + return num; + } + + private int ProcessCustomers(ImportExecuteContext context, + ImportRow[] batch, + DateTime utcNow, + List allAffiliateIds, + IList allCustomerRoles) + { + _customerRepository.AutoCommitEnabled = true; + + Customer lastInserted = null; + Customer lastUpdated = null; + + var guestRole = allCustomerRoles.FirstOrDefault(x => x.SystemName == SystemCustomerRoleNames.Guests); + var registeredRole = allCustomerRoles.FirstOrDefault(x => x.SystemName == SystemCustomerRoleNames.Registered); + var adminRole = allCustomerRoles.FirstOrDefault(x => x.SystemName == SystemCustomerRoleNames.Administrators); + var forumModeratorRole = allCustomerRoles.FirstOrDefault(x => x.SystemName == SystemCustomerRoleNames.ForumModerators); + + foreach (var row in batch) + { + object key; + var customerId = 0; + Customer customer = null; + + if (row.DataRow.TryGetValue("Id", out key) && key.ToString().ToInt() > 0) + { + customerId = key.ToString().ToInt(); + customer = _customerService.GetCustomerById(customerId); + } + + if (customer == null && row.DataRow.TryGetValue("CustomerGuid", out key)) + { + customer = _customerService.GetCustomerByGuid(new Guid(key.ToString())); + } + + if (customer == null) + { + customer = new Customer(); + } + else + { + _customerRepository.Context.LoadCollection(customer, (Customer x) => x.CustomerRoles); + } + + var email = row.GetDataValue("Email"); + var affiliateId = row.GetDataValue("AffiliateId"); + var isGuest = row.GetDataValue("IsGuest"); + var isRegistered = row.GetDataValue("IsRegistered"); + var isAdmin = row.GetDataValue("IsAdministrator"); + var isForumModerator = row.GetDataValue("IsForumModerator"); + + row.Initialize(customer, email.HasValue() ? email : customerId.ToString()); + + row.SetProperty(context.Result, customer, (x) => x.CustomerGuid); + row.SetProperty(context.Result, customer, (x) => x.Username); + row.SetProperty(context.Result, customer, (x) => x.Email); + row.SetProperty(context.Result, customer, (x) => x.Password); + row.SetProperty(context.Result, customer, (x) => x.PasswordFormatId); + row.SetProperty(context.Result, customer, (x) => x.PasswordSalt); + row.SetProperty(context.Result, customer, (x) => x.AdminComment); + row.SetProperty(context.Result, customer, (x) => x.IsTaxExempt); + row.SetProperty(context.Result, customer, (x) => x.Active); + row.SetProperty(context.Result, customer, (x) => x.IsSystemAccount); + row.SetProperty(context.Result, customer, (x) => x.SystemName); + row.SetProperty(context.Result, customer, (x) => x.LastIpAddress); + row.SetProperty(context.Result, customer, (x) => x.LastLoginDateUtc); + row.SetProperty(context.Result, customer, (x) => x.LastActivityDateUtc); + + row.SetProperty(context.Result, customer, (x) => x.CreatedOnUtc, utcNow); + row.SetProperty(context.Result, customer, (x) => x.LastActivityDateUtc, utcNow); + + if (affiliateId != 0 && allAffiliateIds.Contains(affiliateId)) + { + row.SetProperty(context.Result, customer, (x) => x.AffiliateId, affiliateId); + } + + UpsertRole(row, guestRole, SystemCustomerRoleNames.Guests, isGuest); + UpsertRole(row, registeredRole, SystemCustomerRoleNames.Registered, isRegistered); + UpsertRole(row, adminRole, SystemCustomerRoleNames.Administrators, isAdmin); + UpsertRole(row, forumModeratorRole, SystemCustomerRoleNames.ForumModerators, isForumModerator); + + if (row.IsTransient) + { + _customerRepository.Insert(customer); + lastInserted = customer; + } + else + { + _customerRepository.Update(customer); + lastUpdated = customer; + } + } + + var num = _customerRepository.Context.SaveChanges(); + + if (lastInserted != null) + _services.EventPublisher.EntityInserted(lastInserted); + if (lastUpdated != null) + _services.EventPublisher.EntityUpdated(lastUpdated); + + return num; + } + + public void Execute(ImportExecuteContext context) + { + var utcNow = DateTime.UtcNow; + var customer = _customerService.GetCustomerById(context.CustomerId); + var allowManagingCustomerRoles = _services.Permissions.Authorize(StandardPermissionProvider.ManageCustomerRoles, customer); + + var allCustomerRoles = _customerService.GetAllCustomerRoles(true); + + var allAffiliateIds = _affiliateService.GetAllAffiliates(true) + .Select(x => x.Id) + .ToList(); + + var allCountryIds = _countryService.GetAllCountries(true) + .Select(x => x.Id) + .ToList(); + + var allStateProvinceIds = _stateProvinceService.GetAllStateProvinces(true) + .Select(x => x.Id) + .ToList(); + + var allCustomerNumbers = _genericAttributeService.GetAttributes(SystemCustomerAttributeNames.CustomerNumber, _attributeKeyGroup) + .Select(x => x.Value) + .ToList(); + + using (var scope = new DbContextScope(ctx: _services.DbContext, autoDetectChanges: false, proxyCreation: false, validateOnSave: false, autoCommit: false)) + { + var segmenter = new ImportDataSegmenter(context.DataTable); + + context.Result.TotalRecords = segmenter.TotalRows; + + while (context.Abort == DataExchangeAbortion.None && segmenter.ReadNextBatch()) + { + var batch = segmenter.CurrentBatch; + + _customerRepository.Context.DetachAll(false); + + context.SetProgress(segmenter.CurrentSegmentFirstRowIndex - 1, segmenter.TotalRows); + + try + { + ProcessCustomers(context, batch, utcNow, allAffiliateIds, allCustomerRoles); + } + catch (Exception exception) + { + context.Result.AddError(exception, segmenter.CurrentSegment, "ProcessCustomers"); + } + + // reduce batch to saved (valid) records. + // No need to perform import operations on errored records. + batch = batch.Where(x => x.Entity != null && !x.IsTransient).ToArray(); + + // update result object + context.Result.NewRecords += batch.Count(x => x.IsNew && !x.IsTransient); + context.Result.ModifiedRecords += batch.Count(x => !x.IsNew && !x.IsTransient); + + try + { + ProcessGenericAttributes(context, batch, allCountryIds, allStateProvinceIds, allCustomerNumbers); + } + catch (Exception exception) + { + context.Result.AddError(exception, segmenter.CurrentSegment, "ProcessGenericAttributes"); + } + } + } + } + } +} diff --git a/src/Libraries/SmartStore.Services/DataExchange/ExportXmlHelper.cs b/src/Libraries/SmartStore.Services/DataExchange/ExportXmlHelper.cs index 425ac57265..6f84b5f064 100644 --- a/src/Libraries/SmartStore.Services/DataExchange/ExportXmlHelper.cs +++ b/src/Libraries/SmartStore.Services/DataExchange/ExportXmlHelper.cs @@ -838,7 +838,9 @@ public void WriteCustomer(dynamic customer, string node) _writer.Write("CustomerGuid", entity.CustomerGuid.ToString()); _writer.Write("Username", entity.Username); _writer.Write("Email", entity.Email); + _writer.Write("Password", entity.Password); _writer.Write("PasswordFormatId", entity.PasswordFormatId.ToString()); + _writer.Write("PasswordSalt", entity.PasswordSalt); _writer.Write("AdminComment", entity.AdminComment); _writer.Write("IsTaxExempt", entity.IsTaxExempt.ToString()); _writer.Write("AffiliateId", entity.AffiliateId.ToString()); diff --git a/src/Libraries/SmartStore.Services/DataExchange/Import/DataImporter.cs b/src/Libraries/SmartStore.Services/DataExchange/Import/DataImporter.cs index 52aaf0b992..56906c4b8a 100644 --- a/src/Libraries/SmartStore.Services/DataExchange/Import/DataImporter.cs +++ b/src/Libraries/SmartStore.Services/DataExchange/Import/DataImporter.cs @@ -6,16 +6,23 @@ using SmartStore.Core; using SmartStore.Core.Data; using SmartStore.Core.Domain.Catalog; +using SmartStore.Core.Domain.Customers; using SmartStore.Core.Domain.DataExchange; +using SmartStore.Core.Domain.Forums; using SmartStore.Core.Domain.Messages; using SmartStore.Core.Domain.Seo; using SmartStore.Core.Localization; using SmartStore.Core.Logging; +using SmartStore.Services.Affiliates; using SmartStore.Services.Catalog; using SmartStore.Services.Catalog.Importer; +using SmartStore.Services.Common; using SmartStore.Services.Customers; +using SmartStore.Services.Customers.Importer; using SmartStore.Services.DataExchange.Csv; using SmartStore.Services.DataExchange.Import.Internal; +using SmartStore.Services.Directory; +using SmartStore.Services.Helpers; using SmartStore.Services.Localization; using SmartStore.Services.Media; using SmartStore.Services.Messages.Importer; @@ -39,6 +46,7 @@ public partial class DataImporter : IDataImporter private readonly Lazy> _productCategoryRepository; private readonly Lazy> _urlRecordRepository; private readonly Lazy> _productRepository; + private readonly Lazy> _customerRepository; private readonly Lazy _languageService; private readonly Lazy _localizedEntityService; @@ -48,8 +56,15 @@ public partial class DataImporter : IDataImporter private readonly Lazy _productService; private readonly Lazy _urlRecordService; private readonly Lazy _storeMappingService; + private readonly Lazy _genericAttributeService; + private readonly Lazy _affiliateService; + private readonly Lazy _countryService; + private readonly Lazy _stateProvinceService; private readonly Lazy _seoSettings; + private readonly Lazy _customerSettings; + private readonly Lazy _dateTimeSettings; + private readonly Lazy _forumSettings; public DataImporter( ICommonServices services, @@ -60,6 +75,7 @@ public DataImporter( Lazy> productCategoryRepository, Lazy> urlRecordRepository, Lazy> productRepository, + Lazy> customerRepository, Lazy languageService, Lazy localizedEntityService, Lazy pictureService, @@ -68,7 +84,14 @@ public DataImporter( Lazy productService, Lazy urlRecordService, Lazy storeMappingService, - Lazy seoSettings) + Lazy genericAttributeService, + Lazy affiliateService, + Lazy countryService, + Lazy stateProvinceService, + Lazy seoSettings, + Lazy customerSettings, + Lazy dateTimeSettings, + Lazy forumSettings) { _services = services; _customerService = customerService; @@ -78,6 +101,8 @@ public DataImporter( _productCategoryRepository = productCategoryRepository; _urlRecordRepository = urlRecordRepository; _productRepository = productRepository; + _customerRepository = customerRepository; + _languageService = languageService; _localizedEntityService = localizedEntityService; _pictureService = pictureService; @@ -86,7 +111,15 @@ public DataImporter( _productService = productService; _urlRecordService = urlRecordService; _storeMappingService = storeMappingService; + _genericAttributeService = genericAttributeService; + _affiliateService = affiliateService; + _countryService = countryService; + _stateProvinceService = stateProvinceService; + _seoSettings = seoSettings; + _customerSettings = customerSettings; + _dateTimeSettings = dateTimeSettings; + _forumSettings = forumSettings; T = NullLocalizer.Instance; } @@ -97,9 +130,6 @@ public DataImporter( private bool HasPermission(DataImporterContext ctx) { - if (ctx.Request.CustomerId == 0) - ctx.Request.CustomerId = _services.WorkContext.CurrentCustomer.Id; // fallback to background task system customer - var customer = _customerService.GetCustomerById(ctx.Request.CustomerId); if (ctx.Request.Profile.EntityType == ImportEntityType.Product) @@ -226,9 +256,6 @@ private void ImportCoreOuter(DataImporterContext ctx) if (ctx.Request.Profile == null || !ctx.Request.Profile.Enabled) return; - if (ctx.Request.CustomerId == 0) - ctx.Request.CustomerId = _services.WorkContext.CurrentCustomer.Id; - var logPath = ctx.Request.Profile.GetImportLogPath(); FileSystemHelper.Delete(logPath); @@ -239,6 +266,11 @@ private void ImportCoreOuter(DataImporterContext ctx) { ctx.Log = logger; + if (ctx.Request.CustomerId == 0) + ctx.Request.CustomerId = _services.WorkContext.CurrentCustomer.Id; // fallback to system background task customer + + ctx.ExecuteContext.CustomerId = ctx.Request.CustomerId; + var files = ctx.Request.Profile.GetImportFiles(); if (files.Count == 0) @@ -268,6 +300,17 @@ private void ImportCoreOuter(DataImporterContext ctx) } else if (ctx.Request.Profile.EntityType == ImportEntityType.Customer) { + ctx.Importer = new CustomerImporter( + _services, + _customerRepository.Value, + _genericAttributeService.Value, + _customerService, + _affiliateService.Value, + _countryService.Value, + _stateProvinceService.Value, + _customerSettings.Value, + _dateTimeSettings.Value, + _forumSettings.Value); } else if (ctx.Request.Profile.EntityType == ImportEntityType.NewsLetterSubscription) { diff --git a/src/Libraries/SmartStore.Services/DataExchange/Import/IEntityImporter.cs b/src/Libraries/SmartStore.Services/DataExchange/Import/IEntityImporter.cs index 051a95132d..1772fce95e 100644 --- a/src/Libraries/SmartStore.Services/DataExchange/Import/IEntityImporter.cs +++ b/src/Libraries/SmartStore.Services/DataExchange/Import/IEntityImporter.cs @@ -1,5 +1,4 @@ -using System; -using System.Linq; +using System.Linq; using System.Collections.Generic; using System.Threading; using SmartStore.Core.Domain.DataExchange; @@ -21,7 +20,6 @@ public class ImportExecuteContext public ImportExecuteContext( CancellationToken cancellation, - int customerId, ProgressValueSetter progressValueSetter, string progressInfo) { @@ -29,14 +27,13 @@ public ImportExecuteContext( _progressValueSetter = progressValueSetter; _progressInfo = progressInfo; - CustomerId = customerId; CustomProperties = new Dictionary(); Result = new ImportResult(); } public IDataTable DataTable { get; internal set; } - public int CustomerId { get; private set; } + public int CustomerId { get; internal set; } /// /// Use this dictionary for any custom data required along the import diff --git a/src/Libraries/SmartStore.Services/DataExchange/Import/Internal/DataImporterContext.cs b/src/Libraries/SmartStore.Services/DataExchange/Import/Internal/DataImporterContext.cs index 2a9b3f3db4..41efff1883 100644 --- a/src/Libraries/SmartStore.Services/DataExchange/Import/Internal/DataImporterContext.cs +++ b/src/Libraries/SmartStore.Services/DataExchange/Import/Internal/DataImporterContext.cs @@ -13,11 +13,7 @@ public DataImporterContext( Request = request; CancellationToken = cancellationToken; - ExecuteContext = new ImportExecuteContext( - CancellationToken, - Request.CustomerId, - Request.ProgressValueSetter, - progressInfo); + ExecuteContext = new ImportExecuteContext(CancellationToken, Request.ProgressValueSetter, progressInfo); } public DataImportRequest Request { get; private set; } diff --git a/src/Libraries/SmartStore.Services/Directory/IStateProvinceService.cs b/src/Libraries/SmartStore.Services/Directory/IStateProvinceService.cs index 95f0c91c2a..e62ff53527 100644 --- a/src/Libraries/SmartStore.Services/Directory/IStateProvinceService.cs +++ b/src/Libraries/SmartStore.Services/Directory/IStateProvinceService.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using System.Linq; using SmartStore.Core.Domain.Directory; namespace SmartStore.Services.Directory @@ -14,12 +15,19 @@ public partial interface IStateProvinceService /// The state/province void DeleteStateProvince(StateProvince stateProvince); - /// - /// Gets a state/province - /// - /// The state/province identifier - /// State/province - StateProvince GetStateProvinceById(int stateProvinceId); + /// + /// Get all states/provinces + /// + /// A value indicating whether to show hidden records + /// + IQueryable GetAllStateProvinces(bool showHidden = false); + + /// + /// Gets a state/province + /// + /// The state/province identifier + /// State/province + StateProvince GetStateProvinceById(int stateProvinceId); /// /// Gets a state/province diff --git a/src/Libraries/SmartStore.Services/Directory/StateProvinceService.cs b/src/Libraries/SmartStore.Services/Directory/StateProvinceService.cs index 27ddf6f5a6..b631dca9e9 100644 --- a/src/Libraries/SmartStore.Services/Directory/StateProvinceService.cs +++ b/src/Libraries/SmartStore.Services/Directory/StateProvinceService.cs @@ -8,10 +8,10 @@ namespace SmartStore.Services.Directory { - /// - /// State province service - /// - public partial class StateProvinceService : IStateProvinceService + /// + /// State province service + /// + public partial class StateProvinceService : IStateProvinceService { #region Constants private const string STATEPROVINCES_ALL_KEY = "SmartStore.stateprovince.all-{0}"; @@ -46,6 +46,7 @@ public StateProvinceService(ICacheManager cacheManager, #endregion #region Methods + /// /// Deletes a state/province /// @@ -63,12 +64,22 @@ public virtual void DeleteStateProvince(StateProvince stateProvince) _eventPublisher.EntityDeleted(stateProvince); } - /// - /// Gets a state/province - /// - /// The state/province identifier - /// State/province - public virtual StateProvince GetStateProvinceById(int stateProvinceId) + public virtual IQueryable GetAllStateProvinces(bool showHidden = false) + { + var query = _stateProvinceRepository.Table; + + if (!showHidden) + query = query.Where(x => x.Published); + + return query; + } + + /// + /// Gets a state/province + /// + /// The state/province identifier + /// State/province + public virtual StateProvince GetStateProvinceById(int stateProvinceId) { if (stateProvinceId == 0) return null; diff --git a/src/Libraries/SmartStore.Services/Messages/Importer/NewsLetterSubscriptionImporter.cs b/src/Libraries/SmartStore.Services/Messages/Importer/NewsLetterSubscriptionImporter.cs index 9cf6be74ac..0037b755f4 100644 --- a/src/Libraries/SmartStore.Services/Messages/Importer/NewsLetterSubscriptionImporter.cs +++ b/src/Libraries/SmartStore.Services/Messages/Importer/NewsLetterSubscriptionImporter.cs @@ -33,7 +33,6 @@ public void Execute(ImportExecuteContext context) using (var scope = new DbContextScope(ctx: _services.DbContext, autoDetectChanges: false, proxyCreation: false, validateOnSave: false, autoCommit: false)) { var segmenter = new ImportDataSegmenter(context.DataTable); - segmenter.Culture = CultureInfo.CurrentCulture; context.Result.TotalRecords = segmenter.TotalRows; diff --git a/src/Libraries/SmartStore.Services/SmartStore.Services.csproj b/src/Libraries/SmartStore.Services/SmartStore.Services.csproj index a3b6819b57..06bf906f25 100644 --- a/src/Libraries/SmartStore.Services/SmartStore.Services.csproj +++ b/src/Libraries/SmartStore.Services/SmartStore.Services.csproj @@ -171,6 +171,7 @@ + diff --git a/src/Presentation/SmartStore.Web/Administration/Controllers/ImportController.cs b/src/Presentation/SmartStore.Web/Administration/Controllers/ImportController.cs index 958680a2fa..112646bb72 100644 --- a/src/Presentation/SmartStore.Web/Administration/Controllers/ImportController.cs +++ b/src/Presentation/SmartStore.Web/Administration/Controllers/ImportController.cs @@ -242,6 +242,7 @@ public ActionResult DeleteConfirmed(int id) public JsonResult FileUpload(int id) { var success = false; + string error = null; string tempFile = ""; string fileList = ""; @@ -265,39 +266,45 @@ public JsonResult FileUpload(int id) var profile = _importService.GetImportProfileById(id); if (profile != null) { - //var extension = Path.GetExtension(profile.FileType); - - //if (postedFile.FileExtension.IsCaseInsensitiveEqual(extension)) - //{ - // var folder = profile.GetImportFolder(true, true); - // var destFile = Path.Combine(folder, Path.GetFileName(postedFile.FileName)); - - // success = postedFile.Stream.ToFile(destFile); - - // if (success) - // { - // var model = new ImportProfileModel(); - // PrepareProfileModel(model, profile, false); - - // fileList = this.RenderPartialViewToString("_ImportFileList", model); - // } - //} - //else - //{ - // NotifyError(T("Admin.Common.FileTypeMustEqual", extension.Substring(1).ToUpper())); - //} + var files = profile.GetImportFiles(); + if (files.Any()) + { + var extension = Path.GetExtension(files.First()); + + if (!postedFile.FileExtension.IsCaseInsensitiveEqual(extension)) + error = T("Admin.Common.FileTypeMustEqual", extension.Substring(1).ToUpper()); + } + + if (!error.HasValue()) + { + var folder = profile.GetImportFolder(true, true); + var destFile = Path.Combine(folder, Path.GetFileName(postedFile.FileName)); + + success = postedFile.Stream.ToFile(destFile); + + if (success) + { + var model = new ImportProfileModel(); + PrepareProfileModel(model, profile, false); + + fileList = this.RenderPartialViewToString("_ImportFileList", model); + } + } } } } if (!success) - NotifyError(T("Admin.Common.UploadFileFailed")); + error = T("Admin.Common.UploadFileFailed"); } else { - NotifyError(T("Admin.AccessDenied.Description")); + error = T("Admin.AccessDenied.Description"); } + if (error.HasValue()) + NotifyError(error); + return Json(new { success = success, tempFile = tempFile, fileList = fileList }); } From b3b30e84d304866bfbfe832fe737d01b7b680b6c Mon Sep 17 00:00:00 2001 From: Murat Cakir Date: Wed, 16 Dec 2015 17:38:47 +0100 Subject: [PATCH 174/707] A new mime type entry in web.config should be removed first --- src/Presentation/SmartStore.Web/Web.config | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Presentation/SmartStore.Web/Web.config b/src/Presentation/SmartStore.Web/Web.config index 9e60aa9751..cd1115ffa2 100644 --- a/src/Presentation/SmartStore.Web/Web.config +++ b/src/Presentation/SmartStore.Web/Web.config @@ -164,13 +164,14 @@ + - + From 76c03330adb6ae5d2ba08dec573ae0c2e45edac9 Mon Sep 17 00:00:00 2001 From: Marcus Gesing Date: Thu, 17 Dec 2015 10:30:01 +0100 Subject: [PATCH 175/707] Had to touch web.config through IIS to avoid 404 for bundles --- src/Presentation/SmartStore.Web/Web.config | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Presentation/SmartStore.Web/Web.config b/src/Presentation/SmartStore.Web/Web.config index cd1115ffa2..db0da925b3 100644 --- a/src/Presentation/SmartStore.Web/Web.config +++ b/src/Presentation/SmartStore.Web/Web.config @@ -1,4 +1,4 @@ - + @@ -92,7 +92,7 @@ - + From 15b4ddd0000b4ed9bb916a18c189afb105fccead Mon Sep 17 00:00:00 2001 From: Marcus Gesing Date: Thu, 17 Dec 2015 17:41:44 +0100 Subject: [PATCH 176/707] Testing product import --- .../Catalog/Importer/ProductImporter.cs | 10 +++++----- .../DataExchange/Import/ImportProfileService.cs | 4 +++- .../Administration/Controllers/ImportController.cs | 10 +++++----- .../Administration/Views/Import/_CreateOrUpdate.cshtml | 4 +++- 4 files changed, 16 insertions(+), 12 deletions(-) diff --git a/src/Libraries/SmartStore.Services/Catalog/Importer/ProductImporter.cs b/src/Libraries/SmartStore.Services/Catalog/Importer/ProductImporter.cs index bfd2d5d27d..dd0195f223 100644 --- a/src/Libraries/SmartStore.Services/Catalog/Importer/ProductImporter.cs +++ b/src/Libraries/SmartStore.Services/Catalog/Importer/ProductImporter.cs @@ -361,7 +361,7 @@ private int ProcessSlugs(ImportExecuteContext context, ImportRow[] batc return _rsUrlRecord.Context.SaveChanges(); } - private int ProcessProducts(ImportExecuteContext context, ImportRow[] batch) + private int ProcessProducts(ImportExecuteContext context, ImportRow[] batch, DateTime utcNow) { _rsProduct.AutoCommitEnabled = true; @@ -507,9 +507,9 @@ private int ProcessProducts(ImportExecuteContext context, ImportRow[] b _storeMappingService.SaveStoreMappings(product, storeIds.ToArray()); } - row.SetProperty(context.Result, product, (x) => x.CreatedOnUtc, DateTime.UtcNow); + row.SetProperty(context.Result, product, (x) => x.CreatedOnUtc, utcNow); - product.UpdatedOnUtc = DateTime.UtcNow; + product.UpdatedOnUtc = utcNow; if (row.IsTransient) { @@ -540,7 +540,7 @@ public void Execute(ImportExecuteContext context) using (var scope = new DbContextScope(ctx: _rsProduct.Context, autoDetectChanges: false, proxyCreation: false, validateOnSave: false)) { var segmenter = new ImportDataSegmenter(context.DataTable); - segmenter.Culture = CultureInfo.CurrentUICulture; + var utcNow = DateTime.UtcNow; context.Result.TotalRecords = segmenter.TotalRows; @@ -558,7 +558,7 @@ public void Execute(ImportExecuteContext context) // =========================================================================== try { - ProcessProducts(context, batch); + ProcessProducts(context, batch, utcNow); } catch (Exception exception) { diff --git a/src/Libraries/SmartStore.Services/DataExchange/Import/ImportProfileService.cs b/src/Libraries/SmartStore.Services/DataExchange/Import/ImportProfileService.cs index 39c0ae708e..47b9edf28c 100644 --- a/src/Libraries/SmartStore.Services/DataExchange/Import/ImportProfileService.cs +++ b/src/Libraries/SmartStore.Services/DataExchange/Import/ImportProfileService.cs @@ -118,7 +118,9 @@ public virtual IQueryable GetImportProfiles(bool? enabled = null) query = query.Where(x => x.Enabled == enabled.Value); } - query = query.OrderBy(x => x.Name); + query = query + .OrderBy(x => x.EntityTypeId) + .ThenBy(x => x.Name); return query; } diff --git a/src/Presentation/SmartStore.Web/Administration/Controllers/ImportController.cs b/src/Presentation/SmartStore.Web/Administration/Controllers/ImportController.cs index 112646bb72..e38db2e8b3 100644 --- a/src/Presentation/SmartStore.Web/Administration/Controllers/ImportController.cs +++ b/src/Presentation/SmartStore.Web/Administration/Controllers/ImportController.cs @@ -67,7 +67,7 @@ private void PrepareProfileModel(ImportProfileModel model, ImportProfile profile .Select(x => Path.GetFileName(x)) .ToList(); - if (profile.FileType == ImportFileType.CSV || profile.FileType == ImportFileType.XLSX) + if (profile.FileType == ImportFileType.CSV) { var converter = new CsvConfigurationConverter(); var config = converter.ConvertFrom(profile.FileTypeConfiguration); @@ -192,7 +192,7 @@ public ActionResult Edit(ImportProfileModel model, bool continueEditing, FormCol profile.Skip = model.Skip; profile.Take = model.Take; - if (profile.FileType == ImportFileType.CSV || profile.FileType == ImportFileType.XLSX) + if (profile.FileType == ImportFileType.CSV && model.CsvConfiguration != null) { CsvConfiguration config = model.CsvConfiguration.Clone(); @@ -293,15 +293,15 @@ public JsonResult FileUpload(int id) } } } - - if (!success) - error = T("Admin.Common.UploadFileFailed"); } else { error = T("Admin.AccessDenied.Description"); } + if (!success && error.IsEmpty()) + error = T("Admin.Common.UploadFileFailed"); + if (error.HasValue()) NotifyError(error); diff --git a/src/Presentation/SmartStore.Web/Administration/Views/Import/_CreateOrUpdate.cshtml b/src/Presentation/SmartStore.Web/Administration/Views/Import/_CreateOrUpdate.cshtml index 59d92a5c9d..c479639b6b 100644 --- a/src/Presentation/SmartStore.Web/Administration/Views/Import/_CreateOrUpdate.cshtml +++ b/src/Presentation/SmartStore.Web/Administration/Views/Import/_CreateOrUpdate.cshtml @@ -1,4 +1,5 @@ @using SmartStore.Admin.Models.DataExchange; +@using SmartStore.Core.Domain.DataExchange; @model ImportProfileModel @{ Html.AddScriptParts("~/bundles/fileupload"); @@ -119,10 +120,11 @@ }
    +

    + @if (Model.CsvConfiguration != null) { var viewData = new ViewDataDictionary(); - viewData.Add("ShowGroupCaption", true); viewData.TemplateInfo.HtmlFieldPrefix = "CsvConfiguration"; viewData.ModelState.Merge(ViewData.ModelState); @Html.Partial("CsvConfiguration", Model.CsvConfiguration, viewData) From 88ef5fc4c858eaeda5f9621aa463cfb1f93c6af7 Mon Sep 17 00:00:00 2001 From: Marcus Gesing Date: Thu, 17 Dec 2015 18:10:36 +0100 Subject: [PATCH 177/707] Resolves #838 The initial compact db creation fails --- .../Migrations/201508042207146_RemoveKeepAlive.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Libraries/SmartStore.Data/Migrations/201508042207146_RemoveKeepAlive.cs b/src/Libraries/SmartStore.Data/Migrations/201508042207146_RemoveKeepAlive.cs index 300ceba25a..8c0dc62ad6 100644 --- a/src/Libraries/SmartStore.Data/Migrations/201508042207146_RemoveKeepAlive.cs +++ b/src/Libraries/SmartStore.Data/Migrations/201508042207146_RemoveKeepAlive.cs @@ -10,7 +10,7 @@ public partial class RemoveKeepAlive : DbMigration, ILocaleResourcesProvider, ID { public override void Up() { - if (HostingEnvironment.IsHosted) + if (HostingEnvironment.IsHosted && DataSettings.Current.IsSqlServer) { Sql("DELETE FROM [dbo].[ScheduleTask] WHERE [Type] = 'SmartStore.Services.Common.KeepAliveTask, SmartStore.Services'"); } From a9300358c3be3bf70bb7de65cc884bacf04222d4 Mon Sep 17 00:00:00 2001 From: Marcus Gesing Date: Thu, 17 Dec 2015 19:59:43 +0100 Subject: [PATCH 178/707] Removed some obsolete import code --- .../Domain/DataExchange/ImportEnums.cs | 11 +- .../DataExchange/Import/IImportManager.cs | 31 - .../DataExchange/Import/ImportManager.cs | 770 ------------------ .../DataExchange/Import/ImportModeFlags.cs | 13 - .../DataExchange/Import/ImportProgressInfo.cs | 63 -- .../DataExchange/Import/ImportRow.cs | 3 - .../Localization/ILocalizationService.cs | 10 +- .../Localization/LocalizationExtentions.cs | 8 +- .../Localization/LocalizationService.cs | 17 +- .../SmartStore.Services.csproj | 4 - .../DependencyRegistrar.cs | 9 +- .../Controllers/LanguageController.cs | 5 +- .../Controllers/ProductController.cs | 2 - 13 files changed, 32 insertions(+), 914 deletions(-) delete mode 100644 src/Libraries/SmartStore.Services/DataExchange/Import/IImportManager.cs delete mode 100644 src/Libraries/SmartStore.Services/DataExchange/Import/ImportManager.cs delete mode 100644 src/Libraries/SmartStore.Services/DataExchange/Import/ImportModeFlags.cs delete mode 100644 src/Libraries/SmartStore.Services/DataExchange/Import/ImportProgressInfo.cs diff --git a/src/Libraries/SmartStore.Core/Domain/DataExchange/ImportEnums.cs b/src/Libraries/SmartStore.Core/Domain/DataExchange/ImportEnums.cs index eb993124dc..00c323ae6a 100644 --- a/src/Libraries/SmartStore.Core/Domain/DataExchange/ImportEnums.cs +++ b/src/Libraries/SmartStore.Core/Domain/DataExchange/ImportEnums.cs @@ -1,4 +1,6 @@ -namespace SmartStore.Core.Domain.DataExchange +using System; + +namespace SmartStore.Core.Domain.DataExchange { /// /// Supported entity types @@ -15,4 +17,11 @@ public enum ImportFileType CSV = 0, XLSX } + + [Flags] + public enum ImportModeFlags + { + Insert = 1, + Update = 2 + } } diff --git a/src/Libraries/SmartStore.Services/DataExchange/Import/IImportManager.cs b/src/Libraries/SmartStore.Services/DataExchange/Import/IImportManager.cs deleted file mode 100644 index 5c26d54af8..0000000000 --- a/src/Libraries/SmartStore.Services/DataExchange/Import/IImportManager.cs +++ /dev/null @@ -1,31 +0,0 @@ -using System; -using System.Threading; - -namespace SmartStore.Services.DataExchange.Import -{ - /// - /// Import manager interface - /// - public interface IImportManager - { - ImportResult ImportProducts( - IDataTable table, - CancellationToken cancellationToken, - IProgress progress = null); - - /// - /// Dumps an instance to a string - /// - /// The result instance - /// The report - string CreateTextReport(ImportResult result); - } - - public static class IImportManagerExtensions - { - public static ImportResult ImportProducts(this IImportManager manager, IDataTable table) - { - return manager.ImportProducts(table, CancellationToken.None); - } - } -} diff --git a/src/Libraries/SmartStore.Services/DataExchange/Import/ImportManager.cs b/src/Libraries/SmartStore.Services/DataExchange/Import/ImportManager.cs deleted file mode 100644 index 6e3632eea9..0000000000 --- a/src/Libraries/SmartStore.Services/DataExchange/Import/ImportManager.cs +++ /dev/null @@ -1,770 +0,0 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Threading; -using System.Threading.Tasks; -using SmartStore.Core.Data; -using SmartStore.Core.Domain.Catalog; -using SmartStore.Data; -using SmartStore.Services.Catalog; -using SmartStore.Core.Events; -using SmartStore.Services.Localization; -using SmartStore.Services.Media; -using SmartStore.Services.Seo; -using SmartStore.Utilities; -using System.Text; -using SmartStore.Core.Domain.Seo; -using SmartStore.Core.Domain.Media; -using SmartStore.Services.Stores; -using SmartStore.Core.Domain.Stores; -using SmartStore.Core; -using System.Globalization; - -namespace SmartStore.Services.DataExchange.Import -{ - /// - /// Import manager - /// - public partial class ImportManager : IImportManager - { - private readonly IProductService _productService; - private readonly ICategoryService _categoryService; - private readonly IManufacturerService _manufacturerService; - private readonly IPictureService _pictureService; - private readonly IUrlRecordService _urlRecordService; - private readonly SeoSettings _seoSettings; - private readonly IEventPublisher _eventPublisher; - private readonly IRepository _rsProduct; - private readonly IRepository _rsProductCategory; - private readonly IRepository _rsProductManufacturer; - private readonly IRepository _rsPicture; - private readonly IRepository _rsProductPicture; - private readonly IRepository _rsUrlRecord; - private readonly ILanguageService _languageService; - private readonly ILocalizedEntityService _localizedEntityService; - private readonly IStoreMappingService _storeMappingService; - - public ImportManager( - IProductService productService, - ICategoryService categoryService, - IManufacturerService manufacturerService, - IPictureService pictureService, - IUrlRecordService urlRecordService, - SeoSettings seoSettings, - IEventPublisher eventPublisher, - IRepository rsProduct, - IRepository rsProductCategory, - IRepository rsProductManufacturer, - IRepository rsPicture, - IRepository rsProductPicture, - IRepository rsUrlRecord, - ILanguageService languageService, - ILocalizedEntityService localizedEntityService, - IStoreMappingService storeMappingService) - { - this._productService = productService; - this._categoryService = categoryService; - this._manufacturerService = manufacturerService; - this._pictureService = pictureService; - this._urlRecordService = urlRecordService; - this._seoSettings = seoSettings; - this._eventPublisher = eventPublisher; - this._rsProduct = rsProduct; - this._rsProductCategory = rsProductCategory; - this._rsProductManufacturer = rsProductManufacturer; - this._rsProductPicture = rsProductPicture; - this._rsUrlRecord = rsUrlRecord; - this._rsPicture = rsPicture; - this._languageService = languageService; - this._localizedEntityService = localizedEntityService; - this._storeMappingService = storeMappingService; - } - - public virtual string CreateTextReport(ImportResult result) - { - var sb = new StringBuilder(); - - using (var writer = new StringWriter(sb)) - { - writer.WriteLine("SUMMARY"); - writer.WriteLine("=================================================================================="); - writer.WriteLine("Started: {0}".FormatCurrent(result.StartDateUtc.ToLocalTime())); - writer.WriteLine("Finished: {0}{1}".FormatCurrent(result.EndDateUtc.ToLocalTime(), result.Cancelled ? " (cancelled by user)" : "")); - writer.WriteLine("Duration: {0}".FormatCurrent((result.EndDateUtc - result.StartDateUtc).ToString("g"))); - - writer.WriteLine(""); - writer.WriteLine("Total rows in source: {0}".FormatCurrent(result.TotalRecords)); - writer.WriteLine("Rows processed: {0}".FormatCurrent(result.AffectedRecords)); - writer.WriteLine("Products imported: {0}".FormatCurrent(result.NewRecords)); - writer.WriteLine("Products updated: {0}".FormatCurrent(result.ModifiedRecords)); - - writer.WriteLine(""); - writer.WriteLine("Warnings: {0}".FormatCurrent(result.Messages.Count(x => x.MessageType == ImportMessageType.Warning))); - writer.WriteLine("Errors: {0}".FormatCurrent(result.Messages.Count(x => x.MessageType == ImportMessageType.Error))); - - writer.WriteLine(""); - writer.WriteLine(""); - writer.WriteLine("MESSAGES"); - writer.WriteLine("=================================================================================="); - - foreach (var message in result.Messages) - { - string msg = string.Empty; - var prefix = new List(); - if (message.AffectedItem != null) - { - prefix.Add("Pos: " + message.AffectedItem.Position + 1); - } - if (message.AffectedField.HasValue()) - { - prefix.Add("Field: " + message.AffectedField); - } - - if (prefix.Any()) - { - msg = "[{0}] ".FormatCurrent(String.Join(", ", prefix)); - } - - msg += message.Message; - - writer.WriteLine("{0}: {1}".FormatCurrent(message.MessageType.ToString().ToUpper(), msg)); - } - } - - return sb.ToString(); - } - - /// - /// Import products from XLSX file - /// - /// Stream - public virtual ImportResult ImportProducts( - IDataTable table, - CancellationToken cancellationToken, - IProgress progress = null) - { - Guard.ArgumentNotNull(() => table); - - var result = new ImportResult(); - int saved = 0; - - if (progress != null) - progress.Report(new ImportProgressInfo { ElapsedTime = TimeSpan.Zero }); - - using (var scope = new DbContextScope(ctx: _rsProduct.Context, autoDetectChanges: false, proxyCreation: false, validateOnSave: false)) - { - try { - var segmenter = new ImportDataSegmenter(table); - - segmenter.Culture = CultureInfo.CurrentUICulture; - - result.TotalRecords = segmenter.TotalRows; - - while (segmenter.ReadNextBatch() && !cancellationToken.IsCancellationRequested) - { - var batch = segmenter.CurrentBatch; - - // Perf: detach all entities - _rsProduct.Context.DetachAll(false); - - // Update progress for calling thread - if (progress != null) - { - progress.Report(new ImportProgressInfo - { - TotalRecords = result.TotalRecords, - TotalProcessed = segmenter.CurrentSegmentFirstRowIndex - 1, - NewRecords = result.NewRecords, - ModifiedRecords = result.ModifiedRecords, - ElapsedTime = DateTime.UtcNow - result.StartDateUtc, - TotalWarnings = result.Messages.Count(x => x.MessageType == ImportMessageType.Warning), - TotalErrors = result.Messages.Count(x => x.MessageType == ImportMessageType.Error), - }); - } - - // =========================================================================== - // 1.) Import products - // =========================================================================== - try - { - saved = ProcessProducts(batch, result); - } - catch (Exception ex) - { - result.AddError(ex, segmenter.CurrentSegment, "ProcessProducts"); - } - - // reduce batch to saved (valid) products. - // No need to perform import operations on errored products. - batch = batch.Where(x => x.Entity != null && !x.IsTransient).ToArray(); - - // update result object - result.NewRecords += batch.Count(x => x.IsNew && !x.IsTransient); - result.ModifiedRecords += batch.Count(x => !x.IsNew && !x.IsTransient); - - // =========================================================================== - // 2.) Import SEO Slugs - // IMPORTANT: Unlike with Products AutoCommitEnabled must be TRUE, - // as Slugs are going to be validated against existing ones in DB. - // =========================================================================== - if (table.HasColumn("SeName") || batch.Any(x => x.IsNew || x.NameChanged)) - { - try - { - _rsProduct.Context.AutoDetectChangesEnabled = true; - ProcessSlugs(batch, result); - } - catch (Exception ex) - { - result.AddError(ex, segmenter.CurrentSegment, "ProcessSeoSlugs"); - } - finally - { - _rsProduct.Context.AutoDetectChangesEnabled = false; - } - } - - // =========================================================================== - // 3.) Import Localizations - // =========================================================================== - try - { - ProcessLocalizations(batch, result); - } - catch (Exception ex) - { - result.AddError(ex, segmenter.CurrentSegment, "ProcessLocalizations"); - } - - // =========================================================================== - // 4.) Import product category mappings - // =========================================================================== - if (table.HasColumn("CategoryIds")) - { - try - { - ProcessProductCategories(batch, result); - } - catch (Exception ex) - { - result.AddError(ex, segmenter.CurrentSegment, "ProcessProductCategories"); - } - } - - // =========================================================================== - // 5.) Import product manufacturer mappings - // =========================================================================== - if (table.HasColumn("ManufacturerIds")) - { - try - { - ProcessProductManufacturers(batch, result); - } - catch (Exception ex) - { - result.AddError(ex, segmenter.CurrentSegment, "ProcessProductManufacturers"); - } - } - - - // =========================================================================== - // 6.) Import product picture mappings - // =========================================================================== - if (table.HasColumn("Picture1") || table.HasColumn("Picture2") || table.HasColumn("Picture3")) - { - try - { - ProcessProductPictures(batch, result); - } - catch (Exception ex) - { - result.AddError(ex, segmenter.CurrentSegment, "ProcessProductPictures"); - } - } - - } - } - catch (Exception ex) - { - result.AddError(ex, null, "ReadFile"); - } - } - - result.EndDateUtc = DateTime.UtcNow; - - if (cancellationToken.IsCancellationRequested) - { - result.Cancelled = true; - result.AddInfo("Import task was cancelled by user"); - } - - return result; - } - - private int ProcessProducts(ImportRow[] batch, ImportResult result) - { - _rsProduct.AutoCommitEnabled = true; - - Product lastInserted = null; - Product lastUpdated = null; - - foreach (var row in batch) - { - Product product = null; - - object key; - var dataRow = row.DataRow; - - // try get by int ID - if (dataRow.TryGetValue("Id", out key) && key.ToString().ToInt() > 0) - { - product = _productService.GetProductById(key.ToString().ToInt()); - } - - // try get by SKU - if (product == null && dataRow.TryGetValue("SKU", out key)) - { - product = _productService.GetProductBySku(key.ToString()); - } - - // try get by GTIN - if (product == null && dataRow.TryGetValue("Gtin", out key)) - { - product = _productService.GetProductByGtin(key.ToString()); - } - - if (product == null) - { - // a Name is required with new products. - if (!row.Segmenter.HasDataColumn("Name")) - { - result.AddError("The 'Name' field is required for new products. Skipping row.", row.GetRowInfo(), "Name"); - continue; - } - product = new Product(); - } - - string name = row.GetDataValue("Name"); - - row.Initialize(product, name); - - if (!row.IsNew) - { - if (!product.Name.Equals(name, StringComparison.OrdinalIgnoreCase)) - { - // Perf: use this later for SeName updates. - row.NameChanged = true; - } - } - - row.SetProperty(result, product, (x) => x.Sku); - row.SetProperty(result, product, (x) => x.Gtin); - row.SetProperty(result, product, (x) => x.ManufacturerPartNumber); - row.SetProperty(result, product, (x) => x.ProductTypeId, (int)ProductType.SimpleProduct); - row.SetProperty(result, product, (x) => x.ParentGroupedProductId); - row.SetProperty(result, product, (x) => x.VisibleIndividually, true); - row.SetProperty(result, product, (x) => x.Name); - row.SetProperty(result, product, (x) => x.ShortDescription); - row.SetProperty(result, product, (x) => x.FullDescription); - row.SetProperty(result, product, (x) => x.ProductTemplateId); - row.SetProperty(result, product, (x) => x.ShowOnHomePage); - row.SetProperty(result, product, (x) => x.HomePageDisplayOrder); - row.SetProperty(result, product, (x) => x.MetaKeywords); - row.SetProperty(result, product, (x) => x.MetaDescription); - row.SetProperty(result, product, (x) => x.MetaTitle); - row.SetProperty(result, product, (x) => x.AllowCustomerReviews, true); - row.SetProperty(result, product, (x) => x.Published, true); - row.SetProperty(result, product, (x) => x.IsGiftCard); - row.SetProperty(result, product, (x) => x.GiftCardTypeId); - row.SetProperty(result, product, (x) => x.RequireOtherProducts); - row.SetProperty(result, product, (x) => x.RequiredProductIds); - row.SetProperty(result, product, (x) => x.AutomaticallyAddRequiredProducts); - row.SetProperty(result, product, (x) => x.IsDownload); - row.SetProperty(result, product, (x) => x.DownloadId); - row.SetProperty(result, product, (x) => x.UnlimitedDownloads, true); - row.SetProperty(result, product, (x) => x.MaxNumberOfDownloads, 10); - row.SetProperty(result, product, (x) => x.DownloadActivationTypeId, 1); - row.SetProperty(result, product, (x) => x.HasSampleDownload); - row.SetProperty(result, product, (x) => x.SampleDownloadId, (int?)null, ZeroToNull); - row.SetProperty(result, product, (x) => x.HasUserAgreement); - row.SetProperty(result, product, (x) => x.UserAgreementText); - row.SetProperty(result, product, (x) => x.IsRecurring); - row.SetProperty(result, product, (x) => x.RecurringCycleLength, 100); - row.SetProperty(result, product, (x) => x.RecurringCyclePeriodId); - row.SetProperty(result, product, (x) => x.RecurringTotalCycles, 10); - row.SetProperty(result, product, (x) => x.IsShipEnabled, true); - row.SetProperty(result, product, (x) => x.IsFreeShipping); - row.SetProperty(result, product, (x) => x.AdditionalShippingCharge); - row.SetProperty(result, product, (x) => x.IsEsd); - row.SetProperty(result, product, (x) => x.IsTaxExempt); - row.SetProperty(result, product, (x) => x.TaxCategoryId, 1); - row.SetProperty(result, product, (x) => x.ManageInventoryMethodId); - row.SetProperty(result, product, (x) => x.StockQuantity, 10000); - row.SetProperty(result, product, (x) => x.DisplayStockAvailability); - row.SetProperty(result, product, (x) => x.DisplayStockQuantity); - row.SetProperty(result, product, (x) => x.MinStockQuantity); - row.SetProperty(result, product, (x) => x.LowStockActivityId); - row.SetProperty(result, product, (x) => x.NotifyAdminForQuantityBelow, 1); - row.SetProperty(result, product, (x) => x.BackorderModeId); - row.SetProperty(result, product, (x) => x.AllowBackInStockSubscriptions); - row.SetProperty(result, product, (x) => x.OrderMinimumQuantity, 1); - row.SetProperty(result, product, (x) => x.OrderMaximumQuantity, 10000); - row.SetProperty(result, product, (x) => x.AllowedQuantities); - row.SetProperty(result, product, (x) => x.DisableBuyButton); - row.SetProperty(result, product, (x) => x.DisableWishlistButton); - row.SetProperty(result, product, (x) => x.AvailableForPreOrder); - row.SetProperty(result, product, (x) => x.CallForPrice); - row.SetProperty(result, product, (x) => x.Price); - row.SetProperty(result, product, (x) => x.OldPrice); - row.SetProperty(result, product, (x) => x.ProductCost); - row.SetProperty(result, product, (x) => x.SpecialPrice); - row.SetProperty(result, product, (x) => x.SpecialPriceStartDateTimeUtc); - row.SetProperty(result, product, (x) => x.SpecialPriceEndDateTimeUtc); - row.SetProperty(result, product, (x) => x.CustomerEntersPrice); - row.SetProperty(result, product, (x) => x.MinimumCustomerEnteredPrice); - row.SetProperty(result, product, (x) => x.MaximumCustomerEnteredPrice, 1000); - row.SetProperty(result, product, (x) => x.Weight); - row.SetProperty(result, product, (x) => x.Length); - row.SetProperty(result, product, (x) => x.Width); - row.SetProperty(result, product, (x) => x.Height); - row.SetProperty(result, product, (x) => x.DeliveryTimeId); - row.SetProperty(result, product, (x) => x.QuantityUnitId); - row.SetProperty(result, product, (x) => x.BasePriceEnabled); - row.SetProperty(result, product, (x) => x.BasePriceMeasureUnit); - row.SetProperty(result, product, (x) => x.BasePriceAmount); - row.SetProperty(result, product, (x) => x.BasePriceBaseAmount); - row.SetProperty(result, product, (x) => x.BundlePerItemPricing); - row.SetProperty(result, product, (x) => x.BundlePerItemShipping); - row.SetProperty(result, product, (x) => x.BundlePerItemShoppingCart); - row.SetProperty(result, product, (x) => x.BundleTitleText); - row.SetProperty(result, product, (x) => x.AvailableStartDateTimeUtc); - row.SetProperty(result, product, (x) => x.AvailableEndDateTimeUtc); - row.SetProperty(result, product, (x) => x.LimitedToStores); - - var storeIds = row.GetDataValue>("StoreIds"); - if (storeIds != null && storeIds.Any()) - { - _storeMappingService.SaveStoreMappings(product, storeIds.ToArray()); - } - - row.SetProperty(result, product, (x) => x.CreatedOnUtc, DateTime.UtcNow); - - product.UpdatedOnUtc = DateTime.UtcNow; - - if (row.IsTransient) - { - _rsProduct.Insert(product); - lastInserted = product; - } - else - { - _rsProduct.Update(product); - lastUpdated = product; - } - } - - // commit whole batch at once - var num = _rsProduct.Context.SaveChanges(); - - // Perf: notify only about LAST insertion and update - if (lastInserted != null) - _eventPublisher.EntityInserted(lastInserted); - if (lastUpdated != null) - _eventPublisher.EntityUpdated(lastUpdated); - - return num; - } - - private int ProcessSlugs(ImportRow[] batch, ImportResult result) - { - var slugMap = new Dictionary(100); - Func slugLookup = ((s) => { - if (slugMap.ContainsKey(s)) - { - return slugMap[s]; - } - return (UrlRecord)null; - }); - - var entityName = typeof(Product).Name; - - foreach (var row in batch) - { - if (row.IsNew || row.NameChanged || row.Segmenter.HasDataColumn("SeName")) - { - try - { - string seName = row.GetDataValue("SeName"); - seName = row.Entity.ValidateSeName(seName, row.Entity.Name, true, _urlRecordService, _seoSettings, extraSlugLookup: slugLookup); - - UrlRecord urlRecord = null; - - if (row.IsNew) - { - // dont't bother validating SeName for new entities. - urlRecord = new UrlRecord - { - EntityId = row.Entity.Id, - EntityName = entityName, - Slug = seName, - LanguageId = 0, - IsActive = true, - }; - _rsUrlRecord.Insert(urlRecord); - } - else - { - urlRecord = _urlRecordService.SaveSlug(row.Entity, seName, 0); - } - - if (urlRecord != null) - { - // a new record was inserted to the store: keep track of it for this batch. - slugMap[seName] = urlRecord; - } - } - catch (Exception ex) - { - result.AddWarning(ex.Message, row.GetRowInfo(), "SeName"); - } - } - } - - // commit whole batch at once - return _rsUrlRecord.Context.SaveChanges(); - } - - private int ProcessLocalizations(ImportRow[] batch, ImportResult result) - { - //_rsProductManufacturer.AutoCommitEnabled = false; - - //string lastInserted = null; - - var languages = _languageService.GetAllLanguages(true); - - foreach (var row in batch) - { - - Product product = null; - - //get product - try - { - product = _productService.GetProductById(row.Entity.Id); - } - catch (Exception ex) - { - result.AddWarning(ex.Message, row.GetRowInfo(), "ProcessLocalizations Product"); - } - - foreach (var lang in languages) - { - string localizedName = row.GetDataValue("Name", lang.UniqueSeoCode); - string localizedShortDescription = row.GetDataValue("ShortDescription", lang.UniqueSeoCode); - string localizedFullDescription = row.GetDataValue("FullDescription", lang.UniqueSeoCode); - - if (localizedName.HasValue()) - { - _localizedEntityService.SaveLocalizedValue(product, x => x.Name, localizedName, lang.Id); - } - if (localizedShortDescription.HasValue()) - { - _localizedEntityService.SaveLocalizedValue(product, x => x.ShortDescription, localizedShortDescription, lang.Id); - } - if (localizedFullDescription.HasValue()) - { - _localizedEntityService.SaveLocalizedValue(product, x => x.FullDescription, localizedFullDescription, lang.Id); - } - } - } - - // commit whole batch at once - var num = _rsProductManufacturer.Context.SaveChanges(); - - // Perf: notify only about LAST insertion and update - //if (lastInserted != null) - // _eventPublisher.EntityInserted(lastInserted); - - return num; - } - - private int ProcessProductCategories(ImportRow[] batch, ImportResult result) - { - _rsProductCategory.AutoCommitEnabled = false; - - ProductCategory lastInserted = null; - - foreach (var row in batch) - { - var categoryIds = row.GetDataValue>("CategoryIds"); - if (categoryIds != null && categoryIds.Any()) - { - try - { - foreach (var id in categoryIds) - { - if (_rsProductCategory.TableUntracked.Where(x => x.ProductId == row.Entity.Id && x.CategoryId == id).FirstOrDefault() == null) - { - // ensure that category exists - var category = _categoryService.GetCategoryById(id); - if (category != null) - { - var productCategory = new ProductCategory - { - ProductId = row.Entity.Id, - CategoryId = category.Id, - IsFeaturedProduct = false, - DisplayOrder = 1 - }; - _rsProductCategory.Insert(productCategory); - lastInserted = productCategory; - } - } - } - } - catch (Exception ex) - { - result.AddWarning(ex.Message, row.GetRowInfo(), "CategoryIds"); - } - } - } - - // commit whole batch at once - var num = _rsProductCategory.Context.SaveChanges(); - - // Perf: notify only about LAST insertion and update - if (lastInserted != null) - _eventPublisher.EntityInserted(lastInserted); - - return num; - } - - private int ProcessProductManufacturers(ImportRow[] batch, ImportResult result) - { - _rsProductManufacturer.AutoCommitEnabled = false; - - ProductManufacturer lastInserted = null; - - foreach (var row in batch) - { - var manufacturerIds = row.GetDataValue>("ManufacturerIds"); - if (manufacturerIds != null && manufacturerIds.Any()) - { - try - { - foreach (var id in manufacturerIds) - { - if (_rsProductManufacturer.TableUntracked.Where(x => x.ProductId == row.Entity.Id && x.ManufacturerId == id).FirstOrDefault() == null) - { - // ensure that manufacturer exists - var manufacturer = _manufacturerService.GetManufacturerById(id); - if (manufacturer != null) - { - var productManufacturer = new ProductManufacturer - { - ProductId = row.Entity.Id, - ManufacturerId = manufacturer.Id, - IsFeaturedProduct = false, - DisplayOrder = 1 - }; - _rsProductManufacturer.Insert(productManufacturer); - lastInserted = productManufacturer; - } - } - } - } - catch (Exception ex) - { - result.AddWarning(ex.Message, row.GetRowInfo(), "ManufacturerIds"); - } - } - } - - // commit whole batch at once - var num = _rsProductManufacturer.Context.SaveChanges(); - - // Perf: notify only about LAST insertion and update - if (lastInserted != null) - _eventPublisher.EntityInserted(lastInserted); - - return num; - } - - private void ProcessProductPictures(ImportRow[] batch, ImportResult result) - { - // true, cause pictures must be saved and assigned an id - // prior adding a mapping. - _rsProductPicture.AutoCommitEnabled = true; - - ProductPicture lastInserted = null; - int equalPictureId = 0; - - foreach (var row in batch) - { - var pictures = new string[] - { - row.GetDataValue("Picture1"), - row.GetDataValue("Picture2"), - row.GetDataValue("Picture3") - }; - - int i = 0; - try - { - for (i = 0; i < pictures.Length; i++) - { - var picture = pictures[i]; - - if (picture.IsEmpty() || !File.Exists(picture)) - continue; - - var currentPictures = _rsProductPicture.TableUntracked.Expand(x => x.Picture).Where(x => x.ProductId == row.Entity.Id).Select(x => x.Picture).ToList(); - var pictureBinary = _pictureService.FindEqualPicture(picture, currentPictures, out equalPictureId); - - if (pictureBinary != null && pictureBinary.Length > 0) - { - // no equal picture found in sequence - var newPicture = _pictureService.InsertPicture(pictureBinary, "image/jpeg", _pictureService.GetPictureSeName(row.EntityDisplayName), true, false, false); - if (newPicture != null) - { - var mapping = new ProductPicture - { - ProductId = row.Entity.Id, - PictureId = newPicture.Id, - DisplayOrder = 1, - }; - _rsProductPicture.Insert(mapping); - lastInserted = mapping; - } - } - else - { - result.AddInfo("Found equal picture in data store. Skipping field.", row.GetRowInfo(), "Picture" + (i + 1).ToString()); - } - } - } - catch (Exception ex) - { - result.AddWarning(ex.Message, row.GetRowInfo(), "Picture" + (i + 1).ToString()); - } - - } - - // Perf: notify only about LAST insertion and update - if (lastInserted != null) - _eventPublisher.EntityInserted(lastInserted); - } - - private int? ZeroToNull(object value, CultureInfo culture) - { - int result; - if (CommonHelper.TryConvert(value, culture, out result) && result > 0) - { - return result; - } - - return (int?)null; - } - } -} diff --git a/src/Libraries/SmartStore.Services/DataExchange/Import/ImportModeFlags.cs b/src/Libraries/SmartStore.Services/DataExchange/Import/ImportModeFlags.cs deleted file mode 100644 index 1e85010067..0000000000 --- a/src/Libraries/SmartStore.Services/DataExchange/Import/ImportModeFlags.cs +++ /dev/null @@ -1,13 +0,0 @@ -using System; - -namespace SmartStore.Services.DataExchange.Import -{ - - [Flags] - public enum ImportModeFlags - { - Insert = 1, - Update = 2 - } - -} diff --git a/src/Libraries/SmartStore.Services/DataExchange/Import/ImportProgressInfo.cs b/src/Libraries/SmartStore.Services/DataExchange/Import/ImportProgressInfo.cs deleted file mode 100644 index 19419845d0..0000000000 --- a/src/Libraries/SmartStore.Services/DataExchange/Import/ImportProgressInfo.cs +++ /dev/null @@ -1,63 +0,0 @@ -using System; - -namespace SmartStore.Services.DataExchange.Import -{ - - public class ImportProgressInfo - { - - public int TotalRecords - { - get; - set; - } - - public int TotalProcessed - { - get; - set; - } - - public double ProcessedPercent - { - get - { - if (TotalRecords == 0) - return 0; - - return ((double)TotalProcessed / (double)TotalRecords) * 100; - } - } - - public int NewRecords - { - get; - set; - } - - public int ModifiedRecords - { - get; - set; - } - - public TimeSpan ElapsedTime - { - get; - set; - } - - public int TotalWarnings - { - get; - set; - } - - public int TotalErrors - { - get; - set; - } - } - -} diff --git a/src/Libraries/SmartStore.Services/DataExchange/Import/ImportRow.cs b/src/Libraries/SmartStore.Services/DataExchange/Import/ImportRow.cs index 9ca5ab441b..5b469a9352 100644 --- a/src/Libraries/SmartStore.Services/DataExchange/Import/ImportRow.cs +++ b/src/Libraries/SmartStore.Services/DataExchange/Import/ImportRow.cs @@ -1,9 +1,6 @@ using System; -using System.Collections.Generic; using System.Globalization; -using System.Linq; using System.Linq.Expressions; -using System.Text; using SmartStore.ComponentModel; using SmartStore.Core; diff --git a/src/Libraries/SmartStore.Services/Localization/ILocalizationService.cs b/src/Libraries/SmartStore.Services/Localization/ILocalizationService.cs index 9f1cc99290..918ad1be88 100644 --- a/src/Libraries/SmartStore.Services/Localization/ILocalizationService.cs +++ b/src/Libraries/SmartStore.Services/Localization/ILocalizationService.cs @@ -1,16 +1,16 @@ using System; using System.Collections.Generic; using System.Xml; +using SmartStore.Core.Domain.DataExchange; using SmartStore.Core.Domain.Localization; using SmartStore.Core.Plugins; -using SmartStore.Services.DataExchange.Import; namespace SmartStore.Services.Localization { - /// - /// Localization manager interface - /// - public partial interface ILocalizationService + /// + /// Localization manager interface + /// + public partial interface ILocalizationService { void ClearCache(); diff --git a/src/Libraries/SmartStore.Services/Localization/LocalizationExtentions.cs b/src/Libraries/SmartStore.Services/Localization/LocalizationExtentions.cs index 8bbd78cf9b..a55b8ab84f 100644 --- a/src/Libraries/SmartStore.Services/Localization/LocalizationExtentions.cs +++ b/src/Libraries/SmartStore.Services/Localization/LocalizationExtentions.cs @@ -1,18 +1,18 @@ using System; using System.Linq.Expressions; using System.Reflection; +using System.Xml; +using SmartStore.ComponentModel; using SmartStore.Core; +using SmartStore.Core.Domain.DataExchange; using SmartStore.Core.Domain.Localization; using SmartStore.Core.Infrastructure; using SmartStore.Core.Plugins; -using System.Xml; using SmartStore.Utilities; -using SmartStore.Services.DataExchange.Import; -using SmartStore.ComponentModel; namespace SmartStore.Services.Localization { - public static class LocalizationExtentions + public static class LocalizationExtentions { /// /// Get localized property of an entity diff --git a/src/Libraries/SmartStore.Services/Localization/LocalizationService.cs b/src/Libraries/SmartStore.Services/Localization/LocalizationService.cs index 21cf03447f..31f83eb7dc 100644 --- a/src/Libraries/SmartStore.Services/Localization/LocalizationService.cs +++ b/src/Libraries/SmartStore.Services/Localization/LocalizationService.cs @@ -1,29 +1,28 @@ using System; +using System.Collections; +using System.Collections.Concurrent; using System.Collections.Generic; using System.Data; using System.IO; using System.Linq; using System.Text; +using System.Text.RegularExpressions; using System.Xml; using SmartStore.Core; using SmartStore.Core.Caching; using SmartStore.Core.Data; +using SmartStore.Core.Domain.DataExchange; using SmartStore.Core.Domain.Localization; using SmartStore.Core.Events; using SmartStore.Core.Logging; using SmartStore.Core.Plugins; -using System.Text.RegularExpressions; -using System.Collections.Concurrent; -using System.Web.Mvc; -using System.Collections; -using SmartStore.Services.DataExchange.Import; namespace SmartStore.Services.Localization { - /// - /// Provides information about localization - /// - public partial class LocalizationService : ILocalizationService + /// + /// Provides information about localization + /// + public partial class LocalizationService : ILocalizationService { #region Constants private const string LOCALESTRINGRESOURCES_ALL_KEY = "SmartStore.lsr.all-{0}"; diff --git a/src/Libraries/SmartStore.Services/SmartStore.Services.csproj b/src/Libraries/SmartStore.Services/SmartStore.Services.csproj index 8af64def3c..b82c8f43a1 100644 --- a/src/Libraries/SmartStore.Services/SmartStore.Services.csproj +++ b/src/Libraries/SmartStore.Services/SmartStore.Services.csproj @@ -198,8 +198,6 @@ - - @@ -361,7 +359,6 @@ - @@ -380,7 +377,6 @@ - diff --git a/src/Presentation/SmartStore.Web.Framework/DependencyRegistrar.cs b/src/Presentation/SmartStore.Web.Framework/DependencyRegistrar.cs index 8c49b043ed..37ea64ef94 100644 --- a/src/Presentation/SmartStore.Web.Framework/DependencyRegistrar.cs +++ b/src/Presentation/SmartStore.Web.Framework/DependencyRegistrar.cs @@ -67,17 +67,16 @@ using SmartStore.Services.Themes; using SmartStore.Services.Topics; using SmartStore.Utilities; -using SmartStore.Web.Framework.Controllers; +using SmartStore.Web.Framework.Bundling; +using SmartStore.Web.Framework.Filters; using SmartStore.Web.Framework.Localization; using SmartStore.Web.Framework.Plugins; +using SmartStore.Web.Framework.Routing; using SmartStore.Web.Framework.Theming; using SmartStore.Web.Framework.UI; using SmartStore.Web.Framework.WebApi; using SmartStore.Web.Framework.WebApi.Configuration; using Module = Autofac.Module; -using SmartStore.Web.Framework.Bundling; -using SmartStore.Web.Framework.Filters; -using SmartStore.Web.Framework.Routing; namespace SmartStore.Web.Framework { @@ -241,8 +240,6 @@ protected override void Load(ContainerBuilder builder) builder.RegisterType().As().InstancePerRequest(); builder.RegisterType().As().InstancePerRequest(); - - builder.RegisterType().As().InstancePerRequest(); builder.RegisterType().As().InstancePerRequest(); builder.RegisterType().As().InstancePerRequest(); diff --git a/src/Presentation/SmartStore.Web/Administration/Controllers/LanguageController.cs b/src/Presentation/SmartStore.Web/Administration/Controllers/LanguageController.cs index 0d7cbbd0dd..e546998d03 100644 --- a/src/Presentation/SmartStore.Web/Administration/Controllers/LanguageController.cs +++ b/src/Presentation/SmartStore.Web/Administration/Controllers/LanguageController.cs @@ -2,15 +2,14 @@ using System.Collections.Generic; using System.IO; using System.Linq; -using System.Text; using System.Web.Mvc; using SmartStore.Admin.Models.Localization; using SmartStore.Core; using SmartStore.Core.Data; using SmartStore.Core.Domain.Common; +using SmartStore.Core.Domain.DataExchange; using SmartStore.Core.Domain.Localization; using SmartStore.Core.Plugins; -using SmartStore.Services.DataExchange.Import; using SmartStore.Services.Localization; using SmartStore.Services.Security; using SmartStore.Services.Stores; @@ -23,7 +22,7 @@ namespace SmartStore.Admin.Controllers { - [AdminAuthorize] + [AdminAuthorize] public partial class LanguageController : AdminControllerBase { #region Fields diff --git a/src/Presentation/SmartStore.Web/Administration/Controllers/ProductController.cs b/src/Presentation/SmartStore.Web/Administration/Controllers/ProductController.cs index 8270ea5cdb..e1f0748bfc 100644 --- a/src/Presentation/SmartStore.Web/Administration/Controllers/ProductController.cs +++ b/src/Presentation/SmartStore.Web/Administration/Controllers/ProductController.cs @@ -23,7 +23,6 @@ using SmartStore.Services.Catalog; using SmartStore.Services.Common; using SmartStore.Services.Customers; -using SmartStore.Services.DataExchange.Import; using SmartStore.Services.Directory; using SmartStore.Services.Discounts; using SmartStore.Services.Helpers; @@ -110,7 +109,6 @@ public ProductController( ITaxCategoryService taxCategoryService, IProductTagService productTagService, ICopyProductService copyProductService, - IImportManager importManager, ICustomerActivityService customerActivityService, IPermissionService permissionService, IAclService aclService, From 8f0e4b30e17b9537fd2a018ec10ec089510b3147 Mon Sep 17 00:00:00 2001 From: Marcus Gesing Date: Fri, 18 Dec 2015 14:33:42 +0100 Subject: [PATCH 179/707] Added category importer --- changelog.md | 1 + .../Domain/DataExchange/ImportEnums.cs | 3 +- .../201512151526290_ImportFramework.cs | 3 +- .../Catalog/Importer/CategoryImporter.cs | 282 ++++++++++++++++++ .../Catalog/Importer/ProductImporter.cs | 13 +- .../Customers/Importer/CustomerImporter.cs | 15 +- .../DataExchange/Import/DataImporter.cs | 5 +- .../SmartStore.Services.csproj | 1 + 8 files changed, 308 insertions(+), 15 deletions(-) create mode 100644 src/Libraries/SmartStore.Services/Catalog/Importer/CategoryImporter.cs diff --git a/changelog.md b/changelog.md index 1c11d670f2..6294b6d91e 100644 --- a/changelog.md +++ b/changelog.md @@ -29,6 +29,7 @@ * Admin > System > System Info shows used application memory (RAM) * Added option to make VATIN mandatory during customer registration * Customer import +* Category import ### Improvements * (Perf) Implemented static caches for URL aliases and localized properties. Increases app startup and request speed by up to 30%. diff --git a/src/Libraries/SmartStore.Core/Domain/DataExchange/ImportEnums.cs b/src/Libraries/SmartStore.Core/Domain/DataExchange/ImportEnums.cs index 00c323ae6a..d3ea351a16 100644 --- a/src/Libraries/SmartStore.Core/Domain/DataExchange/ImportEnums.cs +++ b/src/Libraries/SmartStore.Core/Domain/DataExchange/ImportEnums.cs @@ -9,7 +9,8 @@ public enum ImportEntityType { Product = 0, Customer, - NewsLetterSubscription + NewsLetterSubscription, + Category } public enum ImportFileType diff --git a/src/Libraries/SmartStore.Data/Migrations/201512151526290_ImportFramework.cs b/src/Libraries/SmartStore.Data/Migrations/201512151526290_ImportFramework.cs index 2bc57f326a..3d1227f9c4 100644 --- a/src/Libraries/SmartStore.Data/Migrations/201512151526290_ImportFramework.cs +++ b/src/Libraries/SmartStore.Data/Migrations/201512151526290_ImportFramework.cs @@ -102,7 +102,8 @@ public void MigrateLocaleResources(LocaleResourcesBuilder builder) builder.AddOrUpdate("Enums.SmartStore.Core.Domain.DataExchange.ImportEntityType.Product", "Product", "Produkt"); builder.AddOrUpdate("Enums.SmartStore.Core.Domain.DataExchange.ImportEntityType.Customer", "Customer", "Kunde"); - builder.AddOrUpdate("Enums.SmartStore.Core.Domain.DataExchange.ImportEntityType.NewsLetterSubscription", "Newsletter Subscribers", "Newsletter Abonnenten"); + builder.AddOrUpdate("Enums.SmartStore.Core.Domain.DataExchange.ImportEntityType.NewsLetterSubscription", "Newsletter Subscriber", "Newsletter Abonnent"); + builder.AddOrUpdate("Enums.SmartStore.Core.Domain.DataExchange.ImportEntityType.Category", "Category", "Warengruppe"); builder.AddOrUpdate("Enums.SmartStore.Core.Domain.DataExchange.ImportFileType.CSV", "Delimiter separated values (.csv)", "Trennzeichen getrennte Werte (.csv)"); builder.AddOrUpdate("Enums.SmartStore.Core.Domain.DataExchange.ImportFileType.XLSX", "Excel (.xlsx)", "Excel (.xlsx)"); diff --git a/src/Libraries/SmartStore.Services/Catalog/Importer/CategoryImporter.cs b/src/Libraries/SmartStore.Services/Catalog/Importer/CategoryImporter.cs new file mode 100644 index 0000000000..2805097bc6 --- /dev/null +++ b/src/Libraries/SmartStore.Services/Catalog/Importer/CategoryImporter.cs @@ -0,0 +1,282 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using SmartStore.Core.Data; +using SmartStore.Core.Domain.Catalog; +using SmartStore.Core.Domain.DataExchange; +using SmartStore.Core.Domain.Media; +using SmartStore.Core.Domain.Seo; +using SmartStore.Core.Events; +using SmartStore.Services.DataExchange.Import; +using SmartStore.Services.Seo; +using SmartStore.Services.Stores; + +namespace SmartStore.Services.Catalog.Importer +{ + public class CategoryImporter : IEntityImporter + { + private readonly IRepository _categoryRepository; + private readonly IRepository _urlRecordRepository; + private readonly IRepository _pictureRepository; + private readonly ICommonServices _services; + private readonly ICategoryService _categoryService; + private readonly IUrlRecordService _urlRecordService; + private readonly ICategoryTemplateService _categoryTemplateService; + private readonly IStoreMappingService _storeMappingService; + private readonly SeoSettings _seoSettings; + + public CategoryImporter( + IRepository categoryRepository, + IRepository urlRecordRepository, + IRepository pictureRepository, + ICommonServices services, + ICategoryService categoryService, + IUrlRecordService urlRecordService, + ICategoryTemplateService categoryTemplateService, + IStoreMappingService storeMappingService, + SeoSettings seoSettings) + { + _categoryRepository = categoryRepository; + _urlRecordRepository = urlRecordRepository; + _pictureRepository = pictureRepository; + _services = services; + _categoryService = categoryService; + _urlRecordService = urlRecordService; + _categoryTemplateService = categoryTemplateService; + _storeMappingService = storeMappingService; + _seoSettings = seoSettings; + } + + private int ProcessSlugs(ImportExecuteContext context, ImportRow[] batch) + { + var slugMap = new Dictionary(100); + Func slugLookup = ((s) => + { + if (slugMap.ContainsKey(s)) + { + return slugMap[s]; + } + return (UrlRecord)null; + }); + + var entityName = typeof(Category).Name; + + foreach (var row in batch) + { + if (row.IsNew || row.NameChanged || row.Segmenter.HasDataColumn("SeName")) + { + try + { + string seName = row.GetDataValue("SeName"); + seName = row.Entity.ValidateSeName(seName, row.Entity.Name, true, _urlRecordService, _seoSettings, extraSlugLookup: slugLookup); + + UrlRecord urlRecord = null; + + if (row.IsNew) + { + // dont't bother validating SeName for new entities. + urlRecord = new UrlRecord + { + EntityId = row.Entity.Id, + EntityName = entityName, + Slug = seName, + LanguageId = 0, + IsActive = true, + }; + _urlRecordRepository.Insert(urlRecord); + } + else + { + urlRecord = _urlRecordService.SaveSlug(row.Entity, seName, 0); + } + + if (urlRecord != null) + { + // a new record was inserted to the store: keep track of it for this batch. + slugMap[seName] = urlRecord; + } + } + catch (Exception exception) + { + context.Result.AddWarning(exception.Message, row.GetRowInfo(), "SeName"); + } + } + } + + // commit whole batch at once + return _urlRecordRepository.Context.SaveChanges(); + } + + private int ProcessCategories(ImportExecuteContext context, + ImportRow[] batch, + DateTime utcNow, + List allCategoryTemplateIds) + { + _categoryRepository.AutoCommitEnabled = true; + + Category lastInserted = null; + Category lastUpdated = null; + var defaultTemplateId = allCategoryTemplateIds.First(); + + foreach (var row in batch) + { + Category category = null; + object key; + + // try get by int ID + if (row.DataRow.TryGetValue("Id", out key) && key.ToString().ToInt() > 0) + { + category = _categoryService.GetCategoryById(key.ToString().ToInt()); + } + + if (category == null) + { + // a Name is required with new categories + if (!row.Segmenter.HasDataColumn("Name")) + { + context.Result.AddError("The 'Name' field is required for new categories. Skipping row.", row.GetRowInfo(), "Name"); + continue; + } + category = new Category + { + CategoryTemplateId = defaultTemplateId + }; + } + + var name = row.GetDataValue("Name"); + + row.Initialize(category, name); + + if (!row.IsNew && !category.Name.Equals(name, StringComparison.OrdinalIgnoreCase)) + { + // Perf: use this later for SeName updates. + row.NameChanged = true; + } + + row.SetProperty(context.Result, category, (x) => x.Name); + row.SetProperty(context.Result, category, (x) => x.FullName); + row.SetProperty(context.Result, category, (x) => x.Description); + row.SetProperty(context.Result, category, (x) => x.BottomDescription); + row.SetProperty(context.Result, category, (x) => x.MetaKeywords); + row.SetProperty(context.Result, category, (x) => x.MetaDescription); + row.SetProperty(context.Result, category, (x) => x.MetaTitle); + row.SetProperty(context.Result, category, (x) => x.ParentCategoryId); // TODO: hierachical data in batch processing? + row.SetProperty(context.Result, category, (x) => x.PageSize, 12); + row.SetProperty(context.Result, category, (x) => x.AllowCustomersToSelectPageSize, true); + row.SetProperty(context.Result, category, (x) => x.PageSizeOptions); + row.SetProperty(context.Result, category, (x) => x.PriceRanges); + row.SetProperty(context.Result, category, (x) => x.ShowOnHomePage); + row.SetProperty(context.Result, category, (x) => x.HasDiscountsApplied); + row.SetProperty(context.Result, category, (x) => x.Published, true); + row.SetProperty(context.Result, category, (x) => x.DisplayOrder); + row.SetProperty(context.Result, category, (x) => x.LimitedToStores); + row.SetProperty(context.Result, category, (x) => x.Alias); + row.SetProperty(context.Result, category, (x) => x.DefaultViewMode); + + if (row.DataRow.TryGetValue("CategoryTemplateId", out key)) + { + int templateId = key.ToString().ToInt(); + if (templateId > 0 && allCategoryTemplateIds.Contains(templateId)) + category.CategoryTemplateId = templateId; + } + + if (row.DataRow.TryGetValue("PictureId", out key)) + { + int pictureId = key.ToString().ToInt(); + if (pictureId > 0 && _pictureRepository.TableUntracked.Any(x => x.Id == pictureId)) + category.PictureId = pictureId; + } + + var storeIds = row.GetDataValue>("StoreIds"); + if (storeIds != null && storeIds.Any()) + { + _storeMappingService.SaveStoreMappings(category, storeIds.ToArray()); + } + + row.SetProperty(context.Result, category, (x) => x.CreatedOnUtc, utcNow); + category.UpdatedOnUtc = utcNow; + + if (row.IsTransient) + { + _categoryRepository.Insert(category); + lastInserted = category; + } + else + { + _categoryRepository.Update(category); + lastUpdated = category; + } + } + + // commit whole batch at once + var num = _categoryRepository.Context.SaveChanges(); + + // Perf: notify only about LAST insertion and update + if (lastInserted != null) + _services.EventPublisher.EntityInserted(lastInserted); + if (lastUpdated != null) + _services.EventPublisher.EntityUpdated(lastUpdated); + + return num; + } + + public void Execute(ImportExecuteContext context) + { + var allCategoryTemplateIds = _categoryTemplateService.GetAllCategoryTemplates() + .Select(x => x.Id) + .ToList(); + + using (var scope = new DbContextScope(ctx: _categoryRepository.Context, autoDetectChanges: false, proxyCreation: false, validateOnSave: false)) + { + var segmenter = new ImportDataSegmenter(context.DataTable); + var utcNow = DateTime.UtcNow; + + context.Result.TotalRecords = segmenter.TotalRows; + + while (context.Abort == DataExchangeAbortion.None && segmenter.ReadNextBatch()) + { + var batch = segmenter.CurrentBatch; + + // Perf: detach all entities + _categoryRepository.Context.DetachAll(false); + + context.SetProgress(segmenter.CurrentSegmentFirstRowIndex - 1, segmenter.TotalRows); + + try + { + ProcessCategories(context, batch, utcNow, allCategoryTemplateIds); + } + catch (Exception exception) + { + context.Result.AddError(exception, segmenter.CurrentSegment, "ProcessCategories"); + } + + // reduce batch to saved (valid) products. + // No need to perform import operations on errored products. + batch = batch.Where(x => x.Entity != null && !x.IsTransient).ToArray(); + + // update result object + context.Result.NewRecords += batch.Count(x => x.IsNew && !x.IsTransient); + context.Result.ModifiedRecords += batch.Count(x => !x.IsNew && !x.IsTransient); + + if (context.DataTable.HasColumn("SeName") || batch.Any(x => x.IsNew || x.NameChanged)) + { + try + { + _categoryRepository.Context.AutoDetectChangesEnabled = true; + ProcessSlugs(context, batch); + } + catch (Exception exception) + { + context.Result.AddError(exception, segmenter.CurrentSegment, "ProcessSlugs"); + } + finally + { + _categoryRepository.Context.AutoDetectChangesEnabled = false; + } + } + } + } + } + } +} diff --git a/src/Libraries/SmartStore.Services/Catalog/Importer/ProductImporter.cs b/src/Libraries/SmartStore.Services/Catalog/Importer/ProductImporter.cs index dd0195f223..24eaa38231 100644 --- a/src/Libraries/SmartStore.Services/Catalog/Importer/ProductImporter.cs +++ b/src/Libraries/SmartStore.Services/Catalog/Importer/ProductImporter.cs @@ -371,24 +371,22 @@ private int ProcessProducts(ImportExecuteContext context, ImportRow[] b foreach (var row in batch) { Product product = null; - object key; - var dataRow = row.DataRow; // try get by int ID - if (dataRow.TryGetValue("Id", out key) && key.ToString().ToInt() > 0) + if (row.DataRow.TryGetValue("Id", out key) && key.ToString().ToInt() > 0) { product = _productService.GetProductById(key.ToString().ToInt()); } // try get by SKU - if (product == null && dataRow.TryGetValue("SKU", out key)) + if (product == null && row.DataRow.TryGetValue("SKU", out key)) { product = _productService.GetProductBySku(key.ToString()); } // try get by GTIN - if (product == null && dataRow.TryGetValue("Gtin", out key)) + if (product == null && row.DataRow.TryGetValue("Gtin", out key)) { product = _productService.GetProductByGtin(key.ToString()); } @@ -404,7 +402,7 @@ private int ProcessProducts(ImportExecuteContext context, ImportRow[] b product = new Product(); } - string name = row.GetDataValue("Name"); + var name = row.GetDataValue("Name"); row.Initialize(product, name); @@ -508,7 +506,6 @@ private int ProcessProducts(ImportExecuteContext context, ImportRow[] b } row.SetProperty(context.Result, product, (x) => x.CreatedOnUtc, utcNow); - product.UpdatedOnUtc = utcNow; if (row.IsTransient) @@ -587,7 +584,7 @@ public void Execute(ImportExecuteContext context) } catch (Exception exception) { - context.Result.AddError(exception, segmenter.CurrentSegment, "ProcessSeoSlugs"); + context.Result.AddError(exception, segmenter.CurrentSegment, "ProcessSlugs"); } finally { diff --git a/src/Libraries/SmartStore.Services/Customers/Importer/CustomerImporter.cs b/src/Libraries/SmartStore.Services/Customers/Importer/CustomerImporter.cs index c5204fe8aa..4236fa81f8 100644 --- a/src/Libraries/SmartStore.Services/Customers/Importer/CustomerImporter.cs +++ b/src/Libraries/SmartStore.Services/Customers/Importer/CustomerImporter.cs @@ -197,7 +197,12 @@ private int ProcessCustomers(ImportExecuteContext context, if (customer == null) { - customer = new Customer(); + customer = new Customer + { + CustomerGuid = new Guid(), + AffiliateId = 0, + Active = true + }; } else { @@ -205,7 +210,6 @@ private int ProcessCustomers(ImportExecuteContext context, } var email = row.GetDataValue("Email"); - var affiliateId = row.GetDataValue("AffiliateId"); var isGuest = row.GetDataValue("IsGuest"); var isRegistered = row.GetDataValue("IsRegistered"); var isAdmin = row.GetDataValue("IsAdministrator"); @@ -231,11 +235,14 @@ private int ProcessCustomers(ImportExecuteContext context, row.SetProperty(context.Result, customer, (x) => x.CreatedOnUtc, utcNow); row.SetProperty(context.Result, customer, (x) => x.LastActivityDateUtc, utcNow); - if (affiliateId != 0 && allAffiliateIds.Contains(affiliateId)) + if (row.DataRow.TryGetValue("AffiliateId", out key)) { - row.SetProperty(context.Result, customer, (x) => x.AffiliateId, affiliateId); + int affiliateId = key.ToString().ToInt(); + if (affiliateId > 0 && allAffiliateIds.Contains(affiliateId)) + customer.AffiliateId = affiliateId; } + UpsertRole(row, guestRole, SystemCustomerRoleNames.Guests, isGuest); UpsertRole(row, registeredRole, SystemCustomerRoleNames.Registered, isRegistered); UpsertRole(row, adminRole, SystemCustomerRoleNames.Administrators, isAdmin); diff --git a/src/Libraries/SmartStore.Services/DataExchange/Import/DataImporter.cs b/src/Libraries/SmartStore.Services/DataExchange/Import/DataImporter.cs index 56906c4b8a..a45fd29155 100644 --- a/src/Libraries/SmartStore.Services/DataExchange/Import/DataImporter.cs +++ b/src/Libraries/SmartStore.Services/DataExchange/Import/DataImporter.cs @@ -132,7 +132,7 @@ private bool HasPermission(DataImporterContext ctx) { var customer = _customerService.GetCustomerById(ctx.Request.CustomerId); - if (ctx.Request.Profile.EntityType == ImportEntityType.Product) + if (ctx.Request.Profile.EntityType == ImportEntityType.Product || ctx.Request.Profile.EntityType == ImportEntityType.Category) return _services.Permissions.Authorize(StandardPermissionProvider.ManageCatalog, customer); if (ctx.Request.Profile.EntityType == ImportEntityType.Customer) @@ -318,6 +318,9 @@ private void ImportCoreOuter(DataImporterContext ctx) _services, _subscriptionRepository.Value); } + else if (ctx.Request.Profile.EntityType == ImportEntityType.Category) + { + } else { throw new SmartException("Unsupported entity type {0}.".FormatInvariant(ctx.Request.Profile.EntityType.ToString())); diff --git a/src/Libraries/SmartStore.Services/SmartStore.Services.csproj b/src/Libraries/SmartStore.Services/SmartStore.Services.csproj index b82c8f43a1..1ad4d843a6 100644 --- a/src/Libraries/SmartStore.Services/SmartStore.Services.csproj +++ b/src/Libraries/SmartStore.Services/SmartStore.Services.csproj @@ -166,6 +166,7 @@ Properties\AssemblyVersionInfo.cs + From bfca09a0c260dcba91fcd40d4dae79bec1812000 Mon Sep 17 00:00:00 2001 From: Marcus Gesing Date: Fri, 18 Dec 2015 17:59:54 +0100 Subject: [PATCH 180/707] More on category import --- .../DataExchange/Import/DataImporter.cs | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/src/Libraries/SmartStore.Services/DataExchange/Import/DataImporter.cs b/src/Libraries/SmartStore.Services/DataExchange/Import/DataImporter.cs index a45fd29155..253551e629 100644 --- a/src/Libraries/SmartStore.Services/DataExchange/Import/DataImporter.cs +++ b/src/Libraries/SmartStore.Services/DataExchange/Import/DataImporter.cs @@ -9,6 +9,7 @@ using SmartStore.Core.Domain.Customers; using SmartStore.Core.Domain.DataExchange; using SmartStore.Core.Domain.Forums; +using SmartStore.Core.Domain.Media; using SmartStore.Core.Domain.Messages; using SmartStore.Core.Domain.Seo; using SmartStore.Core.Localization; @@ -41,18 +42,21 @@ public partial class DataImporter : IDataImporter private readonly ICustomerService _customerService; private readonly Lazy> _subscriptionRepository; + private readonly Lazy> _pictureRepository; private readonly Lazy> _productPictureRepository; private readonly Lazy> _productManufacturerRepository; private readonly Lazy> _productCategoryRepository; private readonly Lazy> _urlRecordRepository; private readonly Lazy> _productRepository; private readonly Lazy> _customerRepository; + private readonly Lazy> _categoryRepository; private readonly Lazy _languageService; private readonly Lazy _localizedEntityService; private readonly Lazy _pictureService; private readonly Lazy _manufacturerService; private readonly Lazy _categoryService; + private readonly Lazy _categoryTemplateService; private readonly Lazy _productService; private readonly Lazy _urlRecordService; private readonly Lazy _storeMappingService; @@ -70,17 +74,20 @@ public DataImporter( ICommonServices services, ICustomerService customerService, Lazy> subscriptionRepository, + Lazy> pictureRepository, Lazy> productPictureRepository, Lazy> productManufacturerRepository, Lazy> productCategoryRepository, Lazy> urlRecordRepository, Lazy> productRepository, Lazy> customerRepository, + Lazy> categoryRepository, Lazy languageService, Lazy localizedEntityService, Lazy pictureService, Lazy manufacturerService, Lazy categoryService, + Lazy categoryTemplateService, Lazy productService, Lazy urlRecordService, Lazy storeMappingService, @@ -96,18 +103,21 @@ public DataImporter( _services = services; _customerService = customerService; _subscriptionRepository = subscriptionRepository; + _pictureRepository = pictureRepository; _productPictureRepository = productPictureRepository; _productManufacturerRepository = productManufacturerRepository; _productCategoryRepository = productCategoryRepository; _urlRecordRepository = urlRecordRepository; _productRepository = productRepository; _customerRepository = customerRepository; + _categoryRepository = categoryRepository; _languageService = languageService; _localizedEntityService = localizedEntityService; _pictureService = pictureService; _manufacturerService = manufacturerService; _categoryService = categoryService; + _categoryTemplateService = categoryTemplateService; _productService = productService; _urlRecordService = urlRecordService; _storeMappingService = storeMappingService; @@ -320,6 +330,16 @@ private void ImportCoreOuter(DataImporterContext ctx) } else if (ctx.Request.Profile.EntityType == ImportEntityType.Category) { + ctx.Importer = new CategoryImporter( + _categoryRepository.Value, + _urlRecordRepository.Value, + _pictureRepository.Value, + _services, + _categoryService.Value, + _urlRecordService.Value, + _categoryTemplateService.Value, + _storeMappingService.Value, + _seoSettings.Value); } else { From 2ca611c9e40cc6566d75a737210d701a1fa36082 Mon Sep 17 00:00:00 2001 From: Marcus Gesing Date: Fri, 18 Dec 2015 20:53:23 +0100 Subject: [PATCH 181/707] Category import: map parent id of inserted records (to build category tree) but leave parent id of updated records untouched --- .../Catalog/Importer/CategoryImporter.cs | 101 ++++++++++++++++-- .../DataExchange/Import/DataImporter.cs | 1 - 2 files changed, 92 insertions(+), 10 deletions(-) diff --git a/src/Libraries/SmartStore.Services/Catalog/Importer/CategoryImporter.cs b/src/Libraries/SmartStore.Services/Catalog/Importer/CategoryImporter.cs index 2805097bc6..8f5c066c8b 100644 --- a/src/Libraries/SmartStore.Services/Catalog/Importer/CategoryImporter.cs +++ b/src/Libraries/SmartStore.Services/Catalog/Importer/CategoryImporter.cs @@ -19,7 +19,6 @@ public class CategoryImporter : IEntityImporter private readonly IRepository _urlRecordRepository; private readonly IRepository _pictureRepository; private readonly ICommonServices _services; - private readonly ICategoryService _categoryService; private readonly IUrlRecordService _urlRecordService; private readonly ICategoryTemplateService _categoryTemplateService; private readonly IStoreMappingService _storeMappingService; @@ -30,7 +29,6 @@ public CategoryImporter( IRepository urlRecordRepository, IRepository pictureRepository, ICommonServices services, - ICategoryService categoryService, IUrlRecordService urlRecordService, ICategoryTemplateService categoryTemplateService, IStoreMappingService storeMappingService, @@ -40,7 +38,6 @@ public CategoryImporter( _urlRecordRepository = urlRecordRepository; _pictureRepository = pictureRepository; _services = services; - _categoryService = categoryService; _urlRecordService = urlRecordService; _categoryTemplateService = categoryTemplateService; _storeMappingService = storeMappingService; @@ -107,13 +104,49 @@ private int ProcessSlugs(ImportExecuteContext context, ImportRow[] bat return _urlRecordRepository.Context.SaveChanges(); } + private int ProcessParentMappings(ImportExecuteContext context, + ImportRow[] batch, + Dictionary oldToNewId) + { + object key1, key2; + + foreach (var row in batch) + { + if (row.DataRow.TryGetValue("Id", out key1) && + row.Segmenter.HasDataColumn("ParentCategoryId") && row.DataRow.TryGetValue("ParentCategoryId", out key2)) + { + var id = key1.ToString().ToInt(); + var parentId = key2.ToString().ToInt(-1); + + if (id != 0 && parentId != -1 && oldToNewId.ContainsKey(id) && oldToNewId.ContainsKey(parentId)) + { + // only touch hierarchical data if child and parent were inserted + if (oldToNewId[id].Inserted && oldToNewId[parentId].Inserted && oldToNewId[id].NewId != 0) + { + var category = _categoryRepository.GetById(oldToNewId[id].NewId); + if (category != null) + { + category.ParentCategoryId = oldToNewId[parentId].NewId; + } + } + } + } + } + + var num = _categoryRepository.Context.SaveChanges(); + + return num; + } + private int ProcessCategories(ImportExecuteContext context, ImportRow[] batch, DateTime utcNow, - List allCategoryTemplateIds) + List allCategoryTemplateIds, + Dictionary oldToNewId) { _categoryRepository.AutoCommitEnabled = true; + object key; Category lastInserted = null; Category lastUpdated = null; var defaultTemplateId = allCategoryTemplateIds.First(); @@ -121,12 +154,16 @@ private int ProcessCategories(ImportExecuteContext context, foreach (var row in batch) { Category category = null; - object key; + var id = 0; // try get by int ID - if (row.DataRow.TryGetValue("Id", out key) && key.ToString().ToInt() > 0) + if (row.DataRow.TryGetValue("Id", out key)) { - category = _categoryService.GetCategoryById(key.ToString().ToInt()); + id = key.ToString().ToInt(); + if (id != 0) + { + category = _categoryRepository.GetById(id); + } } if (category == null) @@ -160,7 +197,6 @@ private int ProcessCategories(ImportExecuteContext context, row.SetProperty(context.Result, category, (x) => x.MetaKeywords); row.SetProperty(context.Result, category, (x) => x.MetaDescription); row.SetProperty(context.Result, category, (x) => x.MetaTitle); - row.SetProperty(context.Result, category, (x) => x.ParentCategoryId); // TODO: hierachical data in batch processing? row.SetProperty(context.Result, category, (x) => x.PageSize, 12); row.SetProperty(context.Result, category, (x) => x.AllowCustomersToSelectPageSize, true); row.SetProperty(context.Result, category, (x) => x.PageSizeOptions); @@ -196,6 +232,11 @@ private int ProcessCategories(ImportExecuteContext context, row.SetProperty(context.Result, category, (x) => x.CreatedOnUtc, utcNow); category.UpdatedOnUtc = utcNow; + if (id != 0 && !oldToNewId.ContainsKey(id)) + { + oldToNewId.Add(id, new ImportCategoryMapping { Inserted = row.IsTransient }); + } + if (row.IsTransient) { _categoryRepository.Insert(category); @@ -211,6 +252,17 @@ private int ProcessCategories(ImportExecuteContext context, // commit whole batch at once var num = _categoryRepository.Context.SaveChanges(); + // get new category ids + foreach (var row in batch) + { + if (row.DataRow.TryGetValue("Id", out key)) + { + var id = key.ToString().ToInt(); + if (id != 0 && oldToNewId.ContainsKey(id)) + oldToNewId[id].NewId = row.Entity.Id; + } + } + // Perf: notify only about LAST insertion and update if (lastInserted != null) _services.EventPublisher.EntityInserted(lastInserted); @@ -222,6 +274,8 @@ private int ProcessCategories(ImportExecuteContext context, public void Execute(ImportExecuteContext context) { + var oldToNewId = new Dictionary(); + var allCategoryTemplateIds = _categoryTemplateService.GetAllCategoryTemplates() .Select(x => x.Id) .ToList(); @@ -244,7 +298,7 @@ public void Execute(ImportExecuteContext context) try { - ProcessCategories(context, batch, utcNow, allCategoryTemplateIds); + ProcessCategories(context, batch, utcNow, allCategoryTemplateIds, oldToNewId); } catch (Exception exception) { @@ -276,7 +330,36 @@ public void Execute(ImportExecuteContext context) } } } + + // map parent id of inserted categories + if (oldToNewId.Any()) + { + segmenter.Reset(); + + while (context.Abort == DataExchangeAbortion.None && segmenter.ReadNextBatch()) + { + var batch = segmenter.CurrentBatch; + + _categoryRepository.Context.DetachAll(false); + + try + { + ProcessParentMappings(context, batch, oldToNewId); + } + catch (Exception exception) + { + context.Result.AddError(exception, segmenter.CurrentSegment, "ProcessParentMappings"); + } + } + } } } } + + + internal class ImportCategoryMapping + { + public int NewId { get; set; } + public bool Inserted { get; set; } + } } diff --git a/src/Libraries/SmartStore.Services/DataExchange/Import/DataImporter.cs b/src/Libraries/SmartStore.Services/DataExchange/Import/DataImporter.cs index 253551e629..8e79251e45 100644 --- a/src/Libraries/SmartStore.Services/DataExchange/Import/DataImporter.cs +++ b/src/Libraries/SmartStore.Services/DataExchange/Import/DataImporter.cs @@ -335,7 +335,6 @@ private void ImportCoreOuter(DataImporterContext ctx) _urlRecordRepository.Value, _pictureRepository.Value, _services, - _categoryService.Value, _urlRecordService.Value, _categoryTemplateService.Value, _storeMappingService.Value, From f5675c6618fc5dd7b8c0ce61b32767e12d15bde1 Mon Sep 17 00:00:00 2001 From: Marcus Gesing Date: Sat, 19 Dec 2015 13:00:59 +0100 Subject: [PATCH 182/707] Export all product picture paths into one, pipe delimited field --- .../Catalog/Importer/ProductImporter.cs | 128 +++++++++--------- .../DataExchange/ExportExtensions.cs | 17 +++ .../DataExchange/Import/DataImporter.cs | 17 +-- .../DataExchange/Import/ImportMessage.cs | 15 +- .../DataExchange/Import/ImportResult.cs | 2 + 5 files changed, 103 insertions(+), 76 deletions(-) diff --git a/src/Libraries/SmartStore.Services/Catalog/Importer/ProductImporter.cs b/src/Libraries/SmartStore.Services/Catalog/Importer/ProductImporter.cs index 24eaa38231..231872f859 100644 --- a/src/Libraries/SmartStore.Services/Catalog/Importer/ProductImporter.cs +++ b/src/Libraries/SmartStore.Services/Catalog/Importer/ProductImporter.cs @@ -19,11 +19,11 @@ namespace SmartStore.Services.Catalog.Importer { public class ProductImporter : IEntityImporter { - private readonly IRepository _rsProductPicture; - private readonly IRepository _rsProductManufacturer; - private readonly IRepository _rsProductCategory; - private readonly IRepository _rsUrlRecord; - private readonly IRepository _rsProduct; + private readonly IRepository _productPictureRepository; + private readonly IRepository _productManufacturerRepository; + private readonly IRepository _productCategoryRepository; + private readonly IRepository _urlRecordRepository; + private readonly IRepository _productRepository; private readonly ICommonServices _services; private readonly ILanguageService _languageService; private readonly ILocalizedEntityService _localizedEntityService; @@ -36,11 +36,11 @@ public class ProductImporter : IEntityImporter private readonly SeoSettings _seoSettings; public ProductImporter( - IRepository rsProductPicture, - IRepository rsProductManufacturer, - IRepository rsProductCategory, - IRepository rsUrlRecord, - IRepository rsProduct, + IRepository productPictureRepository, + IRepository productManufacturerRepository, + IRepository productCategoryRepository, + IRepository urlRecordRepository, + IRepository productRepository, ICommonServices services, ILanguageService languageService, ILocalizedEntityService localizedEntityService, @@ -52,11 +52,11 @@ public ProductImporter( IStoreMappingService storeMappingService, SeoSettings seoSettings) { - _rsProductPicture = rsProductPicture; - _rsProductManufacturer = rsProductManufacturer; - _rsProductCategory = rsProductCategory; - _rsUrlRecord = rsUrlRecord; - _rsProduct = rsProduct; + _productPictureRepository = productPictureRepository; + _productManufacturerRepository = productManufacturerRepository; + _productCategoryRepository = productCategoryRepository; + _urlRecordRepository = urlRecordRepository; + _productRepository = productRepository; _services = services; _languageService = languageService; _localizedEntityService = localizedEntityService; @@ -82,34 +82,38 @@ public ProductImporter( private void ProcessProductPictures(ImportExecuteContext context, ImportRow[] batch) { - // true, cause pictures must be saved and assigned an id - // prior adding a mapping. - _rsProductPicture.AutoCommitEnabled = true; + // true, cause pictures must be saved and assigned an id prior adding a mapping. + _productPictureRepository.AutoCommitEnabled = true; ProductPicture lastInserted = null; - int equalPictureId = 0; + var equalPictureId = 0; foreach (var row in batch) { - var pictures = new string[] - { - row.GetDataValue("Picture1"), - row.GetDataValue("Picture2"), - row.GetDataValue("Picture3") - }; + var count = -1; + var thumbPaths = row.GetDataValue>("PictureThumbPaths"); - int i = 0; - try + if (thumbPaths == null) + continue; + + foreach (var path in thumbPaths.Where(x => x.HasValue() && File.Exists(x))) { - for (i = 0; i < pictures.Length; i++) + try { - var picture = pictures[i]; + var currentProductPictures = _productPictureRepository.TableUntracked.Expand(x => x.Picture) + .Where(x => x.ProductId == row.Entity.Id) + .ToList(); - if (picture.IsEmpty() || !File.Exists(picture)) - continue; + var currentPictures = currentProductPictures + .Select(x => x.Picture) + .ToList(); - var currentPictures = _rsProductPicture.TableUntracked.Expand(x => x.Picture).Where(x => x.ProductId == row.Entity.Id).Select(x => x.Picture).ToList(); - var pictureBinary = _pictureService.FindEqualPicture(picture, currentPictures, out equalPictureId); + if (count == -1) + { + count = (currentProductPictures.Any() ? currentProductPictures.Select(x => x.DisplayOrder).Max() : 0); + } + + var pictureBinary = _pictureService.FindEqualPicture(path, currentPictures, out equalPictureId); if (pictureBinary != null && pictureBinary.Length > 0) { @@ -121,23 +125,25 @@ private void ProcessProductPictures(ImportExecuteContext context, ImportRow[] batch) { - _rsProductManufacturer.AutoCommitEnabled = false; + _productManufacturerRepository.AutoCommitEnabled = false; ProductManufacturer lastInserted = null; @@ -160,7 +166,7 @@ private int ProcessProductManufacturers(ImportExecuteContext context, ImportRow< { foreach (var id in manufacturerIds) { - if (_rsProductManufacturer.TableUntracked.Where(x => x.ProductId == row.Entity.Id && x.ManufacturerId == id).FirstOrDefault() == null) + if (_productManufacturerRepository.TableUntracked.Where(x => x.ProductId == row.Entity.Id && x.ManufacturerId == id).FirstOrDefault() == null) { // ensure that manufacturer exists var manufacturer = _manufacturerService.GetManufacturerById(id); @@ -173,7 +179,7 @@ private int ProcessProductManufacturers(ImportExecuteContext context, ImportRow< IsFeaturedProduct = false, DisplayOrder = 1 }; - _rsProductManufacturer.Insert(productManufacturer); + _productManufacturerRepository.Insert(productManufacturer); lastInserted = productManufacturer; } } @@ -187,7 +193,7 @@ private int ProcessProductManufacturers(ImportExecuteContext context, ImportRow< } // commit whole batch at once - var num = _rsProductManufacturer.Context.SaveChanges(); + var num = _productManufacturerRepository.Context.SaveChanges(); // Perf: notify only about LAST insertion and update if (lastInserted != null) @@ -198,7 +204,7 @@ private int ProcessProductManufacturers(ImportExecuteContext context, ImportRow< private int ProcessProductCategories(ImportExecuteContext context, ImportRow[] batch) { - _rsProductCategory.AutoCommitEnabled = false; + _productCategoryRepository.AutoCommitEnabled = false; ProductCategory lastInserted = null; @@ -211,7 +217,7 @@ private int ProcessProductCategories(ImportExecuteContext context, ImportRow x.ProductId == row.Entity.Id && x.CategoryId == id).FirstOrDefault() == null) + if (_productCategoryRepository.TableUntracked.Where(x => x.ProductId == row.Entity.Id && x.CategoryId == id).FirstOrDefault() == null) { // ensure that category exists var category = _categoryService.GetCategoryById(id); @@ -224,7 +230,7 @@ private int ProcessProductCategories(ImportExecuteContext context, ImportRow[] batc LanguageId = 0, IsActive = true, }; - _rsUrlRecord.Insert(urlRecord); + _urlRecordRepository.Insert(urlRecord); } else { @@ -358,12 +364,12 @@ private int ProcessSlugs(ImportExecuteContext context, ImportRow[] batc } // commit whole batch at once - return _rsUrlRecord.Context.SaveChanges(); + return _urlRecordRepository.Context.SaveChanges(); } private int ProcessProducts(ImportExecuteContext context, ImportRow[] batch, DateTime utcNow) { - _rsProduct.AutoCommitEnabled = true; + _productRepository.AutoCommitEnabled = true; Product lastInserted = null; Product lastUpdated = null; @@ -510,18 +516,18 @@ private int ProcessProducts(ImportExecuteContext context, ImportRow[] b if (row.IsTransient) { - _rsProduct.Insert(product); + _productRepository.Insert(product); lastInserted = product; } else { - _rsProduct.Update(product); + _productRepository.Update(product); lastUpdated = product; } } // commit whole batch at once - var num = _rsProduct.Context.SaveChanges(); + var num = _productRepository.Context.SaveChanges(); // Perf: notify only about LAST insertion and update if (lastInserted != null) @@ -534,7 +540,7 @@ private int ProcessProducts(ImportExecuteContext context, ImportRow[] b public void Execute(ImportExecuteContext context) { - using (var scope = new DbContextScope(ctx: _rsProduct.Context, autoDetectChanges: false, proxyCreation: false, validateOnSave: false)) + using (var scope = new DbContextScope(ctx: _productRepository.Context, autoDetectChanges: false, proxyCreation: false, validateOnSave: false)) { var segmenter = new ImportDataSegmenter(context.DataTable); var utcNow = DateTime.UtcNow; @@ -546,7 +552,7 @@ public void Execute(ImportExecuteContext context) var batch = segmenter.CurrentBatch; // Perf: detach all entities - _rsProduct.Context.DetachAll(false); + _productRepository.Context.DetachAll(false); context.SetProgress(segmenter.CurrentSegmentFirstRowIndex - 1, segmenter.TotalRows); @@ -579,7 +585,7 @@ public void Execute(ImportExecuteContext context) { try { - _rsProduct.Context.AutoDetectChangesEnabled = true; + _productRepository.Context.AutoDetectChangesEnabled = true; ProcessSlugs(context, batch); } catch (Exception exception) @@ -588,7 +594,7 @@ public void Execute(ImportExecuteContext context) } finally { - _rsProduct.Context.AutoDetectChangesEnabled = false; + _productRepository.Context.AutoDetectChangesEnabled = false; } } @@ -637,7 +643,7 @@ public void Execute(ImportExecuteContext context) // =========================================================================== // 6.) Import product picture mappings // =========================================================================== - if (context.DataTable.HasColumn("Picture1") || context.DataTable.HasColumn("Picture2") || context.DataTable.HasColumn("Picture3")) + if (context.DataTable.HasColumn("PictureThumbPaths")) { try { diff --git a/src/Libraries/SmartStore.Services/DataExchange/ExportExtensions.cs b/src/Libraries/SmartStore.Services/DataExchange/ExportExtensions.cs index 3d65d673c8..a0c9f14dcc 100644 --- a/src/Libraries/SmartStore.Services/DataExchange/ExportExtensions.cs +++ b/src/Libraries/SmartStore.Services/DataExchange/ExportExtensions.cs @@ -128,5 +128,22 @@ public static string ResolveFileNamePattern(this ExportProfile profile, Store st return result; } + + /// + /// Join values into a string that can be used for exporting + /// + /// Type + /// Enumerable of values to join + /// Joined values + public static string JoinForExport(this IEnumerable values) + { + if (values == null) + return ""; + + if (typeof(T) == typeof(string)) + return string.Join("|", values); // because file paths cannot contain pipes + + return string.Join(",", values); + } } } diff --git a/src/Libraries/SmartStore.Services/DataExchange/Import/DataImporter.cs b/src/Libraries/SmartStore.Services/DataExchange/Import/DataImporter.cs index 8e79251e45..3a081417a1 100644 --- a/src/Libraries/SmartStore.Services/DataExchange/Import/DataImporter.cs +++ b/src/Libraries/SmartStore.Services/DataExchange/Import/DataImporter.cs @@ -176,23 +176,12 @@ private void LogResult(DataImporterContext ctx) foreach (var message in result.Messages) { - string prefix = null; - - if (message.AffectedItem != null) - prefix.Grow("Pos: " + (message.AffectedItem.Position + 1).ToString(), ", "); - - if (message.AffectedField.HasValue()) - prefix.Grow("Field: " + message.AffectedField, ", "); - - if (prefix.HasValue()) - message.Message = "[{0}] {1}".FormatInvariant(prefix, message.Message); - if (message.MessageType == ImportMessageType.Error) - ctx.Log.Error(message.Message); + ctx.Log.Error(message.ToString()); else if (message.MessageType == ImportMessageType.Warning) - ctx.Log.Warning(message.Message); + ctx.Log.Warning(message.ToString()); else - ctx.Log.Information(message.Message); + ctx.Log.Information(message.ToString()); } } diff --git a/src/Libraries/SmartStore.Services/DataExchange/Import/ImportMessage.cs b/src/Libraries/SmartStore.Services/DataExchange/Import/ImportMessage.cs index 245aabc173..7285a6a52b 100644 --- a/src/Libraries/SmartStore.Services/DataExchange/Import/ImportMessage.cs +++ b/src/Libraries/SmartStore.Services/DataExchange/Import/ImportMessage.cs @@ -39,7 +39,20 @@ public string Message public override string ToString() { - return "{0} - {1}".FormatCurrent(MessageType.ToString().ToUpper(), Message.EmptyNull()); + var result = Message.NaIfEmpty(); + + string appendix = null; + + if (AffectedItem != null) + appendix = appendix.Grow("Pos: " + (AffectedItem.Position + 1).ToString(), ", "); + + if (AffectedField.HasValue()) + appendix = appendix.Grow("Field: " + AffectedField, ", "); + + if (appendix.HasValue()) + result = "{0} [{1}]".FormatInvariant(result, appendix); + + return result; } } diff --git a/src/Libraries/SmartStore.Services/DataExchange/Import/ImportResult.cs b/src/Libraries/SmartStore.Services/DataExchange/Import/ImportResult.cs index 7e52d3948e..d648387876 100644 --- a/src/Libraries/SmartStore.Services/DataExchange/Import/ImportResult.cs +++ b/src/Libraries/SmartStore.Services/DataExchange/Import/ImportResult.cs @@ -106,8 +106,10 @@ public ImportMessage AddError(Exception exception, int? affectedBatch = null, st public ImportMessage AddMessage(string message, ImportMessageType severity, ImportRowInfo affectedRow = null, string affectedField = null) { var msg = new ImportMessage(message, severity); + msg.AffectedItem = affectedRow; msg.AffectedField = affectedField; + this.Messages.Add(msg); return msg; } From 75467a75057405817bfe14808c776a31f2d3c8bc Mon Sep 17 00:00:00 2001 From: Marcus Gesing Date: Sat, 19 Dec 2015 16:46:29 +0100 Subject: [PATCH 183/707] Category import: Treat picture as in product import thus exchange the local picture path --- .../Catalog/Importer/CategoryImporter.cs | 34 +++++++++++++++---- .../DataExchange/Import/DataImporter.cs | 1 + .../Media/IPictureService.cs | 17 +++++----- .../Media/PictureService.cs | 18 +++++----- 4 files changed, 45 insertions(+), 25 deletions(-) diff --git a/src/Libraries/SmartStore.Services/Catalog/Importer/CategoryImporter.cs b/src/Libraries/SmartStore.Services/Catalog/Importer/CategoryImporter.cs index 8f5c066c8b..233a36e638 100644 --- a/src/Libraries/SmartStore.Services/Catalog/Importer/CategoryImporter.cs +++ b/src/Libraries/SmartStore.Services/Catalog/Importer/CategoryImporter.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.IO; using System.Linq; using SmartStore.Core.Data; using SmartStore.Core.Domain.Catalog; @@ -8,6 +9,7 @@ using SmartStore.Core.Domain.Seo; using SmartStore.Core.Events; using SmartStore.Services.DataExchange.Import; +using SmartStore.Services.Media; using SmartStore.Services.Seo; using SmartStore.Services.Stores; @@ -22,6 +24,7 @@ public class CategoryImporter : IEntityImporter private readonly IUrlRecordService _urlRecordService; private readonly ICategoryTemplateService _categoryTemplateService; private readonly IStoreMappingService _storeMappingService; + private readonly IPictureService _pictureService; private readonly SeoSettings _seoSettings; public CategoryImporter( @@ -32,6 +35,7 @@ public CategoryImporter( IUrlRecordService urlRecordService, ICategoryTemplateService categoryTemplateService, IStoreMappingService storeMappingService, + IPictureService pictureService, SeoSettings seoSettings) { _categoryRepository = categoryRepository; @@ -41,6 +45,7 @@ public CategoryImporter( _urlRecordService = urlRecordService; _categoryTemplateService = categoryTemplateService; _storeMappingService = storeMappingService; + _pictureService = pictureService; _seoSettings = seoSettings; } @@ -147,8 +152,10 @@ private int ProcessCategories(ImportExecuteContext context, _categoryRepository.AutoCommitEnabled = true; object key; + Picture picture = null; Category lastInserted = null; Category lastUpdated = null; + var equalPictureId = 0; var defaultTemplateId = allCategoryTemplateIds.First(); foreach (var row in batch) @@ -216,19 +223,32 @@ private int ProcessCategories(ImportExecuteContext context, category.CategoryTemplateId = templateId; } - if (row.DataRow.TryGetValue("PictureId", out key)) - { - int pictureId = key.ToString().ToInt(); - if (pictureId > 0 && _pictureRepository.TableUntracked.Any(x => x.Id == pictureId)) - category.PictureId = pictureId; - } - var storeIds = row.GetDataValue>("StoreIds"); if (storeIds != null && storeIds.Any()) { _storeMappingService.SaveStoreMappings(category, storeIds.ToArray()); } + if (row.DataRow.TryGetValue("PictureThumbPath", out key)) + { + var thumbPath = key.ToString(); + if (thumbPath.HasValue() && File.Exists(thumbPath)) + { + var pictures = new List(); + if (category.PictureId.HasValue && (picture = _pictureRepository.GetById(category.PictureId.Value)) != null) + pictures.Add(picture); + + var pictureBinary = _pictureService.FindEqualPicture(thumbPath, pictures, out equalPictureId); + + if (pictureBinary != null && pictureBinary.Length > 0 && + (picture = _pictureService.InsertPicture(pictureBinary, "image/jpeg", _pictureService.GetPictureSeName(row.EntityDisplayName), true, false, false)) != null) + { + category.PictureId = picture.Id; + } + } + } + + row.SetProperty(context.Result, category, (x) => x.CreatedOnUtc, utcNow); category.UpdatedOnUtc = utcNow; diff --git a/src/Libraries/SmartStore.Services/DataExchange/Import/DataImporter.cs b/src/Libraries/SmartStore.Services/DataExchange/Import/DataImporter.cs index 3a081417a1..b455823401 100644 --- a/src/Libraries/SmartStore.Services/DataExchange/Import/DataImporter.cs +++ b/src/Libraries/SmartStore.Services/DataExchange/Import/DataImporter.cs @@ -327,6 +327,7 @@ private void ImportCoreOuter(DataImporterContext ctx) _urlRecordService.Value, _categoryTemplateService.Value, _storeMappingService.Value, + _pictureService.Value, _seoSettings.Value); } else diff --git a/src/Libraries/SmartStore.Services/Media/IPictureService.cs b/src/Libraries/SmartStore.Services/Media/IPictureService.cs index 85bc1741b5..ce9f231349 100644 --- a/src/Libraries/SmartStore.Services/Media/IPictureService.cs +++ b/src/Libraries/SmartStore.Services/Media/IPictureService.cs @@ -5,10 +5,10 @@ namespace SmartStore.Services.Media { - /// - /// Picture service interface - /// - public partial interface IPictureService + /// + /// Picture service interface + /// + public partial interface IPictureService { /// /// Validates input picture dimensions and prevents that the image size exceeds global max size @@ -22,20 +22,19 @@ public partial interface IPictureService /// Finds an equal picture by comparing the binary buffer /// /// The picture to find a duplicate for - /// The sequence of product pictures to seek within for duplicates + /// The sequence of pictures to seek within for duplicates /// Id of equal picture if any /// The picture binary for path when no picture equals in the sequence, null otherwise. - byte[] FindEqualPicture(string path, IEnumerable productPictures, out int equalPictureId); + byte[] FindEqualPicture(string path, IEnumerable pictures, out int equalPictureId); /// /// Finds an equal picture by comparing the binary buffer /// /// Binary picture data - /// The sequence of product pictures to seek within for duplicates + /// The sequence of pictures to seek within for duplicates /// Id of equal picture if any /// The picture binary for path when no picture equals in the sequence, null otherwise. - byte[] FindEqualPicture(byte[] pictureBinary, IEnumerable productPictures, out int equalPictureId); - + byte[] FindEqualPicture(byte[] pictureBinary, IEnumerable pictures, out int equalPictureId); /// /// Gets the loaded picture binary depending on picture storage settings diff --git a/src/Libraries/SmartStore.Services/Media/PictureService.cs b/src/Libraries/SmartStore.Services/Media/PictureService.cs index 95c58fb845..563993234f 100644 --- a/src/Libraries/SmartStore.Services/Media/PictureService.cs +++ b/src/Libraries/SmartStore.Services/Media/PictureService.cs @@ -154,17 +154,21 @@ public virtual byte[] ValidatePicture(byte[] pictureBinary) } } - public byte[] FindEqualPicture(string path, IEnumerable productPictures, out int equalPictureId) + #endregion + + #region Methods + + public byte[] FindEqualPicture(string path, IEnumerable pictures, out int equalPictureId) { - return FindEqualPicture(File.ReadAllBytes(path), productPictures, out equalPictureId); + return FindEqualPicture(File.ReadAllBytes(path), pictures, out equalPictureId); } - public byte[] FindEqualPicture(byte[] pictureBinary, IEnumerable productPictures, out int equalPictureId) + public byte[] FindEqualPicture(byte[] pictureBinary, IEnumerable pictures, out int equalPictureId) { equalPictureId = 0; try { - foreach (var picture in productPictures) + foreach (var picture in pictures) { var otherPictureBinary = LoadPictureBinary(picture); @@ -187,11 +191,7 @@ public byte[] FindEqualPicture(byte[] pictureBinary, IEnumerable produc } } - #endregion - - #region Methods - - public virtual string GetPictureSeName(string name) + public virtual string GetPictureSeName(string name) { return SeoHelper.GetSeName(name, true, false); } From 1f2343125dc621ad95bc880abbb6803977007630 Mon Sep 17 00:00:00 2001 From: Marcus Gesing Date: Sun, 20 Dec 2015 13:01:25 +0100 Subject: [PATCH 184/707] Extended data import column mapping --- .../DataExchange/ColumnMap.cs | 67 ++++++++++++------- .../Import/ImportDataSegmenter.cs | 4 +- .../DataExchange/Import/ImportRow.cs | 26 +++++-- 3 files changed, 67 insertions(+), 30 deletions(-) diff --git a/src/Libraries/SmartStore.Services/DataExchange/ColumnMap.cs b/src/Libraries/SmartStore.Services/DataExchange/ColumnMap.cs index 5149e2c6d8..f602b1238b 100644 --- a/src/Libraries/SmartStore.Services/DataExchange/ColumnMap.cs +++ b/src/Libraries/SmartStore.Services/DataExchange/ColumnMap.cs @@ -1,69 +1,80 @@ using System; using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; namespace SmartStore.Services.DataExchange { public class ColumnMap { - private readonly Dictionary _map = new Dictionary(StringComparer.OrdinalIgnoreCase); + private readonly Dictionary _map = new Dictionary(StringComparer.OrdinalIgnoreCase); - public IReadOnlyDictionary Mappings + public IReadOnlyDictionary Mappings { get { return _map; } } - public void AddMapping(string sourceName, string mappedName) + public void AddMapping(string sourceName, string entityProperty, string defaultValue = null) { - AddMapping(sourceName, null, mappedName); + AddMapping(sourceName, null, entityProperty, defaultValue); } - public void AddMapping(string sourceName, string index, string mappedName) + public void AddMapping(string sourceName, string index, string entityProperty, string defaultValue = null) { Guard.ArgumentNotEmpty(() => sourceName); - Guard.ArgumentNotEmpty(() => mappedName); + Guard.ArgumentNotEmpty(() => entityProperty); - _map[CreateName(sourceName, index)] = mappedName; + _map[CreateSourceName(sourceName, index)] = new ColumnMappingValue + { + EntityProperty = entityProperty, + DefaultValue = defaultValue + }; } /// - /// Gets a mapped column name + /// Gets a mapped column value /// - /// The name of the column to get a mapped name for. - /// The mapped column name OR - if the name is unmapped - the passed - public string GetMappedName(string sourceName) + /// The name of the column to get a mapped value for. + /// The mapped column name OR - if the name is unmapped - a value with the passed + public ColumnMappingValue GetMapping(string sourceName) { - string result; + ColumnMappingValue result; + if (_map.TryGetValue(sourceName, out result)) { return result; } - return sourceName; + return new ColumnMappingValue { EntityProperty = sourceName }; } /// - /// Gets a mapped column name + /// Gets a mapped column value /// - /// The name of the column to get a mapped name for. + /// The name of the column to get a mapped value for. /// The column index, e.g. a language code (de, en etc.) - /// The mapped column name OR - if the name is unmapped - the passed [] - public string GetMappedName(string sourceName, string index) + /// The mapped column name OR - if the name is unmapped - a value with the passed [] + public ColumnMappingValue GetMapping(string sourceName, string index) + { + return GetMapping(CreateSourceName(sourceName, index)); + } + + public string GetMappedProperty(string sourceName) { - sourceName = CreateName(sourceName, index); + ColumnMappingValue result; - string result; if (_map.TryGetValue(sourceName, out result)) { - return result; + return result.EntityProperty; } return sourceName; } - internal static string CreateName(string name, string index) + public string GetMappedProperty(string sourceName, string index) + { + return GetMappedProperty(CreateSourceName(sourceName, index)); + } + + internal static string CreateSourceName(string name, string index) { if (index.HasValue()) { @@ -73,4 +84,12 @@ internal static string CreateName(string name, string index) return name; } } + + + public class ColumnMappingValue + { + public string EntityProperty { get; set; } + + public string DefaultValue { get; set; } + } } diff --git a/src/Libraries/SmartStore.Services/DataExchange/Import/ImportDataSegmenter.cs b/src/Libraries/SmartStore.Services/DataExchange/Import/ImportDataSegmenter.cs index 4bcb355089..d9ecad1d7b 100644 --- a/src/Libraries/SmartStore.Services/DataExchange/Import/ImportDataSegmenter.cs +++ b/src/Libraries/SmartStore.Services/DataExchange/Import/ImportDataSegmenter.cs @@ -89,12 +89,12 @@ public int BatchSize public bool HasDataColumn(string name) { - return _table.HasColumn(_columnMap.GetMappedName(name)); + return _table.HasColumn(_columnMap.GetMappedProperty(name)); } public bool HasDataColumn(string name, string index) { - return _table.HasColumn(_columnMap.GetMappedName(name, index)); + return _table.HasColumn(_columnMap.GetMappedProperty(name, index)); } /// diff --git a/src/Libraries/SmartStore.Services/DataExchange/Import/ImportRow.cs b/src/Libraries/SmartStore.Services/DataExchange/Import/ImportRow.cs index 5b469a9352..da18417c95 100644 --- a/src/Libraries/SmartStore.Services/DataExchange/Import/ImportRow.cs +++ b/src/Libraries/SmartStore.Services/DataExchange/Import/ImportRow.cs @@ -91,7 +91,7 @@ public TProp GetDataValue(string columnName) public TProp GetDataValue(string columnName, string index) { object value; - if (_row.TryGetValue(_segmenter.ColumnMap.GetMappedName(columnName, index), out value)) + if (_row.TryGetValue(_segmenter.ColumnMap.GetMappedProperty(columnName, index), out value)) { return value.Convert(_segmenter.Culture); } @@ -117,7 +117,25 @@ public bool SetProperty( var fastProp = FastProperty.GetProperty(target.GetUnproxiedType(), propName, PropertyCachingStrategy.EagerCached); object value; - if (_row.TryGetValue(_segmenter.ColumnMap.GetMappedName(propName), out value)) + var mapping = _segmenter.ColumnMap.GetMapping(propName); + + if (mapping.DefaultValue != null) + { + try + { + if (mapping.DefaultValue.IsEmpty()) + defaultValue = default(TProp); // ignore called in value and explicitly convert to default + else + defaultValue = mapping.DefaultValue.Convert(_segmenter.Culture); + } + catch (Exception exception) + { + var msg = "Failed to convert default value '{0}'. Please specify a convertable default value. {1}"; + result.AddWarning(msg.FormatInvariant(mapping.DefaultValue.NaIfEmpty(), exception.Message), this.GetRowInfo(), propName); + } + } + + if (_row.TryGetValue(mapping.EntityProperty, out value)) { // source contains field value. Set it. TProp converted; @@ -147,9 +165,9 @@ public bool SetProperty( } } } - catch (Exception ex) + catch (Exception exception) { - result.AddWarning("Conversion failed: " + ex.Message, this.GetRowInfo(), propName); + result.AddWarning("Conversion failed: " + exception.Message, this.GetRowInfo(), propName); } return false; From 85e62269dc15eec4cfee40ed40d42db620d573c1 Mon Sep 17 00:00:00 2001 From: Marcus Gesing Date: Mon, 21 Dec 2015 12:41:31 +0100 Subject: [PATCH 185/707] Getting started with import column mapping --- .../DataExchange/ColumnMap.cs | 95 --------------- .../Import/ColumnMapping/ColumnMap.cs | 112 ++++++++++++++++++ .../ColumnMapping}/ColumnMapConverter.cs | 15 ++- .../SmartStore.Services.csproj | 4 +- .../Controllers/ImportController.cs | 109 ++++++++++++++--- .../Infrastructure/AdminStartupTask.cs | 2 +- .../Models/DataExchange/ImportProfileModel.cs | 15 +++ .../Administration/SmartStore.Admin.csproj | 1 + .../Views/Import/_ColumnMappings.cshtml | 7 ++ .../Views/Import/_CreateOrUpdate.cshtml | 2 + 10 files changed, 249 insertions(+), 113 deletions(-) delete mode 100644 src/Libraries/SmartStore.Services/DataExchange/ColumnMap.cs create mode 100644 src/Libraries/SmartStore.Services/DataExchange/Import/ColumnMapping/ColumnMap.cs rename src/Libraries/SmartStore.Services/DataExchange/{ => Import/ColumnMapping}/ColumnMapConverter.cs (77%) create mode 100644 src/Presentation/SmartStore.Web/Administration/Views/Import/_ColumnMappings.cshtml diff --git a/src/Libraries/SmartStore.Services/DataExchange/ColumnMap.cs b/src/Libraries/SmartStore.Services/DataExchange/ColumnMap.cs deleted file mode 100644 index f602b1238b..0000000000 --- a/src/Libraries/SmartStore.Services/DataExchange/ColumnMap.cs +++ /dev/null @@ -1,95 +0,0 @@ -using System; -using System.Collections.Generic; - -namespace SmartStore.Services.DataExchange -{ - public class ColumnMap - { - private readonly Dictionary _map = new Dictionary(StringComparer.OrdinalIgnoreCase); - - public IReadOnlyDictionary Mappings - { - get { return _map; } - } - - public void AddMapping(string sourceName, string entityProperty, string defaultValue = null) - { - AddMapping(sourceName, null, entityProperty, defaultValue); - } - - public void AddMapping(string sourceName, string index, string entityProperty, string defaultValue = null) - { - Guard.ArgumentNotEmpty(() => sourceName); - Guard.ArgumentNotEmpty(() => entityProperty); - - _map[CreateSourceName(sourceName, index)] = new ColumnMappingValue - { - EntityProperty = entityProperty, - DefaultValue = defaultValue - }; - } - - /// - /// Gets a mapped column value - /// - /// The name of the column to get a mapped value for. - /// The mapped column name OR - if the name is unmapped - a value with the passed - public ColumnMappingValue GetMapping(string sourceName) - { - ColumnMappingValue result; - - if (_map.TryGetValue(sourceName, out result)) - { - return result; - } - - return new ColumnMappingValue { EntityProperty = sourceName }; - } - - /// - /// Gets a mapped column value - /// - /// The name of the column to get a mapped value for. - /// The column index, e.g. a language code (de, en etc.) - /// The mapped column name OR - if the name is unmapped - a value with the passed [] - public ColumnMappingValue GetMapping(string sourceName, string index) - { - return GetMapping(CreateSourceName(sourceName, index)); - } - - public string GetMappedProperty(string sourceName) - { - ColumnMappingValue result; - - if (_map.TryGetValue(sourceName, out result)) - { - return result.EntityProperty; - } - - return sourceName; - } - - public string GetMappedProperty(string sourceName, string index) - { - return GetMappedProperty(CreateSourceName(sourceName, index)); - } - - internal static string CreateSourceName(string name, string index) - { - if (index.HasValue()) - { - name += String.Concat("[", index, "]"); - } - - return name; - } - } - - - public class ColumnMappingValue - { - public string EntityProperty { get; set; } - - public string DefaultValue { get; set; } - } -} diff --git a/src/Libraries/SmartStore.Services/DataExchange/Import/ColumnMapping/ColumnMap.cs b/src/Libraries/SmartStore.Services/DataExchange/Import/ColumnMapping/ColumnMap.cs new file mode 100644 index 0000000000..b7f588d487 --- /dev/null +++ b/src/Libraries/SmartStore.Services/DataExchange/Import/ColumnMapping/ColumnMap.cs @@ -0,0 +1,112 @@ +using System; +using System.Collections.Generic; + +namespace SmartStore.Services.DataExchange.Import +{ + public class ColumnMap + { + private readonly Dictionary _map = new Dictionary(StringComparer.OrdinalIgnoreCase); + + public IReadOnlyDictionary Mappings + { + get { return _map; } + } + + public void AddMapping(string sourceColumn, string entityProperty, string defaultValue = null) + { + AddMapping(sourceColumn, null, entityProperty, defaultValue); + } + + public void AddMapping(string sourceColumn, string index, string entityProperty, string defaultValue = null) + { + Guard.ArgumentNotEmpty(() => sourceColumn); + Guard.ArgumentNotEmpty(() => entityProperty); + + _map[CreateSourceName(sourceColumn, index)] = new ColumnMappingValue + { + EntityProperty = entityProperty, + DefaultValue = defaultValue + }; + } + + /// + /// Gets a mapped column value + /// + /// The name of the column to get a mapped value for. + /// The mapped column value OR - if the name is unmapped - a value with the passed + public ColumnMappingValue GetMapping(string sourceColumn) + { + ColumnMappingValue result; + + if (_map.TryGetValue(sourceColumn, out result)) + { + return result; + } + + return new ColumnMappingValue { EntityProperty = sourceColumn }; + } + + /// + /// Gets a mapped column value + /// + /// The name of the column to get a mapped value for. + /// The column index, e.g. a language code (de, en etc.) + /// The mapped column value OR - if the name is unmapped - a value with the passed [] + public ColumnMappingValue GetMapping(string sourceColumn, string index) + { + return GetMapping(CreateSourceName(sourceColumn, index)); + } + + /// + /// Gets a mapped property name + /// + /// The name of the column to get a mapped property name for. + /// The mapped property name OR - if the name is unmapped - the passed [] + public string GetMappedProperty(string sourceColumn) + { + ColumnMappingValue result; + + if (_map.TryGetValue(sourceColumn, out result)) + { + return result.EntityProperty; + } + + return sourceColumn; + } + + /// + /// Gets a mapped property name + /// + /// The name of the column to get a mapped property name for. + /// The column index, e.g. a language code (de, en etc.) + /// The mapped property name OR - if the name is unmapped - the passed [] + public string GetMappedProperty(string sourceColumn, string index) + { + return GetMappedProperty(CreateSourceName(sourceColumn, index)); + } + + internal static string CreateSourceName(string name, string index) + { + if (index.HasValue()) + { + name += String.Concat("[", index, "]"); + } + + return name; + } + } + + + public class ColumnMappingValue + { + /// + /// The property name of the target entity + /// + public string EntityProperty { get; set; } + + /// + /// An optional default value + /// + public string DefaultValue { get; set; } + } +} diff --git a/src/Libraries/SmartStore.Services/DataExchange/ColumnMapConverter.cs b/src/Libraries/SmartStore.Services/DataExchange/Import/ColumnMapping/ColumnMapConverter.cs similarity index 77% rename from src/Libraries/SmartStore.Services/DataExchange/ColumnMapConverter.cs rename to src/Libraries/SmartStore.Services/DataExchange/Import/ColumnMapping/ColumnMapConverter.cs index 0fa97b26f0..12f251bd4d 100644 --- a/src/Libraries/SmartStore.Services/DataExchange/ColumnMapConverter.cs +++ b/src/Libraries/SmartStore.Services/DataExchange/Import/ColumnMapping/ColumnMapConverter.cs @@ -4,7 +4,7 @@ using Newtonsoft.Json; using SmartStore.ComponentModel; -namespace SmartStore.Services.DataExchange +namespace SmartStore.Services.DataExchange.Import { public class ColumnMapConverter : TypeConverterBase { @@ -41,6 +41,14 @@ public override object ConvertFrom(CultureInfo culture, object value) return base.ConvertFrom(culture, value); } + public T ConvertFrom(string value) + { + if (value.HasValue()) + return (T)ConvertFrom(CultureInfo.InvariantCulture, value); + + return default(T); + } + public override object ConvertTo(CultureInfo culture, string format, object value, Type to) { if (to == typeof(string)) @@ -57,5 +65,10 @@ public override object ConvertTo(CultureInfo culture, string format, object valu return base.ConvertTo(culture, format, value, to); } + + public string ConvertTo(object value) + { + return (string)ConvertTo(CultureInfo.InvariantCulture, null, value, typeof(string)); + } } } diff --git a/src/Libraries/SmartStore.Services/SmartStore.Services.csproj b/src/Libraries/SmartStore.Services/SmartStore.Services.csproj index 1ad4d843a6..405df35f5a 100644 --- a/src/Libraries/SmartStore.Services/SmartStore.Services.csproj +++ b/src/Libraries/SmartStore.Services/SmartStore.Services.csproj @@ -174,8 +174,8 @@ - - + + diff --git a/src/Presentation/SmartStore.Web/Administration/Controllers/ImportController.cs b/src/Presentation/SmartStore.Web/Administration/Controllers/ImportController.cs index e38db2e8b3..af761f78d9 100644 --- a/src/Presentation/SmartStore.Web/Administration/Controllers/ImportController.cs +++ b/src/Presentation/SmartStore.Web/Administration/Controllers/ImportController.cs @@ -45,8 +45,68 @@ public ImportController( #region Utilities + private List PrepareColumnMappingModels(ImportProfile profile, CsvConfiguration csvConfiguration) + { + var models = new List(); + + try + { + var mapConverter = new ColumnMapConverter(); + var map = mapConverter.ConvertFrom(profile.ColumnMapping); + + if (map != null && map.Mappings.Any()) + { + models = map.Mappings + .Select(x => + { + var mapModel = new ColumnMappingItemModel + { + SourceColumn = x.Key, + EntityProperty = x.Value.EntityProperty, + DefaultValue = x.Value.DefaultValue + }; + return mapModel; + }) + .ToList(); + } + else + { + var files = profile.GetImportFiles(); + if (files.Any()) + { + var filePath = files.First(); + using (var stream = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.Read)) + { + var dataTable = LightweightDataTable.FromFile(Path.GetFileName(filePath), stream, stream.Length, csvConfiguration, 0, 2); + + foreach (var column in dataTable.Columns) + { + models.Add(new ColumnMappingItemModel + { + SourceColumn = column.Name + }); + } + + return models; + } + } + } + } + catch (Exception exception) + { + NotifyError(exception); + } + return models; + } + private void PrepareProfileModel(ImportProfileModel model, ImportProfile profile, bool forEdit) { + if (forEdit) + { + model.AvailableEntityTypes = ImportEntityType.Product.ToSelectList(false).ToList(); + model.AvailableFileTypes = ImportFileType.CSV.ToSelectList(false).ToList(); + } + if (profile != null) { model.Id = profile.Id; @@ -67,12 +127,19 @@ private void PrepareProfileModel(ImportProfileModel model, ImportProfile profile .Select(x => Path.GetFileName(x)) .ToList(); - if (profile.FileType == ImportFileType.CSV) + if (forEdit) { - var converter = new CsvConfigurationConverter(); - var config = converter.ConvertFrom(profile.FileTypeConfiguration); + CsvConfiguration csvConfiguration = null; + + if (profile.FileType == ImportFileType.CSV) + { + var csvConverter = new CsvConfigurationConverter(); + csvConfiguration = csvConverter.ConvertFrom(profile.FileTypeConfiguration); + + model.CsvConfiguration = new CsvConfigurationModel(csvConfiguration ?? CsvConfiguration.ExcelFriendlyConfiguration); + } - model.CsvConfiguration = new CsvConfigurationModel(config ?? CsvConfiguration.ExcelFriendlyConfiguration); + model.ColumnMappings = PrepareColumnMappingModels(profile, csvConfiguration); } } else @@ -80,12 +147,6 @@ private void PrepareProfileModel(ImportProfileModel model, ImportProfile profile model.Name = model.EntityType.GetLocalizedEnum(_services.Localization, _services.WorkContext); model.ExistingFileNames = new List(); } - - if (forEdit) - { - model.AvailableEntityTypes = ImportEntityType.Product.ToSelectList(false).ToList(); - model.AvailableFileTypes = ImportFileType.CSV.ToSelectList(false).ToList(); - } } #endregion @@ -192,12 +253,32 @@ public ActionResult Edit(ImportProfileModel model, bool continueEditing, FormCol profile.Skip = model.Skip; profile.Take = model.Take; - if (profile.FileType == ImportFileType.CSV && model.CsvConfiguration != null) + if (model.ColumnMappings != null && model.ColumnMappings.Any()) + { + var map = new ColumnMap(); + var mapConverter = new ColumnMapConverter(); + + model.ColumnMappings.Each(x => map.AddMapping(x.SourceColumn, x.EntityProperty, x.DefaultValue)); + profile.ColumnMapping = mapConverter.ConvertTo(map); + } + else + { + profile.ColumnMapping = null; + } + + if (profile.FileType == ImportFileType.CSV) { - CsvConfiguration config = model.CsvConfiguration.Clone(); + if (model.CsvConfiguration != null) + { + CsvConfiguration config = model.CsvConfiguration.Clone(); - var converter = new CsvConfigurationConverter(); - profile.FileTypeConfiguration = converter.ConvertTo(config); + var csvConverter = new CsvConfigurationConverter(); + profile.FileTypeConfiguration = csvConverter.ConvertTo(config); + } + else + { + profile.FileTypeConfiguration = null; + } } _importService.UpdateImportProfile(profile); diff --git a/src/Presentation/SmartStore.Web/Administration/Infrastructure/AdminStartupTask.cs b/src/Presentation/SmartStore.Web/Administration/Infrastructure/AdminStartupTask.cs index fd624d63ce..c9f1b6ef7e 100644 --- a/src/Presentation/SmartStore.Web/Administration/Infrastructure/AdminStartupTask.cs +++ b/src/Presentation/SmartStore.Web/Administration/Infrastructure/AdminStartupTask.cs @@ -1,7 +1,7 @@ using SmartStore.ComponentModel; using SmartStore.Core.Infrastructure; -using SmartStore.Services.DataExchange; using SmartStore.Services.DataExchange.Csv; +using SmartStore.Services.DataExchange.Import; namespace SmartStore.Admin.Infrastructure { diff --git a/src/Presentation/SmartStore.Web/Administration/Models/DataExchange/ImportProfileModel.cs b/src/Presentation/SmartStore.Web/Administration/Models/DataExchange/ImportProfileModel.cs index 76cc11caff..9f512f4ec5 100644 --- a/src/Presentation/SmartStore.Web/Administration/Models/DataExchange/ImportProfileModel.cs +++ b/src/Presentation/SmartStore.Web/Administration/Models/DataExchange/ImportProfileModel.cs @@ -47,5 +47,20 @@ public partial class ImportProfileModel : EntityModelBase public string TempFileName { get; set; } public CsvConfigurationModel CsvConfiguration { get; set; } + public List ColumnMappings { get; set; } + } + + + public class ColumnMappingItemModel + { + [SmartResourceDisplayName("Admin.DataExchange.ColumnMapping.SourceColumn")] + public string SourceColumn { get; set; } + + [SmartResourceDisplayName("Admin.DataExchange.ColumnMapping.EntityProperty")] + public string EntityProperty { get; set; } + public List AvailableEntityProperties { get; set; } + + [SmartResourceDisplayName("Admin.DataExchange.ColumnMapping.DefaultValue")] + public string DefaultValue { get; set; } } } \ No newline at end of file diff --git a/src/Presentation/SmartStore.Web/Administration/SmartStore.Admin.csproj b/src/Presentation/SmartStore.Web/Administration/SmartStore.Admin.csproj index b850530104..5b0852f437 100644 --- a/src/Presentation/SmartStore.Web/Administration/SmartStore.Admin.csproj +++ b/src/Presentation/SmartStore.Web/Administration/SmartStore.Admin.csproj @@ -544,6 +544,7 @@ + diff --git a/src/Presentation/SmartStore.Web/Administration/Views/Import/_ColumnMappings.cshtml b/src/Presentation/SmartStore.Web/Administration/Views/Import/_ColumnMappings.cshtml new file mode 100644 index 0000000000..8492e891f4 --- /dev/null +++ b/src/Presentation/SmartStore.Web/Administration/Views/Import/_ColumnMappings.cshtml @@ -0,0 +1,7 @@ +@using SmartStore.Admin.Models.DataExchange; +@model ImportProfileModel +
    + @foreach (var mapping in Model.ColumnMappings) + { + } +
    \ No newline at end of file diff --git a/src/Presentation/SmartStore.Web/Administration/Views/Import/_CreateOrUpdate.cshtml b/src/Presentation/SmartStore.Web/Administration/Views/Import/_CreateOrUpdate.cshtml index c479639b6b..7724afcf8e 100644 --- a/src/Presentation/SmartStore.Web/Administration/Views/Import/_CreateOrUpdate.cshtml +++ b/src/Presentation/SmartStore.Web/Administration/Views/Import/_CreateOrUpdate.cshtml @@ -130,6 +130,8 @@ @Html.Partial("CsvConfiguration", Model.CsvConfiguration, viewData) } +@Html.Partial("_ColumnMappings") + \ No newline at end of file From 69e20c822984225d80c9389e6c893fe6bc567876 Mon Sep 17 00:00:00 2001 From: Michael Herzog Date: Tue, 22 Dec 2015 16:21:14 +0100 Subject: [PATCH 188/707] Closes #815 Spelling: Import Summary message: Admin.Common.ImportFromExcel.QuickStats --- .../SmartStore.Data/Migrations/201403262015448_ImportExcel.cs | 2 +- .../SmartStore.Web/App_Data/Localization/App/en/all.smres.xml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Libraries/SmartStore.Data/Migrations/201403262015448_ImportExcel.cs b/src/Libraries/SmartStore.Data/Migrations/201403262015448_ImportExcel.cs index 3cf4f4c6b5..aa992d333a 100644 --- a/src/Libraries/SmartStore.Data/Migrations/201403262015448_ImportExcel.cs +++ b/src/Libraries/SmartStore.Data/Migrations/201403262015448_ImportExcel.cs @@ -44,7 +44,7 @@ public void MigrateLocaleResources(LocaleResourcesBuilder builder) "{0} von {1} Zeilen verarbeitet."); builder.AddOrUpdate("Admin.Common.ImportFromExcel.QuickStats", - "{0} new, {1} updated - with {2} warning(s) und {3} error(s).", + "{0} new, {1} updated - with {2} warning(s) and {3} error(s).", "{0} neu, {1} aktualisiert - bei {2} Warnung(en) und {3} Fehler(n)."); builder.AddOrUpdate("Admin.Common.ImportFromExcel.ActiveSince", diff --git a/src/Presentation/SmartStore.Web/App_Data/Localization/App/en/all.smres.xml b/src/Presentation/SmartStore.Web/App_Data/Localization/App/en/all.smres.xml index 1faea7a6fb..7881f9406c 100644 --- a/src/Presentation/SmartStore.Web/App_Data/Localization/App/en/all.smres.xml +++ b/src/Presentation/SmartStore.Web/App_Data/Localization/App/en/all.smres.xml @@ -3269,7 +3269,7 @@ {0} of {1} rows processed. - {0} new, {1} updated - with {2} warning(s) und {3} error(s). + {0} new, {1} updated - with {2} warning(s) and {3} error(s). Please wait while the import is being executed From 692d735d49fe27be283db3bf19f377bd9418be5c Mon Sep 17 00:00:00 2001 From: Marcus Gesing Date: Wed, 23 Dec 2015 12:21:06 +0100 Subject: [PATCH 189/707] Validating and persisting import column mappings --- .../201512151526290_ImportFramework.cs | 7 +- .../ColumnMapping/ColumnMapConverter.cs | 4 +- .../Administration/Content/admin.less | 4 + .../Controllers/ImportController.cs | 126 ++++++++++-------- .../Models/DataExchange/ImportProfileModel.cs | 11 +- .../Views/Import/_ColumnMappings.cshtml | 27 ++-- .../Views/Import/_CreateOrUpdate.cshtml | 23 +++- 7 files changed, 127 insertions(+), 75 deletions(-) diff --git a/src/Libraries/SmartStore.Data/Migrations/201512151526290_ImportFramework.cs b/src/Libraries/SmartStore.Data/Migrations/201512151526290_ImportFramework.cs index a35e51d2e5..30dbca2b49 100644 --- a/src/Libraries/SmartStore.Data/Migrations/201512151526290_ImportFramework.cs +++ b/src/Libraries/SmartStore.Data/Migrations/201512151526290_ImportFramework.cs @@ -196,10 +196,15 @@ public void MigrateLocaleResources(LocaleResourcesBuilder builder) "Sie knnen optional fr jedes Feld der Importdatei festlegen, zu welcher Entittseigenschaft dessen Daten importiert werden sollen. Zudem ist die Angabe eines Standardwertes mglich, der angewendet wird, wenn das Importfeld leer ist."); builder.AddOrUpdate("Admin.DataExchange.ColumnMapping.ImportField", "Import Field", "Importfeld"); - builder.AddOrUpdate("Admin.DataExchange.ColumnMapping.ImportFieldIndex", "Index (language code etc.)", "Index (Sprach-Code etc.)"); + builder.AddOrUpdate("Admin.DataExchange.ColumnMapping.ImportFieldIndex", "Language Code etc.", "Sprach-Code etc."); builder.AddOrUpdate("Admin.DataExchange.ColumnMapping.EntityProperty", "Entity property", "Eigenschaft der Entitt"); builder.AddOrUpdate("Admin.DataExchange.ColumnMapping.DefaultValue", "Default Value", "Standard Wert"); + builder.AddOrUpdate("Admin.DataExchange.ColumnMapping.Validate.EntityMultipleMapped", + "The entity property \"{0}\" was assigned several times. Please assign each property only once.", + "Die Entittseigenschaft \"{0}\" wurde mehrfach zugeodnet. Bitte ordnen Sie jede Eigenschaft nur einmal zu."); + + builder.Delete( "Admin.DataExchange.Export.LastExecution", "Admin.DataExchange.Export.Offset", diff --git a/src/Libraries/SmartStore.Services/DataExchange/Import/ColumnMapping/ColumnMapConverter.cs b/src/Libraries/SmartStore.Services/DataExchange/Import/ColumnMapping/ColumnMapConverter.cs index 12f251bd4d..7d6abcdc6d 100644 --- a/src/Libraries/SmartStore.Services/DataExchange/Import/ColumnMapping/ColumnMapConverter.cs +++ b/src/Libraries/SmartStore.Services/DataExchange/Import/ColumnMapping/ColumnMapConverter.cs @@ -27,12 +27,12 @@ public override object ConvertFrom(CultureInfo culture, object value) { if (value is string) { - var dict = JsonConvert.DeserializeObject>((string)value); + var dict = JsonConvert.DeserializeObject>((string)value); var map = new ColumnMap(); foreach (var kvp in dict) { - map.AddMapping(kvp.Key, kvp.Value); + map.AddMapping(kvp.Key, kvp.Value.EntityProperty, kvp.Value.DefaultValue); } return map; diff --git a/src/Presentation/SmartStore.Web/Administration/Content/admin.less b/src/Presentation/SmartStore.Web/Administration/Content/admin.less index bef6c3f293..a27117a25a 100644 --- a/src/Presentation/SmartStore.Web/Administration/Content/admin.less +++ b/src/Presentation/SmartStore.Web/Administration/Content/admin.less @@ -891,6 +891,10 @@ tr.adminSeparator hr { select, input { margin-bottom: 0; } + .control-large { + width: 500px; + min-width: 500px; + } } /* SERVER CONTROLS */ diff --git a/src/Presentation/SmartStore.Web/Administration/Controllers/ImportController.cs b/src/Presentation/SmartStore.Web/Administration/Controllers/ImportController.cs index fcf41629e3..33e1d7644c 100644 --- a/src/Presentation/SmartStore.Web/Administration/Controllers/ImportController.cs +++ b/src/Presentation/SmartStore.Web/Administration/Controllers/ImportController.cs @@ -45,63 +45,59 @@ public ImportController( #region Utilities - private List PrepareColumnMappingModels(ImportProfile profile, CsvConfiguration csvConfiguration) + private void PrepareColumnMappingModels(ImportProfile profile, ImportProfileModel model, CsvConfiguration csvConfiguration, ColumnMap invalidMap = null) { - var models = new List(); + model.ColumnMappings = new List(); + model.AvailableEntityProperties = new List(); try { var files = profile.GetImportFiles(); if (!files.Any()) - return models; + return; var filePath = files.First(); var mapConverter = new ColumnMapConverter(); - var map = mapConverter.ConvertFrom(profile.ColumnMapping); + + var map = (invalidMap != null ? invalidMap : mapConverter.ConvertFrom(profile.ColumnMapping)); var hasMappings = (map != null && map.Mappings.Any()); var destProperties = _importService.GetImportableEntityProperties(profile.EntityType); + model.AvailableEntityProperties = destProperties + .Select(x => new SelectListItem { Value = x.Key, Text = x.Value }) + .OrderBy(x => x.Text) + .ToList(); + using (var stream = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.Read)) { + var index = 0; var dataTable = LightweightDataTable.FromFile(Path.GetFileName(filePath), stream, stream.Length, csvConfiguration, 0, 2); - foreach (var column in dataTable.Columns) + foreach (var column in dataTable.Columns.Where(x => x.Name.HasValue())) { - var sourceName = column.Name; - if (sourceName.IsEmpty()) - continue; - - var mapModel = new ColumnMappingItemModel(); + var mapModel = new ColumnMappingItemModel + { + Index = index++, + Column = column.Name + }; - var x1 = sourceName.IndexOf('['); - var x2 = sourceName.IndexOf(']'); + var x1 = column.Name.IndexOf('['); + var x2 = column.Name.IndexOf(']'); if (x1 != -1 && x2 != -1 && x2 > x1) { - mapModel.SourceColumn = sourceName.Substring(0, x1); - mapModel.SourceColumnIndex = sourceName.Substring(x1 + 1, x2 - x1 - 1); + mapModel.ColumnWithoutIndex = column.Name.Substring(0, x1); + mapModel.ColumnIndex = column.Name.Substring(x1 + 1, x2 - x1 - 1); } else { - mapModel.SourceColumn = sourceName; + mapModel.ColumnWithoutIndex = column.Name; } - mapModel.AvailableEntityProperties = destProperties - .Select(x => - { - return new SelectListItem - { - Value = "{0}¶{1}".FormatInvariant(sourceName, x.Key), - Text = (x.Key.IsCaseInsensitiveEqual(x.Value) ? x.Value : "{0} ({1})".FormatInvariant(x.Key, x.Value)), - Selected = (x.Key == sourceName) - }; - }) - .ToList(); - if (hasMappings) { - var mapping = map.Mappings.FirstOrDefault(x => x.Key == sourceName); + var mapping = map.Mappings.FirstOrDefault(x => x.Key == column.Name); if (mapping.Value != null) { mapModel.EntityProperty = mapping.Value.EntityProperty; @@ -109,7 +105,7 @@ private List PrepareColumnMappingModels(ImportProfile pr } } - models.Add(mapModel); + model.ColumnMappings.Add(mapModel); } } } @@ -117,10 +113,9 @@ private List PrepareColumnMappingModels(ImportProfile pr { NotifyError(exception); } - return models; } - private void PrepareProfileModel(ImportProfileModel model, ImportProfile profile, bool forEdit) + private void PrepareProfileModel(ImportProfileModel model, ImportProfile profile, bool forEdit, ColumnMap invalidMap = null) { if (forEdit) { @@ -161,7 +156,7 @@ private void PrepareProfileModel(ImportProfileModel model, ImportProfile profile model.CsvConfiguration = new CsvConfigurationModel(csvConfiguration); } - model.ColumnMappings = PrepareColumnMappingModels(profile, csvConfiguration ?? CsvConfiguration.ExcelFriendlyConfiguration); + PrepareColumnMappingModels(profile, model, csvConfiguration ?? CsvConfiguration.ExcelFriendlyConfiguration, invalidMap); } } else @@ -267,6 +262,42 @@ public ActionResult Edit(ImportProfileModel model, bool continueEditing, FormCol if (profile == null) return RedirectToAction("List"); + var map = new ColumnMap(); + var mapConverter = new ColumnMapConverter(); + var filePath = profile.GetImportFiles().First(); + + CsvConfiguration csvConfig = null; + if (model.CsvConfiguration != null) + { + csvConfig = model.CsvConfiguration.Clone(); + } + + using (var stream = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.Read)) + { + var index = 0; + var dataTable = LightweightDataTable.FromFile(Path.GetFileName(filePath), stream, stream.Length, csvConfig ?? CsvConfiguration.ExcelFriendlyConfiguration, 0, 2); + + foreach (var column in dataTable.Columns.Where(x => x.Name.HasValue())) + { + var key = "ColumnMapping.EntityProperty." + index.ToString(); + if (form.AllKeys.Contains(key)) + { + var entityProperty = form[key]; + if (entityProperty.HasValue()) + { + if (map.Mappings.Any(x => x.Value.EntityProperty.IsCaseInsensitiveEqual(entityProperty))) + { + ModelState.AddModelError(key, T("Admin.DataExchange.ColumnMapping.Validate.EntityMultipleMapped", entityProperty)); + } + + var defaultValue = form["ColumnMapping.DefaultValue." + index.ToString()]; + map.AddMapping(column.Name, entityProperty, defaultValue); + } + } + ++index; + } + } + if (ModelState.IsValid) { profile.Name = model.Name; @@ -274,33 +305,14 @@ public ActionResult Edit(ImportProfileModel model, bool continueEditing, FormCol profile.Enabled = model.Enabled; profile.Skip = model.Skip; profile.Take = model.Take; + profile.FileTypeConfiguration = null; - if (model.ColumnMappings != null && model.ColumnMappings.Any()) - { - var map = new ColumnMap(); - var mapConverter = new ColumnMapConverter(); + profile.ColumnMapping = mapConverter.ConvertTo(map); - model.ColumnMappings.Each(x => map.AddMapping(x.SourceColumn, x.EntityProperty, x.DefaultValue)); - profile.ColumnMapping = mapConverter.ConvertTo(map); - } - else + if (profile.FileType == ImportFileType.CSV && csvConfig != null) { - profile.ColumnMapping = null; - } - - if (profile.FileType == ImportFileType.CSV) - { - if (model.CsvConfiguration != null) - { - CsvConfiguration config = model.CsvConfiguration.Clone(); - - var csvConverter = new CsvConfigurationConverter(); - profile.FileTypeConfiguration = csvConverter.ConvertTo(config); - } - else - { - profile.FileTypeConfiguration = null; - } + var csvConverter = new CsvConfigurationConverter(); + profile.FileTypeConfiguration = csvConverter.ConvertTo(csvConfig); } _importService.UpdateImportProfile(profile); @@ -310,7 +322,7 @@ public ActionResult Edit(ImportProfileModel model, bool continueEditing, FormCol return (continueEditing ? RedirectToAction("Edit", new { id = profile.Id }) : RedirectToAction("List")); } - PrepareProfileModel(model, profile, true); + PrepareProfileModel(model, profile, true, map); return View(model); } diff --git a/src/Presentation/SmartStore.Web/Administration/Models/DataExchange/ImportProfileModel.cs b/src/Presentation/SmartStore.Web/Administration/Models/DataExchange/ImportProfileModel.cs index e94418de1b..b45fd937c8 100644 --- a/src/Presentation/SmartStore.Web/Administration/Models/DataExchange/ImportProfileModel.cs +++ b/src/Presentation/SmartStore.Web/Administration/Models/DataExchange/ImportProfileModel.cs @@ -49,18 +49,17 @@ public partial class ImportProfileModel : EntityModelBase public CsvConfigurationModel CsvConfiguration { get; set; } public List ColumnMappings { get; set; } + public List AvailableEntityProperties { get; set; } } public class ColumnMappingItemModel { - public string SourceColumn { get; set; } - - public string SourceColumnIndex { get; set; } - + public int Index { get; set; } + public string Column { get; set; } + public string ColumnWithoutIndex { get; set; } + public string ColumnIndex { get; set; } public string EntityProperty { get; set; } - public List AvailableEntityProperties { get; set; } - public string DefaultValue { get; set; } } } \ No newline at end of file diff --git a/src/Presentation/SmartStore.Web/Administration/Views/Import/_ColumnMappings.cshtml b/src/Presentation/SmartStore.Web/Administration/Views/Import/_ColumnMappings.cshtml index fb58dfb295..96dd2a534a 100644 --- a/src/Presentation/SmartStore.Web/Administration/Views/Import/_ColumnMappings.cshtml +++ b/src/Presentation/SmartStore.Web/Administration/Views/Import/_ColumnMappings.cshtml @@ -13,27 +13,38 @@ - - - + + + - @foreach (var mapping in Model.ColumnMappings.OrderBy(x => x.SourceColumn)) + @foreach (var mapping in Model.ColumnMappings.OrderBy(x => x.ColumnWithoutIndex)) { } diff --git a/src/Presentation/SmartStore.Web/Administration/Views/Import/_CreateOrUpdate.cshtml b/src/Presentation/SmartStore.Web/Administration/Views/Import/_CreateOrUpdate.cshtml index fdd7767892..a9c0dddec5 100644 --- a/src/Presentation/SmartStore.Web/Administration/Views/Import/_CreateOrUpdate.cshtml +++ b/src/Presentation/SmartStore.Web/Administration/Views/Import/_CreateOrUpdate.cshtml @@ -177,7 +177,28 @@ return false; }); - $('#ImportColumnMappings').find('select').selectWrapper(); + $('#ImportColumnMappings').find('select').select2({ + allowClear: true, + minimumResultsForSearch: 16, + formatResult: columnMappingSelectItemFormatting, + formatSelection: columnMappingSelectItemFormatting + }); + + function columnMappingSelectItemFormatting(item) { + try { + var option = $(item.element); + + var html = '
    ' + item.text + ''; + if (option.length !== 0) { + html += ' (' + option.val() + ')'; + } + html += '
    '; + + return html; + } + catch (e) { } + return item.text; + } }); \ No newline at end of file From 66c96dd15e64f64bd263eeeec016c8b3ee237688 Mon Sep 17 00:00:00 2001 From: Marcus Gesing Date: Wed, 23 Dec 2015 12:47:23 +0100 Subject: [PATCH 190/707] Button to reset all column mappings for an import profile --- .../201512151526290_ImportFramework.cs | 4 ++-- .../Controllers/ImportController.cs | 18 ++++++++++++++++++ .../Views/Import/_ColumnMappings.cshtml | 8 +++++++- .../Views/Import/_CreateOrUpdate.cshtml | 14 ++++++++++++++ 4 files changed, 41 insertions(+), 3 deletions(-) diff --git a/src/Libraries/SmartStore.Data/Migrations/201512151526290_ImportFramework.cs b/src/Libraries/SmartStore.Data/Migrations/201512151526290_ImportFramework.cs index 30dbca2b49..5caf8d7ec8 100644 --- a/src/Libraries/SmartStore.Data/Migrations/201512151526290_ImportFramework.cs +++ b/src/Libraries/SmartStore.Data/Migrations/201512151526290_ImportFramework.cs @@ -192,8 +192,8 @@ public void MigrateLocaleResources(LocaleResourcesBuilder builder) builder.AddOrUpdate("Admin.Promotions.NewsLetterSubscriptions.Fields.NewsLetterSubscriptionGuid", "Subscription GUID", "Abonnement GUID"); builder.AddOrUpdate("Admin.DataExchange.ColumnMapping.Note", - "For each field of the import file you can optionally set to which entity property whose data is to be imported. Specifying a default value is also possible, which is applied when the import field is empty.", - "Sie knnen optional fr jedes Feld der Importdatei festlegen, zu welcher Entittseigenschaft dessen Daten importiert werden sollen. Zudem ist die Angabe eines Standardwertes mglich, der angewendet wird, wenn das Importfeld leer ist."); + "For each field of the import file you can optionally set to which entity property whose data is to be imported. Specifying a default value is also possible, which is applied when the import field is empty. Through Reset all made assignments are reset to their original values.", + "Sie knnen optional fr jedes Feld der Importdatei festlegen, nach welcher Entittseigenschaft dessen Daten importiert werden sollen. Zudem ist die Angabe eines Standardwertes mglich, der angewendet wird, wenn das Importfeld leer ist. ber Zurcksetzen werden alle gettigten Zuordnungen auf ihre Ursprungswerte zurckgesetzt."); builder.AddOrUpdate("Admin.DataExchange.ColumnMapping.ImportField", "Import Field", "Importfeld"); builder.AddOrUpdate("Admin.DataExchange.ColumnMapping.ImportFieldIndex", "Language Code etc.", "Sprach-Code etc."); diff --git a/src/Presentation/SmartStore.Web/Administration/Controllers/ImportController.cs b/src/Presentation/SmartStore.Web/Administration/Controllers/ImportController.cs index 33e1d7644c..9fecdbe9ea 100644 --- a/src/Presentation/SmartStore.Web/Administration/Controllers/ImportController.cs +++ b/src/Presentation/SmartStore.Web/Administration/Controllers/ImportController.cs @@ -327,6 +327,24 @@ public ActionResult Edit(ImportProfileModel model, bool continueEditing, FormCol return View(model); } + [HttpPost] + public ActionResult ResetColumnMappings(int id) + { + if (!_services.Permissions.Authorize(StandardPermissionProvider.ManageImports)) + return AccessDeniedView(); + + var profile = _importService.GetImportProfileById(id); + if (profile == null) + return RedirectToAction("List"); + + profile.ColumnMapping = null; + _importService.UpdateImportProfile(profile); + + NotifySuccess(T("Admin.Common.TaskSuccessfullyProcessed")); + + return RedirectToAction("Edit", new { id = profile.Id }); + } + [HttpPost, ActionName("Delete")] public ActionResult DeleteConfirmed(int id) { diff --git a/src/Presentation/SmartStore.Web/Administration/Views/Import/_ColumnMappings.cshtml b/src/Presentation/SmartStore.Web/Administration/Views/Import/_ColumnMappings.cshtml index 96dd2a534a..bc5bfd60b1 100644 --- a/src/Presentation/SmartStore.Web/Administration/Views/Import/_ColumnMappings.cshtml +++ b/src/Presentation/SmartStore.Web/Administration/Views/Import/_ColumnMappings.cshtml @@ -6,7 +6,13 @@
    - @T("Admin.DataExchange.ColumnMapping.Note") + @Html.Raw(T("Admin.DataExchange.ColumnMapping.Note")) +
    + +
    +
    diff --git a/src/Presentation/SmartStore.Web/Administration/Views/Import/_CreateOrUpdate.cshtml b/src/Presentation/SmartStore.Web/Administration/Views/Import/_CreateOrUpdate.cshtml index a9c0dddec5..bd24686006 100644 --- a/src/Presentation/SmartStore.Web/Administration/Views/Import/_CreateOrUpdate.cshtml +++ b/src/Presentation/SmartStore.Web/Administration/Views/Import/_CreateOrUpdate.cshtml @@ -177,6 +177,20 @@ return false; }); + // reset column mappings button + $('#ResetColumnMappings').click(function (e) { + e.preventDefault(); + + if (confirm('@T("Admin.Common.AskToProceed")')) { + var form = '
    '; + $('body').append(form); + $('#ResetColumnMappingsForm').submit(); + } + + return false; + }); + + // init column mappings select $('#ImportColumnMappings').find('select').select2({ allowClear: true, minimumResultsForSearch: 16, From 4c90c15a64d832b9855271612cf3fb4afd3012e0 Mon Sep 17 00:00:00 2001 From: Marcus Gesing Date: Fri, 25 Dec 2015 11:03:25 +0100 Subject: [PATCH 191/707] Further implementation of import column mapping --- .../Localization/LocalizationHelper.cs | 22 ++- .../201512151526290_ImportFramework.cs | 9 +- .../Catalog/Importer/CategoryImporter.cs | 14 +- .../Catalog/Importer/ProductImporter.cs | 24 ++-- .../Customers/Importer/CustomerImporter.cs | 8 +- .../Import/ColumnMapping/ColumnMap.cs | 76 +++++++--- .../ColumnMapping/ColumnMapConverter.cs | 2 +- .../DataExchange/Import/DataImporter.cs | 5 + .../Import/DataTable/LightweightDataTable.cs | 14 +- .../DataExchange/Import/IEntityImporter.cs | 77 +---------- .../Import/ImportDataSegmenter.cs | 5 +- .../Import/ImportExecuteContext.cs | 130 ++++++++++++++++++ .../DataExchange/Import/ImportRow.cs | 78 ++++++----- .../NewsLetterSubscriptionImporter.cs | 5 +- .../SmartStore.Services.csproj | 1 + .../Controllers/ImportController.cs | 78 +++++++---- .../Models/DataExchange/ImportProfileModel.cs | 11 +- .../Views/Import/_ColumnMappings.cshtml | 37 +++-- .../Views/Import/_CreateOrUpdate.cshtml | 16 ++- .../Controllers/CommonController.cs | 25 +--- .../DataExchange/ImportDataSegmenterTests.cs | 8 +- 21 files changed, 403 insertions(+), 242 deletions(-) create mode 100644 src/Libraries/SmartStore.Services/DataExchange/Import/ImportExecuteContext.cs diff --git a/src/Libraries/SmartStore.Core/Localization/LocalizationHelper.cs b/src/Libraries/SmartStore.Core/Localization/LocalizationHelper.cs index d4c940ee36..118128c58e 100644 --- a/src/Libraries/SmartStore.Core/Localization/LocalizationHelper.cs +++ b/src/Libraries/SmartStore.Core/Localization/LocalizationHelper.cs @@ -1,11 +1,10 @@ -using System; -using System.Collections.Generic; +using System.Collections.Generic; using System.Globalization; using System.Linq; namespace SmartStore.Core.Localization { - public static class LocalizationHelper + public static class LocalizationHelper { private readonly static HashSet _cultureCodes = new HashSet( @@ -18,5 +17,20 @@ public static bool IsValidCultureCode(string cultureCode) return _cultureCodes.Contains(cultureCode); } - } + public static string GetLanguageNativeName(string locale) + { + try + { + if (locale.HasValue()) + { + var info = CultureInfo.GetCultureInfoByIetfLanguageTag(locale); + if (info != null) + return info.NativeName; + } + } + catch { } + + return null; + } + } } diff --git a/src/Libraries/SmartStore.Data/Migrations/201512151526290_ImportFramework.cs b/src/Libraries/SmartStore.Data/Migrations/201512151526290_ImportFramework.cs index 5caf8d7ec8..d54bff9b5c 100644 --- a/src/Libraries/SmartStore.Data/Migrations/201512151526290_ImportFramework.cs +++ b/src/Libraries/SmartStore.Data/Migrations/201512151526290_ImportFramework.cs @@ -65,6 +65,8 @@ public void MigrateLocaleResources(LocaleResourcesBuilder builder) "Specifies the number of records to be skipped.", "Legt die Anzahl der zu berspringenden Datenstze fest."); + builder.AddOrUpdate("Common.Unknown", "Unknown", "Unbekannt"); + builder.AddOrUpdate("Common.Language", "Language", "Sprache"); builder.AddOrUpdate("Admin.Common.ImportFile", "Import file", "Importdatei"); builder.AddOrUpdate("Admin.Common.ImportFiles", "Import files", "Importdateien"); builder.AddOrUpdate("Admin.Common.CsvConfiguration", "CSV Configuration", "CSV Konfiguration"); @@ -192,13 +194,12 @@ public void MigrateLocaleResources(LocaleResourcesBuilder builder) builder.AddOrUpdate("Admin.Promotions.NewsLetterSubscriptions.Fields.NewsLetterSubscriptionGuid", "Subscription GUID", "Abonnement GUID"); builder.AddOrUpdate("Admin.DataExchange.ColumnMapping.Note", - "For each field of the import file you can optionally set to which entity property whose data is to be imported. Specifying a default value is also possible, which is applied when the import field is empty. Through Reset all made assignments are reset to their original values.", - "Sie knnen optional fr jedes Feld der Importdatei festlegen, nach welcher Entittseigenschaft dessen Daten importiert werden sollen. Zudem ist die Angabe eines Standardwertes mglich, der angewendet wird, wenn das Importfeld leer ist. ber Zurcksetzen werden alle gettigten Zuordnungen auf ihre Ursprungswerte zurckgesetzt."); + "For each field of the import file you can optionally set whether and to which entity property the data is to be imported. Specifying a default value is also possible, which is applied when the import field is empty. Through Reset all made assignments are reset to their original values.", + "Sie knnen optional fr jedes Feld der Importdatei festlegen, ob und nach welcher Entittseigenschaft dessen Daten importiert werden sollen. Zudem ist die Angabe eines Standardwertes mglich, der angewendet wird, wenn das Importfeld leer ist. ber Zurcksetzen werden alle gettigten Zuordnungen auf ihre Ursprungswerte zurckgesetzt."); builder.AddOrUpdate("Admin.DataExchange.ColumnMapping.ImportField", "Import Field", "Importfeld"); - builder.AddOrUpdate("Admin.DataExchange.ColumnMapping.ImportFieldIndex", "Language Code etc.", "Sprach-Code etc."); builder.AddOrUpdate("Admin.DataExchange.ColumnMapping.EntityProperty", "Entity property", "Eigenschaft der Entitt"); - builder.AddOrUpdate("Admin.DataExchange.ColumnMapping.DefaultValue", "Default Value", "Standard Wert"); + builder.AddOrUpdate("Admin.DataExchange.ColumnMapping.DefaultValue", "Default Value", "Standardwert"); builder.AddOrUpdate("Admin.DataExchange.ColumnMapping.Validate.EntityMultipleMapped", "The entity property \"{0}\" was assigned several times. Please assign each property only once.", diff --git a/src/Libraries/SmartStore.Services/Catalog/Importer/CategoryImporter.cs b/src/Libraries/SmartStore.Services/Catalog/Importer/CategoryImporter.cs index 233a36e638..50ffb37a4e 100644 --- a/src/Libraries/SmartStore.Services/Catalog/Importer/CategoryImporter.cs +++ b/src/Libraries/SmartStore.Services/Catalog/Importer/CategoryImporter.cs @@ -49,7 +49,7 @@ public CategoryImporter( _seoSettings = seoSettings; } - private int ProcessSlugs(ImportExecuteContext context, ImportRow[] batch) + private int ProcessSlugs(IImportExecuteContext context, ImportRow[] batch) { var slugMap = new Dictionary(100); Func slugLookup = ((s) => @@ -109,7 +109,7 @@ private int ProcessSlugs(ImportExecuteContext context, ImportRow[] bat return _urlRecordRepository.Context.SaveChanges(); } - private int ProcessParentMappings(ImportExecuteContext context, + private int ProcessParentMappings(IImportExecuteContext context, ImportRow[] batch, Dictionary oldToNewId) { @@ -143,7 +143,7 @@ private int ProcessParentMappings(ImportExecuteContext context, return num; } - private int ProcessCategories(ImportExecuteContext context, + private int ProcessCategories(IImportExecuteContext context, ImportRow[] batch, DateTime utcNow, List allCategoryTemplateIds, @@ -292,8 +292,9 @@ private int ProcessCategories(ImportExecuteContext context, return num; } - public void Execute(ImportExecuteContext context) + public void Execute(IImportExecuteContext context) { + var utcNow = DateTime.UtcNow; var oldToNewId = new Dictionary(); var allCategoryTemplateIds = _categoryTemplateService.GetAllCategoryTemplates() @@ -302,8 +303,7 @@ public void Execute(ImportExecuteContext context) using (var scope = new DbContextScope(ctx: _categoryRepository.Context, autoDetectChanges: false, proxyCreation: false, validateOnSave: false)) { - var segmenter = new ImportDataSegmenter(context.DataTable); - var utcNow = DateTime.UtcNow; + var segmenter = context.GetSegmenter(); context.Result.TotalRecords = segmenter.TotalRows; @@ -333,7 +333,7 @@ public void Execute(ImportExecuteContext context) context.Result.NewRecords += batch.Count(x => x.IsNew && !x.IsTransient); context.Result.ModifiedRecords += batch.Count(x => !x.IsNew && !x.IsTransient); - if (context.DataTable.HasColumn("SeName") || batch.Any(x => x.IsNew || x.NameChanged)) + if (context.HasColumn("SeName") || batch.Any(x => x.IsNew || x.NameChanged)) { try { diff --git a/src/Libraries/SmartStore.Services/Catalog/Importer/ProductImporter.cs b/src/Libraries/SmartStore.Services/Catalog/Importer/ProductImporter.cs index 231872f859..dba41684e4 100644 --- a/src/Libraries/SmartStore.Services/Catalog/Importer/ProductImporter.cs +++ b/src/Libraries/SmartStore.Services/Catalog/Importer/ProductImporter.cs @@ -80,7 +80,7 @@ public ProductImporter( return (int?)null; } - private void ProcessProductPictures(ImportExecuteContext context, ImportRow[] batch) + private void ProcessProductPictures(IImportExecuteContext context, ImportRow[] batch) { // true, cause pictures must be saved and assigned an id prior adding a mapping. _productPictureRepository.AutoCommitEnabled = true; @@ -151,7 +151,7 @@ private void ProcessProductPictures(ImportExecuteContext context, ImportRow[] batch) + private int ProcessProductManufacturers(IImportExecuteContext context, ImportRow[] batch) { _productManufacturerRepository.AutoCommitEnabled = false; @@ -202,7 +202,7 @@ private int ProcessProductManufacturers(ImportExecuteContext context, ImportRow< return num; } - private int ProcessProductCategories(ImportExecuteContext context, ImportRow[] batch) + private int ProcessProductCategories(IImportExecuteContext context, ImportRow[] batch) { _productCategoryRepository.AutoCommitEnabled = false; @@ -253,7 +253,7 @@ private int ProcessProductCategories(ImportExecuteContext context, ImportRow[] batch) + private int ProcessLocalizations(IImportExecuteContext context, ImportRow[] batch) { //_rsProductManufacturer.AutoCommitEnabled = false; @@ -307,7 +307,7 @@ private int ProcessLocalizations(ImportExecuteContext context, ImportRow[] batch) + private int ProcessSlugs(IImportExecuteContext context, ImportRow[] batch) { var slugMap = new Dictionary(100); Func slugLookup = ((s) => @@ -367,7 +367,7 @@ private int ProcessSlugs(ImportExecuteContext context, ImportRow[] batc return _urlRecordRepository.Context.SaveChanges(); } - private int ProcessProducts(ImportExecuteContext context, ImportRow[] batch, DateTime utcNow) + private int ProcessProducts(IImportExecuteContext context, ImportRow[] batch, DateTime utcNow) { _productRepository.AutoCommitEnabled = true; @@ -538,11 +538,11 @@ private int ProcessProducts(ImportExecuteContext context, ImportRow[] b return num; } - public void Execute(ImportExecuteContext context) + public void Execute(IImportExecuteContext context) { using (var scope = new DbContextScope(ctx: _productRepository.Context, autoDetectChanges: false, proxyCreation: false, validateOnSave: false)) { - var segmenter = new ImportDataSegmenter(context.DataTable); + var segmenter = context.GetSegmenter(); var utcNow = DateTime.UtcNow; context.Result.TotalRecords = segmenter.TotalRows; @@ -581,7 +581,7 @@ public void Execute(ImportExecuteContext context) // IMPORTANT: Unlike with Products AutoCommitEnabled must be TRUE, // as Slugs are going to be validated against existing ones in DB. // =========================================================================== - if (context.DataTable.HasColumn("SeName") || batch.Any(x => x.IsNew || x.NameChanged)) + if (context.HasColumn("SeName") || batch.Any(x => x.IsNew || x.NameChanged)) { try { @@ -613,7 +613,7 @@ public void Execute(ImportExecuteContext context) // =========================================================================== // 4.) Import product category mappings // =========================================================================== - if (context.DataTable.HasColumn("CategoryIds")) + if (context.HasColumn("CategoryIds")) { try { @@ -628,7 +628,7 @@ public void Execute(ImportExecuteContext context) // =========================================================================== // 5.) Import product manufacturer mappings // =========================================================================== - if (context.DataTable.HasColumn("ManufacturerIds")) + if (context.HasColumn("ManufacturerIds")) { try { @@ -643,7 +643,7 @@ public void Execute(ImportExecuteContext context) // =========================================================================== // 6.) Import product picture mappings // =========================================================================== - if (context.DataTable.HasColumn("PictureThumbPaths")) + if (context.HasColumn("PictureThumbPaths")) { try { diff --git a/src/Libraries/SmartStore.Services/Customers/Importer/CustomerImporter.cs b/src/Libraries/SmartStore.Services/Customers/Importer/CustomerImporter.cs index 4236fa81f8..e486a5c7f0 100644 --- a/src/Libraries/SmartStore.Services/Customers/Importer/CustomerImporter.cs +++ b/src/Libraries/SmartStore.Services/Customers/Importer/CustomerImporter.cs @@ -72,7 +72,7 @@ private void UpsertRole(ImportRow row, CustomerRole role, string roleS } } - private int ProcessGenericAttributes(ImportExecuteContext context, + private int ProcessGenericAttributes(IImportExecuteContext context, ImportRow[] batch, List allCountryIds, List allStateProvinceIds, @@ -162,7 +162,7 @@ private int ProcessGenericAttributes(ImportExecuteContext context, return num; } - private int ProcessCustomers(ImportExecuteContext context, + private int ProcessCustomers(IImportExecuteContext context, ImportRow[] batch, DateTime utcNow, List allAffiliateIds, @@ -270,7 +270,7 @@ private int ProcessCustomers(ImportExecuteContext context, return num; } - public void Execute(ImportExecuteContext context) + public void Execute(IImportExecuteContext context) { var utcNow = DateTime.UtcNow; var customer = _customerService.GetCustomerById(context.CustomerId); @@ -296,7 +296,7 @@ public void Execute(ImportExecuteContext context) using (var scope = new DbContextScope(ctx: _services.DbContext, autoDetectChanges: false, proxyCreation: false, validateOnSave: false, autoCommit: false)) { - var segmenter = new ImportDataSegmenter(context.DataTable); + var segmenter = context.GetSegmenter(); context.Result.TotalRecords = segmenter.TotalRows; diff --git a/src/Libraries/SmartStore.Services/DataExchange/Import/ColumnMapping/ColumnMap.cs b/src/Libraries/SmartStore.Services/DataExchange/Import/ColumnMapping/ColumnMap.cs index b7f588d487..df66ad1e56 100644 --- a/src/Libraries/SmartStore.Services/DataExchange/Import/ColumnMapping/ColumnMap.cs +++ b/src/Libraries/SmartStore.Services/DataExchange/Import/ColumnMapping/ColumnMap.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Linq; namespace SmartStore.Services.DataExchange.Import { @@ -7,11 +8,63 @@ public class ColumnMap { private readonly Dictionary _map = new Dictionary(StringComparer.OrdinalIgnoreCase); + private static bool IsIndexed(string name) + { + return (name.EmptyNull().EndsWith("]") && name.EmptyNull().Contains("[")); + } + + private static string CreateSourceName(string name, string index) + { + if (index.HasValue()) + { + name += String.Concat("[", index, "]"); + } + + return name; + } + public IReadOnlyDictionary Mappings { get { return _map; } } + public static bool ParseSourceColumn(string sourceColumn, out string columnWithoutIndex, out string index) + { + columnWithoutIndex = sourceColumn; + index = null; + + var result = true; + + if (sourceColumn.HasValue() && IsIndexed(sourceColumn)) + { + var x1 = sourceColumn.IndexOf('['); + var x2 = sourceColumn.IndexOf(']', x1); + + if (x1 != -1 && x2 != -1 && x2 > x1) + { + columnWithoutIndex = sourceColumn.Substring(0, x1); + index = sourceColumn.Substring(x1 + 1, x2 - x1 - 1); + } + else + { + result = false; + } + } + + return result; + } + + public IEnumerable> GetInvalidMappings() + { + var mappings = Mappings.Where(x => + !IsIndexed(x.Key) && + x.Value.Property.HasValue() && + Mappings.Count(y => y.Value.Property.IsCaseInsensitiveEqual(x.Value.Property)) > 1 + ); + + return mappings; + } + public void AddMapping(string sourceColumn, string entityProperty, string defaultValue = null) { AddMapping(sourceColumn, null, entityProperty, defaultValue); @@ -20,12 +73,11 @@ public void AddMapping(string sourceColumn, string entityProperty, string defaul public void AddMapping(string sourceColumn, string index, string entityProperty, string defaultValue = null) { Guard.ArgumentNotEmpty(() => sourceColumn); - Guard.ArgumentNotEmpty(() => entityProperty); _map[CreateSourceName(sourceColumn, index)] = new ColumnMappingValue { - EntityProperty = entityProperty, - DefaultValue = defaultValue + Property = entityProperty, + Default = defaultValue }; } @@ -43,7 +95,7 @@ public ColumnMappingValue GetMapping(string sourceColumn) return result; } - return new ColumnMappingValue { EntityProperty = sourceColumn }; + return new ColumnMappingValue { Property = sourceColumn }; } /// @@ -68,7 +120,7 @@ public string GetMappedProperty(string sourceColumn) if (_map.TryGetValue(sourceColumn, out result)) { - return result.EntityProperty; + return result.Property; } return sourceColumn; @@ -84,16 +136,6 @@ public string GetMappedProperty(string sourceColumn, string index) { return GetMappedProperty(CreateSourceName(sourceColumn, index)); } - - internal static string CreateSourceName(string name, string index) - { - if (index.HasValue()) - { - name += String.Concat("[", index, "]"); - } - - return name; - } } @@ -102,11 +144,11 @@ public class ColumnMappingValue /// /// The property name of the target entity /// - public string EntityProperty { get; set; } + public string Property { get; set; } /// /// An optional default value /// - public string DefaultValue { get; set; } + public string Default { get; set; } } } diff --git a/src/Libraries/SmartStore.Services/DataExchange/Import/ColumnMapping/ColumnMapConverter.cs b/src/Libraries/SmartStore.Services/DataExchange/Import/ColumnMapping/ColumnMapConverter.cs index 7d6abcdc6d..78cbd7fa13 100644 --- a/src/Libraries/SmartStore.Services/DataExchange/Import/ColumnMapping/ColumnMapConverter.cs +++ b/src/Libraries/SmartStore.Services/DataExchange/Import/ColumnMapping/ColumnMapConverter.cs @@ -32,7 +32,7 @@ public override object ConvertFrom(CultureInfo culture, object value) foreach (var kvp in dict) { - map.AddMapping(kvp.Key, kvp.Value.EntityProperty, kvp.Value.DefaultValue); + map.AddMapping(kvp.Key, null, kvp.Value.Property, kvp.Value.Default); } return map; diff --git a/src/Libraries/SmartStore.Services/DataExchange/Import/DataImporter.cs b/src/Libraries/SmartStore.Services/DataExchange/Import/DataImporter.cs index b455823401..55ab3376fb 100644 --- a/src/Libraries/SmartStore.Services/DataExchange/Import/DataImporter.cs +++ b/src/Libraries/SmartStore.Services/DataExchange/Import/DataImporter.cs @@ -270,6 +270,11 @@ private void ImportCoreOuter(DataImporterContext ctx) ctx.ExecuteContext.CustomerId = ctx.Request.CustomerId; + { + var mapConverter = new ColumnMapConverter(); + ctx.ExecuteContext.ColumnMap = mapConverter.ConvertFrom(ctx.Request.Profile.ColumnMapping) ?? new ColumnMap(); + } + var files = ctx.Request.Profile.GetImportFiles(); if (files.Count == 0) diff --git a/src/Libraries/SmartStore.Services/DataExchange/Import/DataTable/LightweightDataTable.cs b/src/Libraries/SmartStore.Services/DataExchange/Import/DataTable/LightweightDataTable.cs index d8ca9b8e8c..99d3f4db48 100644 --- a/src/Libraries/SmartStore.Services/DataExchange/Import/DataTable/LightweightDataTable.cs +++ b/src/Libraries/SmartStore.Services/DataExchange/Import/DataTable/LightweightDataTable.cs @@ -42,20 +42,20 @@ public LightweightDataTable(IList columns, IList data) public bool HasColumn(string name) { + if (name.IsEmpty()) + return false; + return _columnIndexes.ContainsKey(name); } public int GetColumnIndex(string name) { - Guard.ArgumentNotEmpty(name, "name"); - int index; - if (!_columnIndexes.TryGetValue(name, out index)) - { - return -1; - } - return index; + if (name.HasValue() && _columnIndexes.TryGetValue(name, out index)) + return index; + + return -1; } public IList Columns diff --git a/src/Libraries/SmartStore.Services/DataExchange/Import/IEntityImporter.cs b/src/Libraries/SmartStore.Services/DataExchange/Import/IEntityImporter.cs index 1772fce95e..a33f2a3ccd 100644 --- a/src/Libraries/SmartStore.Services/DataExchange/Import/IEntityImporter.cs +++ b/src/Libraries/SmartStore.Services/DataExchange/Import/IEntityImporter.cs @@ -1,78 +1,7 @@ -using System.Linq; -using System.Collections.Generic; -using System.Threading; -using SmartStore.Core.Domain.DataExchange; - -namespace SmartStore.Services.DataExchange.Import +namespace SmartStore.Services.DataExchange.Import { - public interface IEntityImporter + public partial interface IEntityImporter { - void Execute(ImportExecuteContext context); - } - - - public class ImportExecuteContext - { - private DataExchangeAbortion _abortion; - private CancellationToken _cancellation; - private ProgressValueSetter _progressValueSetter; - private string _progressInfo; - - public ImportExecuteContext( - CancellationToken cancellation, - ProgressValueSetter progressValueSetter, - string progressInfo) - { - _cancellation = cancellation; - _progressValueSetter = progressValueSetter; - _progressInfo = progressInfo; - - CustomProperties = new Dictionary(); - Result = new ImportResult(); - } - - public IDataTable DataTable { get; internal set; } - - public int CustomerId { get; internal set; } - - /// - /// Use this dictionary for any custom data required along the import - /// - public Dictionary CustomProperties { get; private set; } - - public ImportResult Result { get; set; } - - public DataExchangeAbortion Abort - { - get - { - if (_cancellation.IsCancellationRequested || IsMaxFailures) - return DataExchangeAbortion.Hard; - - return _abortion; - } - set - { - _abortion = value; - } - } - - public bool IsMaxFailures - { - get - { - return Result.Messages.Count(x => x.MessageType == ImportMessageType.Error) > 11; - } - } - - public void SetProgress(int value, int maximum) - { - try - { - if (_progressValueSetter != null) - _progressValueSetter.Invoke(value, maximum, _progressInfo.FormatInvariant(value, maximum)); - } - catch { } - } + void Execute(IImportExecuteContext context); } } diff --git a/src/Libraries/SmartStore.Services/DataExchange/Import/ImportDataSegmenter.cs b/src/Libraries/SmartStore.Services/DataExchange/Import/ImportDataSegmenter.cs index d9ecad1d7b..991398d73f 100644 --- a/src/Libraries/SmartStore.Services/DataExchange/Import/ImportDataSegmenter.cs +++ b/src/Libraries/SmartStore.Services/DataExchange/Import/ImportDataSegmenter.cs @@ -21,16 +21,17 @@ public class ImportDataSegmenter where T : BaseEntity private readonly IDictionary _columnIndexes = new Dictionary(StringComparer.OrdinalIgnoreCase); - public ImportDataSegmenter(IDataTable table) + public ImportDataSegmenter(IDataTable table, ColumnMap map) { Guard.ArgumentNotNull(() => table); + Guard.ArgumentNotNull(() => map); _table = table; + _columnMap = map; _bof = true; _pageable = new PagedList(0, BATCHSIZE, table.Rows.Count); _culture = CultureInfo.InvariantCulture; - _columnMap = new ColumnMap(); } public CultureInfo Culture diff --git a/src/Libraries/SmartStore.Services/DataExchange/Import/ImportExecuteContext.cs b/src/Libraries/SmartStore.Services/DataExchange/Import/ImportExecuteContext.cs new file mode 100644 index 0000000000..3a0ebe03a2 --- /dev/null +++ b/src/Libraries/SmartStore.Services/DataExchange/Import/ImportExecuteContext.cs @@ -0,0 +1,130 @@ +using System.Collections.Generic; +using System.Linq; +using System.Threading; +using SmartStore.Core; +using SmartStore.Core.Domain.DataExchange; + +namespace SmartStore.Services.DataExchange.Import +{ + public interface IImportExecuteContext + { + /// + /// Context customer identifier + /// + int CustomerId { get; } + + /// + /// Use this dictionary for any custom data required along the export + /// + Dictionary CustomProperties { get; set; } + + /// + /// Result of the import + /// + ImportResult Result { get; set; } + + /// + /// Indicates whether and how to abort the import + /// + DataExchangeAbortion Abort { get; set; } + + /// + /// Creates a segmenter instance + /// + /// + /// + ImportDataSegmenter GetSegmenter() where TEntity : BaseEntity; + + /// + /// Whether the data source contains a particular column + /// + /// + /// + bool HasColumn(string name); + + /// + /// Allows to set a progress message + /// + /// Progress value + /// /// Progress maximum + void SetProgress(int value, int maximum); + } + + + public class ImportExecuteContext : IImportExecuteContext + { + private DataExchangeAbortion _abortion; + private CancellationToken _cancellation; + private ProgressValueSetter _progressValueSetter; + private string _progressInfo; + + public ImportExecuteContext( + CancellationToken cancellation, + ProgressValueSetter progressValueSetter, + string progressInfo) + { + _cancellation = cancellation; + _progressValueSetter = progressValueSetter; + _progressInfo = progressInfo; + + CustomProperties = new Dictionary(); + Result = new ImportResult(); + } + + public IDataTable DataTable { get; internal set; } + + public ColumnMap ColumnMap { get; internal set; } + + public int CustomerId { get; internal set; } + + /// + /// Use this dictionary for any custom data required along the import + /// + public Dictionary CustomProperties { get; set; } + + public ImportResult Result { get; set; } + + public DataExchangeAbortion Abort + { + get + { + if (_cancellation.IsCancellationRequested || IsMaxFailures) + return DataExchangeAbortion.Hard; + + return _abortion; + } + set + { + _abortion = value; + } + } + + public bool IsMaxFailures + { + get + { + return Result.Messages.Count(x => x.MessageType == ImportMessageType.Error) > 11; + } + } + + public ImportDataSegmenter GetSegmenter() where TEntity : BaseEntity + { + return new ImportDataSegmenter(DataTable, ColumnMap); + } + + public bool HasColumn(string name) + { + return DataTable.HasColumn(name); + } + + public void SetProgress(int value, int maximum) + { + try + { + if (_progressValueSetter != null) + _progressValueSetter.Invoke(value, maximum, _progressInfo.FormatInvariant(value, maximum)); + } + catch { } + } + } +} diff --git a/src/Libraries/SmartStore.Services/DataExchange/Import/ImportRow.cs b/src/Libraries/SmartStore.Services/DataExchange/Import/ImportRow.cs index da18417c95..662d4c32b5 100644 --- a/src/Libraries/SmartStore.Services/DataExchange/Import/ImportRow.cs +++ b/src/Libraries/SmartStore.Services/DataExchange/Import/ImportRow.cs @@ -18,6 +18,27 @@ public class ImportRow where T : BaseEntity private readonly ImportDataSegmenter _segmenter; private readonly IDataRow _row; + private TProp GetDefaultValue(ColumnMappingValue mapping, string columnName, TProp defaultValue, ImportResult result = null) + { + if (mapping != null && mapping.Default.HasValue()) + { + try + { + return mapping.Default.Convert(_segmenter.Culture); + } + catch (Exception exception) + { + if (result != null) + { + var msg = "Failed to convert default value '{0}'. Please specify a convertable default value. {1}"; + result.AddWarning(msg.FormatInvariant(mapping.Default, exception.Message), this.GetRowInfo(), columnName); + } + } + } + + return defaultValue; + } + public ImportRow(ImportDataSegmenter parent, IDataRow row, int position) { _segmenter = parent; @@ -91,12 +112,14 @@ public TProp GetDataValue(string columnName) public TProp GetDataValue(string columnName, string index) { object value; - if (_row.TryGetValue(_segmenter.ColumnMap.GetMappedProperty(columnName, index), out value)) + var mapping = _segmenter.ColumnMap.GetMapping(columnName, index); + + if (_row.TryGetValue(mapping.Property, out value) && value != DBNull.Value) { return value.Convert(_segmenter.Culture); } - return default(TProp); + return GetDefaultValue(mapping, columnName, default(TProp)); } public bool SetProperty( @@ -109,33 +132,16 @@ public bool SetProperty( // TBD: (MC) do not check for perf reason? //CheckInitialized(); + var isPropertySet = false; var pi = prop.ExtractPropertyInfo(); var propName = pi.Name; try { - var fastProp = FastProperty.GetProperty(target.GetUnproxiedType(), propName, PropertyCachingStrategy.EagerCached); - object value; var mapping = _segmenter.ColumnMap.GetMapping(propName); - if (mapping.DefaultValue != null) - { - try - { - if (mapping.DefaultValue.IsEmpty()) - defaultValue = default(TProp); // ignore called in value and explicitly convert to default - else - defaultValue = mapping.DefaultValue.Convert(_segmenter.Culture); - } - catch (Exception exception) - { - var msg = "Failed to convert default value '{0}'. Please specify a convertable default value. {1}"; - result.AddWarning(msg.FormatInvariant(mapping.DefaultValue.NaIfEmpty(), exception.Message), this.GetRowInfo(), propName); - } - } - - if (_row.TryGetValue(mapping.EntityProperty, out value)) + if (_row.TryGetValue(mapping.Property, out value)) { // source contains field value. Set it. TProp converted; @@ -143,25 +149,33 @@ public bool SetProperty( { converted = converter(value, _segmenter.Culture); } + else if (value == DBNull.Value || value.ToString().IsCaseInsensitiveEqual("NULL")) + { + converted = GetDefaultValue(mapping, propName, defaultValue, result); + } else { - converted = value.ToString().ToUpper().Equals("NULL") - ? default(TProp) - : value.Convert(_segmenter.Culture); + converted = value.Convert(_segmenter.Culture); } + var fastProp = FastProperty.GetProperty(target.GetUnproxiedType(), propName, PropertyCachingStrategy.EagerCached); fastProp.SetValue(target, converted); - return true; + isPropertySet = true; } else { - // source does not contain field data or is empty... - if (IsTransient && defaultValue != null) + if (IsTransient) { - // ...but the entity is new. In this case - // set the default value if given. - fastProp.SetValue(target, defaultValue); - return true; + defaultValue = GetDefaultValue(mapping, propName, defaultValue, result); + + // source does not contain field data or is empty... + if (defaultValue != null) + { + // ...but the entity is new. In this case set the default value if given. + var fastProp = FastProperty.GetProperty(target.GetUnproxiedType(), propName, PropertyCachingStrategy.EagerCached); + fastProp.SetValue(target, defaultValue); + isPropertySet = true; + } } } } @@ -170,7 +184,7 @@ public bool SetProperty( result.AddWarning("Conversion failed: " + exception.Message, this.GetRowInfo(), propName); } - return false; + return isPropertySet; } public ImportRowInfo GetRowInfo() diff --git a/src/Libraries/SmartStore.Services/Messages/Importer/NewsLetterSubscriptionImporter.cs b/src/Libraries/SmartStore.Services/Messages/Importer/NewsLetterSubscriptionImporter.cs index 0037b755f4..5bf83c4755 100644 --- a/src/Libraries/SmartStore.Services/Messages/Importer/NewsLetterSubscriptionImporter.cs +++ b/src/Libraries/SmartStore.Services/Messages/Importer/NewsLetterSubscriptionImporter.cs @@ -1,6 +1,5 @@ using System; using System.Collections.Generic; -using System.Globalization; using System.Linq; using SmartStore.Core.Data; using SmartStore.Core.Domain.DataExchange; @@ -22,7 +21,7 @@ public NewsLetterSubscriptionImporter( _subscriptionRepository = subscriptionRepository; } - public void Execute(ImportExecuteContext context) + public void Execute(IImportExecuteContext context) { var utcNow = DateTime.UtcNow; var currentStoreId = _services.StoreContext.CurrentStore.Id; @@ -32,7 +31,7 @@ public void Execute(ImportExecuteContext context) using (var scope = new DbContextScope(ctx: _services.DbContext, autoDetectChanges: false, proxyCreation: false, validateOnSave: false, autoCommit: false)) { - var segmenter = new ImportDataSegmenter(context.DataTable); + var segmenter = context.GetSegmenter(); context.Result.TotalRecords = segmenter.TotalRows; diff --git a/src/Libraries/SmartStore.Services/SmartStore.Services.csproj b/src/Libraries/SmartStore.Services/SmartStore.Services.csproj index 405df35f5a..344a61ef2a 100644 --- a/src/Libraries/SmartStore.Services/SmartStore.Services.csproj +++ b/src/Libraries/SmartStore.Services/SmartStore.Services.csproj @@ -190,6 +190,7 @@ + diff --git a/src/Presentation/SmartStore.Web/Administration/Controllers/ImportController.cs b/src/Presentation/SmartStore.Web/Administration/Controllers/ImportController.cs index 9fecdbe9ea..11418e16e9 100644 --- a/src/Presentation/SmartStore.Web/Administration/Controllers/ImportController.cs +++ b/src/Presentation/SmartStore.Web/Administration/Controllers/ImportController.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Globalization; using System.IO; using System.Linq; using System.Web.Mvc; @@ -8,6 +9,7 @@ using SmartStore.Core.Domain; using SmartStore.Core.Domain.DataExchange; using SmartStore.Core.IO; +using SmartStore.Core.Localization; using SmartStore.Services; using SmartStore.Services.DataExchange.Csv; using SmartStore.Services.DataExchange.Import; @@ -30,17 +32,20 @@ public class ImportController : AdminControllerBase private readonly IImportProfileService _importService; private readonly IDateTimeHelper _dateTimeHelper; private readonly ITaskScheduler _taskScheduler; + private readonly ILanguageService _languageService; public ImportController( ICommonServices services, IImportProfileService importService, IDateTimeHelper dateTimeHelper, - ITaskScheduler taskScheduler) + ITaskScheduler taskScheduler, + ILanguageService languageService) { _services = services; _importService = importService; _dateTimeHelper = dateTimeHelper; _taskScheduler = taskScheduler; + _languageService = languageService; } #region Utilities @@ -58,6 +63,7 @@ private void PrepareColumnMappingModels(ImportProfile profile, ImportProfileMode var filePath = files.First(); var mapConverter = new ColumnMapConverter(); + var allLanguages = _languageService.GetAllLanguages(true); var map = (invalidMap != null ? invalidMap : mapConverter.ConvertFrom(profile.ColumnMapping)); var hasMappings = (map != null && map.Mappings.Any()); @@ -71,28 +77,35 @@ private void PrepareColumnMappingModels(ImportProfile profile, ImportProfileMode using (var stream = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.Read)) { - var index = 0; - var dataTable = LightweightDataTable.FromFile(Path.GetFileName(filePath), stream, stream.Length, csvConfiguration, 0, 2); + var dataTable = LightweightDataTable.FromFile(Path.GetFileName(filePath), stream, stream.Length, csvConfiguration, 0, 1); foreach (var column in dataTable.Columns.Where(x => x.Name.HasValue())) { + string columnWithoutIndex; + string columnIndex; + ColumnMap.ParseSourceColumn(column.Name, out columnWithoutIndex, out columnIndex); + var mapModel = new ColumnMappingItemModel { - Index = index++, - Column = column.Name + Index = dataTable.Columns.IndexOf(column), + Column = column.Name, + ColumnWithoutIndex = columnWithoutIndex, + ColumnIndex = columnIndex }; - var x1 = column.Name.IndexOf('['); - var x2 = column.Name.IndexOf(']'); - - if (x1 != -1 && x2 != -1 && x2 > x1) + if (destProperties.ContainsKey(column.Name)) { - mapModel.ColumnWithoutIndex = column.Name.Substring(0, x1); - mapModel.ColumnIndex = column.Name.Substring(x1 + 1, x2 - x1 - 1); + mapModel.ColumnLocalized = destProperties[column.Name]; } - else + + if (columnIndex.HasValue()) { - mapModel.ColumnWithoutIndex = column.Name; + var language = allLanguages.FirstOrDefault(x => x.UniqueSeoCode.IsCaseInsensitiveEqual(columnIndex)); + if (language != null) + { + mapModel.LanguageDescription = LocalizationHelper.GetLanguageNativeName(language.LanguageCulture); + mapModel.FlagImageFileName = language.FlagImageFileName; + } } if (hasMappings) @@ -100,8 +113,9 @@ private void PrepareColumnMappingModels(ImportProfile profile, ImportProfileMode var mapping = map.Mappings.FirstOrDefault(x => x.Key == column.Name); if (mapping.Value != null) { - mapModel.EntityProperty = mapping.Value.EntityProperty; - mapModel.DefaultValue = mapping.Value.DefaultValue; + mapModel.Property = mapping.Value.Property; + mapModel.Default = mapping.Value.Default; + mapModel.IsNilProperty = mapping.Value.Property.IsEmpty(); } } @@ -274,27 +288,35 @@ public ActionResult Edit(ImportProfileModel model, bool continueEditing, FormCol using (var stream = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.Read)) { - var index = 0; - var dataTable = LightweightDataTable.FromFile(Path.GetFileName(filePath), stream, stream.Length, csvConfig ?? CsvConfiguration.ExcelFriendlyConfiguration, 0, 2); + var dataTable = LightweightDataTable.FromFile(Path.GetFileName(filePath), stream, stream.Length, csvConfig ?? CsvConfiguration.ExcelFriendlyConfiguration, 0, 1); foreach (var column in dataTable.Columns.Where(x => x.Name.HasValue())) { - var key = "ColumnMapping.EntityProperty." + index.ToString(); + var index = dataTable.Columns.IndexOf(column); + var key = "ColumnMapping.Property." + index.ToString(); + if (form.AllKeys.Contains(key)) { + // allow to nil an entity property name to explicitly ignore a column var entityProperty = form[key]; - if (entityProperty.HasValue()) - { - if (map.Mappings.Any(x => x.Value.EntityProperty.IsCaseInsensitiveEqual(entityProperty))) - { - ModelState.AddModelError(key, T("Admin.DataExchange.ColumnMapping.Validate.EntityMultipleMapped", entityProperty)); - } + var defaultValue = form["ColumnMapping.Default." + index.ToString()]; - var defaultValue = form["ColumnMapping.DefaultValue." + index.ToString()]; - map.AddMapping(column.Name, entityProperty, defaultValue); - } + map.AddMapping(column.Name, null, entityProperty, defaultValue); + } + } + + // add model state error for invalid mappings + foreach (var invalidMapping in map.GetInvalidMappings()) + { + // do not mark columns as invalid where column name equals entity property name + if (invalidMapping.Key != invalidMapping.Value.Property) + { + var column = dataTable.Columns.First(x => x.Name == invalidMapping.Key); + var index = dataTable.Columns.IndexOf(column); + var key = "ColumnMapping.Property." + index.ToString(); + + ModelState.AddModelError(key, T("Admin.DataExchange.ColumnMapping.Validate.EntityMultipleMapped", invalidMapping.Value.Property)); } - ++index; } } diff --git a/src/Presentation/SmartStore.Web/Administration/Models/DataExchange/ImportProfileModel.cs b/src/Presentation/SmartStore.Web/Administration/Models/DataExchange/ImportProfileModel.cs index b45fd937c8..7310512284 100644 --- a/src/Presentation/SmartStore.Web/Administration/Models/DataExchange/ImportProfileModel.cs +++ b/src/Presentation/SmartStore.Web/Administration/Models/DataExchange/ImportProfileModel.cs @@ -56,10 +56,17 @@ public partial class ImportProfileModel : EntityModelBase public class ColumnMappingItemModel { public int Index { get; set; } + public bool IsNilProperty { get; set; } + public string Column { get; set; } public string ColumnWithoutIndex { get; set; } public string ColumnIndex { get; set; } - public string EntityProperty { get; set; } - public string DefaultValue { get; set; } + public string ColumnLocalized { get; set; } + + public string LanguageDescription { get; set; } + public string FlagImageFileName { get; set; } + + public string Property { get; set; } + public string Default { get; set; } } } \ No newline at end of file diff --git a/src/Presentation/SmartStore.Web/Administration/Views/Import/_ColumnMappings.cshtml b/src/Presentation/SmartStore.Web/Administration/Views/Import/_ColumnMappings.cshtml index bc5bfd60b1..4dc8045232 100644 --- a/src/Presentation/SmartStore.Web/Administration/Views/Import/_ColumnMappings.cshtml +++ b/src/Presentation/SmartStore.Web/Administration/Views/Import/_ColumnMappings.cshtml @@ -19,8 +19,8 @@
    @T("Admin.DataExchange.ColumnMapping.ImportField")@T("Admin.DataExchange.ColumnMapping.ImportFieldIndex")@T("Admin.DataExchange.ColumnMapping.EntityProperty")@T("Admin.DataExchange.ColumnMapping.ImportField")@T("Admin.DataExchange.ColumnMapping.ImportFieldIndex")@T("Admin.DataExchange.ColumnMapping.EntityProperty") @T("Admin.DataExchange.ColumnMapping.DefaultValue")
    - @mapping.SourceColumn + @mapping.ColumnWithoutIndex - @mapping.SourceColumnIndex + @mapping.ColumnIndex - @Html.DropDownList("ColumnMappings.EntityProperty", mapping.AvailableEntityProperties, Model.UnspecifiedString) + +
    + @Html.ValidationMessage("ColumnMapping.EntityProperty." + mapping.Index.ToString())
    - @Html.Editor("ColumnMappings.DefaultValue", mapping.DefaultValue) +
    - - + + @@ -30,27 +30,46 @@ { } diff --git a/src/Presentation/SmartStore.Web/Administration/Views/Import/_CreateOrUpdate.cshtml b/src/Presentation/SmartStore.Web/Administration/Views/Import/_CreateOrUpdate.cshtml index bd24686006..35f4e90cf8 100644 --- a/src/Presentation/SmartStore.Web/Administration/Views/Import/_CreateOrUpdate.cshtml +++ b/src/Presentation/SmartStore.Web/Administration/Views/Import/_CreateOrUpdate.cshtml @@ -200,15 +200,17 @@ function columnMappingSelectItemFormatting(item) { try { - var option = $(item.element); + if (item.text.length > 0) { + var option = $(item.element); - var html = '
    ' + item.text + ''; - if (option.length !== 0) { - html += ' (' + option.val() + ')'; - } - html += '
    '; + var html = '
    ' + item.text + ''; + if (option.length !== 0) { + html += ' (' + option.val() + ')'; + } + html += '
    '; - return html; + return html; + } } catch (e) { } diff --git a/src/Presentation/SmartStore.Web/Controllers/CommonController.cs b/src/Presentation/SmartStore.Web/Controllers/CommonController.cs index 877c920a2d..09ae5b0110 100644 --- a/src/Presentation/SmartStore.Web/Controllers/CommonController.cs +++ b/src/Presentation/SmartStore.Web/Controllers/CommonController.cs @@ -22,6 +22,7 @@ using SmartStore.Core.Domain.Tax; using SmartStore.Core.Domain.Themes; using SmartStore.Core.Infrastructure; +using SmartStore.Core.Localization; using SmartStore.Core.Themes; using SmartStore.Services; using SmartStore.Services.Catalog; @@ -158,7 +159,7 @@ protected LanguageSelectorModel PrepareLanguageSelectorModel() { Id = x.Id, Name = x.Name, - NativeName = GetLanguageNativeName(x.LanguageCulture) ?? x.Name, + NativeName = LocalizationHelper.GetLanguageNativeName(x.LanguageCulture) ?? x.Name, ISOCode = x.LanguageCulture, SeoCode = x.UniqueSeoCode, FlagImageFileName = x.FlagImageFileName @@ -200,28 +201,6 @@ protected LanguageSelectorModel PrepareLanguageSelectorModel() return model; } - // TODO: (MC) zentral auslagern - private string GetLanguageNativeName(string locale) - { - try - { - if (!string.IsNullOrEmpty(locale)) - { - var info = CultureInfo.GetCultureInfoByIetfLanguageTag(locale); - if (info == null) - { - return null; - } - return info.NativeName; - } - return null; - } - catch - { - return null; - } - } - [NonAction] protected CurrencySelectorModel PrepareCurrencySelectorModel() { diff --git a/src/Tests/SmartStore.Services.Tests/DataExchange/ImportDataSegmenterTests.cs b/src/Tests/SmartStore.Services.Tests/DataExchange/ImportDataSegmenterTests.cs index ceb0fb3d93..d36888d507 100644 --- a/src/Tests/SmartStore.Services.Tests/DataExchange/ImportDataSegmenterTests.cs +++ b/src/Tests/SmartStore.Services.Tests/DataExchange/ImportDataSegmenterTests.cs @@ -1,8 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; +using System.Collections.Generic; using NUnit.Framework; using SmartStore.Core.Domain.Catalog; using SmartStore.Services.DataExchange.Import; @@ -28,7 +24,7 @@ public void CanResolveColumnIndexNames() }; var table = new LightweightDataTable(columns, new List()); - var segmenter = new ImportDataSegmenter(table); + var segmenter = new ImportDataSegmenter(table, new ColumnMap()); segmenter.ColumnMap.AddMapping("Attr[Material]", "material"); segmenter.ColumnMap.AddMapping("Name[it]", "name_it"); From 324a35b371036a7053ff18830e25b7a1990e8c43 Mon Sep 17 00:00:00 2001 From: Marcus Gesing Date: Fri, 25 Dec 2015 12:11:25 +0100 Subject: [PATCH 192/707] Removed a redundant HasColumn method --- .../Catalog/Importer/CategoryImporter.cs | 8 ++++---- .../Catalog/Importer/ProductImporter.cs | 12 ++++++------ .../DataExchange/Import/ImportDataSegmenter.cs | 4 ++-- .../DataExchange/Import/ImportExecuteContext.cs | 12 ------------ 4 files changed, 12 insertions(+), 24 deletions(-) diff --git a/src/Libraries/SmartStore.Services/Catalog/Importer/CategoryImporter.cs b/src/Libraries/SmartStore.Services/Catalog/Importer/CategoryImporter.cs index 50ffb37a4e..2b6bd7a2c3 100644 --- a/src/Libraries/SmartStore.Services/Catalog/Importer/CategoryImporter.cs +++ b/src/Libraries/SmartStore.Services/Catalog/Importer/CategoryImporter.cs @@ -65,7 +65,7 @@ private int ProcessSlugs(IImportExecuteContext context, ImportRow[] ba foreach (var row in batch) { - if (row.IsNew || row.NameChanged || row.Segmenter.HasDataColumn("SeName")) + if (row.IsNew || row.NameChanged || row.Segmenter.HasColumn("SeName")) { try { @@ -118,7 +118,7 @@ private int ProcessParentMappings(IImportExecuteContext context, foreach (var row in batch) { if (row.DataRow.TryGetValue("Id", out key1) && - row.Segmenter.HasDataColumn("ParentCategoryId") && row.DataRow.TryGetValue("ParentCategoryId", out key2)) + row.Segmenter.HasColumn("ParentCategoryId") && row.DataRow.TryGetValue("ParentCategoryId", out key2)) { var id = key1.ToString().ToInt(); var parentId = key2.ToString().ToInt(-1); @@ -176,7 +176,7 @@ private int ProcessCategories(IImportExecuteContext context, if (category == null) { // a Name is required with new categories - if (!row.Segmenter.HasDataColumn("Name")) + if (!row.Segmenter.HasColumn("Name")) { context.Result.AddError("The 'Name' field is required for new categories. Skipping row.", row.GetRowInfo(), "Name"); continue; @@ -333,7 +333,7 @@ public void Execute(IImportExecuteContext context) context.Result.NewRecords += batch.Count(x => x.IsNew && !x.IsTransient); context.Result.ModifiedRecords += batch.Count(x => !x.IsNew && !x.IsTransient); - if (context.HasColumn("SeName") || batch.Any(x => x.IsNew || x.NameChanged)) + if (segmenter.HasColumn("SeName") || batch.Any(x => x.IsNew || x.NameChanged)) { try { diff --git a/src/Libraries/SmartStore.Services/Catalog/Importer/ProductImporter.cs b/src/Libraries/SmartStore.Services/Catalog/Importer/ProductImporter.cs index dba41684e4..f3aafc0f6f 100644 --- a/src/Libraries/SmartStore.Services/Catalog/Importer/ProductImporter.cs +++ b/src/Libraries/SmartStore.Services/Catalog/Importer/ProductImporter.cs @@ -323,7 +323,7 @@ private int ProcessSlugs(IImportExecuteContext context, ImportRow[] bat foreach (var row in batch) { - if (row.IsNew || row.NameChanged || row.Segmenter.HasDataColumn("SeName")) + if (row.IsNew || row.NameChanged || row.Segmenter.HasColumn("SeName")) { try { @@ -400,7 +400,7 @@ private int ProcessProducts(IImportExecuteContext context, ImportRow[] if (product == null) { // a Name is required with new products. - if (!row.Segmenter.HasDataColumn("Name")) + if (!row.Segmenter.HasColumn("Name")) { context.Result.AddError("The 'Name' field is required for new products. Skipping row.", row.GetRowInfo(), "Name"); continue; @@ -581,7 +581,7 @@ public void Execute(IImportExecuteContext context) // IMPORTANT: Unlike with Products AutoCommitEnabled must be TRUE, // as Slugs are going to be validated against existing ones in DB. // =========================================================================== - if (context.HasColumn("SeName") || batch.Any(x => x.IsNew || x.NameChanged)) + if (segmenter.HasColumn("SeName") || batch.Any(x => x.IsNew || x.NameChanged)) { try { @@ -613,7 +613,7 @@ public void Execute(IImportExecuteContext context) // =========================================================================== // 4.) Import product category mappings // =========================================================================== - if (context.HasColumn("CategoryIds")) + if (segmenter.HasColumn("CategoryIds")) { try { @@ -628,7 +628,7 @@ public void Execute(IImportExecuteContext context) // =========================================================================== // 5.) Import product manufacturer mappings // =========================================================================== - if (context.HasColumn("ManufacturerIds")) + if (segmenter.HasColumn("ManufacturerIds")) { try { @@ -643,7 +643,7 @@ public void Execute(IImportExecuteContext context) // =========================================================================== // 6.) Import product picture mappings // =========================================================================== - if (context.HasColumn("PictureThumbPaths")) + if (segmenter.HasColumn("PictureThumbPaths")) { try { diff --git a/src/Libraries/SmartStore.Services/DataExchange/Import/ImportDataSegmenter.cs b/src/Libraries/SmartStore.Services/DataExchange/Import/ImportDataSegmenter.cs index 991398d73f..7ca1197f0f 100644 --- a/src/Libraries/SmartStore.Services/DataExchange/Import/ImportDataSegmenter.cs +++ b/src/Libraries/SmartStore.Services/DataExchange/Import/ImportDataSegmenter.cs @@ -88,12 +88,12 @@ public int BatchSize get { return BATCHSIZE; } } - public bool HasDataColumn(string name) + public bool HasColumn(string name) { return _table.HasColumn(_columnMap.GetMappedProperty(name)); } - public bool HasDataColumn(string name, string index) + public bool HasColumn(string name, string index) { return _table.HasColumn(_columnMap.GetMappedProperty(name, index)); } diff --git a/src/Libraries/SmartStore.Services/DataExchange/Import/ImportExecuteContext.cs b/src/Libraries/SmartStore.Services/DataExchange/Import/ImportExecuteContext.cs index 3a0ebe03a2..79562488d6 100644 --- a/src/Libraries/SmartStore.Services/DataExchange/Import/ImportExecuteContext.cs +++ b/src/Libraries/SmartStore.Services/DataExchange/Import/ImportExecuteContext.cs @@ -35,13 +35,6 @@ public interface IImportExecuteContext /// ImportDataSegmenter GetSegmenter() where TEntity : BaseEntity; - /// - /// Whether the data source contains a particular column - /// - /// - /// - bool HasColumn(string name); - /// /// Allows to set a progress message /// @@ -112,11 +105,6 @@ public ImportDataSegmenter GetSegmenter() where TEntity : Base return new ImportDataSegmenter(DataTable, ColumnMap); } - public bool HasColumn(string name) - { - return DataTable.HasColumn(name); - } - public void SetProgress(int value, int maximum) { try From 8244642b9ef38f49a798ed394bdebb4867e43549 Mon Sep 17 00:00:00 2001 From: Marcus Gesing Date: Fri, 25 Dec 2015 12:53:24 +0100 Subject: [PATCH 193/707] Removed ImportRow.DataRow property because Importer would get round default value handling here. --- .../Catalog/Importer/CategoryImporter.cs | 80 +++++++------------ .../Catalog/Importer/ProductImporter.cs | 20 ++--- .../Customers/Importer/CustomerImporter.cs | 27 +++---- .../DataExchange/Import/ImportRow.cs | 5 -- 4 files changed, 47 insertions(+), 85 deletions(-) diff --git a/src/Libraries/SmartStore.Services/Catalog/Importer/CategoryImporter.cs b/src/Libraries/SmartStore.Services/Catalog/Importer/CategoryImporter.cs index 2b6bd7a2c3..a547f07928 100644 --- a/src/Libraries/SmartStore.Services/Catalog/Importer/CategoryImporter.cs +++ b/src/Libraries/SmartStore.Services/Catalog/Importer/CategoryImporter.cs @@ -113,26 +113,21 @@ private int ProcessParentMappings(IImportExecuteContext context, ImportRow[] batch, Dictionary oldToNewId) { - object key1, key2; - foreach (var row in batch) { - if (row.DataRow.TryGetValue("Id", out key1) && - row.Segmenter.HasColumn("ParentCategoryId") && row.DataRow.TryGetValue("ParentCategoryId", out key2)) - { - var id = key1.ToString().ToInt(); - var parentId = key2.ToString().ToInt(-1); + var id = row.GetDataValue("Id"); + var rawParentId = row.GetDataValue("ParentCategoryId"); + var parentId = rawParentId.ToInt(-1); - if (id != 0 && parentId != -1 && oldToNewId.ContainsKey(id) && oldToNewId.ContainsKey(parentId)) + if (id != 0 && parentId != -1 && oldToNewId.ContainsKey(id) && oldToNewId.ContainsKey(parentId)) + { + // only touch hierarchical data if child and parent were inserted + if (oldToNewId[id].Inserted && oldToNewId[parentId].Inserted && oldToNewId[id].NewId != 0) { - // only touch hierarchical data if child and parent were inserted - if (oldToNewId[id].Inserted && oldToNewId[parentId].Inserted && oldToNewId[id].NewId != 0) + var category = _categoryRepository.GetById(oldToNewId[id].NewId); + if (category != null) { - var category = _categoryRepository.GetById(oldToNewId[id].NewId); - if (category != null) - { - category.ParentCategoryId = oldToNewId[parentId].NewId; - } + category.ParentCategoryId = oldToNewId[parentId].NewId; } } } @@ -151,7 +146,6 @@ private int ProcessCategories(IImportExecuteContext context, { _categoryRepository.AutoCommitEnabled = true; - object key; Picture picture = null; Category lastInserted = null; Category lastUpdated = null; @@ -161,16 +155,11 @@ private int ProcessCategories(IImportExecuteContext context, foreach (var row in batch) { Category category = null; - var id = 0; + var id = row.GetDataValue("Id"); - // try get by int ID - if (row.DataRow.TryGetValue("Id", out key)) + if (id != 0) { - id = key.ToString().ToInt(); - if (id != 0) - { - category = _categoryRepository.GetById(id); - } + category = _categoryRepository.GetById(id); } if (category == null) @@ -216,11 +205,10 @@ private int ProcessCategories(IImportExecuteContext context, row.SetProperty(context.Result, category, (x) => x.Alias); row.SetProperty(context.Result, category, (x) => x.DefaultViewMode); - if (row.DataRow.TryGetValue("CategoryTemplateId", out key)) + var templateId = row.GetDataValue("CategoryTemplateId"); + if (templateId > 0 && allCategoryTemplateIds.Contains(templateId)) { - int templateId = key.ToString().ToInt(); - if (templateId > 0 && allCategoryTemplateIds.Contains(templateId)) - category.CategoryTemplateId = templateId; + category.CategoryTemplateId = templateId; } var storeIds = row.GetDataValue>("StoreIds"); @@ -229,26 +217,22 @@ private int ProcessCategories(IImportExecuteContext context, _storeMappingService.SaveStoreMappings(category, storeIds.ToArray()); } - if (row.DataRow.TryGetValue("PictureThumbPath", out key)) + var thumbPath = row.GetDataValue("PictureThumbPath"); + if (thumbPath.HasValue() && File.Exists(thumbPath)) { - var thumbPath = key.ToString(); - if (thumbPath.HasValue() && File.Exists(thumbPath)) - { - var pictures = new List(); - if (category.PictureId.HasValue && (picture = _pictureRepository.GetById(category.PictureId.Value)) != null) - pictures.Add(picture); + var pictures = new List(); + if (category.PictureId.HasValue && (picture = _pictureRepository.GetById(category.PictureId.Value)) != null) + pictures.Add(picture); - var pictureBinary = _pictureService.FindEqualPicture(thumbPath, pictures, out equalPictureId); + var pictureBinary = _pictureService.FindEqualPicture(thumbPath, pictures, out equalPictureId); - if (pictureBinary != null && pictureBinary.Length > 0 && - (picture = _pictureService.InsertPicture(pictureBinary, "image/jpeg", _pictureService.GetPictureSeName(row.EntityDisplayName), true, false, false)) != null) - { - category.PictureId = picture.Id; - } + if (pictureBinary != null && pictureBinary.Length > 0 && + (picture = _pictureService.InsertPicture(pictureBinary, "image/jpeg", _pictureService.GetPictureSeName(row.EntityDisplayName), true, false, false)) != null) + { + category.PictureId = picture.Id; } } - row.SetProperty(context.Result, category, (x) => x.CreatedOnUtc, utcNow); category.UpdatedOnUtc = utcNow; @@ -275,12 +259,10 @@ private int ProcessCategories(IImportExecuteContext context, // get new category ids foreach (var row in batch) { - if (row.DataRow.TryGetValue("Id", out key)) - { - var id = key.ToString().ToInt(); - if (id != 0 && oldToNewId.ContainsKey(id)) - oldToNewId[id].NewId = row.Entity.Id; - } + var id = row.GetDataValue("Id"); + + if (id != 0 && oldToNewId.ContainsKey(id)) + oldToNewId[id].NewId = row.Entity.Id; } // Perf: notify only about LAST insertion and update @@ -352,7 +334,7 @@ public void Execute(IImportExecuteContext context) } // map parent id of inserted categories - if (oldToNewId.Any()) + if (oldToNewId.Any() && segmenter.HasColumn("Id") && segmenter.HasColumn("ParentCategoryId")) { segmenter.Reset(); diff --git a/src/Libraries/SmartStore.Services/Catalog/Importer/ProductImporter.cs b/src/Libraries/SmartStore.Services/Catalog/Importer/ProductImporter.cs index f3aafc0f6f..b115a270eb 100644 --- a/src/Libraries/SmartStore.Services/Catalog/Importer/ProductImporter.cs +++ b/src/Libraries/SmartStore.Services/Catalog/Importer/ProductImporter.cs @@ -376,25 +376,17 @@ private int ProcessProducts(IImportExecuteContext context, ImportRow[] foreach (var row in batch) { - Product product = null; - object key; - - // try get by int ID - if (row.DataRow.TryGetValue("Id", out key) && key.ToString().ToInt() > 0) - { - product = _productService.GetProductById(key.ToString().ToInt()); - } + var id = row.GetDataValue("Id"); + var product = _productService.GetProductById(id); - // try get by SKU - if (product == null && row.DataRow.TryGetValue("SKU", out key)) + if (product == null) { - product = _productService.GetProductBySku(key.ToString()); + product = _productService.GetProductBySku(row.GetDataValue("Sku")); } - // try get by GTIN - if (product == null && row.DataRow.TryGetValue("Gtin", out key)) + if (product == null) { - product = _productService.GetProductByGtin(key.ToString()); + product = _productService.GetProductByGtin(row.GetDataValue("Gtin")); } if (product == null) diff --git a/src/Libraries/SmartStore.Services/Customers/Importer/CustomerImporter.cs b/src/Libraries/SmartStore.Services/Customers/Importer/CustomerImporter.cs index e486a5c7f0..f148f2cd6b 100644 --- a/src/Libraries/SmartStore.Services/Customers/Importer/CustomerImporter.cs +++ b/src/Libraries/SmartStore.Services/Customers/Importer/CustomerImporter.cs @@ -180,19 +180,14 @@ private int ProcessCustomers(IImportExecuteContext context, foreach (var row in batch) { - object key; - var customerId = 0; - Customer customer = null; + var id = row.GetDataValue("Id"); + var customer = _customerService.GetCustomerById(id); - if (row.DataRow.TryGetValue("Id", out key) && key.ToString().ToInt() > 0) - { - customerId = key.ToString().ToInt(); - customer = _customerService.GetCustomerById(customerId); - } - - if (customer == null && row.DataRow.TryGetValue("CustomerGuid", out key)) + if (customer == null) { - customer = _customerService.GetCustomerByGuid(new Guid(key.ToString())); + var guid = row.GetDataValue("CustomerGuid"); + if (guid.HasValue()) + customer = _customerService.GetCustomerByGuid(new Guid(guid)); } if (customer == null) @@ -214,8 +209,9 @@ private int ProcessCustomers(IImportExecuteContext context, var isRegistered = row.GetDataValue("IsRegistered"); var isAdmin = row.GetDataValue("IsAdministrator"); var isForumModerator = row.GetDataValue("IsForumModerator"); + var affiliateId = row.GetDataValue("AffiliateId"); - row.Initialize(customer, email.HasValue() ? email : customerId.ToString()); + row.Initialize(customer, email.HasValue() ? email : id.ToString()); row.SetProperty(context.Result, customer, (x) => x.CustomerGuid); row.SetProperty(context.Result, customer, (x) => x.Username); @@ -235,14 +231,11 @@ private int ProcessCustomers(IImportExecuteContext context, row.SetProperty(context.Result, customer, (x) => x.CreatedOnUtc, utcNow); row.SetProperty(context.Result, customer, (x) => x.LastActivityDateUtc, utcNow); - if (row.DataRow.TryGetValue("AffiliateId", out key)) + if (affiliateId > 0 && allAffiliateIds.Contains(affiliateId)) { - int affiliateId = key.ToString().ToInt(); - if (affiliateId > 0 && allAffiliateIds.Contains(affiliateId)) - customer.AffiliateId = affiliateId; + customer.AffiliateId = affiliateId; } - UpsertRole(row, guestRole, SystemCustomerRoleNames.Guests, isGuest); UpsertRole(row, registeredRole, SystemCustomerRoleNames.Registered, isRegistered); UpsertRole(row, adminRole, SystemCustomerRoleNames.Administrators, isAdmin); diff --git a/src/Libraries/SmartStore.Services/DataExchange/Import/ImportRow.cs b/src/Libraries/SmartStore.Services/DataExchange/Import/ImportRow.cs index 662d4c32b5..33279b7d7b 100644 --- a/src/Libraries/SmartStore.Services/DataExchange/Import/ImportRow.cs +++ b/src/Libraries/SmartStore.Services/DataExchange/Import/ImportRow.cs @@ -73,11 +73,6 @@ public bool IsNew get { return _isNew; } } - public IDataRow DataRow - { - get { return _row; } - } - public ImportDataSegmenter Segmenter { get { return _segmenter; } From 10155563a180c74c6ba2e20665ecd4ca064fb7f8 Mon Sep 17 00:00:00 2001 From: Marcus Gesing Date: Fri, 25 Dec 2015 19:12:20 +0100 Subject: [PATCH 194/707] Testing importers --- .../Catalog/Importer/CategoryImporter.cs | 119 +++++++++++++----- .../Controllers/ImportController.cs | 19 +-- .../Administration/SmartStore.Admin.csproj | 1 - .../Views/Import/_CreateOrUpdate.cshtml | 37 +++--- .../Views/Import/_ImportFileList.cshtml | 13 -- 5 files changed, 113 insertions(+), 76 deletions(-) delete mode 100644 src/Presentation/SmartStore.Web/Administration/Views/Import/_ImportFileList.cshtml diff --git a/src/Libraries/SmartStore.Services/Catalog/Importer/CategoryImporter.cs b/src/Libraries/SmartStore.Services/Catalog/Importer/CategoryImporter.cs index a547f07928..08c0223ee6 100644 --- a/src/Libraries/SmartStore.Services/Catalog/Importer/CategoryImporter.cs +++ b/src/Libraries/SmartStore.Services/Catalog/Importer/CategoryImporter.cs @@ -111,7 +111,7 @@ private int ProcessSlugs(IImportExecuteContext context, ImportRow[] ba private int ProcessParentMappings(IImportExecuteContext context, ImportRow[] batch, - Dictionary oldToNewId) + Dictionary srcToDestId) { foreach (var row in batch) { @@ -119,15 +119,55 @@ private int ProcessParentMappings(IImportExecuteContext context, var rawParentId = row.GetDataValue("ParentCategoryId"); var parentId = rawParentId.ToInt(-1); - if (id != 0 && parentId != -1 && oldToNewId.ContainsKey(id) && oldToNewId.ContainsKey(parentId)) + if (id != 0 && parentId != -1 && srcToDestId.ContainsKey(id) && srcToDestId.ContainsKey(parentId)) { // only touch hierarchical data if child and parent were inserted - if (oldToNewId[id].Inserted && oldToNewId[parentId].Inserted && oldToNewId[id].NewId != 0) + if (srcToDestId[id].Inserted && srcToDestId[parentId].Inserted && srcToDestId[id].DestinationId != 0) { - var category = _categoryRepository.GetById(oldToNewId[id].NewId); + var category = _categoryRepository.GetById(srcToDestId[id].DestinationId); if (category != null) { - category.ParentCategoryId = oldToNewId[parentId].NewId; + category.ParentCategoryId = srcToDestId[parentId].DestinationId; + } + } + } + } + + var num = _categoryRepository.Context.SaveChanges(); + + return num; + } + + private int ProcessPictures(IImportExecuteContext context, + ImportRow[] batch, + Dictionary srcToDestId) + { + Picture picture = null; + var equalPictureId = 0; + + foreach (var row in batch) + { + var srcId = row.GetDataValue("Id"); + var thumbPath = row.GetDataValue("PictureThumbPath"); + + if (srcId != 0 && srcToDestId.ContainsKey(srcId) && thumbPath.HasValue() && File.Exists(thumbPath)) + { + var category = _categoryRepository.GetById(srcToDestId[srcId].DestinationId); + + if (category != null) + { + var pictures = new List(); + if (category.PictureId.HasValue && (picture = _pictureRepository.GetById(category.PictureId.Value)) != null) + pictures.Add(picture); + + var pictureBinary = _pictureService.FindEqualPicture(thumbPath, pictures, out equalPictureId); + + if (pictureBinary != null && pictureBinary.Length > 0 && + (picture = _pictureService.InsertPicture(pictureBinary, "image/jpeg", _pictureService.GetPictureSeName(row.EntityDisplayName), true, false, false)) != null) + { + category.PictureId = picture.Id; + + _categoryRepository.Update(category); } } } @@ -142,14 +182,14 @@ private int ProcessCategories(IImportExecuteContext context, ImportRow[] batch, DateTime utcNow, List allCategoryTemplateIds, - Dictionary oldToNewId) + Dictionary srcToDestId) { _categoryRepository.AutoCommitEnabled = true; - Picture picture = null; + //Picture picture = null; Category lastInserted = null; Category lastUpdated = null; - var equalPictureId = 0; + //var equalPictureId = 0; var defaultTemplateId = allCategoryTemplateIds.First(); foreach (var row in batch) @@ -217,28 +257,28 @@ private int ProcessCategories(IImportExecuteContext context, _storeMappingService.SaveStoreMappings(category, storeIds.ToArray()); } - var thumbPath = row.GetDataValue("PictureThumbPath"); - if (thumbPath.HasValue() && File.Exists(thumbPath)) - { - var pictures = new List(); - if (category.PictureId.HasValue && (picture = _pictureRepository.GetById(category.PictureId.Value)) != null) - pictures.Add(picture); + //var thumbPath = row.GetDataValue("PictureThumbPath"); + //if (thumbPath.HasValue() && File.Exists(thumbPath)) + //{ + // var pictures = new List(); + // if (category.PictureId.HasValue && (picture = _pictureRepository.GetById(category.PictureId.Value)) != null) + // pictures.Add(picture); - var pictureBinary = _pictureService.FindEqualPicture(thumbPath, pictures, out equalPictureId); + // var pictureBinary = _pictureService.FindEqualPicture(thumbPath, pictures, out equalPictureId); - if (pictureBinary != null && pictureBinary.Length > 0 && - (picture = _pictureService.InsertPicture(pictureBinary, "image/jpeg", _pictureService.GetPictureSeName(row.EntityDisplayName), true, false, false)) != null) - { - category.PictureId = picture.Id; - } - } + // if (pictureBinary != null && pictureBinary.Length > 0 && + // (picture = _pictureService.InsertPicture(pictureBinary, "image/jpeg", _pictureService.GetPictureSeName(row.EntityDisplayName), true, false, false)) != null) + // { + // category.PictureId = picture.Id; + // } + //} row.SetProperty(context.Result, category, (x) => x.CreatedOnUtc, utcNow); category.UpdatedOnUtc = utcNow; - if (id != 0 && !oldToNewId.ContainsKey(id)) + if (id != 0 && !srcToDestId.ContainsKey(id)) { - oldToNewId.Add(id, new ImportCategoryMapping { Inserted = row.IsTransient }); + srcToDestId.Add(id, new ImportCategoryMapping { Inserted = row.IsTransient }); } if (row.IsTransient) @@ -261,8 +301,8 @@ private int ProcessCategories(IImportExecuteContext context, { var id = row.GetDataValue("Id"); - if (id != 0 && oldToNewId.ContainsKey(id)) - oldToNewId[id].NewId = row.Entity.Id; + if (id != 0 && srcToDestId.ContainsKey(id)) + srcToDestId[id].DestinationId = row.Entity.Id; } // Perf: notify only about LAST insertion and update @@ -277,7 +317,7 @@ private int ProcessCategories(IImportExecuteContext context, public void Execute(IImportExecuteContext context) { var utcNow = DateTime.UtcNow; - var oldToNewId = new Dictionary(); + var srcToDestId = new Dictionary(); var allCategoryTemplateIds = _categoryTemplateService.GetAllCategoryTemplates() .Select(x => x.Id) @@ -300,7 +340,7 @@ public void Execute(IImportExecuteContext context) try { - ProcessCategories(context, batch, utcNow, allCategoryTemplateIds, oldToNewId); + ProcessCategories(context, batch, utcNow, allCategoryTemplateIds, srcToDestId); } catch (Exception exception) { @@ -315,6 +355,7 @@ public void Execute(IImportExecuteContext context) context.Result.NewRecords += batch.Count(x => x.IsNew && !x.IsTransient); context.Result.ModifiedRecords += batch.Count(x => !x.IsNew && !x.IsTransient); + // process slugs if (segmenter.HasColumn("SeName") || batch.Any(x => x.IsNew || x.NameChanged)) { try @@ -331,10 +372,28 @@ public void Execute(IImportExecuteContext context) _categoryRepository.Context.AutoDetectChangesEnabled = false; } } + + // process pictures + if (srcToDestId.Any() && segmenter.HasColumn("PictureThumbPath")) + { + try + { + _categoryRepository.Context.AutoDetectChangesEnabled = true; + ProcessPictures(context, batch, srcToDestId); + } + catch (Exception exception) + { + context.Result.AddError(exception, segmenter.CurrentSegment, "ProcessPictures"); + } + finally + { + _categoryRepository.Context.AutoDetectChangesEnabled = false; + } + } } // map parent id of inserted categories - if (oldToNewId.Any() && segmenter.HasColumn("Id") && segmenter.HasColumn("ParentCategoryId")) + if (srcToDestId.Any() && segmenter.HasColumn("Id") && segmenter.HasColumn("ParentCategoryId")) { segmenter.Reset(); @@ -346,7 +405,7 @@ public void Execute(IImportExecuteContext context) try { - ProcessParentMappings(context, batch, oldToNewId); + ProcessParentMappings(context, batch, srcToDestId); } catch (Exception exception) { @@ -361,7 +420,7 @@ public void Execute(IImportExecuteContext context) internal class ImportCategoryMapping { - public int NewId { get; set; } + public int DestinationId { get; set; } public bool Inserted { get; set; } } } diff --git a/src/Presentation/SmartStore.Web/Administration/Controllers/ImportController.cs b/src/Presentation/SmartStore.Web/Administration/Controllers/ImportController.cs index 11418e16e9..9c2d6b565f 100644 --- a/src/Presentation/SmartStore.Web/Administration/Controllers/ImportController.cs +++ b/src/Presentation/SmartStore.Web/Administration/Controllers/ImportController.cs @@ -399,7 +399,6 @@ public JsonResult FileUpload(int id) var success = false; string error = null; string tempFile = ""; - string fileList = ""; if (_services.Permissions.Authorize(StandardPermissionProvider.ManageImports)) { @@ -436,14 +435,6 @@ public JsonResult FileUpload(int id) var destFile = Path.Combine(folder, Path.GetFileName(postedFile.FileName)); success = postedFile.Stream.ToFile(destFile); - - if (success) - { - var model = new ImportProfileModel(); - PrepareProfileModel(model, profile, false); - - fileList = this.RenderPartialViewToString("_ImportFileList", model); - } } } } @@ -460,7 +451,7 @@ public JsonResult FileUpload(int id) if (error.HasValue()) NotifyError(error); - return Json(new { success = success, tempFile = tempFile, fileList = fileList }); + return Json(new { success = success, tempFile = tempFile }); } [HttpPost] @@ -522,6 +513,7 @@ public ActionResult DownloadImportFile(int id, string name) return result; } + [HttpPost] public ActionResult DeleteImportFile(int id, string name) { if (_services.Permissions.Authorize(StandardPermissionProvider.ManageImports)) @@ -531,14 +523,9 @@ public ActionResult DeleteImportFile(int id, string name) { var path = Path.Combine(profile.GetImportFolder(true), name); FileSystemHelper.Delete(path); - - var model = new ImportProfileModel(); - PrepareProfileModel(model, profile, false); - - return PartialView("_ImportFileList", model); } } - return new EmptyResult(); + return RedirectToAction("Edit", new { id = id }); } } } \ No newline at end of file diff --git a/src/Presentation/SmartStore.Web/Administration/SmartStore.Admin.csproj b/src/Presentation/SmartStore.Web/Administration/SmartStore.Admin.csproj index 5b0852f437..8aa8fd5f3f 100644 --- a/src/Presentation/SmartStore.Web/Administration/SmartStore.Admin.csproj +++ b/src/Presentation/SmartStore.Web/Administration/SmartStore.Admin.csproj @@ -542,7 +542,6 @@ - diff --git a/src/Presentation/SmartStore.Web/Administration/Views/Import/_CreateOrUpdate.cshtml b/src/Presentation/SmartStore.Web/Administration/Views/Import/_CreateOrUpdate.cshtml index 35f4e90cf8..2212f50131 100644 --- a/src/Presentation/SmartStore.Web/Administration/Views/Import/_CreateOrUpdate.cshtml +++ b/src/Presentation/SmartStore.Web/Administration/Views/Import/_CreateOrUpdate.cshtml @@ -39,12 +39,22 @@ - + @if (Model.ScheduleTaskId > 0) @@ -152,9 +162,8 @@ $('#ImportFileList').html(data.result.tempFile); $('#ImportFileUploadContainer').hide(); // just one initial file to specify the file type } - - if (!_.isEmpty(data.result.fileList)) { - $('#ImportFileList').html(data.result.fileList); + else { + location.href = '@Url.Action("Edit", new { id = Model.Id })'; } } } @@ -163,17 +172,13 @@ // delete import file $('#ImportFileList').on('click', '.import-file-delete', function (e) { e.preventDefault(); - var url = '@Url.Action("DeleteImportFile", new { id = Model.Id })'; - - $({}).doAjax({ - type: 'POST', - url: url + '?name=' + encodeURIComponent($(this).attr('data-filename')), - ask: '@T("Admin.Common.AreYouSure")', - callbackSuccess: function (resp) { - if (!_.isEmpty(resp)) - $('#ImportFileList').html(resp); - } - }); + + if (confirm('@T("Admin.Common.AskToProceed")')) { + var form = ''; + $('body').append(form); + $('#DeleteImportFileForm').submit(); + } + return false; }); diff --git a/src/Presentation/SmartStore.Web/Administration/Views/Import/_ImportFileList.cshtml b/src/Presentation/SmartStore.Web/Administration/Views/Import/_ImportFileList.cshtml deleted file mode 100644 index be0f5d9703..0000000000 --- a/src/Presentation/SmartStore.Web/Administration/Views/Import/_ImportFileList.cshtml +++ /dev/null @@ -1,13 +0,0 @@ -@using SmartStore.Admin.Models.DataExchange; -@model ImportProfileModel -@foreach (var fileName in Model.ExistingFileNames) -{ -

    - @Html.IconForFileExtension(Path.GetExtension(fileName), false) - @fileName - - -

    -} \ No newline at end of file From f33cfa4c2df887f3c661d3a05539dbd2e203e07d Mon Sep 17 00:00:00 2001 From: Marcus Gesing Date: Fri, 25 Dec 2015 19:41:15 +0100 Subject: [PATCH 195/707] Hide export profiles where the provider is decorated with hidden attribute --- .../Controllers/ExportController.cs | 49 ++++++++++++++++--- 1 file changed, 42 insertions(+), 7 deletions(-) diff --git a/src/Presentation/SmartStore.Web/Administration/Controllers/ExportController.cs b/src/Presentation/SmartStore.Web/Administration/Controllers/ExportController.cs index 32f84d8afd..2e719959ec 100644 --- a/src/Presentation/SmartStore.Web/Administration/Controllers/ExportController.cs +++ b/src/Presentation/SmartStore.Web/Administration/Controllers/ExportController.cs @@ -488,13 +488,17 @@ public ActionResult List() foreach (var profile in profiles) { - var profileModel = new ExportProfileModel(); + var provider = providers.FirstOrDefault(x => x.Metadata.SystemName == profile.ProviderSystemName); + if (provider != null) + { + var profileModel = new ExportProfileModel(); - PrepareProfileModel(profileModel, profile, providers.FirstOrDefault(x => x.Metadata.SystemName == profile.ProviderSystemName), false); + PrepareProfileModel(profileModel, profile, provider, false); - profileModel.TaskModel = profile.ScheduleTask.ToScheduleTaskModel(_services.Localization, _dateTimeHelper, Url); + profileModel.TaskModel = profile.ScheduleTask.ToScheduleTaskModel(_services.Localization, _dateTimeHelper, Url); - model.Add(profileModel); + model.Add(profileModel); + } } return View(model); @@ -613,6 +617,8 @@ public ActionResult Edit(int id) return RedirectToAction("List"); var provider = _exportService.LoadProvider(profile.ProviderSystemName); + if (provider.Metadata.IsHidden) + return RedirectToAction("List"); var model = new ExportProfileModel(); @@ -634,6 +640,8 @@ public ActionResult Edit(ExportProfileModel model, bool continueEditing) return RedirectToAction("List"); var provider = _exportService.LoadProvider(profile.ProviderSystemName); + if (provider.Metadata.IsHidden) + return RedirectToAction("List"); if (!ModelState.IsValid) { @@ -754,6 +762,10 @@ public ActionResult DeleteConfirmed(int id) if (profile == null) return RedirectToAction("List"); + var provider = _exportService.LoadProvider(profile.ProviderSystemName); + if (provider.Metadata.IsHidden) + return RedirectToAction("List"); + try { _exportService.DeleteExportProfile(profile); @@ -779,6 +791,10 @@ public ActionResult Preview(int id) if (profile == null) return RedirectToAction("List"); + var provider = _exportService.LoadProvider(profile.ProviderSystemName); + if (provider.Metadata.IsHidden) + return RedirectToAction("List"); + if (!profile.Enabled) { NotifyInfo(T("Admin.DataExchange.Export.EnableProfileForPreview")); @@ -786,8 +802,6 @@ public ActionResult Preview(int id) return RedirectToAction("Edit", new { id = profile.Id }); } - var provider = _exportService.LoadProvider(profile.ProviderSystemName); - var request = new DataExportRequest(profile, provider); var totalRecords = _dataExporter.GetDataCount(request); @@ -814,7 +828,8 @@ public ActionResult PreviewList(GridCommand command, int id, int totalRecords) if (_services.Permissions.Authorize(StandardPermissionProvider.ManageExports) && (profile = _exportService.GetExportProfileById(id)) != null && - (provider = _exportService.LoadProvider(profile.ProviderSystemName)) != null) + (provider = _exportService.LoadProvider(profile.ProviderSystemName)) != null && + !provider.Metadata.IsHidden) { var productModel = new List(); var orderModel = new List(); @@ -981,6 +996,10 @@ public ActionResult Execute(int id, string selectedIds) if (profile == null) return RedirectToAction("List"); + var provider = _exportService.LoadProvider(profile.ProviderSystemName); + if (provider.Metadata.IsHidden) + return RedirectToAction("List"); + var taskParams = new Dictionary(); taskParams.Add("CurrentCustomerId", _services.WorkContext.CurrentCustomer.Id.ToString()); @@ -1090,6 +1109,8 @@ public ActionResult CreateDeployment(int id) return RedirectToAction("List"); var provider = _exportService.LoadProvider(profile.ProviderSystemName); + if (provider.Metadata.IsHidden) + return RedirectToAction("List"); //var fileSystemName = ExportDeploymentType.FileSystem.GetLocalizedEnum(_services.Localization, _services.WorkContext); @@ -1115,6 +1136,10 @@ public ActionResult CreateDeployment(ExportDeploymentModel model, bool continueE if (profile == null) return RedirectToAction("List"); + var provider = _exportService.LoadProvider(profile.ProviderSystemName); + if (provider.Metadata.IsHidden) + return RedirectToAction("List"); + if (ModelState.IsValid) { var deployment = new ExportDeployment(); @@ -1141,6 +1166,8 @@ public ActionResult EditDeployment(int id) return RedirectToAction("List"); var provider = _exportService.LoadProvider(deployment.Profile.ProviderSystemName); + if (provider.Metadata.IsHidden) + return RedirectToAction("List"); var model = PrepareDeploymentModel(deployment, provider, true); @@ -1158,6 +1185,10 @@ public ActionResult EditDeployment(ExportDeploymentModel model, bool continueEdi if (deployment == null) return RedirectToAction("List"); + var provider = _exportService.LoadProvider(deployment.Profile.ProviderSystemName); + if (provider.Metadata.IsHidden) + return RedirectToAction("List"); + if (ModelState.IsValid) { ModelToEntity(model, deployment); @@ -1183,6 +1214,10 @@ public ActionResult DeleteDeployment(int id) if (deployment == null) return RedirectToAction("List"); + var provider = _exportService.LoadProvider(deployment.Profile.ProviderSystemName); + if (provider.Metadata.IsHidden) + return RedirectToAction("List"); + int profileId = deployment.ProfileId; _exportService.DeleteExportDeployment(deployment); From 77221c4bbf26dd00f93ea149987bcb71a8a85930 Mon Sep 17 00:00:00 2001 From: Marcus Gesing Date: Sat, 26 Dec 2015 11:24:27 +0100 Subject: [PATCH 196/707] Minor changes --- .../Catalog/Importer/CategoryImporter.cs | 18 ------------------ .../DataExchange/DataExporter.cs | 3 +++ .../DataExchange/IDataExporter.cs | 1 + 3 files changed, 4 insertions(+), 18 deletions(-) diff --git a/src/Libraries/SmartStore.Services/Catalog/Importer/CategoryImporter.cs b/src/Libraries/SmartStore.Services/Catalog/Importer/CategoryImporter.cs index 08c0223ee6..e0e5a2bdf2 100644 --- a/src/Libraries/SmartStore.Services/Catalog/Importer/CategoryImporter.cs +++ b/src/Libraries/SmartStore.Services/Catalog/Importer/CategoryImporter.cs @@ -186,10 +186,8 @@ private int ProcessCategories(IImportExecuteContext context, { _categoryRepository.AutoCommitEnabled = true; - //Picture picture = null; Category lastInserted = null; Category lastUpdated = null; - //var equalPictureId = 0; var defaultTemplateId = allCategoryTemplateIds.First(); foreach (var row in batch) @@ -257,22 +255,6 @@ private int ProcessCategories(IImportExecuteContext context, _storeMappingService.SaveStoreMappings(category, storeIds.ToArray()); } - //var thumbPath = row.GetDataValue("PictureThumbPath"); - //if (thumbPath.HasValue() && File.Exists(thumbPath)) - //{ - // var pictures = new List(); - // if (category.PictureId.HasValue && (picture = _pictureRepository.GetById(category.PictureId.Value)) != null) - // pictures.Add(picture); - - // var pictureBinary = _pictureService.FindEqualPicture(thumbPath, pictures, out equalPictureId); - - // if (pictureBinary != null && pictureBinary.Length > 0 && - // (picture = _pictureService.InsertPicture(pictureBinary, "image/jpeg", _pictureService.GetPictureSeName(row.EntityDisplayName), true, false, false)) != null) - // { - // category.PictureId = picture.Id; - // } - //} - row.SetProperty(context.Result, category, (x) => x.CreatedOnUtc, utcNow); category.UpdatedOnUtc = utcNow; diff --git a/src/Libraries/SmartStore.Services/DataExchange/DataExporter.cs b/src/Libraries/SmartStore.Services/DataExchange/DataExporter.cs index d8d3006017..5a6d2268d3 100644 --- a/src/Libraries/SmartStore.Services/DataExchange/DataExporter.cs +++ b/src/Libraries/SmartStore.Services/DataExchange/DataExporter.cs @@ -202,6 +202,9 @@ private void SetProgress(DataExporterContext ctx, string message) private bool HasPermission(DataExporterContext ctx) { + if (ctx.Request.HasPermission) + return true; + if (ctx.Request.CustomerId == 0) ctx.Request.CustomerId = _services.WorkContext.CurrentCustomer.Id; // fallback to background task system customer diff --git a/src/Libraries/SmartStore.Services/DataExchange/IDataExporter.cs b/src/Libraries/SmartStore.Services/DataExchange/IDataExporter.cs index 8e30fa9974..97f7cec7f1 100644 --- a/src/Libraries/SmartStore.Services/DataExchange/IDataExporter.cs +++ b/src/Libraries/SmartStore.Services/DataExchange/IDataExporter.cs @@ -43,6 +43,7 @@ public DataExportRequest(ExportProfile profile, Provider provid public ProgressValueSetter ProgressValueSetter { get; set; } public int CustomerId { get; set; } + public bool HasPermission { get; set; } public IList EntitiesToExport { get; set; } From a70471841a8bc6db38da69abd5f9a8fcc42d7a52 Mon Sep 17 00:00:00 2001 From: Marcus Gesing Date: Sat, 26 Dec 2015 11:35:56 +0100 Subject: [PATCH 197/707] Updated changelog --- changelog.md | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/changelog.md b/changelog.md index 6294b6d91e..3d69214836 100644 --- a/changelog.md +++ b/changelog.md @@ -3,7 +3,8 @@ ## SmartStore.NET 2.5 ### New Features -* #701 Implement new export framework +* New export and import framework +* Import of customer and category data * #141 Payment and shipping methods by customer roles * #67 Restrict payment methods to countries * #94 Restrict payment methods to shipping methods @@ -28,8 +29,6 @@ * #722 System > SEO Names: Implement editing of an UrlRecord * Admin > System > System Info shows used application memory (RAM) * Added option to make VATIN mandatory during customer registration -* Customer import -* Category import ### Improvements * (Perf) Implemented static caches for URL aliases and localized properties. Increases app startup and request speed by up to 30%. From 872ac5e10049b78319fc8460586dce5113e28520 Mon Sep 17 00:00:00 2001 From: Marcus Gesing Date: Sun, 27 Dec 2015 12:49:19 +0100 Subject: [PATCH 198/707] Resolves #841 Activity log for deleting an order --- changelog.md | 1 + .../201512151526290_ImportFramework.cs | 5 ++ .../Setup/Builder/ActivityLogTypeMigrator.cs | 68 +++++++++++++++++++ .../SmartStore.Data/SmartStore.Data.csproj | 1 + .../Controllers/OrderController.cs | 15 +++- 5 files changed, 88 insertions(+), 2 deletions(-) create mode 100644 src/Libraries/SmartStore.Data/Setup/Builder/ActivityLogTypeMigrator.cs diff --git a/changelog.md b/changelog.md index 3d69214836..9447f0b4da 100644 --- a/changelog.md +++ b/changelog.md @@ -29,6 +29,7 @@ * #722 System > SEO Names: Implement editing of an UrlRecord * Admin > System > System Info shows used application memory (RAM) * Added option to make VATIN mandatory during customer registration +* #841 Activity log for deleting an order ### Improvements * (Perf) Implemented static caches for URL aliases and localized properties. Increases app startup and request speed by up to 30%. diff --git a/src/Libraries/SmartStore.Data/Migrations/201512151526290_ImportFramework.cs b/src/Libraries/SmartStore.Data/Migrations/201512151526290_ImportFramework.cs index d54bff9b5c..85b09659d2 100644 --- a/src/Libraries/SmartStore.Data/Migrations/201512151526290_ImportFramework.cs +++ b/src/Libraries/SmartStore.Data/Migrations/201512151526290_ImportFramework.cs @@ -48,6 +48,7 @@ public void Seed(SmartObjectContext context) context.MigrateLocaleResources(MigrateLocaleResources); var permissionMigrator = new PermissionMigrator(context); + var activityLogMigrator = new ActivityLogTypeMigrator(context); permissionMigrator.AddPermission(new PermissionRecord { @@ -55,6 +56,8 @@ public void Seed(SmartObjectContext context) SystemName = "ManageImports", Category = "Configuration" }, new string[] { SystemCustomerRoleNames.Administrators }); + + activityLogMigrator.AddActivityLogType("DeleteOrder", "Delete order", "Auftrag gelscht"); } public void MigrateLocaleResources(LocaleResourcesBuilder builder) @@ -227,6 +230,8 @@ public void MigrateLocaleResources(LocaleResourcesBuilder builder) "Admin.Common.ImportFromExcel.DownloadReport", "Admin.Common.ImportFromExcel.NoReportAvailable" ); + + builder.AddOrUpdate("ActivityLog.DeleteOrder", "Deleted order {0}", "Auftrag {0} gelscht"); } } } diff --git a/src/Libraries/SmartStore.Data/Setup/Builder/ActivityLogTypeMigrator.cs b/src/Libraries/SmartStore.Data/Setup/Builder/ActivityLogTypeMigrator.cs new file mode 100644 index 0000000000..b397af928a --- /dev/null +++ b/src/Libraries/SmartStore.Data/Setup/Builder/ActivityLogTypeMigrator.cs @@ -0,0 +1,68 @@ +using System.Data.Entity; +using System.Linq; +using SmartStore.Core.Domain.Configuration; +using SmartStore.Core.Domain.Localization; +using SmartStore.Core.Domain.Logging; + +namespace SmartStore.Data.Setup +{ + internal class ActivityLogTypeMigrator + { + private readonly SmartObjectContext _ctx; + private readonly DbSet _activityLogTypeRecords; + + public ActivityLogTypeMigrator(SmartObjectContext ctx) + { + Guard.ArgumentNotNull(() => ctx); + + _ctx = ctx; + _activityLogTypeRecords = _ctx.Set(); + } + + private Language GetDefaultAdminLanguage(DbSet settingRecords, DbSet languageRecords) + { + const string settingKey = "LocalizationSettings.DefaultAdminLanguageId"; + + var defaultAdminLanguageSetting = settingRecords.FirstOrDefault(x => x.Name == settingKey && x.StoreId == 0); + + if (defaultAdminLanguageSetting == null) + defaultAdminLanguageSetting = settingRecords.FirstOrDefault(x => x.Name == settingKey); + + if (defaultAdminLanguageSetting != null) + { + var defaultAdminLanguageId = defaultAdminLanguageSetting.Value.ToInt(); + if (defaultAdminLanguageId != 0) + { + var language = languageRecords.FirstOrDefault(x => x.Id == defaultAdminLanguageId); + if (language != null) + return language; + } + } + + return languageRecords.First(); + } + + public void AddActivityLogType(string systemKeyword, string enName, string deName) + { + Guard.ArgumentNotEmpty(() => systemKeyword); + Guard.ArgumentNotEmpty(() => enName); + Guard.ArgumentNotEmpty(() => deName); + + var record = _activityLogTypeRecords.FirstOrDefault(x => x.SystemKeyword == systemKeyword); + + if (record == null) + { + var language = GetDefaultAdminLanguage(_ctx.Set(), _ctx.Set()); + + _activityLogTypeRecords.Add(new ActivityLogType + { + Enabled = true, + SystemKeyword = systemKeyword, + Name = (language.UniqueSeoCode.IsCaseInsensitiveEqual("de") ? deName : enName) + }); + + _ctx.SaveChanges(); + } + } + } +} diff --git a/src/Libraries/SmartStore.Data/SmartStore.Data.csproj b/src/Libraries/SmartStore.Data/SmartStore.Data.csproj index afc16698c0..951d5703c5 100644 --- a/src/Libraries/SmartStore.Data/SmartStore.Data.csproj +++ b/src/Libraries/SmartStore.Data/SmartStore.Data.csproj @@ -376,6 +376,7 @@ 201512151526290_ImportFramework.cs + diff --git a/src/Presentation/SmartStore.Web/Administration/Controllers/OrderController.cs b/src/Presentation/SmartStore.Web/Administration/Controllers/OrderController.cs index 0bdc537cac..fd82849786 100644 --- a/src/Presentation/SmartStore.Web/Administration/Controllers/OrderController.cs +++ b/src/Presentation/SmartStore.Web/Administration/Controllers/OrderController.cs @@ -15,6 +15,7 @@ using SmartStore.Core.Domain.Tax; using SmartStore.Core.Events; using SmartStore.Core.Html; +using SmartStore.Core.Logging; using SmartStore.Services; using SmartStore.Services.Affiliates; using SmartStore.Services.Catalog; @@ -80,6 +81,7 @@ public partial class OrderController : AdminControllerBase private readonly ICustomerService _customerService; private readonly PluginMediator _pluginMediator; private readonly IAffiliateService _affiliateService; + private readonly ICustomerActivityService _customerActivityService; private readonly CatalogSettings _catalogSettings; private readonly CurrencySettings _currencySettings; @@ -119,7 +121,8 @@ public OrderController(IOrderService orderService, ICustomerService customerService, PluginMediator pluginMediator, IAffiliateService affiliateService, - CatalogSettings catalogSettings, CurrencySettings currencySettings, TaxSettings taxSettings, + ICustomerActivityService customerActivityService, + CatalogSettings catalogSettings, CurrencySettings currencySettings, TaxSettings taxSettings, MeasureSettings measureSettings, PdfSettings pdfSettings, AddressSettings addressSettings, IPdfConverter pdfConverter, ICommonServices services, Lazy pictureService) { @@ -156,6 +159,7 @@ public OrderController(IOrderService orderService, this._customerService = customerService; this._pluginMediator = pluginMediator; this._affiliateService = affiliateService; + this._customerActivityService = customerActivityService; this._catalogSettings = catalogSettings; this._currencySettings = currencySettings; @@ -1230,7 +1234,14 @@ public ActionResult Delete(int id) return RedirectToAction("List"); _orderProcessingService.DeleteOrder(order); - return RedirectToAction("List"); + + var msg = T("ActivityLog.DeleteOrder", order.GetOrderNumber()); + + _customerActivityService.InsertActivity("DeleteOrder", msg); + + NotifySuccess(msg); + + return RedirectToAction("List"); } public ActionResult Print(int orderId, bool pdf = false) From 843894147cc06437abd14f7f36a3246206b9c861 Mon Sep 17 00:00:00 2001 From: Marcus Gesing Date: Mon, 28 Dec 2015 10:41:48 +0100 Subject: [PATCH 199/707] Resolves #840 Activity Log: Have option to exclude search engine activity --- changelog.md | 3 +- .../Logging/ICustomerActivityService.cs | 33 +++++--- .../201512151526290_ImportFramework.cs | 19 ++++- .../Customers/CustomerService.cs | 5 ++ .../Customers/ICustomerService.cs | 18 +++-- .../Logging/CustomerActivityService.cs | 26 ++++-- .../Controllers/ActivityLogController.cs | 33 ++++++-- .../Infrastructure/AutoMapperStartupTask.cs | 6 +- .../Models/Logging/ActivityLogModel.cs | 4 + .../Models/Logging/ActivityLogSearchModel.cs | 11 ++- .../Views/ActivityLog/ListLogs.cshtml | 79 +++++++++++-------- .../Shared/EditorTemplates/Boolean.cshtml | 2 +- 12 files changed, 165 insertions(+), 74 deletions(-) diff --git a/changelog.md b/changelog.md index 9447f0b4da..5c0d0e40fd 100644 --- a/changelog.md +++ b/changelog.md @@ -29,6 +29,7 @@ * #722 System > SEO Names: Implement editing of an UrlRecord * Admin > System > System Info shows used application memory (RAM) * Added option to make VATIN mandatory during customer registration +* #840 Activity log: Have option to exclude search engine activity * #841 Activity log for deleting an order ### Improvements @@ -79,7 +80,7 @@ * #796 Selected specification in product filter mask is displayed with default language (not localized) * #805 Product filter is reset if 'product sorting' or 'view mode' or 'amount of displayed products per page' is changed * Hide link to a topic page if it is limited to stores -* #829 Activity Log: Searching by customer email out of function +* #829 Activity log: Searching by customer email out of function ## SmartStore.NET 2.2.2 diff --git a/src/Libraries/SmartStore.Core/Logging/ICustomerActivityService.cs b/src/Libraries/SmartStore.Core/Logging/ICustomerActivityService.cs index 0ee497d1f8..3ff8526a96 100644 --- a/src/Libraries/SmartStore.Core/Logging/ICustomerActivityService.cs +++ b/src/Libraries/SmartStore.Core/Logging/ICustomerActivityService.cs @@ -74,20 +74,27 @@ ActivityLog InsertActivity(string systemKeyword, /// Activity log void DeleteActivity(ActivityLog activityLog); - /// - /// Gets all activity log items - /// - /// Log item creation from; null to load all customers - /// Log item creation to; null to load all customers - /// Customer identifier; null to load all customers - /// Activity log type identifier - /// Page index - /// Page size + /// + /// Gets all activity log items + /// + /// Log item creation from; null to load all customers + /// Log item creation to; null to load all customers + /// Customer identifier; null to load all customers + /// Activity log type identifier + /// Page index + /// Page size /// Customer email - /// Activity log collection - IPagedList GetAllActivities(DateTime? createdOnFrom, - DateTime? createdOnTo, int? customerId, - int activityLogTypeId, int pageIndex, int pageSize, string email = null); + /// Customer system name + /// Activity log collection + IPagedList GetAllActivities( + DateTime? createdOnFrom, + DateTime? createdOnTo, + int? customerId, + int activityLogTypeId, + int pageIndex, + int pageSize, + string email = null, + bool? customerSystemAccount = null); /// /// Gets an activity log item diff --git a/src/Libraries/SmartStore.Data/Migrations/201512151526290_ImportFramework.cs b/src/Libraries/SmartStore.Data/Migrations/201512151526290_ImportFramework.cs index 85b09659d2..1f9332d58e 100644 --- a/src/Libraries/SmartStore.Data/Migrations/201512151526290_ImportFramework.cs +++ b/src/Libraries/SmartStore.Data/Migrations/201512151526290_ImportFramework.cs @@ -228,10 +228,27 @@ public void MigrateLocaleResources(LocaleResourcesBuilder builder) "Admin.Common.ImportFromExcel.Cancel", "Admin.Common.ImportFromExcel.Cancelled", "Admin.Common.ImportFromExcel.DownloadReport", - "Admin.Common.ImportFromExcel.NoReportAvailable" + "Admin.Common.ImportFromExcel.NoReportAvailable", + "Admin.Configuration.ActivityLog.ActivityLog.Fields.ActivityLogTypeColumn" ); builder.AddOrUpdate("ActivityLog.DeleteOrder", "Deleted order {0}", "Auftrag {0} gelscht"); + + builder.AddOrUpdate("Admin.System.SystemCustomerNames.SearchEngine", "Search Engine", "Suchmaschine"); + builder.AddOrUpdate("Admin.System.SystemCustomerNames.BackgroundTask", "Background Task", "Geplante Aufgabe"); + builder.AddOrUpdate("Admin.System.SystemCustomerNames.PdfConverter", "PDF Converter", "PDF-Konvertierer"); + + builder.AddOrUpdate("Admin.Configuration.ActivityLog.ActivityLog.Fields.CustomerSystemAccount", + "Customer system account", + "Kundensystemkonto", + "Filters results by customer system accounts.", + "Filtert Ergebnisse nach Kundenystemkonten."); + + builder.AddOrUpdate("Admin.Configuration.ActivityLog.ActivityLog.Fields.CustomerEmail", + "Customer Email", + "Kunden-E-Mail", + "Filters results by customer email address.", + "Filtert Ergebnisse nach E-Mail-Adresse der Kunden."); } } } diff --git a/src/Libraries/SmartStore.Services/Customers/CustomerService.cs b/src/Libraries/SmartStore.Services/Customers/CustomerService.cs index 3537ba424f..3e60ff4baa 100644 --- a/src/Libraries/SmartStore.Services/Customers/CustomerService.cs +++ b/src/Libraries/SmartStore.Services/Customers/CustomerService.cs @@ -291,6 +291,11 @@ where customerIds.Contains(c.Id) return sortedCustomers; } + public virtual IList GetSystemAccountCustomers() + { + return _customerRepository.Table.Where(x => x.IsSystemAccount).ToList(); + } + public virtual Customer GetCustomerByGuid(Guid customerGuid) { if (customerGuid == Guid.Empty) diff --git a/src/Libraries/SmartStore.Services/Customers/ICustomerService.cs b/src/Libraries/SmartStore.Services/Customers/ICustomerService.cs index ec4b470074..0f7a914a77 100644 --- a/src/Libraries/SmartStore.Services/Customers/ICustomerService.cs +++ b/src/Libraries/SmartStore.Services/Customers/ICustomerService.cs @@ -88,12 +88,18 @@ IPagedList GetOnlineCustomers(DateTime lastActivityFromUtc, /// Customers IList GetCustomersByIds(int[] customerIds); - /// - /// Gets a customer by GUID - /// - /// Customer GUID - /// A customer - Customer GetCustomerByGuid(Guid customerGuid); + /// + /// Get system account customers + /// + /// System account customers + IList GetSystemAccountCustomers(); + + /// + /// Gets a customer by GUID + /// + /// Customer GUID + /// A customer + Customer GetCustomerByGuid(Guid customerGuid); /// /// Get customer by email diff --git a/src/Libraries/SmartStore.Services/Logging/CustomerActivityService.cs b/src/Libraries/SmartStore.Services/Logging/CustomerActivityService.cs index 08d4a77083..61ba8f21ad 100644 --- a/src/Libraries/SmartStore.Services/Logging/CustomerActivityService.cs +++ b/src/Libraries/SmartStore.Services/Logging/CustomerActivityService.cs @@ -213,19 +213,33 @@ public virtual void DeleteActivity(ActivityLog activityLog) /// Page index /// Page size /// Customer email + /// Customer system name /// Activity log collection - public virtual IPagedList GetAllActivities(DateTime? createdOnFrom, - DateTime? createdOnTo, int? customerId, int activityLogTypeId, - int pageIndex, int pageSize, string email = null) + public virtual IPagedList GetAllActivities( + DateTime? createdOnFrom, + DateTime? createdOnTo, + int? customerId, + int activityLogTypeId, + int pageIndex, + int pageSize, + string email = null, + bool? customerSystemAccount = null) { var query = _activityLogRepository.Table; - if (email.HasValue()) + if (email.HasValue() || customerSystemAccount.HasValue) { + var queryCustomers = _customerRepository.Table; + + if (email.HasValue()) + queryCustomers = queryCustomers.Where(x => x.Email == email); + + if (customerSystemAccount.HasValue) + queryCustomers = queryCustomers.Where(x => x.IsSystemAccount == customerSystemAccount.Value); + query = from al in _activityLogRepository.Table - join c in _customerRepository.Table on al.CustomerId equals c.Id - where c.Email == email + join c in queryCustomers on al.CustomerId equals c.Id select al; } diff --git a/src/Presentation/SmartStore.Web/Administration/Controllers/ActivityLogController.cs b/src/Presentation/SmartStore.Web/Administration/Controllers/ActivityLogController.cs index 479b394285..e6c49b910e 100644 --- a/src/Presentation/SmartStore.Web/Administration/Controllers/ActivityLogController.cs +++ b/src/Presentation/SmartStore.Web/Administration/Controllers/ActivityLogController.cs @@ -5,6 +5,7 @@ using SmartStore.Admin.Models.Logging; using SmartStore.Core.Domain.Common; using SmartStore.Core.Logging; +using SmartStore.Services.Customers; using SmartStore.Services.Helpers; using SmartStore.Services.Security; using SmartStore.Web.Framework.Controllers; @@ -20,7 +21,8 @@ public partial class ActivityLogController : AdminControllerBase #region Fields private readonly ICustomerActivityService _customerActivityService; - private readonly IDateTimeHelper _dateTimeHelper; + private readonly ICustomerService _customerService; + private readonly IDateTimeHelper _dateTimeHelper; private readonly IPermissionService _permissionService; private readonly AdminAreaSettings _adminAreaSettings; @@ -30,11 +32,13 @@ public partial class ActivityLogController : AdminControllerBase public ActivityLogController( ICustomerActivityService customerActivityService, - IDateTimeHelper dateTimeHelper, + ICustomerService customerService, + IDateTimeHelper dateTimeHelper, IPermissionService permissionService, AdminAreaSettings adminAreaSettings) { this._customerActivityService = customerActivityService; + this._customerService = customerService; this._dateTimeHelper = dateTimeHelper; this._permissionService = permissionService; this._adminAreaSettings = adminAreaSettings; @@ -132,17 +136,34 @@ public JsonResult ListActivityLogs(GridCommand command, ActivityLogSearchModel m DateTime? endDateValue = (model.CreatedOnTo == null) ? null : (DateTime?)_dateTimeHelper.ConvertToUtcTime(model.CreatedOnTo.Value, _dateTimeHelper.CurrentTimeZone).AddDays(1); - var activityLog = _customerActivityService.GetAllActivities(startDateValue, endDateValue,null, model.ActivityLogTypeId, - command.Page - 1, command.PageSize, model.CustomerEmail); + var activityLog = _customerActivityService.GetAllActivities(startDateValue, endDateValue, null, model.ActivityLogTypeId, + command.Page - 1, command.PageSize, model.CustomerEmail, model.CustomerSystemAccount); - var gridModel = new GridModel + var systemAccountCustomers = _customerService.GetSystemAccountCustomers(); + + var gridModel = new GridModel { Data = activityLog.Select(x => { var m = x.ToModel(); + var systemCustomer = systemAccountCustomers.FirstOrDefault(y => y.Id == x.CustomerId); + m.CreatedOn = _dateTimeHelper.ConvertToUserTime(x.CreatedOnUtc, DateTimeKind.Utc); + m.IsSystemAccount = (systemCustomer != null); + + if (systemCustomer != null) + { + if (systemCustomer.IsSearchEngineAccount()) + m.SystemAccountName = T("Admin.System.SystemCustomerNames.SearchEngine"); + else if (systemCustomer.IsBackgroundTaskAccount()) + m.SystemAccountName = T("Admin.System.SystemCustomerNames.BackgroundTask"); + else if (systemCustomer.IsPdfConverter()) + m.SystemAccountName = T("Admin.System.SystemCustomerNames.PdfConverter"); + else + m.SystemAccountName = "".NaIfEmpty(); + } + return m; - }), Total = activityLog.TotalCount }; diff --git a/src/Presentation/SmartStore.Web/Administration/Infrastructure/AutoMapperStartupTask.cs b/src/Presentation/SmartStore.Web/Administration/Infrastructure/AutoMapperStartupTask.cs index be8da41f25..37c9efe5ed 100644 --- a/src/Presentation/SmartStore.Web/Administration/Infrastructure/AutoMapperStartupTask.cs +++ b/src/Presentation/SmartStore.Web/Administration/Infrastructure/AutoMapperStartupTask.cs @@ -315,8 +315,10 @@ public void Execute() Mapper.CreateMap() .ForMember(dest => dest.ActivityLogTypeName, mo => mo.MapFrom(src => src.ActivityLogType.Name)) .ForMember(dest => dest.CustomerEmail, mo => mo.MapFrom(src => src.Customer.Email)) - .ForMember(dest => dest.CreatedOn, mo => mo.Ignore()); - //currencies + .ForMember(dest => dest.CreatedOn, mo => mo.Ignore()) + .ForMember(dest => dest.IsSystemAccount, mo => mo.Ignore()) + .ForMember(dest => dest.SystemAccountName, mo => mo.Ignore()); + //currencies Mapper.CreateMap() .ForMember(dest => dest.CreatedOn, mo => mo.Ignore()) .ForMember(dest => dest.IsPrimaryExchangeRateCurrency, mo => mo.Ignore()) diff --git a/src/Presentation/SmartStore.Web/Administration/Models/Logging/ActivityLogModel.cs b/src/Presentation/SmartStore.Web/Administration/Models/Logging/ActivityLogModel.cs index f686e115bb..7b5b9a57ac 100644 --- a/src/Presentation/SmartStore.Web/Administration/Models/Logging/ActivityLogModel.cs +++ b/src/Presentation/SmartStore.Web/Administration/Models/Logging/ActivityLogModel.cs @@ -20,5 +20,9 @@ public partial class ActivityLogModel : EntityModelBase [SmartResourceDisplayName("Admin.Configuration.ActivityLog.ActivityLog.Fields.CreatedOn")] public DateTime CreatedOn { get; set; } + + [SmartResourceDisplayName("Admin.Customers.Customers.Fields.IsSystemAccount")] + public bool IsSystemAccount { get; set; } + public string SystemAccountName { get; set; } } } diff --git a/src/Presentation/SmartStore.Web/Administration/Models/Logging/ActivityLogSearchModel.cs b/src/Presentation/SmartStore.Web/Administration/Models/Logging/ActivityLogSearchModel.cs index 210b7d644a..9e17c5bbcf 100644 --- a/src/Presentation/SmartStore.Web/Administration/Models/Logging/ActivityLogSearchModel.cs +++ b/src/Presentation/SmartStore.Web/Administration/Models/Logging/ActivityLogSearchModel.cs @@ -10,6 +10,10 @@ public class ActivityLogSearchModel : ModelBase { public int GridPageSize { get; set; } + [SmartResourceDisplayName("Admin.Configuration.ActivityLog.ActivityLog.Fields.ActivityLogType")] + public int ActivityLogTypeId { get; set; } + public IList ActivityLogType { get; set; } + [SmartResourceDisplayName("Admin.Configuration.ActivityLog.ActivityLog.Fields.CreatedOnFrom")] public DateTime? CreatedOnFrom { get; set; } @@ -20,8 +24,7 @@ public class ActivityLogSearchModel : ModelBase [AllowHtml] public string CustomerEmail { get; set; } - [SmartResourceDisplayName("Admin.Configuration.ActivityLog.ActivityLog.Fields.ActivityLogType")] - public int ActivityLogTypeId { get; set; } - public IList ActivityLogType { get; set; } - } + [SmartResourceDisplayName("Admin.Configuration.ActivityLog.ActivityLog.Fields.CustomerSystemAccount")] + public bool? CustomerSystemAccount { get; set; } + } } \ No newline at end of file diff --git a/src/Presentation/SmartStore.Web/Administration/Views/ActivityLog/ListLogs.cshtml b/src/Presentation/SmartStore.Web/Administration/Views/ActivityLog/ListLogs.cshtml index bf1eb8813b..dbd3b7329e 100644 --- a/src/Presentation/SmartStore.Web/Administration/Views/ActivityLog/ListLogs.cshtml +++ b/src/Presentation/SmartStore.Web/Administration/Views/ActivityLog/ListLogs.cshtml @@ -23,22 +23,30 @@

    @T("Admin.DataExchange.ColumnMapping.ImportField")@T("Admin.DataExchange.ColumnMapping.ImportFieldIndex")@T("Admin.DataExchange.ColumnMapping.ImportField")@T("Common.Language") @T("Admin.DataExchange.ColumnMapping.EntityProperty") @T("Admin.DataExchange.ColumnMapping.DefaultValue")
    - @mapping.ColumnWithoutIndex + @if (mapping.ColumnLocalized.HasValue()) + { +
    @mapping.ColumnLocalized
    + } +
    @mapping.Column
    - @mapping.ColumnIndex + @if (mapping.ColumnIndex.HasValue()) + { + if (mapping.LanguageDescription.HasValue()) + { + if (mapping.FlagImageFileName.HasValue()) + { + Icon + } + @mapping.LanguageDescription + } + else + { + @T("Common.Unknown") + } + } - @foreach (var prop in Model.AvailableEntityProperties) { - var select = ((mapping.EntityProperty.HasValue() && prop.Value.IsCaseInsensitiveEqual(mapping.EntityProperty)) || - (!mapping.EntityProperty.HasValue() && prop.Value.IsCaseInsensitiveEqual(mapping.Column))); + var select = !mapping.IsNilProperty && + ((mapping.Property.HasValue() && prop.Value.IsCaseInsensitiveEqual(mapping.Property)) || + (!mapping.Property.HasValue() && prop.Value.IsCaseInsensitiveEqual(mapping.ColumnWithoutIndex))); }
    - @Html.ValidationMessage("ColumnMapping.EntityProperty." + mapping.Index.ToString()) + @Html.ValidationMessage("ColumnMapping.Property." + mapping.Index.ToString())
    - +
      - @Html.Partial("_ImportFileList", Model) + @foreach (var fileName in Model.ExistingFileNames) + { +

    + @Html.IconForFileExtension(Path.GetExtension(fileName), false) + @fileName + + +

    + }
    - - - - - - - - + + + + + + + + + + + + - - - - + + + + - - - - + + + + + + + + + + + + + + + + + + + + + + +
    - @Html.SmartLabelFor(model => model.CreatedOnFrom) - - @Html.EditorFor(model => model.CreatedOnFrom) -
    - @Html.SmartLabelFor(model => model.CreatedOnTo) - - @Html.EditorFor(model => model.CreatedOnTo) -
    + @Html.SmartLabelFor(model => model.CreatedOnFrom) + + @Html.EditorFor(model => model.CreatedOnFrom) +
    + @Html.SmartLabelFor(model => model.CreatedOnTo) + + @Html.EditorFor(model => model.CreatedOnTo) +
    + @Html.SmartLabelFor(model => model.ActivityLogTypeId) + + @Html.DropDownListFor(ModelBase => ModelBase.ActivityLogTypeId, Model.ActivityLogType, T("Common.Unspecified")) +
    @Html.SmartLabelFor(model => model.CustomerEmail) @@ -47,14 +55,14 @@ @Html.EditorFor(model => model.CustomerEmail)
    - @Html.SmartLabelFor(model => model.ActivityLogTypeId) - - @Html.DropDownListFor(ModelBase => ModelBase.ActivityLogTypeId, Model.ActivityLogType, T("Common.Unspecified")) -
    + @Html.SmartLabelFor(model => model.CustomerSystemAccount) + + @Html.EditorFor(model => Model.CustomerSystemAccount) +
      @@ -89,12 +97,14 @@ .HtmlAttributes(new { style = "text-align:center" }) .HeaderHtmlAttributes(new { style = "text-align:center" }); columns.Bound(x => x.ActivityLogTypeName); + columns.Bound(x => x.Comment); columns.Bound(x => x.CustomerId) - .Template(x => Html.ActionLink(x.CustomerEmail, "Edit", "Customer", new { id = x.CustomerId }, new { })) .ClientTemplate("\"><#= CustomerEmail #>"); - columns.Bound(x => x.Comment); + columns.Bound(x => x.IsSystemAccount) + .ClientTemplate(" <#= SystemAccountName #>") + .Width(220); columns.Bound(x => x.CreatedOn) - .Width(180); + .Width(200); }) .DataBinding(dataBinding => { @@ -146,20 +156,20 @@ $('.checkboxGroups').attr('checked', $(this).is(':checked')).change(); }); - //wire up checkboxes. + //wire up checkboxes. $(document).on('change', '#activityLog-grid input[type=checkbox][id!=mastercheckbox]', function (e) { var $check = $(this); if ($check.is(":checked") == true) { var checked = jQuery.inArray($check.val(), selectedIds); if (checked == -1) { - //add id to selectedIds. + //add id to selectedIds. selectedIds.push($check.val()); } } else { var checked = jQuery.inArray($check.val(), selectedIds); if (checked > -1) { - //remove id from selectedIds. + //remove id from selectedIds. selectedIds = $.grep(selectedIds, function (item, index) { return item != $check.val(); }); @@ -179,11 +189,12 @@ }); function onDataBinding(e) { - var searchModel = { + var searchModel = { + ActivityLogTypeId: $('#ActivityLogTypeId').val(), CreatedOnFrom: $('#@Html.FieldIdFor(model => model.CreatedOnFrom)').val(), CreatedOnTo: $('#@Html.FieldIdFor(model => model.CreatedOnTo)').val(), - CustomerEmail: $('#@Html.FieldIdFor(model => model.CustomerEmail)').val(), - ActivityLogTypeId: $('#ActivityLogTypeId').val() + CustomerEmail: $('#@Html.FieldIdFor(model => model.CustomerEmail)').val(), + CustomerSystemAccount: $('#@Html.FieldIdFor(model => model.CustomerSystemAccount)').val() }; e.data = searchModel; } @@ -192,7 +203,7 @@ $('#activityLog-grid input[type=checkbox][id!=mastercheckbox]').each(function () { var currentId = $(this).val(); var checked = jQuery.inArray(currentId, selectedIds); - //set checked based on if current checkbox's value is in selectedIds. + //set checked based on if current checkbox's value is in selectedIds. $(this).attr('checked', checked > -1); }); diff --git a/src/Presentation/SmartStore.Web/Views/Shared/EditorTemplates/Boolean.cshtml b/src/Presentation/SmartStore.Web/Views/Shared/EditorTemplates/Boolean.cshtml index 58f0a1f824..d67441694a 100644 --- a/src/Presentation/SmartStore.Web/Views/Shared/EditorTemplates/Boolean.cshtml +++ b/src/Presentation/SmartStore.Web/Views/Shared/EditorTemplates/Boolean.cshtml @@ -18,7 +18,7 @@ get { return new List { - new SelectListItem { Text = T("Common.Undefined").ToString(), Value = String.Empty, Selected = !Value.HasValue }, + new SelectListItem { Text = T("Common.Unspecified").ToString(), Value = String.Empty, Selected = !Value.HasValue }, new SelectListItem { Text = T("Common.Yes").ToString(), Value = "true", Selected = Value.HasValue && Value.Value }, new SelectListItem { Text = T("Common.No").ToString(), Value = "false", Selected = Value.HasValue && !Value.Value }, }; From 1d520969f53c0133f0b2d5fc4dbd19275484d031 Mon Sep 17 00:00:00 2001 From: Marcus Gesing Date: Mon, 28 Dec 2015 12:45:36 +0100 Subject: [PATCH 200/707] Minor change --- .../DataExchange/ExportExtensions.cs | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/src/Libraries/SmartStore.Services/DataExchange/ExportExtensions.cs b/src/Libraries/SmartStore.Services/DataExchange/ExportExtensions.cs index a0c9f14dcc..3d65d673c8 100644 --- a/src/Libraries/SmartStore.Services/DataExchange/ExportExtensions.cs +++ b/src/Libraries/SmartStore.Services/DataExchange/ExportExtensions.cs @@ -128,22 +128,5 @@ public static string ResolveFileNamePattern(this ExportProfile profile, Store st return result; } - - /// - /// Join values into a string that can be used for exporting - /// - /// Type - /// Enumerable of values to join - /// Joined values - public static string JoinForExport(this IEnumerable values) - { - if (values == null) - return ""; - - if (typeof(T) == typeof(string)) - return string.Join("|", values); // because file paths cannot contain pipes - - return string.Join(",", values); - } } } From b193504387fc2ab4422bb7174632b21530519a68 Mon Sep 17 00:00:00 2001 From: Marcus Gesing Date: Mon, 28 Dec 2015 14:59:08 +0100 Subject: [PATCH 201/707] Added exception handling when executing child action to reach a plugin configuration page --- .../Migrations/201512151526290_ImportFramework.cs | 4 ++++ .../Views/Plugin/ConfigurePlugin.cshtml | 13 ++++++++++++- 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/src/Libraries/SmartStore.Data/Migrations/201512151526290_ImportFramework.cs b/src/Libraries/SmartStore.Data/Migrations/201512151526290_ImportFramework.cs index 1f9332d58e..ce556e3c97 100644 --- a/src/Libraries/SmartStore.Data/Migrations/201512151526290_ImportFramework.cs +++ b/src/Libraries/SmartStore.Data/Migrations/201512151526290_ImportFramework.cs @@ -249,6 +249,10 @@ public void MigrateLocaleResources(LocaleResourcesBuilder builder) "Kunden-E-Mail", "Filters results by customer email address.", "Filtert Ergebnisse nach E-Mail-Adresse der Kunden."); + + builder.AddOrUpdate("Admin.Configuration.Plugins.UnknownError", + "An unknown error occurred in the configuration page of the plugin. Please refer to the following message for details.", + "Beim Aufruf der Konfigurationsseite des Plugins ist ein unbekannter Fehler aufgetreten. Details entnehmen Sie bitte der folgenden Meldung."); } } } diff --git a/src/Presentation/SmartStore.Web/Administration/Views/Plugin/ConfigurePlugin.cshtml b/src/Presentation/SmartStore.Web/Administration/Views/Plugin/ConfigurePlugin.cshtml index 2122382080..74f552e016 100644 --- a/src/Presentation/SmartStore.Web/Administration/Views/Plugin/ConfigurePlugin.cshtml +++ b/src/Presentation/SmartStore.Web/Administration/Views/Plugin/ConfigurePlugin.cshtml @@ -20,7 +20,18 @@ @if (Model.ConfigurationRoute != null && Model.ConfigurationRoute.Action.HasValue()) { - @Html.Action(Model.ConfigurationRoute.Action, Model.ConfigurationRoute.Controller, Model.ConfigurationRoute.RouteValues); + try + { + @Html.Action(Model.ConfigurationRoute.Action, Model.ConfigurationRoute.Controller, Model.ConfigurationRoute.RouteValues); + } + catch (Exception exception) + { +
    + @T("Admin.Configuration.Plugins.UnknownError") +
    + +
    @exception.ToString()
    + } } else { From 045f6cada27980b29fe7e5b3a1ae5a66bd1f6a7b Mon Sep 17 00:00:00 2001 From: Marcus Gesing Date: Mon, 28 Dec 2015 16:58:48 +0100 Subject: [PATCH 202/707] Changed a string resource --- .../Migrations/201512151526290_ImportFramework.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Libraries/SmartStore.Data/Migrations/201512151526290_ImportFramework.cs b/src/Libraries/SmartStore.Data/Migrations/201512151526290_ImportFramework.cs index ce556e3c97..fc73822866 100644 --- a/src/Libraries/SmartStore.Data/Migrations/201512151526290_ImportFramework.cs +++ b/src/Libraries/SmartStore.Data/Migrations/201512151526290_ImportFramework.cs @@ -251,8 +251,8 @@ public void MigrateLocaleResources(LocaleResourcesBuilder builder) "Filtert Ergebnisse nach E-Mail-Adresse der Kunden."); builder.AddOrUpdate("Admin.Configuration.Plugins.UnknownError", - "An unknown error occurred in the configuration page of the plugin. Please refer to the following message for details.", - "Beim Aufruf der Konfigurationsseite des Plugins ist ein unbekannter Fehler aufgetreten. Details entnehmen Sie bitte der folgenden Meldung."); + "An unknown error occurred when calling a plugin. Please refer to the following message for details.", + "Beim Aufruf eines Plugins ist ein unbekannter Fehler aufgetreten. Details entnehmen Sie bitte der folgenden Meldung."); } } } From 65de4b50f28a1e347265158206bf857cd132342a Mon Sep 17 00:00:00 2001 From: Marcus Gesing Date: Mon, 28 Dec 2015 21:08:58 +0100 Subject: [PATCH 203/707] Some more changed string resources --- .../Migrations/201512151526290_ImportFramework.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Libraries/SmartStore.Data/Migrations/201512151526290_ImportFramework.cs b/src/Libraries/SmartStore.Data/Migrations/201512151526290_ImportFramework.cs index fc73822866..df084212a5 100644 --- a/src/Libraries/SmartStore.Data/Migrations/201512151526290_ImportFramework.cs +++ b/src/Libraries/SmartStore.Data/Migrations/201512151526290_ImportFramework.cs @@ -148,7 +148,7 @@ public void MigrateLocaleResources(LocaleResourcesBuilder builder) builder.AddOrUpdate("Admin.DataExchange.Csv.Quote", "Quote character", "Anfhrungszeichen", - "Spacifies the quotation character.", + "Specifies the quotation character.", "Legt das zu verwendende Anfhrungszeichen fest."); builder.AddOrUpdate("Admin.DataExchange.Csv.Escape", @@ -197,7 +197,7 @@ public void MigrateLocaleResources(LocaleResourcesBuilder builder) builder.AddOrUpdate("Admin.Promotions.NewsLetterSubscriptions.Fields.NewsLetterSubscriptionGuid", "Subscription GUID", "Abonnement GUID"); builder.AddOrUpdate("Admin.DataExchange.ColumnMapping.Note", - "For each field of the import file you can optionally set whether and to which entity property the data is to be imported. Specifying a default value is also possible, which is applied when the import field is empty. Through Reset all made assignments are reset to their original values.", + "For each field of the import file you can optionally set whether and to which entity property the data is to be imported. It is also possible to define a default value which is applied when the import field is empty. Through Clear all made assignments are reset to their original values.", "Sie knnen optional fr jedes Feld der Importdatei festlegen, ob und nach welcher Entittseigenschaft dessen Daten importiert werden sollen. Zudem ist die Angabe eines Standardwertes mglich, der angewendet wird, wenn das Importfeld leer ist. ber Zurcksetzen werden alle gettigten Zuordnungen auf ihre Ursprungswerte zurckgesetzt."); builder.AddOrUpdate("Admin.DataExchange.ColumnMapping.ImportField", "Import Field", "Importfeld"); From 177bd689c9cca528316eabc7935c8fb83c93cb0a Mon Sep 17 00:00:00 2001 From: Murat Cakir Date: Tue, 29 Dec 2015 17:56:20 +0100 Subject: [PATCH 204/707] EnumerableConverter can also convert from intrinsic numeric types --- .../TypeConversion/EnumerableConverter.cs | 11 ++++++++++- src/Tests/SmartStore.Core.Tests/ConversionTests.cs | 5 +++++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/src/Libraries/SmartStore.Core/ComponentModel/TypeConversion/EnumerableConverter.cs b/src/Libraries/SmartStore.Core/ComponentModel/TypeConversion/EnumerableConverter.cs index b265dbf8aa..b7120d9ede 100644 --- a/src/Libraries/SmartStore.Core/ComponentModel/TypeConversion/EnumerableConverter.cs +++ b/src/Libraries/SmartStore.Core/ComponentModel/TypeConversion/EnumerableConverter.cs @@ -78,7 +78,7 @@ private static Func, object> CreateSequenceActivator(Type sequenc public override bool CanConvertFrom(Type type) { - return type == typeof(string); + return type == typeof(string) || typeof(IConvertible).IsAssignableFrom(type); } public override bool CanConvertTo(Type type) @@ -105,6 +105,15 @@ public override object ConvertFrom(CultureInfo culture, object value) return _activator(result); } + if (value is IConvertible) + { + var result2 = (new object[] { value }) + .Select(x => Convert.ChangeType(value, typeof(T))) + .Cast(); + + return _activator(result2); + } + return base.ConvertFrom(culture, value); } diff --git a/src/Tests/SmartStore.Core.Tests/ConversionTests.cs b/src/Tests/SmartStore.Core.Tests/ConversionTests.cs index bd4dddc45c..f9a3e61f96 100644 --- a/src/Tests/SmartStore.Core.Tests/ConversionTests.cs +++ b/src/Tests/SmartStore.Core.Tests/ConversionTests.cs @@ -171,6 +171,11 @@ public void CanConvertEnumerables() var list3 = new List(new int[] { 1,2,3,4,5 }); var str = list3.Convert(); Assert.AreEqual("1,2,3,4,5", str); + + var list4 = ((double)5).Convert>(); + list4.ShouldBe>(); + Assert.AreEqual(1, list4.Count); + Assert.AreEqual(5, list4[0]); } [Test] From fc059d573c303a3429749f181437c28224ad917e Mon Sep 17 00:00:00 2001 From: Marcus Gesing Date: Wed, 30 Dec 2015 11:21:38 +0100 Subject: [PATCH 205/707] Minor improvement --- .../ComponentModel/TypeConversion/EnumerableConverter.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Libraries/SmartStore.Core/ComponentModel/TypeConversion/EnumerableConverter.cs b/src/Libraries/SmartStore.Core/ComponentModel/TypeConversion/EnumerableConverter.cs index b7120d9ede..1980693205 100644 --- a/src/Libraries/SmartStore.Core/ComponentModel/TypeConversion/EnumerableConverter.cs +++ b/src/Libraries/SmartStore.Core/ComponentModel/TypeConversion/EnumerableConverter.cs @@ -146,7 +146,7 @@ protected virtual string[] GetStringArray(string input) { if (!String.IsNullOrEmpty(input)) { - var splitChar = ','; + var splitChar = '|'; if (input.IndexOf(splitChar) < 0) { @@ -154,9 +154,9 @@ protected virtual string[] GetStringArray(string input) { splitChar = ';'; } - else if (input.IndexOf('|') > -1) + else if (input.IndexOf(',') > -1) { - splitChar = '|'; + splitChar = ','; } } From dcdc59130dc7954f9865253b949d7dff59ab0f60 Mon Sep 17 00:00:00 2001 From: Marcus Gesing Date: Mon, 4 Jan 2016 11:20:56 +0100 Subject: [PATCH 206/707] More settings to control creation of SEO names --- changelog.md | 1 + .../SmartStore.Core/Domain/Seo/SeoSettings.cs | 62 ++++++-- .../SmartStore.Core/Utilities/SeoHelper.cs | 142 +++++++++--------- .../201508121735397_AddSyncMapping.cs | 2 +- .../201512151526290_ImportFramework.cs | 25 +++ .../SmartStore.Services/Seo/SeoExtensions.cs | 3 +- .../Controllers/SettingController.cs | 29 +++- .../Settings/GeneralCommonSettingsModel.cs | 11 +- .../Views/Setting/GeneralCommon.cshtml | 77 ++++++++-- .../Seo/SeoExtensionsTests.cs | 32 ++-- 10 files changed, 276 insertions(+), 108 deletions(-) diff --git a/changelog.md b/changelog.md index 5c0d0e40fd..ac7dd3701f 100644 --- a/changelog.md +++ b/changelog.md @@ -31,6 +31,7 @@ * Added option to make VATIN mandatory during customer registration * #840 Activity log: Have option to exclude search engine activity * #841 Activity log for deleting an order +* More settings to control creation of SEO names ### Improvements * (Perf) Implemented static caches for URL aliases and localized properties. Increases app startup and request speed by up to 30%. diff --git a/src/Libraries/SmartStore.Core/Domain/Seo/SeoSettings.cs b/src/Libraries/SmartStore.Core/Domain/Seo/SeoSettings.cs index f6ec324336..aa0b352df3 100644 --- a/src/Libraries/SmartStore.Core/Domain/Seo/SeoSettings.cs +++ b/src/Libraries/SmartStore.Core/Domain/Seo/SeoSettings.cs @@ -1,25 +1,68 @@ - +using System; using System.Collections.Generic; using SmartStore.Core.Configuration; namespace SmartStore.Core.Domain.Seo { - public class SeoSettings : ISettings + public class SeoSettings : ISettings { public SeoSettings() { PageTitleSeparator = ". "; PageTitleSeoAdjustment = PageTitleSeoAdjustment.PagenameAfterStorename; - DefaultTitle = "Your store"; + DefaultTitle = "Shop"; DefaultMetaKeywords = ""; DefaultMetaDescription = ""; - AllowUnicodeCharsInUrls = true; - CanonicalHostNameRule = Seo.CanonicalHostNameRule.NoRule; - ReservedUrlRecordSlugs = new List { "admin", "install", "recentlyviewedproducts", "newproducts", "compareproducts", "clearcomparelist", "setproductreviewhelpfulness", "login", "register", "logout", "cart", "wishlist", "emailwishlist", "checkout", "contactus", "passwordrecovery", "subscribenewsletter", "blog", "boards", "inboxupdate", "sentupdate", "news", "sitemap", "sitemapseo", "search", "config", "api", "odata" }; - ExtraRobotsDisallows = new List { "/blog/tag/", "/blog/month/", "/producttags/" }; + AllowUnicodeCharsInUrls = false; + CanonicalHostNameRule = CanonicalHostNameRule.NoRule; LoadAllUrlAliasesOnStartup = true; + + ExtraRobotsDisallows = new List { "/blog/tag/", "/blog/month/", "/producttags/" }; + + ReservedUrlRecordSlugs = new List + { + "admin", + "install", + "recentlyviewedproducts", + "newproducts", + "compareproducts", + "clearcomparelist", + "setproductreviewhelpfulness", + "login", + "register", + "logout", + "cart", + "wishlist", + "emailwishlist", + "checkout", + "contactus", + "passwordrecovery", + "subscribenewsletter", + "blog", + "boards", + "inboxupdate", + "sentupdate", + "news", + "sitemap", + "sitemapseo", + "search", + "config", + "api", + "odata" + }; + + SeoNameCharConversion = string.Join(Environment.NewLine, new List + { + "ä;ae", + "ö;oe", + "ü;ue", + "Ä;Ae", + "Ö;Oe", + "Ü;Ue", + "ß;ss" + }); } - + public string PageTitleSeparator { get; set; } public PageTitleSeoAdjustment PageTitleSeoAdjustment { get; set; } public string DefaultTitle { get; set; } @@ -28,8 +71,9 @@ public SeoSettings() public bool ConvertNonWesternChars { get; set; } public bool AllowUnicodeCharsInUrls { get; set; } + public string SeoNameCharConversion { get; set; } - public bool CanonicalUrlsEnabled { get; set; } + public bool CanonicalUrlsEnabled { get; set; } public CanonicalHostNameRule CanonicalHostNameRule { get; set; } /// diff --git a/src/Libraries/SmartStore.Core/Utilities/SeoHelper.cs b/src/Libraries/SmartStore.Core/Utilities/SeoHelper.cs index f76b247354..3dec92a6d4 100644 --- a/src/Libraries/SmartStore.Core/Utilities/SeoHelper.cs +++ b/src/Libraries/SmartStore.Core/Utilities/SeoHelper.cs @@ -1,107 +1,109 @@ using System; using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; -using System.Linq; using System.Text; namespace SmartStore.Utilities { - + public static class SeoHelper { + private static readonly string _okChars = "abcdefghijklmnopqrstuvwxyz1234567890 _-/"; + private static readonly object _lock = new object(); private static Dictionary _seoCharacterTable; - private static readonly object s_lock = new object(); + private static Dictionary _userSeoCharacterTable; /// - /// Get SE name + /// Get SEO friendly string /// - /// Name + /// String to be converted /// A value indicating whether non western chars should be converted /// A value indicating whether Unicode chars are allowed - /// Result + /// Raw data of semicolon separated char conversions + /// SEO friendly string [SuppressMessage("ReSharper", "PossibleNullReferenceException")] - public static string GetSeName(string name, bool convertNonWesternChars, bool allowUnicodeCharsInUrls) + public static string GetSeName(string name, bool convertNonWesternChars, bool allowUnicodeCharsInUrls, string charConversions = null) { if (String.IsNullOrEmpty(name)) return name; - string okChars = "abcdefghijklmnopqrstuvwxyz1234567890 _-/"; + name = name.Trim().ToLowerInvariant(); - if (convertNonWesternChars) + if (charConversions != null && _userSeoCharacterTable == null) { - if (_seoCharacterTable == null) - InitializeSeoCharacterTable(); + InitializeUserSeoCharacterTable(charConversions); + } + + if (convertNonWesternChars && _seoCharacterTable == null) + { + InitializeSeoCharacterTable(); } var sb = new StringBuilder(); foreach (char c in name) { - string c2 = c.ToString(); - if (convertNonWesternChars) + var c2 = c.ToString(); + + if (charConversions != null && _userSeoCharacterTable != null && _userSeoCharacterTable.ContainsKey(c2)) { - if (_seoCharacterTable.ContainsKey(c2)) - c2 = _seoCharacterTable[c2]; + sb.Append(_userSeoCharacterTable[c2]); + continue; } - switch (c2) + if (convertNonWesternChars && _seoCharacterTable.ContainsKey(c2)) { - case "ä": - sb.Append("ae"); - break; - case "ö": - sb.Append("oe"); - break; - case "ü": - sb.Append("ue"); - break; - case "ß": - sb.Append("ss"); - break; - case "Ä": - sb.Append("AE"); - break; - case "Ö": - sb.Append("OE"); - break; - case "Ü": - sb.Append("UE"); - break; + c2 = _seoCharacterTable[c2]; + } - case "é": - case "è": - case "ê": - sb.Append('e'); - break; - case "á": - case "à": - case "â": - sb.Append('a'); - break; - case "ú": - case "ù": - case "û": - sb.Append('u'); - break; - case "ó": - case "ò": - case "ô": - sb.Append('o'); - break; + if (_okChars.Contains(c2) || (allowUnicodeCharsInUrls && char.IsLetterOrDigit(c))) + { + sb.Append(c2); + } + } + + sb.Replace(" ", "-"); - default: - if (okChars.Contains(c2)) - sb.Append(c2); - break; - } // switch + var result = sb.ToString(); + + while (result.Contains("--")) + { + result = result.Replace("--", "-"); } - string name2 = sb.ToString(); - name2 = name2.Replace(" ", "-"); - while (name2.Contains("--")) - name2 = name2.Replace("--", "-"); - while (name2.Contains("__")) - name2 = name2.Replace("__", "_"); + while (result.Contains("__")) + { + result = result.Replace("__", "_"); + } + return result.Trim('/'); + } + + public static void ResetUserSeoCharacterTable() + { + if (_userSeoCharacterTable != null) + { + _userSeoCharacterTable.Clear(); + _userSeoCharacterTable = null; + } + } - return name2.Trim('/'); + private static void InitializeUserSeoCharacterTable(string charConversions) + { + lock (_lock) + { + if (_userSeoCharacterTable == null) + { + _userSeoCharacterTable = new Dictionary(); + + string strLeft, strRight; + + foreach (var conversion in charConversions.SplitSafe(Environment.NewLine)) + { + if (conversion.SplitToPair(out strLeft, out strRight, ";") && strLeft.HasValue() && !_userSeoCharacterTable.ContainsKey(strLeft)) + { + _userSeoCharacterTable.Add(strLeft, strRight); + } + } + } + } } /// @@ -115,7 +117,7 @@ public static string GetSeName(string name, bool convertNonWesternChars, bool al /// private static void InitializeSeoCharacterTable() { - lock (s_lock) + lock (_lock) { if (_seoCharacterTable == null) { diff --git a/src/Libraries/SmartStore.Data/Migrations/201508121735397_AddSyncMapping.cs b/src/Libraries/SmartStore.Data/Migrations/201508121735397_AddSyncMapping.cs index b3499775ea..ce062a376e 100644 --- a/src/Libraries/SmartStore.Data/Migrations/201508121735397_AddSyncMapping.cs +++ b/src/Libraries/SmartStore.Data/Migrations/201508121735397_AddSyncMapping.cs @@ -96,7 +96,7 @@ public void MigrateLocaleResources(LocaleResourcesBuilder builder) builder.AddOrUpdate("Admin.Configuration.Settings.GeneralCommon.ExtraRobotsDisallows", "Extra Disallows for robots.txt", "Extra Disallows fr robots.txt", - "Enter additional paths that should be included as Disallow entries in your robots.txt. Each entry has to entered in a new line.", + "Enter additional paths that should be included as Disallow entries in your robots.txt. Each entry has to be entered in a new line.", "Geben Sie hier zustzliche Pfade an, die als Disallow-Eintrge zur robots.txt hinzugefgt werden sollen. Jeder Eintrag muss in einer neuen Zeile erfolgen."); builder.AddOrUpdate("Admin.Configuration.Settings.Catalog.DefaultSortOrderMode", diff --git a/src/Libraries/SmartStore.Data/Migrations/201512151526290_ImportFramework.cs b/src/Libraries/SmartStore.Data/Migrations/201512151526290_ImportFramework.cs index df084212a5..2073f9aecc 100644 --- a/src/Libraries/SmartStore.Data/Migrations/201512151526290_ImportFramework.cs +++ b/src/Libraries/SmartStore.Data/Migrations/201512151526290_ImportFramework.cs @@ -3,6 +3,7 @@ namespace SmartStore.Data.Migrations using System.Data.Entity.Migrations; using Core.Domain.Customers; using Core.Domain.Security; + using Core.Domain.Seo; using Setup; public partial class ImportFramework : DbMigration, ILocaleResourcesProvider, IDataSeeder @@ -58,6 +59,12 @@ public void Seed(SmartObjectContext context) }, new string[] { SystemCustomerRoleNames.Administrators }); activityLogMigrator.AddActivityLogType("DeleteOrder", "Delete order", "Auftrag gelscht"); + + context.MigrateSettings(x => + { + var seoSettings = new SeoSettings(); + x.Add("seosettings.seonamecharconversion", seoSettings.SeoNameCharConversion); + }); } public void MigrateLocaleResources(LocaleResourcesBuilder builder) @@ -253,6 +260,24 @@ public void MigrateLocaleResources(LocaleResourcesBuilder builder) builder.AddOrUpdate("Admin.Configuration.Plugins.UnknownError", "An unknown error occurred when calling a plugin. Please refer to the following message for details.", "Beim Aufruf eines Plugins ist ein unbekannter Fehler aufgetreten. Details entnehmen Sie bitte der folgenden Meldung."); + + builder.AddOrUpdate("Admin.Configuration.Settings.GeneralCommon.AllowUnicodeCharsInUrls", + "Allow unicode characters", + "Unicode-Zeichen erlauben", + "Check whether SEO names can contain letters that are classified as unicode characters.", + "Legt fest, ob als Unicode-Zeichen eingestufte Buchstaben in SEO relevanten Namen erlaubt sind."); + + builder.AddOrUpdate("Admin.Configuration.Settings.GeneralCommon.SeoNameCharConversion", + "Characters to be converted", + "Zu konvertierende Zeichen", + "Allows an individual conversion of characters for SEO name creation. Enter the old and the new character separated by a semicolon, e.g. ;ae. Each entry has to be entered in a new line.", + "Ermglicht das individuelle Konvertieren von Zeichen bei der Erstellung SEO Namen. Geben Sie hier durch Semikolon getrennt das alte und das neue Zeichen ein, z.B. ;ae. Jeder Eintrag muss in einer neuen Zeile erfolgen."); + + builder.AddOrUpdate("Admin.Configuration.Settings.GeneralCommon.TestSeoNameCreation", + "Check string", + "Zeichenkette prfen", + "Enter any string to check the SEO name creation. Changed settings must be saved before.", + "Geben Sie eine beliebige Zeichenkette ein, um daraus den SEO Namen zu erstellen. Genderte Einstellungen mssen zuvor gespeichert werden."); } } } diff --git a/src/Libraries/SmartStore.Services/Seo/SeoExtensions.cs b/src/Libraries/SmartStore.Services/Seo/SeoExtensions.cs index e6cc541ac4..67337bbb66 100644 --- a/src/Libraries/SmartStore.Services/Seo/SeoExtensions.cs +++ b/src/Libraries/SmartStore.Services/Seo/SeoExtensions.cs @@ -304,7 +304,8 @@ public static string GetSeName(string name, SeoSettings seoSettings) return SeoHelper.GetSeName( name, seoSettings == null ? false : seoSettings.ConvertNonWesternChars, - seoSettings == null ? false : seoSettings.AllowUnicodeCharsInUrls); + seoSettings == null ? false : seoSettings.AllowUnicodeCharsInUrls, + seoSettings == null ? null : seoSettings.SeoNameCharConversion); } #endregion diff --git a/src/Presentation/SmartStore.Web/Administration/Controllers/SettingController.cs b/src/Presentation/SmartStore.Web/Administration/Controllers/SettingController.cs index 8ad100f9ee..086be63a26 100644 --- a/src/Presentation/SmartStore.Web/Administration/Controllers/SettingController.cs +++ b/src/Presentation/SmartStore.Web/Administration/Controllers/SettingController.cs @@ -31,6 +31,7 @@ using SmartStore.Services.Orders; using SmartStore.Services.Security; using SmartStore.Services.Tax; +using SmartStore.Utilities; using SmartStore.Web.Framework; using SmartStore.Web.Framework.Controllers; using SmartStore.Web.Framework.Filters; @@ -1014,6 +1015,8 @@ public ActionResult GeneralCommon() model.SeoSettings.DefaultMetaKeywords = seoSettings.DefaultMetaKeywords; model.SeoSettings.DefaultMetaDescription = seoSettings.DefaultMetaDescription; model.SeoSettings.ConvertNonWesternChars = seoSettings.ConvertNonWesternChars; + model.SeoSettings.AllowUnicodeCharsInUrls = seoSettings.AllowUnicodeCharsInUrls; + model.SeoSettings.SeoNameCharConversion = seoSettings.SeoNameCharConversion; model.SeoSettings.CanonicalUrlsEnabled = seoSettings.CanonicalUrlsEnabled; model.SeoSettings.CanonicalHostNameRule = seoSettings.CanonicalHostNameRule; model.SeoSettings.ExtraRobotsDisallows = String.Join(Environment.NewLine, seoSettings.ExtraRobotsDisallows); @@ -1187,11 +1190,15 @@ public ActionResult GeneralCommon(GeneralCommonSettingsModel model, FormCollecti //seo settings var seoSettings = _services.Settings.LoadSetting(storeScope); + var resetUserSeoCharacterTable = (seoSettings.SeoNameCharConversion != model.SeoSettings.SeoNameCharConversion); + seoSettings.PageTitleSeparator = model.SeoSettings.PageTitleSeparator; seoSettings.PageTitleSeoAdjustment = model.SeoSettings.PageTitleSeoAdjustment; seoSettings.DefaultTitle = model.SeoSettings.DefaultTitle; seoSettings.DefaultMetaKeywords = model.SeoSettings.DefaultMetaKeywords; seoSettings.DefaultMetaDescription = model.SeoSettings.DefaultMetaDescription; + seoSettings.AllowUnicodeCharsInUrls = model.SeoSettings.AllowUnicodeCharsInUrls; + seoSettings.SeoNameCharConversion = model.SeoSettings.SeoNameCharConversion; seoSettings.ConvertNonWesternChars = model.SeoSettings.ConvertNonWesternChars; seoSettings.CanonicalUrlsEnabled = model.SeoSettings.CanonicalUrlsEnabled; seoSettings.CanonicalHostNameRule = model.SeoSettings.CanonicalHostNameRule; @@ -1199,6 +1206,11 @@ public ActionResult GeneralCommon(GeneralCommonSettingsModel model, FormCollecti StoreDependingSettings.UpdateSettings(seoSettings, form, storeScope, _services.Settings); + if (resetUserSeoCharacterTable) + { + SeoHelper.ResetUserSeoCharacterTable(); + } + //security settings var securitySettings = _services.Settings.LoadSetting(storeScope); if (securitySettings.AdminAreaAllowedIpAddresses == null) @@ -1492,11 +1504,24 @@ public ActionResult ToggleFullText(GeneralCommonSettingsModel model) return RedirectToAction("GeneralCommon"); } + [HttpPost] + public ActionResult TestSeoNameCreation(GeneralCommonSettingsModel model) + { + var storeScope = this.GetActiveStoreScopeConfiguration(_services.StoreService, _services.WorkContext); + var seoSettings = _services.Settings.LoadSetting(storeScope); + // we always test against persisted settings + var result = SeoHelper.GetSeName(model.SeoSettings.TestSeoNameCreation, + seoSettings.ConvertNonWesternChars, + seoSettings.AllowUnicodeCharsInUrls, + seoSettings.SeoNameCharConversion); + + return Content(result); + } - //all settings - public ActionResult AllSettings() + //all settings + public ActionResult AllSettings() { if (!_services.Permissions.Authorize(StandardPermissionProvider.ManageSettings)) return AccessDeniedView(); diff --git a/src/Presentation/SmartStore.Web/Administration/Models/Settings/GeneralCommonSettingsModel.cs b/src/Presentation/SmartStore.Web/Administration/Models/Settings/GeneralCommonSettingsModel.cs index db49b69053..bc1821522a 100644 --- a/src/Presentation/SmartStore.Web/Administration/Models/Settings/GeneralCommonSettingsModel.cs +++ b/src/Presentation/SmartStore.Web/Administration/Models/Settings/GeneralCommonSettingsModel.cs @@ -81,7 +81,16 @@ public partial class SeoSettingsModel [SmartResourceDisplayName("Admin.Configuration.Settings.GeneralCommon.ConvertNonWesternChars")] public bool ConvertNonWesternChars { get; set; } - [SmartResourceDisplayName("Admin.Configuration.Settings.GeneralCommon.CanonicalUrlsEnabled")] + [SmartResourceDisplayName("Admin.Configuration.Settings.GeneralCommon.AllowUnicodeCharsInUrls")] + public bool AllowUnicodeCharsInUrls { get; set; } + + [SmartResourceDisplayName("Admin.Configuration.Settings.GeneralCommon.SeoNameCharConversion")] + public string SeoNameCharConversion { get; set; } + + [SmartResourceDisplayName("Admin.Configuration.Settings.GeneralCommon.TestSeoNameCreation")] + public string TestSeoNameCreation { get; set; } + + [SmartResourceDisplayName("Admin.Configuration.Settings.GeneralCommon.CanonicalUrlsEnabled")] public bool CanonicalUrlsEnabled { get; set; } [SmartResourceDisplayName("Admin.Configuration.Settings.GeneralCommon.CanonicalHostNameRule")] diff --git a/src/Presentation/SmartStore.Web/Administration/Views/Setting/GeneralCommon.cshtml b/src/Presentation/SmartStore.Web/Administration/Views/Setting/GeneralCommon.cshtml index 60c57ccd7f..83029516f0 100644 --- a/src/Presentation/SmartStore.Web/Administration/Views/Setting/GeneralCommon.cshtml +++ b/src/Presentation/SmartStore.Web/Administration/Views/Setting/GeneralCommon.cshtml @@ -27,8 +27,8 @@ $("#@Html.FieldIdFor(model => model.StoreInformationSettings.StoreClosed)").click(toggleStoreClosed); $("#@Html.FieldIdFor(model => model.CaptchaSettings.Enabled)").change(function () { $('#SecuritySettingTable').find('.captcha-setting').toggle($(this).is(':checked')); - }).trigger('change'); - $("#@Html.FieldIdFor(model => model.LocalizationSettings.SeoFriendlyUrlsForLanguagesEnabled)").click(toggleSeoLanguageUrls); + }).trigger('change'); + $("#@Html.FieldIdFor(model => model.LocalizationSettings.SeoFriendlyUrlsForLanguagesEnabled)").click(toggleSeoLanguageUrls); toggleStoreClosed(); toggleSeoLanguageUrls(); @@ -36,6 +36,17 @@ $("#@Html.FieldIdFor(model => model.SocialSettings.ShowSocialLinksInFooter)").change(function () { $('#SocialLinkTable').find('.social-link').toggle($(this).is(':checked')); }).trigger('change'); + + // test creation of SEO names + $('#TestSeoNameCreationButton').click(function () { + $(this).closest('form').doAjax({ + type: 'POST', + url: '@Url.Action("TestSeoNameCreation")', + callbackSuccess: function (resp) { + $('#TestSeoNameCreationResult').text(resp); + } + }); + }); }); function toggleStoreClosed() { @@ -148,15 +159,6 @@ @Html.ValidationMessageFor(model => model.SeoSettings.DefaultMetaDescription)
    - @Html.SmartLabelFor(model => model.SeoSettings.ConvertNonWesternChars) - - @Html.SettingEditorFor(model => model.SeoSettings.ConvertNonWesternChars) - @Html.ValidationMessageFor(model => model.SeoSettings.ConvertNonWesternChars) -
    @Html.SmartLabelFor(model => model.SeoSettings.CanonicalUrlsEnabled) @@ -185,6 +187,59 @@ @Html.ValidationMessageFor(model => model.SeoSettings.ExtraRobotsDisallows)
    +
    +
    @T("Admin.System.SeNames")
    +
    +
    + @Html.SmartLabelFor(model => model.SeoSettings.ConvertNonWesternChars) + + @Html.SettingEditorFor(model => model.SeoSettings.ConvertNonWesternChars) + @Html.ValidationMessageFor(model => model.SeoSettings.ConvertNonWesternChars) +
    + @Html.SmartLabelFor(model => model.SeoSettings.AllowUnicodeCharsInUrls) + + @Html.SettingEditorFor(model => model.SeoSettings.AllowUnicodeCharsInUrls) + @Html.ValidationMessageFor(model => model.SeoSettings.AllowUnicodeCharsInUrls) +
    + @Html.SmartLabelFor(model => model.SeoSettings.SeoNameCharConversion) + + @Html.TextAreaFor(model => model.SeoSettings.SeoNameCharConversion, new { @class = "input-large", style = "height:250px" }) + @Html.ValidationMessageFor(model => model.SeoSettings.SeoNameCharConversion) +
    + @Html.SmartLabelFor(model => model.SeoSettings.TestSeoNameCreation) + + @Html.EditorFor(model => model.SeoSettings.TestSeoNameCreation) + + +
    +   + +
    } @helper TabSecuritySettings() diff --git a/src/Tests/SmartStore.Services.Tests/Seo/SeoExtensionsTests.cs b/src/Tests/SmartStore.Services.Tests/Seo/SeoExtensionsTests.cs index 08d600fd58..3d57edf05a 100644 --- a/src/Tests/SmartStore.Services.Tests/Seo/SeoExtensionsTests.cs +++ b/src/Tests/SmartStore.Services.Tests/Seo/SeoExtensionsTests.cs @@ -1,11 +1,11 @@ -using SmartStore.Services.Seo; -using SmartStore.Tests; +using System; using NUnit.Framework; +using SmartStore.Tests; using SmartStore.Utilities; namespace SmartStore.Services.Tests.Seo { - [TestFixture] + [TestFixture] public class SeoExtensionsTests { [Test] @@ -38,17 +38,23 @@ public void Can_convert_non_western_chars() { //german letters with diacritics SeoHelper.GetSeName("testäöü", true, false).ShouldEqual("testaou"); - SeoHelper.GetSeName("testäöü", false, false).ShouldEqual("testaeoeue"); - } + SeoHelper.GetSeName("testäöü", false, false).ShouldEqual("test"); + + var charConversions = string.Join(Environment.NewLine, new string[] { "ä;ae", "ö;oe", "ü;ue" }); + + SeoHelper.GetSeName("testäöü", false, false, charConversions).ShouldEqual("testaeoeue"); + + SeoHelper.ResetUserSeoCharacterTable(); + } - //[Test] - //public void Can_allow_unicode_chars() - //{ - // //russian letters - //SeoHelper.GetSeName("testтест", false, true).ShouldEqual("testтест"); - //SeoHelper.GetSeName("testтест", false, false).ShouldEqual("test"); - //} - } + [Test] + public void Can_allow_unicode_chars() + { + //russian letters + SeoHelper.GetSeName("testтест", false, true).ShouldEqual("testтест"); + SeoHelper.GetSeName("testтест", false, false).ShouldEqual("test"); + } + } } From 6a8e630235f9ec4e1a765c0498b898f7a6b640e3 Mon Sep 17 00:00:00 2001 From: Marcus Gesing Date: Mon, 4 Jan 2016 13:31:57 +0100 Subject: [PATCH 207/707] Some UI cosmetic at setting pages --- .../201506181858349_AclRecordCustomerRole.cs | 8 +- .../Administration/Content/admin.less | 46 +- .../Views/Setting/Catalog.cshtml | 510 +++++++++--------- .../Administration/Views/Setting/Forum.cshtml | 9 +- .../Views/Setting/GeneralCommon.cshtml | 29 +- .../Administration/Views/Setting/Media.cshtml | 60 +-- .../Views/Setting/RewardPoints.cshtml | 130 ++--- .../Views/Setting/Shipping.cshtml | 11 +- .../Views/Setting/ShoppingCart.cshtml | 13 +- .../Administration/Views/Setting/Tax.cshtml | 29 +- 10 files changed, 428 insertions(+), 417 deletions(-) diff --git a/src/Libraries/SmartStore.Data/Migrations/201506181858349_AclRecordCustomerRole.cs b/src/Libraries/SmartStore.Data/Migrations/201506181858349_AclRecordCustomerRole.cs index c25739afec..655737641f 100644 --- a/src/Libraries/SmartStore.Data/Migrations/201506181858349_AclRecordCustomerRole.cs +++ b/src/Libraries/SmartStore.Data/Migrations/201506181858349_AclRecordCustomerRole.cs @@ -124,19 +124,19 @@ before you can assign them to all subcategories and products.
    "Show manufacturers on homepage", "Zeige Hersteller auf der Homepage", "Specifies whether manufacturers will be displayed on the homepage.", - "Bestimmt ob Hersteller auf der Homepage angezeigt werden."); + "Legt fest, ob Hersteller auf der Homepage angezeigt werden."); builder.AddOrUpdate("Admin.Configuration.Settings.Catalog.ShowManufacturerPictures", "Show manufacturer pictures on homepage", "Zeige Herstellerbilder auf der Homepage", "Specifies whether manufacturers will be displayed as images or textual links on the homepage.", - "Bestimmt ob Hersteller auf der Homepage als Bilder oder textuelle Links angezeigt werden."); + "Legt fest, ob Hersteller auf der Homepage als Bilder oder textuelle Links angezeigt werden."); builder.AddOrUpdate("Admin.Configuration.Settings.CustomerUser.CustomerNumberEnabled", "Customers can enter a customer number", "Kunden knnen Kundennummer hinterlegen", "Specifies whether customers can enter a customer number.", - "Bestimmt ob Kunden eine Kundennummer hinterlegen knnen."); + "Legt fest, ob Kunden eine Kundennummer hinterlegen knnen."); builder.AddOrUpdate("Account.Fields.CustomerNumber", "Customer number", @@ -146,7 +146,7 @@ before you can assign them to all subcategories and products.
    "Customers must enter a VATIN", "Kunden mssen eine Steuernummer angeben", "Specifies whether Customers must enter a VAT identification number.", - "Bestimmt ob Kunden bei der Registrierung eine Steuernummer angeben mssen."); + "Legt fest, ob Kunden bei der Registrierung eine Steuernummer angeben mssen."); builder.AddOrUpdate("Account.Fields.Vat.Required", "Please enter your VATIN", diff --git a/src/Presentation/SmartStore.Web/Administration/Content/admin.less b/src/Presentation/SmartStore.Web/Administration/Content/admin.less index a27117a25a..eff6584861 100644 --- a/src/Presentation/SmartStore.Web/Administration/Content/admin.less +++ b/src/Presentation/SmartStore.Web/Administration/Content/admin.less @@ -395,26 +395,33 @@ td.adminData > input[type="checkbox"] { .admin-config-group { .title, - .small-title { + .small-title, + .head { font-family: @headingsFontFamily; font-weight: @headingsFontWeight; color: inherit; border-bottom: 1px solid #ddd; } - .title { + .sub-title { + font-family: @baseFontFamily; + font-size: @baseFontSize; + font-weight: normal; + } + .title, + .head { font-size: @fontSizeLarge; - margin: 12px 0; padding: 8px 0; } + .head { + margin-bottom: 12px; + } + .title { + margin: 12px 0; + } .small-title { margin: 2px 0; padding: 2px 0; } - .sub-title { - font-family: @baseFontFamily; - font-size: @baseFontSize; - font-weight: normal; - } } @@ -809,6 +816,16 @@ td.adminTitle > .ctl-label { } } } +tr.adminGroup { + > td { + padding-top: 18px; + } + + label { + padding-bottom: 3px; + text-decoration: underline; + } +} td.adminTitle:hover a.hint { .opacity(100); @@ -850,13 +867,14 @@ td.adminData .t-combobox { width: 306px; } -tr.adminSeparator hr { - background-color: #D3D3D3; - border: medium none; - color: #D3D3D3; +tr.adminSeparator hr, +td.adminSeparator hr { + border: medium none; + background-color: #ddd; + color: #ddd; height: 1px; - margin-top: 10px; - margin-bottom: 10px; + margin-top: 12px; + margin-bottom: 12px; padding: 0; } diff --git a/src/Presentation/SmartStore.Web/Administration/Views/Setting/Catalog.cshtml b/src/Presentation/SmartStore.Web/Administration/Views/Setting/Catalog.cshtml index 3e8d9e4a19..48dbb84b82 100644 --- a/src/Presentation/SmartStore.Web/Administration/Views/Setting/Catalog.cshtml +++ b/src/Presentation/SmartStore.Web/Administration/Views/Setting/Catalog.cshtml @@ -257,8 +257,7 @@ @Html.ValidationMessageFor(model => model.IgnoreFeaturedProducts)
    @Html.SmartLabelFor(model => model.CompareProductsEnabled)
    @Html.SmartLabelFor(model => model.EnableHtmlTextCollapser) @@ -365,257 +363,272 @@ @helper TabProductListSettings() { -
    - @T("Common.Navigation") - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
    - @Html.SmartLabelFor(model => model.ShowProductsFromSubcategories) - - @Html.SettingEditorFor(model => model.ShowProductsFromSubcategories) - @Html.ValidationMessageFor(model => model.ShowProductsFromSubcategories) -
    - @Html.SmartLabelFor(model => model.IncludeFeaturedProductsInNormalLists) - - @Html.SettingEditorFor(model => model.IncludeFeaturedProductsInNormalLists) - @Html.ValidationMessageFor(model => model.IncludeFeaturedProductsInNormalLists) -
    - @Html.SmartLabelFor(model => model.ShowCategoryProductNumber) - - @Html.SettingEditorFor(model => model.ShowCategoryProductNumber) - @Html.ValidationMessageFor(model => model.ShowCategoryProductNumber) -
    - @Html.SmartLabelFor(model => model.ShowCategoryProductNumberIncludingSubcategories) - - @Html.SettingEditorFor(model => model.ShowCategoryProductNumberIncludingSubcategories) - @Html.ValidationMessageFor(model => model.ShowCategoryProductNumberIncludingSubcategories) -
    - @Html.SmartLabelFor(model => model.CategoryBreadcrumbEnabled) - - @Html.SettingEditorFor(model => model.CategoryBreadcrumbEnabled) - @Html.ValidationMessageFor(model => model.CategoryBreadcrumbEnabled) -
    - @Html.SmartLabelFor(model => model.FilterEnabled) - - @Html.SettingEditorFor(model => model.FilterEnabled) - @Html.ValidationMessageFor(model => model.FilterEnabled) -
    - @Html.SmartLabelFor(model => model.MaxFilterItemsToDisplay) - - @Html.SettingEditorFor(model => model.MaxFilterItemsToDisplay) - @Html.ValidationMessageFor(model => model.MaxFilterItemsToDisplay) -
    - @Html.SmartLabelFor(model => model.ExpandAllFilterCriteria) - - @Html.SettingEditorFor(model => model.ExpandAllFilterCriteria) - @Html.ValidationMessageFor(model => model.ExpandAllFilterCriteria) -
    + + + + + + + + + + + + + + + + + + + + + + + - - - - + + + + + + + + + + + + -
    +
    +
    @T("Common.Navigation")
    +
    +
    + @Html.SmartLabelFor(model => model.ShowProductsFromSubcategories) + + @Html.SettingEditorFor(model => model.ShowProductsFromSubcategories) + @Html.ValidationMessageFor(model => model.ShowProductsFromSubcategories) +
    + @Html.SmartLabelFor(model => model.IncludeFeaturedProductsInNormalLists) + + @Html.SettingEditorFor(model => model.IncludeFeaturedProductsInNormalLists) + @Html.ValidationMessageFor(model => model.IncludeFeaturedProductsInNormalLists) +
    + @Html.SmartLabelFor(model => model.ShowCategoryProductNumber) + + @Html.SettingEditorFor(model => model.ShowCategoryProductNumber) + @Html.ValidationMessageFor(model => model.ShowCategoryProductNumber) +
    + @Html.SmartLabelFor(model => model.ShowCategoryProductNumberIncludingSubcategories) + + @Html.SettingEditorFor(model => model.ShowCategoryProductNumberIncludingSubcategories) + @Html.ValidationMessageFor(model => model.ShowCategoryProductNumberIncludingSubcategories) +
    + @Html.SmartLabelFor(model => model.CategoryBreadcrumbEnabled) + + @Html.SettingEditorFor(model => model.CategoryBreadcrumbEnabled) + @Html.ValidationMessageFor(model => model.CategoryBreadcrumbEnabled) +
    - @Html.SmartLabelFor(model => model.SubCategoryDisplayType) - - @Html.SettingOverrideCheckbox(model => Model.SubCategoryDisplayType) - @Html.DropDownListFor(model => model.SubCategoryDisplayType, Model.AvailableSubCategoryDisplayTypes) - @Html.ValidationMessageFor(model => model.SubCategoryDisplayType) -
    + @Html.SmartLabelFor(model => model.FilterEnabled) + + @Html.SettingEditorFor(model => model.FilterEnabled) + @Html.ValidationMessageFor(model => model.FilterEnabled) +
    + @Html.SmartLabelFor(model => model.MaxFilterItemsToDisplay) + + @Html.SettingEditorFor(model => model.MaxFilterItemsToDisplay) + @Html.ValidationMessageFor(model => model.MaxFilterItemsToDisplay) +
    + @Html.SmartLabelFor(model => model.ExpandAllFilterCriteria) + + @Html.SettingEditorFor(model => model.ExpandAllFilterCriteria) + @Html.ValidationMessageFor(model => model.ExpandAllFilterCriteria) +
    -
    +
    + @Html.SmartLabelFor(model => model.SubCategoryDisplayType) + + @Html.SettingOverrideCheckbox(model => Model.SubCategoryDisplayType) + @Html.DropDownListFor(model => model.SubCategoryDisplayType, Model.AvailableSubCategoryDisplayTypes) + @Html.ValidationMessageFor(model => model.SubCategoryDisplayType) +
    -
    - @T("Common.List") - - - - - - - - - - - - - - - - - - - - - - - - - -
    - @Html.SmartLabelFor(model => model.AllowProductSorting) - - @Html.SettingEditorFor(model => model.AllowProductSorting) - @Html.ValidationMessageFor(model => model.AllowProductSorting) -
    - @Html.SmartLabelFor(model => model.DefaultViewMode) - - @Html.SettingOverrideCheckbox(model => Model.DefaultViewMode) - @Html.DropDownListFor(model => model.DefaultViewMode, Model.AvailableDefaultViewModes) - @Html.ValidationMessageFor(model => model.DefaultViewMode) -
    - @Html.SmartLabelFor(model => model.DefaultSortOrder) - - @Html.SettingOverrideCheckbox(model => Model.DefaultSortOrder) - @Html.DropDownListFor(model => model.DefaultSortOrder, Model.AvailableSortOrderModes) - @Html.ValidationMessageFor(model => model.DefaultSortOrder) -
    - @Html.SmartLabelFor(model => model.AllowProductViewModeChanging) - - @Html.SettingEditorFor(model => model.AllowProductViewModeChanging) - @Html.ValidationMessageFor(model => model.AllowProductViewModeChanging) -
    - @Html.SmartLabelFor(model => model.DefaultPageSizeOptions) - - @Html.SettingEditorFor(model => model.DefaultPageSizeOptions) - @Html.ValidationMessageFor(model => model.DefaultPageSizeOptions) -
    - @Html.SmartLabelFor(model => model.PriceDisplayType) - - @Html.SettingOverrideCheckbox(model => Model.PriceDisplayType) - @Html.DropDownListFor(model => model.PriceDisplayType, Model.AvailablePriceDisplayTypes) - @Html.ValidationMessageFor(model => model.PriceDisplayType) -
    -
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +
    @T("Common.List")
    +
    +
    + @Html.SmartLabelFor(model => model.AllowProductSorting) + + @Html.SettingEditorFor(model => model.AllowProductSorting) + @Html.ValidationMessageFor(model => model.AllowProductSorting) +
    + @Html.SmartLabelFor(model => model.DefaultViewMode) + + @Html.SettingOverrideCheckbox(model => Model.DefaultViewMode) + @Html.DropDownListFor(model => model.DefaultViewMode, Model.AvailableDefaultViewModes) + @Html.ValidationMessageFor(model => model.DefaultViewMode) +
    + @Html.SmartLabelFor(model => model.DefaultSortOrder) + + @Html.SettingOverrideCheckbox(model => Model.DefaultSortOrder) + @Html.DropDownListFor(model => model.DefaultSortOrder, Model.AvailableSortOrderModes) + @Html.ValidationMessageFor(model => model.DefaultSortOrder) +
    + @Html.SmartLabelFor(model => model.AllowProductViewModeChanging) + + @Html.SettingEditorFor(model => model.AllowProductViewModeChanging) + @Html.ValidationMessageFor(model => model.AllowProductViewModeChanging) +
    + @Html.SmartLabelFor(model => model.DefaultPageSizeOptions) + + @Html.SettingEditorFor(model => model.DefaultPageSizeOptions) + @Html.ValidationMessageFor(model => model.DefaultPageSizeOptions) +
    + @Html.SmartLabelFor(model => model.PriceDisplayType) + + @Html.SettingOverrideCheckbox(model => Model.PriceDisplayType) + @Html.DropDownListFor(model => model.PriceDisplayType, Model.AvailablePriceDisplayTypes) + @Html.ValidationMessageFor(model => model.PriceDisplayType) +
    -
    - @T("Admin.Catalog.Products") - - - - - - - - - - - - - - - - - - - - - -
    - @Html.SmartLabelFor(model => model.ShowDeliveryTimesInProductLists) - - @Html.SettingEditorFor(model => model.ShowDeliveryTimesInProductLists) - @Html.ValidationMessageFor(model => model.ShowDeliveryTimesInProductLists) -
    - @Html.SmartLabelFor(model => model.ShowBasePriceInProductLists) - - @Html.SettingEditorFor(model => model.ShowBasePriceInProductLists) - @Html.ValidationMessageFor(model => model.ShowBasePriceInProductLists) -
    - @Html.SmartLabelFor(model => model.ShowColorSquaresInLists) - - @Html.SettingEditorFor(model => model.ShowColorSquaresInLists) - @Html.ValidationMessageFor(model => model.ShowColorSquaresInLists) -
    - @Html.SmartLabelFor(model => model.HideBuyButtonInLists) - - @Html.SettingEditorFor(model => model.HideBuyButtonInLists) - @Html.ValidationMessageFor(model => model.HideBuyButtonInLists) -
    - @Html.SmartLabelFor(model => model.LabelAsNewForMaxDays) - - @Html.SettingEditorFor(model => model.LabelAsNewForMaxDays) - @Html.ValidationMessageFor(model => model.LabelAsNewForMaxDays) -
    -
    + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +
    @T("Admin.Catalog.Products")
    +
    +
    + @Html.SmartLabelFor(model => model.ShowDeliveryTimesInProductLists) + + @Html.SettingEditorFor(model => model.ShowDeliveryTimesInProductLists) + @Html.ValidationMessageFor(model => model.ShowDeliveryTimesInProductLists) +
    + @Html.SmartLabelFor(model => model.ShowBasePriceInProductLists) + + @Html.SettingEditorFor(model => model.ShowBasePriceInProductLists) + @Html.ValidationMessageFor(model => model.ShowBasePriceInProductLists) +
    + @Html.SmartLabelFor(model => model.ShowColorSquaresInLists) + + @Html.SettingEditorFor(model => model.ShowColorSquaresInLists) + @Html.ValidationMessageFor(model => model.ShowColorSquaresInLists) +
    + @Html.SmartLabelFor(model => model.HideBuyButtonInLists) + + @Html.SettingEditorFor(model => model.HideBuyButtonInLists) + @Html.ValidationMessageFor(model => model.HideBuyButtonInLists) +
    + @Html.SmartLabelFor(model => model.LabelAsNewForMaxDays) + + @Html.SettingEditorFor(model => model.LabelAsNewForMaxDays) + @Html.ValidationMessageFor(model => model.LabelAsNewForMaxDays) +
    -
    - @T("Admin.Catalog.ProductTags") - - - - - - - - - - - - - - - - - -
    - @Html.SmartLabelFor(model => model.NumberOfProductTags) - - @Html.SettingEditorFor(model => model.NumberOfProductTags) - @Html.ValidationMessageFor(model => model.NumberOfProductTags) -
    - @Html.SmartLabelFor(model => model.ProductsByTagPageSize) - - @Html.SettingEditorFor(model => model.ProductsByTagPageSize) - @Html.ValidationMessageFor(model => model.ProductsByTagPageSize) -
    - @Html.SmartLabelFor(model => model.ProductsByTagAllowCustomersToSelectPageSize) - - @Html.SettingEditorFor(model => model.ProductsByTagAllowCustomersToSelectPageSize) - @Html.ValidationMessageFor(model => model.ProductsByTagAllowCustomersToSelectPageSize) -
    - @Html.SmartLabelFor(model => model.ProductsByTagPageSizeOptions) - - @Html.SettingEditorFor(model => model.ProductsByTagPageSizeOptions) - @Html.ValidationMessageFor(model => model.ProductsByTagPageSizeOptions) -
    -
    + + + + + + + + + + + + + + + + + + + + +
    +
    +
    @T("Admin.Catalog.ProductTags")
    +
    +
    + @Html.SmartLabelFor(model => model.NumberOfProductTags) + + @Html.SettingEditorFor(model => model.NumberOfProductTags) + @Html.ValidationMessageFor(model => model.NumberOfProductTags) +
    + @Html.SmartLabelFor(model => model.ProductsByTagPageSize) + + @Html.SettingEditorFor(model => model.ProductsByTagPageSize) + @Html.ValidationMessageFor(model => model.ProductsByTagPageSize) +
    + @Html.SmartLabelFor(model => model.ProductsByTagAllowCustomersToSelectPageSize) + + @Html.SettingEditorFor(model => model.ProductsByTagAllowCustomersToSelectPageSize) + @Html.ValidationMessageFor(model => model.ProductsByTagAllowCustomersToSelectPageSize) +
    + @Html.SmartLabelFor(model => model.ProductsByTagPageSizeOptions) + + @Html.SettingEditorFor(model => model.ProductsByTagPageSizeOptions) + @Html.ValidationMessageFor(model => model.ProductsByTagPageSizeOptions) +
    } @helper TabUserSettings() { - +
    + + +
    @Html.SmartLabelFor(model => model.ShowProductReviewsInProductLists) @@ -693,7 +706,7 @@ @helper TabProductDetailSettings() { - +
    - + - + -
    @Html.SmartLabelFor(model => model.RecentlyViewedProductsEnabled) @@ -834,8 +847,7 @@ } @helper TabProductSearchSettings() { - - +
    - diff --git a/src/Presentation/SmartStore.Web/Administration/Views/Setting/Forum.cshtml b/src/Presentation/SmartStore.Web/Administration/Views/Setting/Forum.cshtml index b89e7f267a..960758edfd 100644 --- a/src/Presentation/SmartStore.Web/Administration/Views/Setting/Forum.cshtml +++ b/src/Presentation/SmartStore.Web/Administration/Views/Setting/Forum.cshtml @@ -1,7 +1,6 @@ @model ForumSettingsModel @using Telerik.Web.Mvc.UI; @{ - //page title ViewBag.Title = T("Admin.Configuration.Settings.Forums").Text; } @using (Html.BeginForm()) @@ -136,8 +135,8 @@ @Html.ValidationMessageFor(model => model.SignaturesEnabled) - - + @@ -169,8 +168,8 @@ @Html.ValidationMessageFor(model => model.NotifyAboutPrivateMessages) - - + diff --git a/src/Presentation/SmartStore.Web/Administration/Views/Setting/GeneralCommon.cshtml b/src/Presentation/SmartStore.Web/Administration/Views/Setting/GeneralCommon.cshtml index 83029516f0..517e7cc211 100644 --- a/src/Presentation/SmartStore.Web/Administration/Views/Setting/GeneralCommon.cshtml +++ b/src/Presentation/SmartStore.Web/Administration/Views/Setting/GeneralCommon.cshtml @@ -424,7 +424,7 @@ - @@ -520,9 +520,9 @@ - + - + - - -
    @Html.SmartLabelFor(model => model.SearchPageProductsPerPage) @@ -873,7 +885,7 @@
    +
    +

    +

    +
    -
    -
    +
    +
    @@ -638,9 +638,9 @@
    -
    -
    +
    +
    @@ -669,9 +669,6 @@ @Html.ValidationMessageFor(model => model.CompanyInformationSettings.TaxNumber)
    } @@ -716,9 +713,9 @@
    -
    -
    +
    +
    @@ -757,9 +754,9 @@
    -
    -
    +
    +
    diff --git a/src/Presentation/SmartStore.Web/Administration/Views/Setting/Media.cshtml b/src/Presentation/SmartStore.Web/Administration/Views/Setting/Media.cshtml index 566f49c981..bc9c1fcc46 100644 --- a/src/Presentation/SmartStore.Web/Administration/Views/Setting/Media.cshtml +++ b/src/Presentation/SmartStore.Web/Administration/Views/Setting/Media.cshtml @@ -1,7 +1,6 @@ @model MediaSettingsModel @using Telerik.Web.Mvc.UI; @{ - //page title ViewBag.Title = T("Admin.Configuration.Settings.Media").Text; } @using (Html.BeginForm()) @@ -162,38 +161,31 @@ @Html.ValidationMessageFor(model => model.MaximumImageSize)
    - -
    - @T("Admin.Configuration.Settings.Media.PicturesStoredIntoDatabase") -
    -
    - @T("Admin.Configuration.Settings.Media.MovePicturesNote") -
    +
    +
    +
    @T("Admin.Configuration.Settings.Media.PicturesStoredIntoDatabase")
    +
    +
    + @T("Admin.Configuration.Settings.Media.MovePicturesNote") +
    + + @T(Model.PicturesStoredIntoDatabase ? "Admin.Configuration.Settings.Media.PicturesStoredIntoDatabase.Database" : "Admin.Configuration.Settings.Media.PicturesStoredIntoDatabase.FileSystem") + - - @if (Model.PicturesStoredIntoDatabase) - { - @T("Admin.Configuration.Settings.Media.PicturesStoredIntoDatabase.Database") - } - else - { - @T("Admin.Configuration.Settings.Media.PicturesStoredIntoDatabase.FileSystem") - } - - - - - + +
    } \ No newline at end of file diff --git a/src/Presentation/SmartStore.Web/Administration/Views/Setting/RewardPoints.cshtml b/src/Presentation/SmartStore.Web/Administration/Views/Setting/RewardPoints.cshtml index c6bf2240dd..769a844e41 100644 --- a/src/Presentation/SmartStore.Web/Administration/Views/Setting/RewardPoints.cshtml +++ b/src/Presentation/SmartStore.Web/Administration/Views/Setting/RewardPoints.cshtml @@ -2,7 +2,6 @@ @using Telerik.Web.Mvc.UI; @using SmartStore.Core.Domain.Orders; @{ - //page title ViewBag.Title = T("Admin.Configuration.Settings.RewardPoints").Text; } @using (Html.BeginForm()) @@ -48,67 +47,70 @@
    -
    - @T("Admin.Configuration.Settings.RewardPoints.Earning") - - - - - - - - - - - - - - - - - - - - - - -
    - @Html.SmartLabelFor(model => model.PointsForRegistration) - - @Html.SettingOverrideCheckbox(model => Model.PointsForRegistration) - @Html.EditorFor(model => model.PointsForRegistration, new { Small = true }) - @Html.ValidationMessageFor(model => model.PointsForRegistration) -
    - @Html.SmartLabelFor(model => model.PointsForProductReview) - - @Html.SettingOverrideCheckbox(model => Model.PointsForProductReview) - @Html.EditorFor(model => model.PointsForProductReview, new { Small = true }) - @Html.ValidationMessageFor(model => model.PointsForProductReview) -
    - @Html.SmartLabelFor(model => model.PointsForPurchases_Amount) - - @Html.SettingOverrideCheckbox(model => Model.PointsForPurchases_OverrideForStore, "#pnlPointsForPurchases") - @T("Admin.Configuration.Settings.RewardPoints.Earning.Hint1") - @Html.EditorFor(model => model.PointsForPurchases_Amount, new { Small = true }) - @Model.PrimaryStoreCurrencyCode -   - @T("Admin.Configuration.Settings.RewardPoints.Earning.Hint2") - @Html.EditorFor(model => model.PointsForPurchases_Points, new { Small = true }) - @T("Admin.Configuration.Settings.RewardPoints.Earning.Hint3") - @Html.ValidationMessageFor(model => model.PointsForPurchases_Amount) - @Html.ValidationMessageFor(model => model.PointsForPurchases_Points) -
    - @Html.SmartLabelFor(model => model.PointsForPurchases_Awarded) - - @Html.SettingOverrideCheckbox(model => Model.PointsForPurchases_Awarded) - @Html.DropDownListFor(model => model.PointsForPurchases_Awarded, ((OrderStatus)Model.PointsForPurchases_Awarded).ToSelectList()) - @Html.ValidationMessageFor(model => model.PointsForPurchases_Awarded) -
    - @Html.SmartLabelFor(model => model.PointsForPurchases_Canceled) - - @Html.SettingOverrideCheckbox(model => Model.PointsForPurchases_Canceled) - @Html.DropDownListFor(model => model.PointsForPurchases_Canceled, ((OrderStatus)Model.PointsForPurchases_Canceled).ToSelectList()) - @Html.ValidationMessageFor(model => model.PointsForPurchases_Canceled) -
    -
    + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +
    @T("Admin.Configuration.Settings.RewardPoints.Earning")
    +
    +
    + @Html.SmartLabelFor(model => model.PointsForRegistration) + + @Html.SettingOverrideCheckbox(model => Model.PointsForRegistration) + @Html.EditorFor(model => model.PointsForRegistration, new { Small = true }) + @Html.ValidationMessageFor(model => model.PointsForRegistration) +
    + @Html.SmartLabelFor(model => model.PointsForProductReview) + + @Html.SettingOverrideCheckbox(model => Model.PointsForProductReview) + @Html.EditorFor(model => model.PointsForProductReview, new { Small = true }) + @Html.ValidationMessageFor(model => model.PointsForProductReview) +
    + @Html.SmartLabelFor(model => model.PointsForPurchases_Amount) + + @Html.SettingOverrideCheckbox(model => Model.PointsForPurchases_OverrideForStore, "#pnlPointsForPurchases") + @T("Admin.Configuration.Settings.RewardPoints.Earning.Hint1") + @Html.EditorFor(model => model.PointsForPurchases_Amount, new { Small = true }) + @Model.PrimaryStoreCurrencyCode +   + @T("Admin.Configuration.Settings.RewardPoints.Earning.Hint2") + @Html.EditorFor(model => model.PointsForPurchases_Points, new { Small = true }) + @T("Admin.Configuration.Settings.RewardPoints.Earning.Hint3") + @Html.ValidationMessageFor(model => model.PointsForPurchases_Amount) + @Html.ValidationMessageFor(model => model.PointsForPurchases_Points) +
    + @Html.SmartLabelFor(model => model.PointsForPurchases_Awarded) + + @Html.SettingOverrideCheckbox(model => Model.PointsForPurchases_Awarded) + @Html.DropDownListFor(model => model.PointsForPurchases_Awarded, ((OrderStatus)Model.PointsForPurchases_Awarded).ToSelectList()) + @Html.ValidationMessageFor(model => model.PointsForPurchases_Awarded) +
    + @Html.SmartLabelFor(model => model.PointsForPurchases_Canceled) + + @Html.SettingOverrideCheckbox(model => Model.PointsForPurchases_Canceled) + @Html.DropDownListFor(model => model.PointsForPurchases_Canceled, ((OrderStatus)Model.PointsForPurchases_Canceled).ToSelectList()) + @Html.ValidationMessageFor(model => model.PointsForPurchases_Canceled) +
    } \ No newline at end of file diff --git a/src/Presentation/SmartStore.Web/Administration/Views/Setting/Shipping.cshtml b/src/Presentation/SmartStore.Web/Administration/Views/Setting/Shipping.cshtml index 56a5139003..65f9355676 100644 --- a/src/Presentation/SmartStore.Web/Administration/Views/Setting/Shipping.cshtml +++ b/src/Presentation/SmartStore.Web/Administration/Views/Setting/Shipping.cshtml @@ -1,6 +1,5 @@ @model ShippingSettingsModel @{ - //page title ViewBag.Title = T("Admin.Configuration.Settings.Shipping").Text; } @using (Html.BeginForm()) @@ -82,14 +81,14 @@ @Html.ValidationMessageFor(model => model.DisplayShipmentEventsToCustomers) - - - @Html.LabelFor(model => model.ShippingOriginAddress, new { style="font-weight: bold" }) - + + + @Html.SmartLabelFor(model => model.ShippingOriginAddress) + @Html.SettingOverrideCheckbox(model => Model.ShippingOriginAddress, "#pnlShippingOriginAddress") - + @Html.EditorFor(model => model.ShippingOriginAddress, "Address") diff --git a/src/Presentation/SmartStore.Web/Administration/Views/Setting/ShoppingCart.cshtml b/src/Presentation/SmartStore.Web/Administration/Views/Setting/ShoppingCart.cshtml index 2a4d51b0b4..34f62d4c96 100644 --- a/src/Presentation/SmartStore.Web/Administration/Views/Setting/ShoppingCart.cshtml +++ b/src/Presentation/SmartStore.Web/Administration/Views/Setting/ShoppingCart.cshtml @@ -1,6 +1,5 @@ @model ShoppingCartSettingsModel @{ - //page title ViewBag.Title = T("Admin.Configuration.Settings.ShoppingCart").Text; } @using (Html.BeginForm()) @@ -142,8 +141,8 @@ - - + +
    @@ -176,10 +175,10 @@ - - -
    - + + +
    + diff --git a/src/Presentation/SmartStore.Web/Administration/Views/Setting/Tax.cshtml b/src/Presentation/SmartStore.Web/Administration/Views/Setting/Tax.cshtml index 150886779f..7f2e872994 100644 --- a/src/Presentation/SmartStore.Web/Administration/Views/Setting/Tax.cshtml +++ b/src/Presentation/SmartStore.Web/Administration/Views/Setting/Tax.cshtml @@ -1,7 +1,6 @@ @model TaxSettingsModel @using Telerik.Web.Mvc.UI; @{ - //page title ViewBag.Title = T("Admin.Configuration.Settings.Tax").Text; } @using (Html.BeginForm()) @@ -150,11 +149,6 @@ @Html.ValidationMessageFor(model => model.HideTaxInOrderSummary) - - -
    - - @Html.SmartLabelFor(model => model.ShowLegalHintsInProductList) @@ -182,8 +176,8 @@ @Html.ValidationMessageFor(model => model.ShowLegalHintsInFooter) - - + +
    @@ -197,21 +191,21 @@ @Html.ValidationMessageFor(model => model.TaxBasedOn) - + - @Html.LabelFor(model => model.DefaultTaxAddress, new { style="font-weight: bold" }) + @Html.SmartLabelFor(model => model.DefaultTaxAddress) @Html.SettingOverrideCheckbox(model => Model.DefaultTaxAddress, "#pnlDefaultTaxAddress") - + @Html.EditorFor(x => x.DefaultTaxAddress, "Address") - - + +
    @@ -243,8 +237,8 @@ @Html.ValidationMessageFor(model => model.ShippingTaxClassId) - - + +
    @@ -276,8 +270,8 @@ @Html.ValidationMessageFor(model => model.PaymentMethodAdditionalFeeTaxClassId) - - + +
    @@ -336,6 +330,5 @@ @Html.ValidationMessageFor(model => model.VatRequired) - } \ No newline at end of file From dd74f1328433631b91676934691606822164a58a Mon Sep 17 00:00:00 2001 From: Marcus Gesing Date: Mon, 4 Jan 2016 17:09:19 +0100 Subject: [PATCH 208/707] Permission list: Added label with permission category --- .../201506181858349_AclRecordCustomerRole.cs | 8 +-- .../201512151526290_ImportFramework.cs | 17 +++++ .../Security/PermissionService.cs | 16 +++-- .../Controllers/SecurityController.cs | 71 ++++++++++--------- .../Models/Security/PermissionRecordModel.cs | 22 +++++- .../Views/Security/Permissions.cshtml | 26 ++++--- 6 files changed, 105 insertions(+), 55 deletions(-) diff --git a/src/Libraries/SmartStore.Data/Migrations/201506181858349_AclRecordCustomerRole.cs b/src/Libraries/SmartStore.Data/Migrations/201506181858349_AclRecordCustomerRole.cs index 655737641f..d8c20d54d3 100644 --- a/src/Libraries/SmartStore.Data/Migrations/201506181858349_AclRecordCustomerRole.cs +++ b/src/Libraries/SmartStore.Data/Migrations/201506181858349_AclRecordCustomerRole.cs @@ -123,13 +123,13 @@ before you can assign them to all subcategories and products.
    builder.AddOrUpdate("Admin.Configuration.Settings.Catalog.ShowManufacturersOnHomepage", "Show manufacturers on homepage", "Zeige Hersteller auf der Homepage", - "Specifies whether manufacturers will be displayed on the homepage.", + "Specifies whether manufacturers are displayed on the homepage.", "Legt fest, ob Hersteller auf der Homepage angezeigt werden."); builder.AddOrUpdate("Admin.Configuration.Settings.Catalog.ShowManufacturerPictures", "Show manufacturer pictures on homepage", "Zeige Herstellerbilder auf der Homepage", - "Specifies whether manufacturers will be displayed as images or textual links on the homepage.", + "Specifies whether manufacturers are displayed as images or textual links on the homepage.", "Legt fest, ob Hersteller auf der Homepage als Bilder oder textuelle Links angezeigt werden."); builder.AddOrUpdate("Admin.Configuration.Settings.CustomerUser.CustomerNumberEnabled", @@ -145,8 +145,8 @@ before you can assign them to all subcategories and products.
    builder.AddOrUpdate("Admin.Configuration.Settings.Tax.VatRequired", "Customers must enter a VATIN", "Kunden mssen eine Steuernummer angeben", - "Specifies whether Customers must enter a VAT identification number.", - "Legt fest, ob Kunden bei der Registrierung eine Steuernummer angeben mssen."); + "Specifies whether customers must enter a VAT identification number.", + "Legt fest, ob Kunden bei der Registrierung eine Steuernummer angeben mssen."); builder.AddOrUpdate("Account.Fields.Vat.Required", "Please enter your VATIN", diff --git a/src/Libraries/SmartStore.Data/Migrations/201512151526290_ImportFramework.cs b/src/Libraries/SmartStore.Data/Migrations/201512151526290_ImportFramework.cs index 2073f9aecc..1c6e87e649 100644 --- a/src/Libraries/SmartStore.Data/Migrations/201512151526290_ImportFramework.cs +++ b/src/Libraries/SmartStore.Data/Migrations/201512151526290_ImportFramework.cs @@ -278,6 +278,23 @@ public void MigrateLocaleResources(LocaleResourcesBuilder builder) "Zeichenkette prfen", "Enter any string to check the SEO name creation. Changed settings must be saved before.", "Geben Sie eine beliebige Zeichenkette ein, um daraus den SEO Namen zu erstellen. Genderte Einstellungen mssen zuvor gespeichert werden."); + + + builder.AddOrUpdate("Admin.System.Warnings.NoPermissionsDefined", + "There are no permissions defined.", + "Es sind keine Zugriffsrechte festgelegt."); + + builder.AddOrUpdate("Admin.System.Warnings.NoCustomerRolesDefined", + "There are no customer roles defined.", + "Es sind keine Kundengruppen festgelegt."); + + builder.AddOrUpdate("Admin.System.Warnings.AccessDeniedToAnonymousRequest", + "Access denied to anonymous request on {0}.", + "Zugriffsverweigerung durch anonyme Anfrage bei {0}."); + + builder.AddOrUpdate("Admin.System.Warnings.AccessDeniedToUser", + "Access denied to user #{0} '{1}' on {2}.", + "Zugriffsverweigerung durch Kunde #{0} '{1}' bei {2}."); } } } diff --git a/src/Libraries/SmartStore.Services/Security/PermissionService.cs b/src/Libraries/SmartStore.Services/Security/PermissionService.cs index 3ea2815466..a3ada9721a 100644 --- a/src/Libraries/SmartStore.Services/Security/PermissionService.cs +++ b/src/Libraries/SmartStore.Services/Security/PermissionService.cs @@ -10,10 +10,10 @@ namespace SmartStore.Services.Security { - /// - /// Permission service - /// - public partial class PermissionService : IPermissionService + /// + /// Permission service + /// + public partial class PermissionService : IPermissionService { #region Constants /// @@ -141,9 +141,11 @@ orderby pr.Id /// Permissions public virtual IList GetAllPermissionRecords() { - var query = from pr in _permissionRecordRepository.Table - orderby pr.Name - select pr; + var query = + from pr in _permissionRecordRepository.Table + orderby pr.Category, pr.Name + select pr; + var permissions = query.ToList(); return permissions; } diff --git a/src/Presentation/SmartStore.Web/Administration/Controllers/SecurityController.cs b/src/Presentation/SmartStore.Web/Administration/Controllers/SecurityController.cs index 794c33e0f8..45b5aa901a 100644 --- a/src/Presentation/SmartStore.Web/Administration/Controllers/SecurityController.cs +++ b/src/Presentation/SmartStore.Web/Administration/Controllers/SecurityController.cs @@ -1,13 +1,11 @@ -using System; -using System.Collections.Generic; +using System.Collections.Generic; using System.Linq; using System.Web.Mvc; using SmartStore.Admin.Models.Customers; using SmartStore.Admin.Models.Security; using SmartStore.Core; -using SmartStore.Services.Customers; -using SmartStore.Services.Localization; using SmartStore.Core.Logging; +using SmartStore.Services.Customers; using SmartStore.Services.Security; using SmartStore.Web.Framework.Controllers; using SmartStore.Web.Framework.Security; @@ -22,7 +20,6 @@ public class SecurityController : AdminControllerBase private readonly IWorkContext _workContext; private readonly IPermissionService _permissionService; private readonly ICustomerService _customerService; - private readonly ILocalizationService _localizationService; #endregion @@ -30,12 +27,11 @@ public class SecurityController : AdminControllerBase public SecurityController(IWorkContext workContext, IPermissionService permissionService, - ICustomerService customerService, ILocalizationService localizationService) + ICustomerService customerService) { this._workContext = workContext; this._permissionService = permissionService; this._customerService = customerService; - this._localizationService = localizationService; } #endregion  @@ -45,14 +41,15 @@ public SecurityController(IWorkContext workContext, public ActionResult AccessDenied(string pageUrl) { var currentCustomer = _workContext.CurrentCustomer; + if (currentCustomer == null || currentCustomer.IsGuest()) { - Logger.Information(string.Format("Access denied to anonymous request on {0}", pageUrl)); + Logger.Information(T("Admin.System.Warnings.AccessDeniedToAnonymousRequest", pageUrl.NaIfEmpty())); return View(); } - Logger.Information(string.Format("Access denied to user #{0} '{1}' on {2}", currentCustomer.Email, currentCustomer.Email, pageUrl)); - + Logger.Information(T("Admin.System.Warnings.AccessDeniedToUser", + currentCustomer.Email.NaIfEmpty(), currentCustomer.Email.NaIfEmpty(), pageUrl.NaIfEmpty())); return View(); } @@ -66,30 +63,38 @@ public ActionResult Permissions() var permissionRecords = _permissionService.GetAllPermissionRecords(); var customerRoles = _customerService.GetAllCustomerRoles(true); + foreach (var pr in permissionRecords) { - model.AvailablePermissions.Add(new PermissionRecordModel() + model.AvailablePermissions.Add(new PermissionRecordModel { Name = pr.Name, - SystemName = pr.SystemName + SystemName = pr.SystemName, + Category = pr.Category }); } + foreach (var cr in customerRoles) { - model.AvailableCustomerRoles.Add(new CustomerRoleModel() + model.AvailableCustomerRoles.Add(new CustomerRoleModel { Id = cr.Id, Name = cr.Name }); } - foreach (var pr in permissionRecords) - foreach (var cr in customerRoles) - { - bool allowed = pr.CustomerRoles.Where(x => x.Id == cr.Id).ToList().Count() > 0; - if (!model.Allowed.ContainsKey(pr.SystemName)) - model.Allowed[pr.SystemName] = new Dictionary(); - model.Allowed[pr.SystemName][cr.Id] = allowed; - } + + foreach (var pr in permissionRecords) + { + foreach (var cr in customerRoles) + { + var allowed = pr.CustomerRoles.Any(x => x.Id == cr.Id); + + if (!model.Allowed.ContainsKey(pr.SystemName)) + model.Allowed[pr.SystemName] = new Dictionary(); + + model.Allowed[pr.SystemName][cr.Id] = allowed; + } + } return View(model); } @@ -103,38 +108,38 @@ public ActionResult PermissionsSave(FormCollection form) var permissionRecords = _permissionService.GetAllPermissionRecords(); var customerRoles = _customerService.GetAllCustomerRoles(true); - foreach (var cr in customerRoles) { - string formKey = "allow_" + cr.Id; - var permissionRecordSystemNamesToRestrict = form[formKey] != null ? form[formKey].Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries).ToList() : new List(); + var restrictedSystemNames = form["allow_" + cr.Id.ToString()].SplitSafe(",").ToList(); - foreach (var pr in permissionRecords) + foreach (var permission in permissionRecords) { + bool allow = restrictedSystemNames.Contains(permission.SystemName); - bool allow = permissionRecordSystemNamesToRestrict.Contains(pr.SystemName); if (allow) { - if (pr.CustomerRoles.Where(x => x.Id == cr.Id).FirstOrDefault() == null) + if (!permission.CustomerRoles.Any(x => x.Id == cr.Id)) { - pr.CustomerRoles.Add(cr); - _permissionService.UpdatePermissionRecord(pr); + permission.CustomerRoles.Add(cr); + _permissionService.UpdatePermissionRecord(permission); } } else { - if (pr.CustomerRoles.Where(x => x.Id == cr.Id).FirstOrDefault() != null) + if (permission.CustomerRoles.Any(x => x.Id == cr.Id)) { - pr.CustomerRoles.Remove(cr); - _permissionService.UpdatePermissionRecord(pr); + permission.CustomerRoles.Remove(cr); + _permissionService.UpdatePermissionRecord(permission); } } } } - NotifySuccess(_localizationService.GetResource("Admin.Configuration.ACL.Updated")); + NotifySuccess(T("Admin.Configuration.ACL.Updated")); + return RedirectToAction("Permissions"); } + #endregion } } diff --git a/src/Presentation/SmartStore.Web/Administration/Models/Security/PermissionRecordModel.cs b/src/Presentation/SmartStore.Web/Administration/Models/Security/PermissionRecordModel.cs index 10840b978c..b444eaa04b 100644 --- a/src/Presentation/SmartStore.Web/Administration/Models/Security/PermissionRecordModel.cs +++ b/src/Presentation/SmartStore.Web/Administration/Models/Security/PermissionRecordModel.cs @@ -6,5 +6,25 @@ public class PermissionRecordModel : ModelBase { public string Name { get; set; } public string SystemName { get; set; } - } + public string Category { get; set; } + + public string CategoryLabel + { + get + { + switch (Category) + { + case "PublicStore": + case "Standard": + return "label-success"; + + case "Plugin": + return ""; + + default: + return "label-info"; + } + } + } + } } \ No newline at end of file diff --git a/src/Presentation/SmartStore.Web/Administration/Views/Security/Permissions.cshtml b/src/Presentation/SmartStore.Web/Administration/Views/Security/Permissions.cshtml index 0d02bfd4b2..743c8f9d8f 100644 --- a/src/Presentation/SmartStore.Web/Administration/Views/Security/Permissions.cshtml +++ b/src/Presentation/SmartStore.Web/Administration/Views/Security/Permissions.cshtml @@ -1,6 +1,6 @@ -@model PermissionMappingModel +@using SmartStore.Utilities; +@model PermissionMappingModel @{ - //page title ViewBag.Title = T("Admin.Configuration.ACL").Text; } @using (Html.BeginForm()) @@ -11,7 +11,9 @@ @T("Admin.Configuration.ACL")
    - +
    @@ -19,12 +21,16 @@ @if (Model.AvailablePermissions.Count == 0) - { - No permissions defined - } - else if (Model.AvailableCustomerRoles.Count == 0) - { - No customer roles available + { +
    + @T("Admin.System.Warnings.NoPermissionsDefined") +
    + } + else if (Model.AvailableCustomerRoles.Count == 0) + { +
    + @T("Admin.System.Warnings.NoCustomerRolesDefined") +
    } else { @@ -48,6 +54,7 @@ { + @Inflector.Titleize(pr.Category).NaIfEmpty() @pr.Name @foreach (var cr in Model.AvailableCustomerRoles) @@ -66,5 +73,4 @@ - } From 8f8a8afb04b0a4d778f83bb8d6fb16871e4cdbca Mon Sep 17 00:00:00 2001 From: Marcus Gesing Date: Mon, 4 Jan 2016 21:13:03 +0100 Subject: [PATCH 209/707] Resolves #26 Company or name in order list --- .../Controllers/OrderController.cs | 27 +- .../Models/Orders/OrderListModel.cs | 5 +- .../Models/Orders/OrderModel.cs | 3 + .../Administration/Views/Order/List.cshtml | 252 +++++++++--------- 4 files changed, 150 insertions(+), 137 deletions(-) diff --git a/src/Presentation/SmartStore.Web/Administration/Controllers/OrderController.cs b/src/Presentation/SmartStore.Web/Administration/Controllers/OrderController.cs index fd82849786..f7adf8147d 100644 --- a/src/Presentation/SmartStore.Web/Administration/Controllers/OrderController.cs +++ b/src/Presentation/SmartStore.Web/Administration/Controllers/OrderController.cs @@ -89,8 +89,9 @@ public partial class OrderController : AdminControllerBase private readonly MeasureSettings _measureSettings; private readonly PdfSettings _pdfSettings; private readonly AddressSettings _addressSettings; + private readonly AdminAreaSettings _adminAreaSettings; - private readonly ICheckoutAttributeFormatter _checkoutAttributeFormatter; + private readonly ICheckoutAttributeFormatter _checkoutAttributeFormatter; private readonly IPdfConverter _pdfConverter; private readonly ICommonServices _services; private readonly Lazy _pictureService; @@ -124,7 +125,8 @@ public OrderController(IOrderService orderService, ICustomerActivityService customerActivityService, CatalogSettings catalogSettings, CurrencySettings currencySettings, TaxSettings taxSettings, MeasureSettings measureSettings, PdfSettings pdfSettings, AddressSettings addressSettings, - IPdfConverter pdfConverter, ICommonServices services, Lazy pictureService) + AdminAreaSettings adminAreaSettings, + IPdfConverter pdfConverter, ICommonServices services, Lazy pictureService) { this._orderService = orderService; this._orderReportService = orderReportService; @@ -167,6 +169,7 @@ public OrderController(IOrderService orderService, this._measureSettings = measureSettings; this._pdfSettings = pdfSettings; this._addressSettings = addressSettings; + this._adminAreaSettings = adminAreaSettings; this._checkoutAttributeFormatter = checkoutAttributeFormatter; _pdfConverter = pdfConverter; @@ -787,15 +790,20 @@ public ActionResult List(OrderListModel model) if (!_permissionService.Authorize(StandardPermissionProvider.ManageOrders)) return AccessDeniedView(); - model.AvailableOrderStatuses = OrderStatus.Pending.ToSelectList(false).ToList(); + var allStores = _storeService.GetAllStores(); + + model.AvailableOrderStatuses = OrderStatus.Pending.ToSelectList(false).ToList(); model.AvailablePaymentStatuses = PaymentStatus.Pending.ToSelectList(false).ToList(); model.AvailableShippingStatuses = ShippingStatus.NotYetShipped.ToSelectList(false).ToList(); - //stores - model.AvailableStores.AddRange(_storeService.GetAllStores().ToList().ToSelectListItems()); - model.AvailableStores.Insert(0, new SelectListItem() { Text = _localizationService.GetResource("Admin.Common.All"), Value = "0" }); + model.AvailableStores = allStores + .Select(x => new SelectListItem { Text = x.Name, Value = x.Id.ToString() }) + .ToList(); - return View(model); + model.GridPageSize = _adminAreaSettings.GridPageSize; + model.StoreCount = allStores.Count; + + return View(model); } [GridAction(EnableCustomBinding = true)] @@ -823,12 +831,13 @@ public ActionResult OrderList(GridCommand command, OrderListModel model) { Id = x.Id, OrderNumber = x.GetOrderNumber(), - StoreName = store != null ? store.Name : "Unknown", + StoreName = (store != null ? store.Name : "".NaIfEmpty()), OrderTotal = _priceFormatter.FormatPrice(x.OrderTotal, true, false), OrderStatus = x.OrderStatus.GetLocalizedEnum(_localizationService, _workContext), PaymentStatus = x.PaymentStatus.GetLocalizedEnum(_localizationService, _workContext), ShippingStatus = x.ShippingStatus.GetLocalizedEnum(_localizationService, _workContext), - CustomerEmail = x.BillingAddress.Email, + CustomerName = x.BillingAddress.GetFullName(), + CustomerEmail = x.BillingAddress.Email, CreatedOn = _dateTimeHelper.ConvertToUserTime(x.CreatedOnUtc, DateTimeKind.Utc), HasNewPaymentNotification = x.HasNewPaymentNotification }; diff --git a/src/Presentation/SmartStore.Web/Administration/Models/Orders/OrderListModel.cs b/src/Presentation/SmartStore.Web/Administration/Models/Orders/OrderListModel.cs index 2d64f5216c..8fc20246ad 100644 --- a/src/Presentation/SmartStore.Web/Administration/Models/Orders/OrderListModel.cs +++ b/src/Presentation/SmartStore.Web/Administration/Models/Orders/OrderListModel.cs @@ -54,9 +54,10 @@ public OrderListModel() [AllowHtml] public string GoDirectlyToNumber { get; set; } - + public int GridPageSize { get; set; } + public int StoreCount { get; set; } - public IList AvailableOrderStatuses { get; set; } + public IList AvailableOrderStatuses { get; set; } public IList AvailablePaymentStatuses { get; set; } public IList AvailableShippingStatuses { get; set; } public IList AvailableStores { get; set; } diff --git a/src/Presentation/SmartStore.Web/Administration/Models/Orders/OrderModel.cs b/src/Presentation/SmartStore.Web/Administration/Models/Orders/OrderModel.cs index 17c2b7be51..c622929029 100644 --- a/src/Presentation/SmartStore.Web/Administration/Models/Orders/OrderModel.cs +++ b/src/Presentation/SmartStore.Web/Administration/Models/Orders/OrderModel.cs @@ -37,10 +37,13 @@ public OrderModel() //customer info [SmartResourceDisplayName("Admin.Orders.Fields.Customer")] public int CustomerId { get; set; } + + [SmartResourceDisplayName("Admin.Orders.List.CustomerName")] public string CustomerName { get; set; } [SmartResourceDisplayName("Admin.Orders.Fields.CustomerEmail")] public string CustomerEmail { get; set; } + [SmartResourceDisplayName("Admin.Orders.Fields.CustomerIP")] public string CustomerIp { get; set; } diff --git a/src/Presentation/SmartStore.Web/Administration/Views/Order/List.cshtml b/src/Presentation/SmartStore.Web/Administration/Views/Order/List.cshtml index 3e50f7232c..47e12fdb99 100644 --- a/src/Presentation/SmartStore.Web/Administration/Views/Order/List.cshtml +++ b/src/Presentation/SmartStore.Web/Administration/Views/Order/List.cshtml @@ -1,10 +1,10 @@ @model OrderListModel @using Telerik.Web.Mvc.UI @{ - var gridPageSize = EngineContext.Current.Resolve().GridPageSize; - var hideProfitReport = false; - - ViewBag.Title = T("Admin.Orders").Text; + var hideProfitReport = false; + var allString = T("Admin.Common.All").Text; + + ViewBag.Title = T("Admin.Orders").Text; } @using (Html.BeginForm()) @@ -39,39 +39,40 @@ @Html.Widget("admin_button_toolbar_after") - - - - - - - - - - - - - - - - - + +
    - @Html.SmartLabelFor(model => model.StartDate) - - @Html.EditorFor(model => model.StartDate) -
    - @Html.SmartLabelFor(model => model.EndDate) - - @Html.EditorFor(model => Model.EndDate) -
    - @Html.SmartLabelFor(model => model.CustomerName) - - @Html.EditorFor(model => Model.CustomerName) -
    - @Html.SmartLabelFor(model => model.CustomerEmail) - - @Html.EditorFor(model => Model.CustomerEmail) -
    + + + + + + + + + + + + + + + + - - - + + - - - - - - - - - + + - - - + + + + @if (Model.StoreCount > 1) + { + + + + + } - - - - - - + + + + + + + + + - - - - - -
    + @Html.SmartLabelFor(model => model.StartDate) + + @Html.EditorFor(model => model.StartDate) +
    + @Html.SmartLabelFor(model => model.EndDate) + + @Html.EditorFor(model => Model.EndDate) +
    + @Html.SmartLabelFor(model => model.CustomerName) + + @Html.EditorFor(model => Model.CustomerName) +
    + @Html.SmartLabelFor(model => model.CustomerEmail) + + @Html.EditorFor(model => Model.CustomerEmail) +
    @Html.SmartLabelFor(model => model.OrderStatusIds) @@ -80,69 +81,72 @@ @Html.DropDownList("OrderStatusIds", Model.AvailableOrderStatuses, null, new { multiple = "multiple" })
    - @Html.SmartLabelFor(model => model.PaymentStatusIds) - +
    + @Html.SmartLabelFor(model => model.PaymentStatusIds) + @Html.DropDownList("PaymentStatusIds", Model.AvailablePaymentStatuses, null, new { multiple = "multiple" }) -
    - @Html.SmartLabelFor(model => model.ShippingStatusIds) - - @Html.DropDownList("ShippingStatusIds", Model.AvailableShippingStatuses, null, new { multiple = "multiple" }) -
    - @Html.SmartLabelFor(model => model.StoreId) - - @Html.DropDownList("StoreId", Model.AvailableStores) -
    - @Html.SmartLabelFor(model => model.OrderGuid) - - @Html.EditorFor(model => Model.OrderGuid) -
    + @Html.SmartLabelFor(model => model.ShippingStatusIds) + + @Html.DropDownList("ShippingStatusIds", Model.AvailableShippingStatuses, null, new { multiple = "multiple" }) +
    + @Html.SmartLabelFor(model => model.StoreId) + + @Html.DropDownListFor(model => model.StoreId, Model.AvailableStores, allString) +
    - @Html.SmartLabelFor(model => model.OrderNumber) - - @Html.EditorFor(model => Model.OrderNumber) -
    - @Html.SmartLabelFor(model => model.GoDirectlyToNumber) - - @Html.EditorFor(model => Model.GoDirectlyToNumber) - + @Html.SmartLabelFor(model => model.OrderGuid) + + @Html.EditorFor(model => Model.OrderGuid) +
    + @Html.SmartLabelFor(model => model.OrderNumber) + + @Html.EditorFor(model => Model.OrderNumber) +
    + @Html.SmartLabelFor(model => model.GoDirectlyToNumber) + + @Html.EditorFor(model => Model.GoDirectlyToNumber) + -
    -   - - -
    + + + + +   + + + + + +

    @@ -150,29 +154,31 @@ @(Html.Telerik().Grid() - .Name("orders-grid") - .ClientEvents(events => events - .OnDataBinding("onDataBinding") - .OnDataBound("onDataBound") - .OnComplete("onComplete")) - .Columns(columns => - { - columns.Bound(x => x.Id) - .ClientTemplate("") - .Title("") - .Width(50) - .HtmlAttributes(new { style = "text-align:center" }) - .HeaderHtmlAttributes(new { style = "text-align:center" }); + .Name("orders-grid") + .ClientEvents(events => events + .OnDataBinding("onDataBinding") + .OnDataBound("onDataBound") + .OnComplete("onComplete")) + .Columns(columns => + { + columns.Bound(x => x.Id) + .ClientTemplate("") + .Title("") + .Width(50) + .HtmlAttributes(new { style = "text-align:center" }) + .HeaderHtmlAttributes(new { style = "text-align:center" }); - columns.Bound(x => x.OrderNumber) + columns.Bound(x => x.OrderNumber) .ClientTemplate(@Html.LabeledOrderNumber()); - columns.Bound(x => x.OrderStatus); - columns.Bound(x => x.PaymentStatus); - columns.Bound(x => x.ShippingStatus); - columns.Bound(x => x.CustomerEmail); - columns.Bound(x => x.StoreName); - columns.Bound(x => x.CreatedOn); - columns.Bound(x => x.OrderTotal) + columns.Bound(x => x.OrderStatus); + columns.Bound(x => x.PaymentStatus); + columns.Bound(x => x.ShippingStatus); + columns.Bound(x => x.CustomerName); + columns.Bound(x => x.CustomerEmail); + columns.Bound(x => x.StoreName) + .Hidden(Model.StoreCount <= 1); + columns.Bound(x => x.CreatedOn); + columns.Bound(x => x.OrderTotal) .Width(180) .RightAlign() .FooterTemplate( @@ -184,17 +190,11 @@ (hideProfitReport ? "" : @T("Admin.Orders.Report.Profit").Text), @T("Admin.Orders.Report.Tax").Text, @T("Admin.Orders.Report.Total").Text)); - columns.Bound(x => x.Id) - .Template(x => Html.ActionLink(T("Admin.Common.View").Text, "Edit", new { id = x.Id })) - .ClientTemplate("\">" + T("Admin.Common.View").Text + "") - .Width(50) - .Centered() - .Title(T("Admin.Common.View").Text); - }) - .Pageable(settings => settings.PageSize(gridPageSize).Position(GridPagerPosition.Both)) - .DataBinding(dataBinding => dataBinding.Ajax().Select("OrderList", "Order")) + }) + .Pageable(settings => settings.PageSize(Model.GridPageSize).Position(GridPagerPosition.Both)) + .DataBinding(dataBinding => dataBinding.Ajax().Select("OrderList", "Order")) .PreserveGridState() - .EnableCustomBinding(true)) + .EnableCustomBinding(true)) From 203765ac463601a49c5d41624186d4cbd1d744d4 Mon Sep 17 00:00:00 2001 From: Marcus Gesing Date: Mon, 4 Jan 2016 21:18:41 +0100 Subject: [PATCH 210/707] Updated changelog --- changelog.md | 1 + 1 file changed, 1 insertion(+) diff --git a/changelog.md b/changelog.md index ac7dd3701f..2decbbfa2f 100644 --- a/changelog.md +++ b/changelog.md @@ -65,6 +65,7 @@ * Simplified handling of SEO names * URLs are not converted to lower case anymore * Product grid sortable by name, price and created on +* #26 Display company or name in order list ### Bugfixes * #523 Redirecting to payment provider performed by core instead of plugin From 2d07edba69861ffb3ddaa25b73181f686b10e457 Mon Sep 17 00:00:00 2001 From: Marcus Gesing Date: Tue, 5 Jan 2016 12:33:42 +0100 Subject: [PATCH 211/707] Added inline editing of country grid. Also resolves #96 --- changelog.md | 1 + .../201512151526290_ImportFramework.cs | 4 + .../Stores/StoreMappingService.cs | 2 +- .../Controllers/SmartController.cs | 17 ++ .../Controllers/CountryController.cs | 189 ++++++++++-------- .../Models/Directory/CountryListModel.cs | 9 + .../Administration/SmartStore.Admin.csproj | 1 + .../Administration/Views/Country/List.cshtml | 112 ++++++----- 8 files changed, 203 insertions(+), 132 deletions(-) create mode 100644 src/Presentation/SmartStore.Web/Administration/Models/Directory/CountryListModel.cs diff --git a/changelog.md b/changelog.md index 2decbbfa2f..72610122db 100644 --- a/changelog.md +++ b/changelog.md @@ -66,6 +66,7 @@ * URLs are not converted to lower case anymore * Product grid sortable by name, price and created on * #26 Display company or name in order list +* Added inline editing of country grid ### Bugfixes * #523 Redirecting to payment provider performed by core instead of plugin diff --git a/src/Libraries/SmartStore.Data/Migrations/201512151526290_ImportFramework.cs b/src/Libraries/SmartStore.Data/Migrations/201512151526290_ImportFramework.cs index 1c6e87e649..24f368ef69 100644 --- a/src/Libraries/SmartStore.Data/Migrations/201512151526290_ImportFramework.cs +++ b/src/Libraries/SmartStore.Data/Migrations/201512151526290_ImportFramework.cs @@ -295,6 +295,10 @@ public void MigrateLocaleResources(LocaleResourcesBuilder builder) builder.AddOrUpdate("Admin.System.Warnings.AccessDeniedToUser", "Access denied to user #{0} '{1}' on {2}.", "Zugriffsverweigerung durch Kunde #{0} '{1}' bei {2}."); + + builder.AddOrUpdate("Admin.Configuration.Countries.CannotDeleteDueToAssociatedAddresses", + "The country cannaot be deleted because it has associated addresses.", + "Das Land kann nicht gelscht werden, weil ihm Adressen zugeordnet sind."); } } } diff --git a/src/Libraries/SmartStore.Services/Stores/StoreMappingService.cs b/src/Libraries/SmartStore.Services/Stores/StoreMappingService.cs index da282801ef..04ff4206ff 100644 --- a/src/Libraries/SmartStore.Services/Stores/StoreMappingService.cs +++ b/src/Libraries/SmartStore.Services/Stores/StoreMappingService.cs @@ -219,7 +219,7 @@ public virtual void UpdateStoreMapping(StoreMapping storeMapping) public virtual int[] GetStoresIdsWithAccess(T entity) where T : BaseEntity, IStoreMappingSupported { if (entity == null) - throw new ArgumentNullException("entity"); + return new int[0]; int entityId = entity.Id; string entityName = typeof(T).Name; diff --git a/src/Presentation/SmartStore.Web.Framework/Controllers/SmartController.cs b/src/Presentation/SmartStore.Web.Framework/Controllers/SmartController.cs index 3b6cf51813..a5169e45c4 100644 --- a/src/Presentation/SmartStore.Web.Framework/Controllers/SmartController.cs +++ b/src/Presentation/SmartStore.Web.Framework/Controllers/SmartController.cs @@ -95,6 +95,23 @@ protected virtual void NotifyError(Exception exception, bool durable = true, boo Services.Notifier.Error(exception.ToAllMessages(), durable); } + /// + /// Pushes an error message to the notification queue that the access to a resource has been denied + /// + /// A value indicating whether a message should be persisted for the next request + /// A value indicating whether the message should be logged + protected virtual void NotifyAccessDenied(bool durable = true, bool log = false) + { + var message = T("Admin.AccessDenied.Description"); + + if (log) + { + Logger.Error(message, null, Services.WorkContext.CurrentCustomer); + } + + Services.Notifier.Error(message, durable); + } + protected virtual ActionResult RedirectToReferrer() { if (Request.UrlReferrer != null && Request.UrlReferrer.ToString().HasValue()) diff --git a/src/Presentation/SmartStore.Web/Administration/Controllers/CountryController.cs b/src/Presentation/SmartStore.Web/Administration/Controllers/CountryController.cs index 17300117c2..bf67df0dae 100644 --- a/src/Presentation/SmartStore.Web/Administration/Controllers/CountryController.cs +++ b/src/Presentation/SmartStore.Web/Administration/Controllers/CountryController.cs @@ -3,8 +3,8 @@ using System.Linq; using System.Web.Mvc; using SmartStore.Admin.Models.Directory; -using SmartStore.Core; using SmartStore.Core.Domain.Directory; +using SmartStore.Services; using SmartStore.Services.Common; using SmartStore.Services.Directory; using SmartStore.Services.Localization; @@ -24,37 +24,31 @@ public class CountryController : AdminControllerBase private readonly ICountryService _countryService; private readonly IStateProvinceService _stateProvinceService; - private readonly ILocalizationService _localizationService; private readonly IAddressService _addressService; - private readonly IPermissionService _permissionService; private readonly ILocalizedEntityService _localizedEntityService; private readonly ILanguageService _languageService; - private readonly IStoreService _storeService; private readonly IStoreMappingService _storeMappingService; + private readonly ICommonServices _services; - #endregion + #endregion #region Constructors - public CountryController(ICountryService countryService, + public CountryController(ICountryService countryService, IStateProvinceService stateProvinceService, - ILocalizationService localizationService, IAddressService addressService, - IPermissionService permissionService, ILocalizedEntityService localizedEntityService, ILanguageService languageService, - IStoreService storeService, - IStoreMappingService storeMappingService) + IStoreMappingService storeMappingService, + ICommonServices services) { _countryService = countryService; _stateProvinceService = stateProvinceService; - _localizationService = localizationService; _addressService = addressService; - _permissionService = permissionService; _localizedEntityService = localizedEntityService; _languageService = languageService; - _storeService = storeService; _storeMappingService = storeMappingService; + _services = services; } #endregion  @@ -66,10 +60,7 @@ private void UpdateLocales(Country country, CountryModel model) { foreach (var localized in model.Locales) { - _localizedEntityService.SaveLocalizedValue(country, - x => x.Name, - localized.Name, - localized.LanguageId); + _localizedEntityService.SaveLocalizedValue(country, x => x.Name, localized.Name, localized.LanguageId); } } @@ -78,10 +69,7 @@ private void UpdateLocales(StateProvince stateProvince, StateProvinceModel model { foreach (var localized in model.Locales) { - _localizedEntityService.SaveLocalizedValue(stateProvince, - x => x.Name, - localized.Name, - localized.LanguageId); + _localizedEntityService.SaveLocalizedValue(stateProvince, x => x.Name, localized.Name, localized.LanguageId); } } @@ -91,19 +79,14 @@ private void PrepareCountryModel(CountryModel model, Country country, bool exclu if (model == null) throw new ArgumentNullException("model"); - var allStores = _storeService.GetAllStores(); + var allStores = _services.StoreService.GetAllStores(); model.AvailableStores = allStores.Select(s => s.ToModel()).ToList(); if (!excludeProperties) { - if (country != null) - model.SelectedStoreIds = _storeMappingService.GetStoresIdsWithAccess(country); - else - model.SelectedStoreIds = new int[0]; + model.SelectedStoreIds = _storeMappingService.GetStoresIdsWithAccess(country); } - - ViewBag.StoreCount = allStores.Count; } #endregion @@ -117,40 +100,85 @@ public ActionResult Index() public ActionResult List() { - if (!_permissionService.Authorize(StandardPermissionProvider.ManageCountries)) + if (!_services.Permissions.Authorize(StandardPermissionProvider.ManageCountries)) return AccessDeniedView(); - var countries = _countryService.GetAllCountries(true); - var model = new GridModel - { - Data = countries.Select(x => x.ToModel()), - Total = countries.Count - }; - return View(model); + var allStores = _services.StoreService.GetAllStores(); + + var model = new CountryListModel + { + StoreCount = allStores.Count + }; + + return View(model); } [HttpPost, GridAction(EnableCustomBinding = true)] public ActionResult CountryList(GridCommand command) { - if (!_permissionService.Authorize(StandardPermissionProvider.ManageCountries)) - return AccessDeniedView(); + var model = new GridModel(); - var countries = _countryService.GetAllCountries(true); - var model = new GridModel - { - Data = countries.Select(x => x.ToModel()), - Total = countries.Count - }; + if (_services.Permissions.Authorize(StandardPermissionProvider.ManageCountries)) + { + var countries = _countryService.GetAllCountries(true); + + model.Data = countries.Select(x => x.ToModel()); + model.Total = countries.Count; + } + else + { + model.Data = Enumerable.Empty(); + + NotifyAccessDenied(); + } return new JsonResult { Data = model }; } - - public ActionResult Create() + + [GridAction(EnableCustomBinding = true)] + public ActionResult CountryUpdate(CountryModel model, GridCommand command) + { + if (_services.Permissions.Authorize(StandardPermissionProvider.ManageCountries)) + { + if (!ModelState.IsValid) + { + var modelStateErrors = ModelState.Values.SelectMany(x => x.Errors).Select(x => x.ErrorMessage); + return Content(modelStateErrors.FirstOrDefault()); + } + + var country = _countryService.GetCountryById(model.Id); + + country = model.ToEntity(country); + _countryService.UpdateCountry(country); + } + + return CountryList(command); + } + + [GridAction(EnableCustomBinding = true)] + public ActionResult CountryDelete(int id, GridCommand command) + { + if (_services.Permissions.Authorize(StandardPermissionProvider.ManageCountries)) + { + if (_addressService.GetAddressTotalByCountryId(id) > 0) + { + return Content(T("Admin.Configuration.Countries.CannotDeleteDueToAssociatedAddresses")); + } + + var country = _countryService.GetCountryById(id); + + _countryService.DeleteCountry(country); + } + + return CountryList(command); + } + + public ActionResult Create() { - if (!_permissionService.Authorize(StandardPermissionProvider.ManageCountries)) + if (!_services.Permissions.Authorize(StandardPermissionProvider.ManageCountries)) return AccessDeniedView(); var model = new CountryModel(); @@ -169,7 +197,7 @@ public ActionResult Create() [HttpPost, ParameterBasedOnFormName("save-continue", "continueEditing")] public ActionResult Create(CountryModel model, bool continueEditing) { - if (!_permissionService.Authorize(StandardPermissionProvider.ManageCountries)) + if (!_services.Permissions.Authorize(StandardPermissionProvider.ManageCountries)) return AccessDeniedView(); if (ModelState.IsValid) @@ -181,7 +209,7 @@ public ActionResult Create(CountryModel model, bool continueEditing) _storeMappingService.SaveStoreMappings(country, model.SelectedStoreIds); - NotifySuccess(_localizationService.GetResource("Admin.Configuration.Countries.Added")); + NotifySuccess(T("Admin.Configuration.Countries.Added")); return continueEditing ? RedirectToAction("Edit", new { id = country.Id }) : RedirectToAction("List"); } @@ -193,7 +221,7 @@ public ActionResult Create(CountryModel model, bool continueEditing) public ActionResult Edit(int id) { - if (!_permissionService.Authorize(StandardPermissionProvider.ManageCountries)) + if (!_services.Permissions.Authorize(StandardPermissionProvider.ManageCountries)) return AccessDeniedView(); var country = _countryService.GetCountryById(id); @@ -215,7 +243,7 @@ public ActionResult Edit(int id) [HttpPost, ParameterBasedOnFormName("save-continue", "continueEditing")] public ActionResult Edit(CountryModel model, bool continueEditing) { - if (!_permissionService.Authorize(StandardPermissionProvider.ManageCountries)) + if (!_services.Permissions.Authorize(StandardPermissionProvider.ManageCountries)) return AccessDeniedView(); var country = _countryService.GetCountryById(model.Id); @@ -231,7 +259,7 @@ public ActionResult Edit(CountryModel model, bool continueEditing) _storeMappingService.SaveStoreMappings(country, model.SelectedStoreIds); - NotifySuccess(_localizationService.GetResource("Admin.Configuration.Countries.Updated")); + NotifySuccess(T("Admin.Configuration.Countries.Updated")); return continueEditing ? RedirectToAction("Edit", new { id = country.Id }) : RedirectToAction("List"); } @@ -244,7 +272,7 @@ public ActionResult Edit(CountryModel model, bool continueEditing) [HttpPost, ActionName("Delete")] public ActionResult DeleteConfirmed(int id) { - if (!_permissionService.Authorize(StandardPermissionProvider.ManageCountries)) + if (!_services.Permissions.Authorize(StandardPermissionProvider.ManageCountries)) return AccessDeniedView(); var country = _countryService.GetCountryById(id); @@ -254,11 +282,12 @@ public ActionResult DeleteConfirmed(int id) try { if (_addressService.GetAddressTotalByCountryId(country.Id) > 0) - throw new SmartException("The country can't be deleted. It has associated addresses"); + throw new SmartException(T("Admin.Configuration.Countries.CannotDeleteDueToAssociatedAddresses")); _countryService.DeleteCountry(country); - NotifySuccess(_localizationService.GetResource("Admin.Configuration.Countries.Deleted")); + NotifySuccess(T("Admin.Configuration.Countries.Deleted")); + return RedirectToAction("List"); } catch (Exception exc) @@ -268,7 +297,6 @@ public ActionResult DeleteConfirmed(int id) } } - #endregion #region States / provinces @@ -276,7 +304,7 @@ public ActionResult DeleteConfirmed(int id) [HttpPost, GridAction(EnableCustomBinding = true)] public ActionResult States(int countryId, GridCommand command) { - if (!_permissionService.Authorize(StandardPermissionProvider.ManageCountries)) + if (!_services.Permissions.Authorize(StandardPermissionProvider.ManageCountries)) return AccessDeniedView(); var states = _stateProvinceService.GetStateProvincesByCountryId(countryId, true) @@ -287,30 +315,33 @@ public ActionResult States(int countryId, GridCommand command) Data = states, Total = states.Count() }; + return new JsonResult { Data = model }; } - //create public ActionResult StateCreatePopup(int countryId) { - if (!_permissionService.Authorize(StandardPermissionProvider.ManageCountries)) + if (!_services.Permissions.Authorize(StandardPermissionProvider.ManageCountries)) return AccessDeniedView(); - var model = new StateProvinceModel(); - model.CountryId = countryId; - //locales + var model = new StateProvinceModel + { + CountryId = countryId + }; + AddLocales(_languageService, model.Locales); + return View(model); } [HttpPost] public ActionResult StateCreatePopup(string btnId, string formId, StateProvinceModel model) { - if (!_permissionService.Authorize(StandardPermissionProvider.ManageCountries)) + if (!_services.Permissions.Authorize(StandardPermissionProvider.ManageCountries)) return AccessDeniedView(); var country = _countryService.GetCountryById(model.CountryId); @@ -327,6 +358,7 @@ public ActionResult StateCreatePopup(string btnId, string formId, StateProvinceM ViewBag.RefreshPage = true; ViewBag.btnId = btnId; ViewBag.formId = formId; + return View(model); } @@ -337,16 +369,15 @@ public ActionResult StateCreatePopup(string btnId, string formId, StateProvinceM //edit public ActionResult StateEditPopup(int id) { - if (!_permissionService.Authorize(StandardPermissionProvider.ManageCountries)) + if (!_services.Permissions.Authorize(StandardPermissionProvider.ManageCountries)) return AccessDeniedView(); var sp = _stateProvinceService.GetStateProvinceById(id); if (sp == null) - //No state found with the specified id return RedirectToAction("List"); var model = sp.ToModel(); - //locales + AddLocales(_languageService, model.Locales, (locale, languageId) => { locale.Name = sp.GetLocalized(x => x.Name, languageId, false, false); @@ -358,12 +389,11 @@ public ActionResult StateEditPopup(int id) [HttpPost] public ActionResult StateEditPopup(string btnId, string formId, StateProvinceModel model) { - if (!_permissionService.Authorize(StandardPermissionProvider.ManageCountries)) + if (!_services.Permissions.Authorize(StandardPermissionProvider.ManageCountries)) return AccessDeniedView(); var sp = _stateProvinceService.GetStateProvinceById(model.Id); if (sp == null) - //No state found with the specified id return RedirectToAction("List"); if (ModelState.IsValid) @@ -376,6 +406,7 @@ public ActionResult StateEditPopup(string btnId, string formId, StateProvinceMod ViewBag.RefreshPage = true; ViewBag.btnId = btnId; ViewBag.formId = formId; + return View(model); } @@ -386,7 +417,7 @@ public ActionResult StateEditPopup(string btnId, string formId, StateProvinceMod [GridAction(EnableCustomBinding = true)] public ActionResult StateDelete(int id, GridCommand command) { - if (!_permissionService.Authorize(StandardPermissionProvider.ManageCountries)) + if (!_services.Permissions.Authorize(StandardPermissionProvider.ManageCountries)) return AccessDeniedView(); var state = _stateProvinceService.GetStateProvinceById(id); @@ -394,35 +425,31 @@ public ActionResult StateDelete(int id, GridCommand command) throw new ArgumentException("No state found with the specified id"); if (_addressService.GetAddressTotalByStateProvinceId(state.Id) > 0) - return Content(_localizationService.GetResource("Admin.Configuration.Countries.States.CantDeleteWithAddresses")); + return Content(T("Admin.Configuration.Countries.States.CantDeleteWithAddresses")); int countryId = state.CountryId; _stateProvinceService.DeleteStateProvince(state); - return States(countryId, command); } [AcceptVerbs(HttpVerbs.Get)] public ActionResult GetStatesByCountryId(string countryId, bool? addEmptyStateIfRequired, bool? addAsterisk) { - //permission validation is not required here - + // permission validation is not required here // This action method gets called via an ajax request - int cid = 0; - int.TryParse(countryId, out cid); - /*if (String.IsNullOrEmpty(countryId)) - throw new ArgumentNullException("countryId");*/ + var country = _countryService.GetCountryById(countryId.ToInt()); - var country = _countryService.GetCountryById(cid /* Convert.ToInt32(countryId) */); var states = country != null ? _stateProvinceService.GetStateProvincesByCountryId(country.Id, true).ToList() : new List(); - var result = (from s in states - select new { id = s.Id, name = s.Name }).ToList(); + var result = (from s in states select new { id = s.Id, name = s.Name }).ToList(); + if (addEmptyStateIfRequired.HasValue && addEmptyStateIfRequired.Value && result.Count == 0) - result.Insert(0, new { id = 0, name = _localizationService.GetResource("Admin.Address.OtherNonUS") }); + result.Insert(0, new { id = 0, name = T("Admin.Address.OtherNonUS").Text }); + if (addAsterisk.HasValue && addAsterisk.Value) result.Insert(0, new { id = 0, name = "*" }); + return Json(result, JsonRequestBehavior.AllowGet); } diff --git a/src/Presentation/SmartStore.Web/Administration/Models/Directory/CountryListModel.cs b/src/Presentation/SmartStore.Web/Administration/Models/Directory/CountryListModel.cs new file mode 100644 index 0000000000..ece27d8805 --- /dev/null +++ b/src/Presentation/SmartStore.Web/Administration/Models/Directory/CountryListModel.cs @@ -0,0 +1,9 @@ +using SmartStore.Web.Framework.Modelling; + +namespace SmartStore.Admin.Models.Directory +{ + public class CountryListModel : ModelBase + { + public int StoreCount { get; set; } + } +} \ No newline at end of file diff --git a/src/Presentation/SmartStore.Web/Administration/SmartStore.Admin.csproj b/src/Presentation/SmartStore.Web/Administration/SmartStore.Admin.csproj index 8aa8fd5f3f..c7ca89c0f8 100644 --- a/src/Presentation/SmartStore.Web/Administration/SmartStore.Admin.csproj +++ b/src/Presentation/SmartStore.Web/Administration/SmartStore.Admin.csproj @@ -258,6 +258,7 @@ + diff --git a/src/Presentation/SmartStore.Web/Administration/Views/Country/List.cshtml b/src/Presentation/SmartStore.Web/Administration/Views/Country/List.cshtml index 5285bcd4d5..833e3badee 100644 --- a/src/Presentation/SmartStore.Web/Administration/Views/Country/List.cshtml +++ b/src/Presentation/SmartStore.Web/Administration/Views/Country/List.cshtml @@ -1,4 +1,4 @@ -@model Telerik.Web.Mvc.GridModel +@model CountryListModel @using Telerik.Web.Mvc.UI @{ ViewBag.Title = T("Admin.Configuration.Countries").Text; @@ -12,62 +12,74 @@  @T("Admin.Common.AddNew") +
    @(Html.Telerik().Grid() - .Name("countries-grid") - .BindTo(Model.Data) - .Columns(columns => - { - columns.Bound(x => x.Name) - .Width(250) - .Template(x => Html.ActionLink(x.Name, "Edit", new { id = x.Id })) - .ClientTemplate("<#= Name #>"); - columns.Bound(x => x.AllowsBilling) - .Width(50) - .Template(item => @Html.SymbolForBool(item.AllowsBilling)) - .ClientTemplate(@Html.SymbolForBool("AllowsBilling")) - .Centered(); - columns.Bound(x => x.AllowsShipping) - .Width(50) - .Template(item => @Html.SymbolForBool(item.AllowsShipping)) - .ClientTemplate(@Html.SymbolForBool("AllowsShipping")) - .Centered(); - columns.Bound(x => x.TwoLetterIsoCode) - .Width(50) - .Centered(); - columns.Bound(x => x.ThreeLetterIsoCode) - .Width(50) - .Centered(); - columns.Bound(x => x.NumericIsoCode) - .Width(50) - .Centered(); - columns.Bound(x => x.SubjectToVat) - .Width(50) - .Template(item => @Html.SymbolForBool(item.SubjectToVat)) - .ClientTemplate(@Html.SymbolForBool("SubjectToVat")) - .Centered(); - columns.Bound(x => x.NumberOfStates) - .Width(50) - .Centered(); - columns.Bound(x => x.DisplayOrder) - .Width(50) - .Centered(); + .Name("countries-grid") + .DataKeys(x => + { + x.Add(y => y.Id).RouteKey("Id"); + }) + .Editable(x => + { + x.Mode(GridEditMode.InLine); + }) + .Columns(columns => + { + columns.Bound(x => x.Name) + .ClientTemplate("<#= Name #>"); + columns.Bound(x => x.AllowsBilling) + .Width(50) + .ClientTemplate(@Html.SymbolForBool("AllowsBilling")) + .Centered(); + columns.Bound(x => x.AllowsShipping) + .ClientTemplate(@Html.SymbolForBool("AllowsShipping")) + .Centered(); + columns.Bound(x => x.TwoLetterIsoCode) + .Centered(); + columns.Bound(x => x.ThreeLetterIsoCode) + .Centered(); + columns.Bound(x => x.NumericIsoCode) + .Centered(); + columns.Bound(x => x.SubjectToVat) + .ClientTemplate(@Html.SymbolForBool("SubjectToVat")) + .Centered(); + columns.Bound(x => x.NumberOfStates) + .ReadOnly() + .Centered(); + columns.Bound(x => x.DisplayOrder) + .Centered(); columns.Bound(x => x.LimitedToStores) - .Template(item => @Html.SymbolForBool(item.LimitedToStores)) .ClientTemplate(@Html.SymbolForBool("LimitedToStores")) .Centered() - .Width(100) - .Hidden(ViewBag.StoreCount <= 1); - columns.Bound(x => x.Published) - .Width(50) - .Template(item => @Html.SymbolForBool(item.Published)) - .ClientTemplate(@Html.SymbolForBool("Published")) - .Centered(); - }) - .DataBinding(dataBinding => dataBinding.Ajax().Select("CountryList", "Country")) - .EnableCustomBinding(true)) + .ReadOnly() + .Hidden(Model.StoreCount <= 1); + columns.Bound(x => x.Published) + .ClientTemplate(@Html.SymbolForBool("Published")) + .Centered(); + columns.Command(commands => + { + commands.Edit().Localize(T); + commands.Delete().Localize(T); + }); + }) + .DataBinding(dataBinding => dataBinding.Ajax() + .Select("CountryList", "Country") + .Update("CountryUpdate", "Country") + .Delete("CountryDelete", "Country") + ) + .ClientEvents(x => x.OnError("CountryGrid_onError")) + .PreserveGridState() + .EnableCustomBinding(true))
    + + From 718323ce9f06773c37a7bbd5e486c0da43fd805f Mon Sep 17 00:00:00 2001 From: Marcus Gesing Date: Tue, 5 Jan 2016 14:03:26 +0100 Subject: [PATCH 212/707] Product import: Store mappings were not applied when inserting new records --- changelog.md | 1 + .../Catalog/Importer/ProductImporter.cs | 38 ++++++++++++++++--- .../Controllers/SmartController.cs | 3 +- .../Controllers/ImportController.cs | 2 +- .../Views/Import/_ColumnMappings.cshtml | 2 +- 5 files changed, 37 insertions(+), 9 deletions(-) diff --git a/changelog.md b/changelog.md index 72610122db..0ca5d818fc 100644 --- a/changelog.md +++ b/changelog.md @@ -84,6 +84,7 @@ * #805 Product filter is reset if 'product sorting' or 'view mode' or 'amount of displayed products per page' is changed * Hide link to a topic page if it is limited to stores * #829 Activity log: Searching by customer email out of function +* Product import: Store mappings were not applied when inserting new records ## SmartStore.NET 2.2.2 diff --git a/src/Libraries/SmartStore.Services/Catalog/Importer/ProductImporter.cs b/src/Libraries/SmartStore.Services/Catalog/Importer/ProductImporter.cs index b115a270eb..c4321349f6 100644 --- a/src/Libraries/SmartStore.Services/Catalog/Importer/ProductImporter.cs +++ b/src/Libraries/SmartStore.Services/Catalog/Importer/ProductImporter.cs @@ -367,6 +367,21 @@ private int ProcessSlugs(IImportExecuteContext context, ImportRow[] bat return _urlRecordRepository.Context.SaveChanges(); } + private void ProcessStoreMappings(IImportExecuteContext context, ImportRow[] batch) + { + foreach (var row in batch) + { + var limitedToStore = row.GetDataValue("LimitedToStores"); + + if (limitedToStore) + { + var storeIds = row.GetDataValue>("StoreIds"); + + _storeMappingService.SaveStoreMappings(row.Entity, storeIds == null ? new int[0] : storeIds.ToArray()); + } + } + } + private int ProcessProducts(IImportExecuteContext context, ImportRow[] batch, DateTime utcNow) { _productRepository.AutoCommitEnabled = true; @@ -497,12 +512,6 @@ private int ProcessProducts(IImportExecuteContext context, ImportRow[] row.SetProperty(context.Result, product, (x) => x.AvailableEndDateTimeUtc); row.SetProperty(context.Result, product, (x) => x.LimitedToStores); - var storeIds = row.GetDataValue>("StoreIds"); - if (storeIds != null && storeIds.Any()) - { - _storeMappingService.SaveStoreMappings(product, storeIds.ToArray()); - } - row.SetProperty(context.Result, product, (x) => x.CreatedOnUtc, utcNow); product.UpdatedOnUtc = utcNow; @@ -590,6 +599,23 @@ public void Execute(IImportExecuteContext context) } } + if (segmenter.HasColumn("LimitedToStores") && segmenter.HasColumn("StoreIds")) + { + try + { + _productRepository.Context.AutoDetectChangesEnabled = true; + ProcessStoreMappings(context, batch); + } + catch (Exception exception) + { + context.Result.AddError(exception, segmenter.CurrentSegment, "ProcessStoreMappings"); + } + finally + { + _productRepository.Context.AutoDetectChangesEnabled = false; + } + } + // =========================================================================== // 3.) Import Localizations // =========================================================================== diff --git a/src/Presentation/SmartStore.Web.Framework/Controllers/SmartController.cs b/src/Presentation/SmartStore.Web.Framework/Controllers/SmartController.cs index a5169e45c4..2debc94ede 100644 --- a/src/Presentation/SmartStore.Web.Framework/Controllers/SmartController.cs +++ b/src/Presentation/SmartStore.Web.Framework/Controllers/SmartController.cs @@ -1,5 +1,6 @@ using System; using System.Text; +using System.Web; using System.Web.Mvc; using SmartStore.Core.Localization; using SmartStore.Core.Logging; @@ -92,7 +93,7 @@ protected virtual void NotifyError(Exception exception, bool durable = true, boo LogException(exception); } - Services.Notifier.Error(exception.ToAllMessages(), durable); + Services.Notifier.Error(HttpUtility.HtmlEncode(exception.ToAllMessages()), durable); } /// diff --git a/src/Presentation/SmartStore.Web/Administration/Controllers/ImportController.cs b/src/Presentation/SmartStore.Web/Administration/Controllers/ImportController.cs index 9c2d6b565f..c56638c2a1 100644 --- a/src/Presentation/SmartStore.Web/Administration/Controllers/ImportController.cs +++ b/src/Presentation/SmartStore.Web/Administration/Controllers/ImportController.cs @@ -125,7 +125,7 @@ private void PrepareColumnMappingModels(ImportProfile profile, ImportProfileMode } catch (Exception exception) { - NotifyError(exception); + NotifyError(exception, true, false); } } diff --git a/src/Presentation/SmartStore.Web/Administration/Views/Import/_ColumnMappings.cshtml b/src/Presentation/SmartStore.Web/Administration/Views/Import/_ColumnMappings.cshtml index 4dc8045232..9e15de2aef 100644 --- a/src/Presentation/SmartStore.Web/Administration/Views/Import/_ColumnMappings.cshtml +++ b/src/Presentation/SmartStore.Web/Administration/Views/Import/_ColumnMappings.cshtml @@ -1,6 +1,6 @@ @using SmartStore.Admin.Models.DataExchange; @model ImportProfileModel -@if (Model.ColumnMappings.Any()) +@if (Model.ColumnMappings != null && Model.ColumnMappings.Any()) {

     

    From 9966961092d437f46883a308a2feea4f3dd75f21 Mon Sep 17 00:00:00 2001 From: Marcus Gesing Date: Tue, 5 Jan 2016 14:08:19 +0100 Subject: [PATCH 213/707] Dito new category import --- .../Catalog/Importer/CategoryImporter.cs | 39 ++++++++++++++++--- 1 file changed, 33 insertions(+), 6 deletions(-) diff --git a/src/Libraries/SmartStore.Services/Catalog/Importer/CategoryImporter.cs b/src/Libraries/SmartStore.Services/Catalog/Importer/CategoryImporter.cs index e0e5a2bdf2..08e43b0448 100644 --- a/src/Libraries/SmartStore.Services/Catalog/Importer/CategoryImporter.cs +++ b/src/Libraries/SmartStore.Services/Catalog/Importer/CategoryImporter.cs @@ -178,6 +178,21 @@ private int ProcessPictures(IImportExecuteContext context, return num; } + private void ProcessStoreMappings(IImportExecuteContext context, ImportRow[] batch) + { + foreach (var row in batch) + { + var limitedToStore = row.GetDataValue("LimitedToStores"); + + if (limitedToStore) + { + var storeIds = row.GetDataValue>("StoreIds"); + + _storeMappingService.SaveStoreMappings(row.Entity, storeIds == null ? new int[0] : storeIds.ToArray()); + } + } + } + private int ProcessCategories(IImportExecuteContext context, ImportRow[] batch, DateTime utcNow, @@ -249,12 +264,6 @@ private int ProcessCategories(IImportExecuteContext context, category.CategoryTemplateId = templateId; } - var storeIds = row.GetDataValue>("StoreIds"); - if (storeIds != null && storeIds.Any()) - { - _storeMappingService.SaveStoreMappings(category, storeIds.ToArray()); - } - row.SetProperty(context.Result, category, (x) => x.CreatedOnUtc, utcNow); category.UpdatedOnUtc = utcNow; @@ -355,6 +364,24 @@ public void Execute(IImportExecuteContext context) } } + // process store mappings + if (segmenter.HasColumn("LimitedToStores") && segmenter.HasColumn("StoreIds")) + { + try + { + _categoryRepository.Context.AutoDetectChangesEnabled = true; + ProcessStoreMappings(context, batch); + } + catch (Exception exception) + { + context.Result.AddError(exception, segmenter.CurrentSegment, "ProcessStoreMappings"); + } + finally + { + _categoryRepository.Context.AutoDetectChangesEnabled = false; + } + } + // process pictures if (srcToDestId.Any() && segmenter.HasColumn("PictureThumbPath")) { From ef6da8abe065e2b65b1740525ec20310503b8eb5 Mon Sep 17 00:00:00 2001 From: Marcus Gesing Date: Tue, 5 Jan 2016 18:11:26 +0100 Subject: [PATCH 214/707] Faulty permission handling in ajax grid actions (no message, infinite loading icon)(part 1) --- changelog.md | 1 + .../201512151526290_ImportFramework.cs | 6 +- .../Controllers/SmartController.cs | 2 +- .../Controllers/AffiliateController.cs | 121 ++++++------ .../Controllers/BlogController.cs | 135 +++++++------ .../Controllers/CampaignController.cs | 35 ++-- .../Controllers/CategoryController.cs | 168 +++++++++-------- .../CheckoutAttributeController.cs | 90 ++++----- .../Controllers/CommonController.cs | 177 +++++++++--------- .../Controllers/CountryController.cs | 43 +++-- .../Controllers/CurrencyController.cs | 25 ++- .../Controllers/CustomerController.cs | 130 +++++++------ .../Controllers/CustomerRoleController.cs | 25 ++- .../Controllers/DiscountController.cs | 87 ++++----- .../Controllers/EmailAccountController.cs | 34 ++-- .../Controllers/ExportController.cs | 12 +- .../Controllers/GiftCardController.cs | 106 ++++++----- 17 files changed, 664 insertions(+), 533 deletions(-) diff --git a/changelog.md b/changelog.md index 0ca5d818fc..2308726b85 100644 --- a/changelog.md +++ b/changelog.md @@ -85,6 +85,7 @@ * Hide link to a topic page if it is limited to stores * #829 Activity log: Searching by customer email out of function * Product import: Store mappings were not applied when inserting new records +* Faulty permission handling in ajax grid actions (no message, infinite loading icon) ## SmartStore.NET 2.2.2 diff --git a/src/Libraries/SmartStore.Data/Migrations/201512151526290_ImportFramework.cs b/src/Libraries/SmartStore.Data/Migrations/201512151526290_ImportFramework.cs index 24f368ef69..7de4cc953b 100644 --- a/src/Libraries/SmartStore.Data/Migrations/201512151526290_ImportFramework.cs +++ b/src/Libraries/SmartStore.Data/Migrations/201512151526290_ImportFramework.cs @@ -297,8 +297,12 @@ public void MigrateLocaleResources(LocaleResourcesBuilder builder) "Zugriffsverweigerung durch Kunde #{0} '{1}' bei {2}."); builder.AddOrUpdate("Admin.Configuration.Countries.CannotDeleteDueToAssociatedAddresses", - "The country cannaot be deleted because it has associated addresses.", + "The country cannot be deleted because it has associated addresses.", "Das Land kann nicht gelscht werden, weil ihm Adressen zugeordnet sind."); + + builder.AddOrUpdate("Admin.Configuration.Countries.States.CantDeleteWithAddresses", + "The state\\province cannot be deleted because it has associated addresses.", + "Das Bundesland\\Region kann nicht gelscht werden, weil ihm Adressen zugeordnet sind."); } } } diff --git a/src/Presentation/SmartStore.Web.Framework/Controllers/SmartController.cs b/src/Presentation/SmartStore.Web.Framework/Controllers/SmartController.cs index 2debc94ede..b5db948b54 100644 --- a/src/Presentation/SmartStore.Web.Framework/Controllers/SmartController.cs +++ b/src/Presentation/SmartStore.Web.Framework/Controllers/SmartController.cs @@ -101,7 +101,7 @@ protected virtual void NotifyError(Exception exception, bool durable = true, boo ///
    /// A value indicating whether a message should be persisted for the next request /// A value indicating whether the message should be logged - protected virtual void NotifyAccessDenied(bool durable = true, bool log = false) + protected virtual void NotifyAccessDenied(bool durable = true, bool log = true) { var message = T("Admin.AccessDenied.Description"); diff --git a/src/Presentation/SmartStore.Web/Administration/Controllers/AffiliateController.cs b/src/Presentation/SmartStore.Web/Administration/Controllers/AffiliateController.cs index e98628b496..cf1e2b3c87 100644 --- a/src/Presentation/SmartStore.Web/Administration/Controllers/AffiliateController.cs +++ b/src/Presentation/SmartStore.Web/Administration/Controllers/AffiliateController.cs @@ -24,7 +24,7 @@ namespace SmartStore.Admin.Controllers { - [AdminAuthorize] + [AdminAuthorize] public partial class AffiliateController : AdminControllerBase { #region Fields @@ -156,23 +156,31 @@ public ActionResult List() [HttpPost, GridAction(EnableCustomBinding = true)] public ActionResult List(GridCommand command) { - if (!_permissionService.Authorize(StandardPermissionProvider.ManageAffiliates)) - return AccessDeniedView(); + var model = new GridModel(); - var affiliates = _affiliateService.GetAllAffiliates(true); - var gridModel = new GridModel - { - Data = affiliates.PagedForCommand(command).Select(x => - { - var m = new AffiliateModel(); - PrepareAffiliateModel(m, x, false); - return m; - }), - Total = affiliates.Count, - }; - return new JsonResult + if (_permissionService.Authorize(StandardPermissionProvider.ManageAffiliates)) + { + var affiliates = _affiliateService.GetAllAffiliates(true); + + model.Data = affiliates.PagedForCommand(command).Select(x => + { + var m = new AffiliateModel(); + PrepareAffiliateModel(m, x, false); + return m; + }); + + model.Total = affiliates.Count; + } + else + { + model.Data = Enumerable.Empty(); + + NotifyAccessDenied(); + } + + return new JsonResult { - Data = gridModel + Data = model }; } @@ -287,31 +295,34 @@ public ActionResult Delete(int id) [HttpPost, GridAction(EnableCustomBinding = true)] public ActionResult AffiliatedOrderList(int affiliateId, GridCommand command) { - if (!_permissionService.Authorize(StandardPermissionProvider.ManageAffiliates)) - return AccessDeniedView(); + var model = new GridModel(); - var affiliate = _affiliateService.GetAffiliateById(affiliateId); - if (affiliate == null) - throw new ArgumentException("No affiliate found with the specified id"); + if (_permissionService.Authorize(StandardPermissionProvider.ManageAffiliates)) + { + var affiliate = _affiliateService.GetAffiliateById(affiliateId); + var orders = _orderService.GetAllOrders(affiliate.Id, command.Page - 1, command.PageSize); + + model.Data = orders.Select(order => + { + var orderModel = new AffiliateModel.AffiliatedOrderModel(); + orderModel.Id = order.Id; + orderModel.OrderStatus = order.OrderStatus.GetLocalizedEnum(_localizationService, _workContext); + orderModel.PaymentStatus = order.PaymentStatus.GetLocalizedEnum(_localizationService, _workContext); + orderModel.ShippingStatus = order.ShippingStatus.GetLocalizedEnum(_localizationService, _workContext); + orderModel.OrderTotal = _priceFormatter.FormatPrice(order.OrderTotal, true, false); + orderModel.CreatedOn = _dateTimeHelper.ConvertToUserTime(order.CreatedOnUtc, DateTimeKind.Utc); + return orderModel; + }); + model.Total = orders.TotalCount; + } + else + { + model.Data = Enumerable.Empty(); - var orders = _orderService.GetAllOrders(affiliate.Id, command.Page - 1, command.PageSize); - var model = new GridModel - { - Data = orders.Select(order => - { - var orderModel = new AffiliateModel.AffiliatedOrderModel(); - orderModel.Id = order.Id; - orderModel.OrderStatus = order.OrderStatus.GetLocalizedEnum(_localizationService, _workContext); - orderModel.PaymentStatus = order.PaymentStatus.GetLocalizedEnum(_localizationService, _workContext); - orderModel.ShippingStatus = order.ShippingStatus.GetLocalizedEnum(_localizationService, _workContext); - orderModel.OrderTotal = _priceFormatter.FormatPrice(order.OrderTotal, true, false); - orderModel.CreatedOn = _dateTimeHelper.ConvertToUserTime(order.CreatedOnUtc, DateTimeKind.Utc); - return orderModel; - }), - Total = orders.TotalCount - }; + NotifyAccessDenied(); + } - return new JsonResult + return new JsonResult { Data = model }; @@ -320,19 +331,16 @@ public ActionResult AffiliatedOrderList(int affiliateId, GridCommand command) [HttpPost, GridAction(EnableCustomBinding = true)] public ActionResult AffiliatedCustomerList(int affiliateId, GridCommand command) { - if (!_permissionService.Authorize(StandardPermissionProvider.ManageAffiliates)) - return AccessDeniedView(); + var model = new GridModel(); - var affiliate = _affiliateService.GetAffiliateById(affiliateId); - if (affiliate == null) - throw new ArgumentException("No affiliate found with the specified id"); + if (_permissionService.Authorize(StandardPermissionProvider.ManageAffiliates)) + { + var affiliate = _affiliateService.GetAffiliateById(affiliateId); + var customers = _customerService.GetAllCustomers(affiliate.Id, command.Page - 1, command.PageSize); - var customers = _customerService.GetAllCustomers(affiliate.Id, command.Page - 1, command.PageSize); - var model = new GridModel - { - Data = customers.Select(customer => - { - var customerModel = new AffiliateModel.AffiliatedCustomerModel + model.Data = customers.Select(customer => + { + var customerModel = new AffiliateModel.AffiliatedCustomerModel { Id = customer.Id, Email = customer.Email, @@ -340,16 +348,23 @@ public ActionResult AffiliatedCustomerList(int affiliateId, GridCommand command) FullName = customer.GetFullName() }; - return customerModel; - }), - Total = customers.TotalCount - }; + return customerModel; + }); + model.Total = customers.TotalCount; + } + else + { + model.Data = Enumerable.Empty(); + + NotifyAccessDenied(); + } return new JsonResult { Data = model }; } + #endregion } } diff --git a/src/Presentation/SmartStore.Web/Administration/Controllers/BlogController.cs b/src/Presentation/SmartStore.Web/Administration/Controllers/BlogController.cs index 98d4a868c4..f0883628b1 100644 --- a/src/Presentation/SmartStore.Web/Administration/Controllers/BlogController.cs +++ b/src/Presentation/SmartStore.Web/Administration/Controllers/BlogController.cs @@ -105,29 +105,37 @@ public ActionResult List() [HttpPost, GridAction(EnableCustomBinding = true)] public ActionResult List(GridCommand command) { - if (!_permissionService.Authorize(StandardPermissionProvider.ManageBlog)) - return AccessDeniedView(); + var model = new GridModel(); + + if (_permissionService.Authorize(StandardPermissionProvider.ManageBlog)) + { + var blogPosts = _blogService.GetAllBlogPosts(0, 0, null, null, command.Page - 1, command.PageSize, true); + + model.Data = blogPosts.Select(x => + { + var m = x.ToModel(); + if (x.StartDateUtc.HasValue) + m.StartDate = _dateTimeHelper.ConvertToUserTime(x.StartDateUtc.Value, DateTimeKind.Utc); + if (x.EndDateUtc.HasValue) + m.EndDate = _dateTimeHelper.ConvertToUserTime(x.EndDateUtc.Value, DateTimeKind.Utc); + m.CreatedOn = _dateTimeHelper.ConvertToUserTime(x.CreatedOnUtc, DateTimeKind.Utc); + m.LanguageName = x.Language.Name; + m.Comments = x.ApprovedCommentCount + x.NotApprovedCommentCount; + return m; + }); + + model.Total = blogPosts.TotalCount; + } + else + { + model.Data = Enumerable.Empty(); + + NotifyAccessDenied(); + } - var blogPosts = _blogService.GetAllBlogPosts(0, 0, null, null, command.Page - 1, command.PageSize, true); - var gridModel = new GridModel - { - Data = blogPosts.Select(x => - { - var m = x.ToModel(); - if (x.StartDateUtc.HasValue) - m.StartDate = _dateTimeHelper.ConvertToUserTime(x.StartDateUtc.Value, DateTimeKind.Utc); - if (x.EndDateUtc.HasValue) - m.EndDate = _dateTimeHelper.ConvertToUserTime(x.EndDateUtc.Value, DateTimeKind.Utc); - m.CreatedOn = _dateTimeHelper.ConvertToUserTime(x.CreatedOnUtc, DateTimeKind.Utc); - m.LanguageName = x.Language.Name; - m.Comments = x.ApprovedCommentCount + x.NotApprovedCommentCount; - return m; - }), - Total = blogPosts.TotalCount - }; return new JsonResult { - Data = gridModel + Data = model }; } @@ -269,71 +277,76 @@ public ActionResult Comments(int? filterByBlogPostId) [HttpPost, GridAction(EnableCustomBinding = true)] public ActionResult Comments(int? filterByBlogPostId, GridCommand command) { - if (!_permissionService.Authorize(StandardPermissionProvider.ManageBlog)) - return AccessDeniedView(); + var model = new GridModel(); - IList comments; - if (filterByBlogPostId.HasValue) - { - //filter comments by blog - var blogPost = _blogService.GetBlogPostById(filterByBlogPostId.Value); - comments = blogPost.BlogComments.OrderBy(bc => bc.CreatedOnUtc).ToList(); - } - else - { - //load all blog comments - comments = _customerContentService.GetAllCustomerContent(0, null); - } + if (_permissionService.Authorize(StandardPermissionProvider.ManageBlog)) + { + IList comments; + if (filterByBlogPostId.HasValue) + { + //filter comments by blog + var blogPost = _blogService.GetBlogPostById(filterByBlogPostId.Value); + comments = blogPost.BlogComments.OrderBy(bc => bc.CreatedOnUtc).ToList(); + } + else + { + //load all blog comments + comments = _customerContentService.GetAllCustomerContent(0, null); + } - var gridModel = new GridModel - { - Data = comments.PagedForCommand(command).Select(blogComment => - { - var commentModel = new BlogCommentModel(); + model.Data = comments.PagedForCommand(command).Select(blogComment => + { + var commentModel = new BlogCommentModel(); var customer = _customerService.GetCustomerById(blogComment.CustomerId); - commentModel.Id = blogComment.Id; - commentModel.BlogPostId = blogComment.BlogPostId; - commentModel.BlogPostTitle = blogComment.BlogPost.Title; - commentModel.CustomerId = blogComment.CustomerId; - commentModel.IpAddress = blogComment.IpAddress; - commentModel.CreatedOn = _dateTimeHelper.ConvertToUserTime(blogComment.CreatedOnUtc, DateTimeKind.Utc); - commentModel.Comment = Core.Html.HtmlUtils.FormatText(blogComment.CommentText, false, true, false, false, false, false); + commentModel.Id = blogComment.Id; + commentModel.BlogPostId = blogComment.BlogPostId; + commentModel.BlogPostTitle = blogComment.BlogPost.Title; + commentModel.CustomerId = blogComment.CustomerId; + commentModel.IpAddress = blogComment.IpAddress; + commentModel.CreatedOn = _dateTimeHelper.ConvertToUserTime(blogComment.CreatedOnUtc, DateTimeKind.Utc); + commentModel.Comment = Core.Html.HtmlUtils.FormatText(blogComment.CommentText, false, true, false, false, false, false); if (customer == null) commentModel.CustomerName = "".NaIfEmpty(); else commentModel.CustomerName = customer.GetFullName(); - return commentModel; - }), - Total = comments.Count, - }; + return commentModel; + }); + + model.Total = comments.Count; + } + else + { + model.Data = Enumerable.Empty(); + + NotifyAccessDenied(); + } + return new JsonResult { - Data = gridModel + Data = model }; } [GridAction(EnableCustomBinding = true)] public ActionResult CommentDelete(int? filterByBlogPostId, int id, GridCommand command) { - if (!_permissionService.Authorize(StandardPermissionProvider.ManageBlog)) - return AccessDeniedView(); + if (_permissionService.Authorize(StandardPermissionProvider.ManageBlog)) + { + var comment = _customerContentService.GetCustomerContentById(id) as BlogComment; - var comment = _customerContentService.GetCustomerContentById(id) as BlogComment; - if (comment == null) - throw new ArgumentException("No comment found with the specified id"); + var blogPost = comment.BlogPost; + _customerContentService.DeleteCustomerContent(comment); - var blogPost = comment.BlogPost; - _customerContentService.DeleteCustomerContent(comment); - //update totals - _blogService.UpdateCommentTotals(blogPost); + //update totals + _blogService.UpdateCommentTotals(blogPost); + } return Comments(filterByBlogPostId, command); } - #endregion } } diff --git a/src/Presentation/SmartStore.Web/Administration/Controllers/CampaignController.cs b/src/Presentation/SmartStore.Web/Administration/Controllers/CampaignController.cs index 7b3b290fd9..51f11cd40c 100644 --- a/src/Presentation/SmartStore.Web/Administration/Controllers/CampaignController.cs +++ b/src/Presentation/SmartStore.Web/Administration/Controllers/CampaignController.cs @@ -88,24 +88,31 @@ public ActionResult List() [HttpPost, GridAction(EnableCustomBinding = true)] public ActionResult List(GridCommand command) { - if (!_permissionService.Authorize(StandardPermissionProvider.ManageCampaigns)) - return AccessDeniedView(); + var model = new GridModel(); - var campaigns = _campaignService.GetAllCampaigns(); - var gridModel = new GridModel - { - Data = campaigns.Select(x => - { - var model = x.ToModel(); - model.CreatedOn = _dateTimeHelper.ConvertToUserTime(x.CreatedOnUtc, DateTimeKind.Utc); - return model; - }), - Total = campaigns.Count - }; + if (_permissionService.Authorize(StandardPermissionProvider.ManageCampaigns)) + { + var campaigns = _campaignService.GetAllCampaigns(); + + model.Data = campaigns.Select(x => + { + var m = x.ToModel(); + m.CreatedOn = _dateTimeHelper.ConvertToUserTime(x.CreatedOnUtc, DateTimeKind.Utc); + return m; + }); + + model.Total = campaigns.Count; + } + else + { + model.Data = Enumerable.Empty(); + + NotifyAccessDenied(); + } return new JsonResult { - Data = gridModel + Data = model }; } diff --git a/src/Presentation/SmartStore.Web/Administration/Controllers/CategoryController.cs b/src/Presentation/SmartStore.Web/Administration/Controllers/CategoryController.cs index c8b714dfab..05822a9c17 100644 --- a/src/Presentation/SmartStore.Web/Administration/Controllers/CategoryController.cs +++ b/src/Presentation/SmartStore.Web/Administration/Controllers/CategoryController.cs @@ -285,24 +285,30 @@ public ActionResult List() [HttpPost, GridAction(EnableCustomBinding = true)] public ActionResult List(GridCommand command, CategoryListModel model) { - if (!_permissionService.Authorize(StandardPermissionProvider.ManageCatalog)) - return AccessDeniedView(); + var gridModel = new GridModel(); - var categories = _categoryService.GetAllCategories(model.SearchCategoryName, command.Page - 1, command.PageSize, true, model.SearchAlias, true, false, model.SearchStoreId); - var mappedCategories = categories.ToDictionary(x => x.Id); + if (_permissionService.Authorize(StandardPermissionProvider.ManageCatalog)) + { + var categories = _categoryService.GetAllCategories(model.SearchCategoryName, command.Page - 1, command.PageSize, true, model.SearchAlias, true, false, model.SearchStoreId); + var mappedCategories = categories.ToDictionary(x => x.Id); - var gridModel = new GridModel - { - Data = categories.Select(x => - { - var categoryModel = x.ToModel(); - categoryModel.Breadcrumb = x.GetCategoryBreadCrumb(_categoryService, mappedCategories); - return categoryModel; - }), - Total = categories.TotalCount - }; + gridModel.Data = categories.Select(x => + { + var categoryModel = x.ToModel(); + categoryModel.Breadcrumb = x.GetCategoryBreadCrumb(_categoryService, mappedCategories); + return categoryModel; + }); + + gridModel.Total = categories.TotalCount; + } + else + { + gridModel.Data = Enumerable.Empty(); - return new JsonResult + NotifyAccessDenied(); + } + + return new JsonResult { Data = gridModel }; @@ -758,17 +764,16 @@ public ActionResult Delete(int id, string deleteType) [HttpPost, GridAction(EnableCustomBinding = true)] public ActionResult ProductList(GridCommand command, int categoryId) { - if (!_permissionService.Authorize(StandardPermissionProvider.ManageCatalog)) - return AccessDeniedView(); - - var productCategories = _categoryService.GetProductCategoriesByCategoryId(categoryId, command.Page - 1, command.PageSize, true); + var model = new GridModel(); - var products = _productService.GetProductsByIds(productCategories.Select(x => x.ProductId).ToArray()); + if (_permissionService.Authorize(StandardPermissionProvider.ManageCatalog)) + { + var productCategories = _categoryService.GetProductCategoriesByCategoryId(categoryId, command.Page - 1, command.PageSize, true); - var model = new GridModel - { - Data = productCategories.Select(x => - { + var products = _productService.GetProductsByIds(productCategories.Select(x => x.ProductId).ToArray()); + + model.Data = productCategories.Select(x => + { var productModel = new CategoryModel.CategoryProductModel { Id = x.Id, @@ -788,13 +793,20 @@ public ActionResult ProductList(GridCommand command, int categoryId) productModel.ProductTypeLabelHint = product.ProductTypeLabelHint; productModel.Published = product.Published; } - + return productModel; - }), - Total = productCategories.TotalCount - }; + }); + + model.Total = productCategories.TotalCount; + } + else + { + model.Data = Enumerable.Empty(); - return new JsonResult + NotifyAccessDenied(); + } + + return new JsonResult { Data = model }; @@ -803,34 +815,32 @@ public ActionResult ProductList(GridCommand command, int categoryId) [GridAction(EnableCustomBinding = true)] public ActionResult ProductUpdate(GridCommand command, CategoryModel.CategoryProductModel model) { - if (!_permissionService.Authorize(StandardPermissionProvider.ManageCatalog)) - return AccessDeniedView(); + if (_permissionService.Authorize(StandardPermissionProvider.ManageCatalog)) + { + var productCategory = _categoryService.GetProductCategoryById(model.Id); - var productCategory = _categoryService.GetProductCategoryById(model.Id); - if (productCategory == null) - throw new ArgumentException("No product category mapping found with the specified id"); + productCategory.IsFeaturedProduct = model.IsFeaturedProduct; + productCategory.DisplayOrder = model.DisplayOrder1; - productCategory.IsFeaturedProduct = model.IsFeaturedProduct; - productCategory.DisplayOrder = model.DisplayOrder1; - _categoryService.UpdateProductCategory(productCategory); + _categoryService.UpdateProductCategory(productCategory); + } - return ProductList(command, productCategory.CategoryId); + return ProductList(command, model.Id); } [GridAction(EnableCustomBinding = true)] public ActionResult ProductDelete(int id, GridCommand command) { - if (!_permissionService.Authorize(StandardPermissionProvider.ManageCatalog)) - return AccessDeniedView(); + if (_permissionService.Authorize(StandardPermissionProvider.ManageCatalog)) + { + var productCategory = _categoryService.GetProductCategoryById(id); - var productCategory = _categoryService.GetProductCategoryById(id); - if (productCategory == null) - throw new ArgumentException("No product category mapping found with the specified id"); + var categoryId = productCategory.CategoryId; - var categoryId = productCategory.CategoryId; - _categoryService.DeleteProductCategory(productCategory); + _categoryService.DeleteProductCategory(productCategory); + } - return ProductList(command, categoryId); + return ProductList(command, id); } public ActionResult ProductAddPopup(int categoryId) @@ -838,7 +848,6 @@ public ActionResult ProductAddPopup(int categoryId) if (!_permissionService.Authorize(StandardPermissionProvider.ManageCatalog)) return AccessDeniedView(); - var ctx = new ProductSearchContext(); ctx.LanguageId = _workContext.WorkingLanguage.Id; ctx.OrderBy = ProductSortingEnum.Position; @@ -864,16 +873,18 @@ public ActionResult ProductAddPopup(int categoryId) var mappedCategories = allCategories.ToDictionary(x => x.Id); foreach (var c in allCategories) { - model.AvailableCategories.Add(new SelectListItem() { Text = c.GetCategoryNameWithPrefix(_categoryService, mappedCategories), Value = c.Id.ToString() }); + model.AvailableCategories.Add(new SelectListItem { Text = c.GetCategoryNameWithPrefix(_categoryService, mappedCategories), Value = c.Id.ToString() }); } - //manufacturers - foreach (var m in _manufacturerService.GetAllManufacturers(true)) - model.AvailableManufacturers.Add(new SelectListItem() { Text = m.Name, Value = m.Id.ToString() }); + //manufacturers + foreach (var m in _manufacturerService.GetAllManufacturers(true)) + { + model.AvailableManufacturers.Add(new SelectListItem { Text = m.Name, Value = m.Id.ToString() }); + } //product types model.AvailableProductTypes = ProductType.SimpleProduct.ToSelectList(false).ToList(); - model.AvailableProductTypes.Insert(0, new SelectListItem() { Text = _localizationService.GetResource("Admin.Common.All"), Value = "0" }); + model.AvailableProductTypes.Insert(0, new SelectListItem { Text = _localizationService.GetResource("Admin.Common.All"), Value = "0" }); return View(model); } @@ -881,35 +892,44 @@ public ActionResult ProductAddPopup(int categoryId) [HttpPost, GridAction(EnableCustomBinding = true)] public ActionResult ProductAddPopupList(GridCommand command, CategoryModel.AddCategoryProductModel model) { - if (!_permissionService.Authorize(StandardPermissionProvider.ManageCatalog)) - return AccessDeniedView(); + var gridModel = new GridModel(); - var gridModel = new GridModel(); - var ctx = new ProductSearchContext(); + if (_permissionService.Authorize(StandardPermissionProvider.ManageCatalog)) + { + var ctx = new ProductSearchContext(); - if (model.SearchCategoryId > 0) - ctx.CategoryIds.Add(model.SearchCategoryId); + if (model.SearchCategoryId > 0) + ctx.CategoryIds.Add(model.SearchCategoryId); - ctx.ManufacturerId = model.SearchManufacturerId; - ctx.Keywords = model.SearchProductName; - ctx.LanguageId = _workContext.WorkingLanguage.Id; - ctx.OrderBy = ProductSortingEnum.Position; - ctx.PageIndex = command.Page - 1; - ctx.PageSize = command.PageSize; - ctx.ShowHidden = true; - ctx.ProductType = model.SearchProductTypeId > 0 ? (ProductType?)model.SearchProductTypeId : null; + ctx.ManufacturerId = model.SearchManufacturerId; + ctx.Keywords = model.SearchProductName; + ctx.LanguageId = _workContext.WorkingLanguage.Id; + ctx.OrderBy = ProductSortingEnum.Position; + ctx.PageIndex = command.Page - 1; + ctx.PageSize = command.PageSize; + ctx.ShowHidden = true; + ctx.ProductType = model.SearchProductTypeId > 0 ? (ProductType?)model.SearchProductTypeId : null; - var products = _productService.SearchProducts(ctx); - gridModel.Data = products.Select(x => + var products = _productService.SearchProducts(ctx); + + gridModel.Data = products.Select(x => + { + var productModel = x.ToModel(); + productModel.ProductTypeName = x.GetProductTypeLabel(_localizationService); + + return productModel; + }); + + gridModel.Total = products.TotalCount; + } + else { - var productModel = x.ToModel(); - productModel.ProductTypeName = x.GetProductTypeLabel(_localizationService); + gridModel.Data = Enumerable.Empty(); - return productModel; - }); + NotifyAccessDenied(); + } - gridModel.Total = products.TotalCount; - return new JsonResult + return new JsonResult { Data = gridModel }; diff --git a/src/Presentation/SmartStore.Web/Administration/Controllers/CheckoutAttributeController.cs b/src/Presentation/SmartStore.Web/Administration/Controllers/CheckoutAttributeController.cs index 78170d9674..4ac32d8493 100644 --- a/src/Presentation/SmartStore.Web/Administration/Controllers/CheckoutAttributeController.cs +++ b/src/Presentation/SmartStore.Web/Administration/Controllers/CheckoutAttributeController.cs @@ -104,7 +104,6 @@ private void PrepareCheckoutAttributeModel(CheckoutAttributeModel model, Checkou #region Checkout attributes - //list public ActionResult Index() { return RedirectToAction("List"); @@ -121,23 +120,31 @@ public ActionResult List() [HttpPost, GridAction(EnableCustomBinding = true)] public ActionResult List(GridCommand command) { - if (!_services.Permissions.Authorize(StandardPermissionProvider.ManageCatalog)) - return AccessDeniedView(); + var model = new GridModel(); - var checkoutAttributes = _checkoutAttributeService.GetAllCheckoutAttributes(true); - var gridModel = new GridModel - { - Data = checkoutAttributes.Select(x => - { - var caModel = x.ToModel(); - caModel.AttributeControlTypeName = x.AttributeControlType.GetLocalizedEnum(_services.Localization, _services.WorkContext); - return caModel; - }), - Total = checkoutAttributes.Count() - }; - return new JsonResult + if (_services.Permissions.Authorize(StandardPermissionProvider.ManageCatalog)) + { + var checkoutAttributes = _checkoutAttributeService.GetAllCheckoutAttributes(true); + + model.Data = checkoutAttributes.Select(x => + { + var caModel = x.ToModel(); + caModel.AttributeControlTypeName = x.AttributeControlType.GetLocalizedEnum(_services.Localization, _services.WorkContext); + return caModel; + }); + + model.Total = checkoutAttributes.Count(); + } + else + { + model.Data = Enumerable.Empty(); + + NotifyAccessDenied(); + } + + return new JsonResult { - Data = gridModel + Data = model }; } @@ -254,31 +261,29 @@ public ActionResult DeleteConfirmed(int id) #region Checkout attribute values - //list [HttpPost, GridAction(EnableCustomBinding = true)] public ActionResult ValueList(int checkoutAttributeId, GridCommand command) { - if (!_services.Permissions.Authorize(StandardPermissionProvider.ManageCatalog)) - return AccessDeniedView(); + var model = new GridModel(); - var values = _checkoutAttributeService.GetCheckoutAttributeValues(checkoutAttributeId); - var gridModel = new GridModel - { - Data = values.Select(x => - { - var model = x.ToModel(); - //locales - //AddLocales(_languageService, model.Locales, (locale, languageId) => - //{ - // locale.Name = x.GetLocalized(y => y.Name, languageId, false, false); - //}); - return model; - }), - Total = values.Count() - }; - return new JsonResult + if (_services.Permissions.Authorize(StandardPermissionProvider.ManageCatalog)) + { + var values = _checkoutAttributeService.GetCheckoutAttributeValues(checkoutAttributeId); + + model.Data = values.Select(x => x.ToModel()); + + model.Total = values.Count(); + } + else + { + model.Data = Enumerable.Empty(); + + NotifyAccessDenied(); + } + + return new JsonResult { - Data = gridModel + Data = model }; } @@ -384,22 +389,19 @@ public ActionResult ValueEditPopup(string btnId, string formId, CheckoutAttribut return View(model); } - //delete [GridAction(EnableCustomBinding = true)] public ActionResult ValueDelete(int valueId, int checkoutAttributeId, GridCommand command) { - if (!_services.Permissions.Authorize(StandardPermissionProvider.ManageCatalog)) - return AccessDeniedView(); + if (_services.Permissions.Authorize(StandardPermissionProvider.ManageCatalog)) + { + var cav = _checkoutAttributeService.GetCheckoutAttributeValueById(valueId); - var cav = _checkoutAttributeService.GetCheckoutAttributeValueById(valueId); - if (cav == null) - throw new ArgumentException("No checkout attribute value found with the specified id"); - _checkoutAttributeService.DeleteCheckoutAttributeValue(cav); + _checkoutAttributeService.DeleteCheckoutAttributeValue(cav); + } return ValueList(checkoutAttributeId, command); } - #endregion } } diff --git a/src/Presentation/SmartStore.Web/Administration/Controllers/CommonController.cs b/src/Presentation/SmartStore.Web/Administration/Controllers/CommonController.cs index ce08f8803f..5127d27256 100644 --- a/src/Presentation/SmartStore.Web/Administration/Controllers/CommonController.cs +++ b/src/Presentation/SmartStore.Web/Administration/Controllers/CommonController.cs @@ -1034,35 +1034,43 @@ public ActionResult GenericAttributes(string entityName, int entityId) [HttpPost, GridAction(EnableCustomBinding = true)] public ActionResult GenericAttributesSelect(string entityName, int entityId, GridCommand command) { - if (!_services.Permissions.Authorize(StandardPermissionProvider.AccessAdminPanel)) - return AccessDeniedView(); + var model = new GridModel(); var storeId = _services.StoreContext.CurrentStore.Id; - ViewBag.StoreId = storeId; + ViewBag.StoreId = storeId; - var model = new List(); - if (entityName.HasValue() && entityId > 0) - { - var attributes = _genericAttributeService.GetAttributesForEntity(entityId, entityName); - var query = from attr in attributes - where attr.StoreId == storeId || attr.StoreId == 0 - select new GenericAttributeModel - { - Id = attr.Id, - EntityId = attr.EntityId, - EntityName = attr.KeyGroup, - Key = attr.Key, - Value = attr.Value - }; - model.AddRange(query); - } + if (_services.Permissions.Authorize(StandardPermissionProvider.AccessAdminPanel)) + { + if (entityName.HasValue() && entityId > 0) + { + var attributes = _genericAttributeService.GetAttributesForEntity(entityId, entityName); + model.Data = attributes + .Where(x => x.StoreId == storeId || x.StoreId == 0) + .Select(x => new GenericAttributeModel + { + Id = x.Id, + EntityId = x.EntityId, + EntityName = x.KeyGroup, + Key = x.Key, + Value = x.Value + }) + .ToList(); + + model.Total = model.Data.Count(); + } + else + { + model.Data = Enumerable.Empty(); + } + } + else + { + model.Data = Enumerable.Empty(); + + NotifyAccessDenied(); + } - var result = new GridModel - { - Data = model, - Total = model.Count - }; return new JsonResult { Data = model @@ -1072,38 +1080,36 @@ public ActionResult GenericAttributesSelect(string entityName, int entityId, Gri [GridAction(EnableCustomBinding = true)] public ActionResult GenericAttributeAdd(GenericAttributeModel model, GridCommand command) { - if (!_services.Permissions.Authorize(StandardPermissionProvider.AccessAdminPanel)) - return AccessDeniedView(); + if (_services.Permissions.Authorize(StandardPermissionProvider.AccessAdminPanel)) + { + model.Key = model.Key.TrimSafe(); + model.Value = model.Value.TrimSafe(); - model.Key = model.Key.TrimSafe(); - model.Value = model.Value.TrimSafe(); + if (!ModelState.IsValid) + { + var modelStateErrorMessages = this.ModelState.Values.SelectMany(x => x.Errors).Select(x => x.ErrorMessage); + return Content(modelStateErrorMessages.FirstOrDefault()); + } - if (!ModelState.IsValid) - { - // display the first model error - var modelStateErrorMessages = this.ModelState.Values.SelectMany(x => x.Errors).Select(x => x.ErrorMessage); - return Content(modelStateErrorMessages.FirstOrDefault()); - } + var storeId = _services.StoreContext.CurrentStore.Id; - var storeId = _services.StoreContext.CurrentStore.Id; - - var attr = _genericAttributeService.GetAttribute(model.EntityName, model.EntityId, model.Key, storeId); - if (attr == null) - { - var ga = new GenericAttribute - { - StoreId = storeId, - KeyGroup = model.EntityName, - EntityId = model.EntityId, - Key = model.Key, - Value = model.Value - }; - _genericAttributeService.InsertAttribute(ga); - } - else - { - return Content(string.Format(_localizationService.GetResource("Admin.Common.GenericAttributes.NameAlreadyExists"), model.Key)); - } + var attr = _genericAttributeService.GetAttribute(model.EntityName, model.EntityId, model.Key, storeId); + if (attr == null) + { + _genericAttributeService.InsertAttribute(new GenericAttribute + { + StoreId = storeId, + KeyGroup = model.EntityName, + EntityId = model.EntityId, + Key = model.Key, + Value = model.Value + }); + } + else + { + return Content(T("Admin.Common.GenericAttributes.NameAlreadyExists", model.Key)); + } + } return GenericAttributesSelect(model.EntityName, model.EntityId, command); } @@ -1111,38 +1117,38 @@ public ActionResult GenericAttributeAdd(GenericAttributeModel model, GridCommand [GridAction(EnableCustomBinding = true)] public ActionResult GenericAttributeUpdate(GenericAttributeModel model, GridCommand command) { - if (!_services.Permissions.Authorize(StandardPermissionProvider.AccessAdminPanel)) - return AccessDeniedView(); + if (_services.Permissions.Authorize(StandardPermissionProvider.AccessAdminPanel)) + { + model.Key = model.Key.TrimSafe(); + model.Value = model.Value.TrimSafe(); - model.Key = model.Key.TrimSafe(); - model.Value = model.Value.TrimSafe(); + if (!ModelState.IsValid) + { + var modelStateErrorMessages = this.ModelState.Values.SelectMany(x => x.Errors).Select(x => x.ErrorMessage); + return Content(modelStateErrorMessages.FirstOrDefault()); + } - if (!ModelState.IsValid) - { - // display the first model error - var modelStateErrorMessages = this.ModelState.Values.SelectMany(x => x.Errors).Select(x => x.ErrorMessage); - return Content(modelStateErrorMessages.FirstOrDefault()); - } + var storeId = _services.StoreContext.CurrentStore.Id; - var storeId = _services.StoreContext.CurrentStore.Id; + var attr = _genericAttributeService.GetAttributeById(model.Id); + // if the key changed, ensure it isn't being used by another attribute + if (!attr.Key.IsCaseInsensitiveEqual(model.Key)) + { + var attr2 = _genericAttributeService.GetAttributesForEntity(model.EntityId, model.EntityName) + .Where(x => x.StoreId == storeId && x.Key.Equals(model.Key, StringComparison.InvariantCultureIgnoreCase)) + .FirstOrDefault(); - var attr = _genericAttributeService.GetAttributeById(model.Id); - // if the key changed, ensure it isn't being used by another attribute - if (!attr.Key.IsCaseInsensitiveEqual(model.Key)) - { - var attr2 = _genericAttributeService.GetAttributesForEntity(model.EntityId, model.EntityName) - .Where(x => x.StoreId == storeId && x.Key.Equals(model.Key, StringComparison.InvariantCultureIgnoreCase)) - .FirstOrDefault(); - if (attr2 != null && attr2.Id != attr.Id) - { - return Content(string.Format(_localizationService.GetResource("Admin.Common.GenericAttributes.NameAlreadyExists"), model.Key)); - } - } + if (attr2 != null && attr2.Id != attr.Id) + { + return Content(T("Admin.Common.GenericAttributes.NameAlreadyExists", model.Key)); + } + } - attr.Key = model.Key; - attr.Value = model.Value; + attr.Key = model.Key; + attr.Value = model.Value; - _genericAttributeService.UpdateAttribute(attr); + _genericAttributeService.UpdateAttribute(attr); + } return GenericAttributesSelect(model.EntityName, model.EntityId, command); } @@ -1150,17 +1156,12 @@ public ActionResult GenericAttributeUpdate(GenericAttributeModel model, GridComm [GridAction(EnableCustomBinding = true)] public ActionResult GenericAttributeDelete(int id, GridCommand command) { - if (!_services.Permissions.Authorize(StandardPermissionProvider.AccessAdminPanel)) - return AccessDeniedView(); - var attr = _genericAttributeService.GetAttributeById(id); - if (attr == null) - { - throw new System.Web.HttpException(404, "No resource found with the specified id"); - } - - _genericAttributeService.DeleteAttribute(attr); + if (_services.Permissions.Authorize(StandardPermissionProvider.AccessAdminPanel)) + { + _genericAttributeService.DeleteAttribute(attr); + } return GenericAttributesSelect(attr.KeyGroup, attr.EntityId, command); } diff --git a/src/Presentation/SmartStore.Web/Administration/Controllers/CountryController.cs b/src/Presentation/SmartStore.Web/Administration/Controllers/CountryController.cs index bf67df0dae..3a4d573b43 100644 --- a/src/Presentation/SmartStore.Web/Administration/Controllers/CountryController.cs +++ b/src/Presentation/SmartStore.Web/Administration/Controllers/CountryController.cs @@ -304,17 +304,22 @@ public ActionResult DeleteConfirmed(int id) [HttpPost, GridAction(EnableCustomBinding = true)] public ActionResult States(int countryId, GridCommand command) { - if (!_services.Permissions.Authorize(StandardPermissionProvider.ManageCountries)) - return AccessDeniedView(); + var model = new GridModel(); - var states = _stateProvinceService.GetStateProvincesByCountryId(countryId, true) - .Select(x => x.ToModel()); + if (_services.Permissions.Authorize(StandardPermissionProvider.ManageCountries)) + { + var states = _stateProvinceService.GetStateProvincesByCountryId(countryId, true) + .Select(x => x.ToModel()); - var model = new GridModel - { - Data = states, - Total = states.Count() - }; + model.Data = states; + model.Total = states.Count(); + } + else + { + model.Data = Enumerable.Empty(); + + NotifyAccessDenied(); + } return new JsonResult { @@ -417,18 +422,18 @@ public ActionResult StateEditPopup(string btnId, string formId, StateProvinceMod [GridAction(EnableCustomBinding = true)] public ActionResult StateDelete(int id, GridCommand command) { - if (!_services.Permissions.Authorize(StandardPermissionProvider.ManageCountries)) - return AccessDeniedView(); - - var state = _stateProvinceService.GetStateProvinceById(id); - if (state == null) - throw new ArgumentException("No state found with the specified id"); + var state = _stateProvinceService.GetStateProvinceById(id); + var countryId = state.CountryId; - if (_addressService.GetAddressTotalByStateProvinceId(state.Id) > 0) - return Content(T("Admin.Configuration.Countries.States.CantDeleteWithAddresses")); + if (_services.Permissions.Authorize(StandardPermissionProvider.ManageCountries)) + { + if (_addressService.GetAddressTotalByStateProvinceId(state.Id) > 0) + { + return Content(T("Admin.Configuration.Countries.States.CantDeleteWithAddresses")); + } - int countryId = state.CountryId; - _stateProvinceService.DeleteStateProvince(state); + _stateProvinceService.DeleteStateProvince(state); + } return States(countryId, command); } diff --git a/src/Presentation/SmartStore.Web/Administration/Controllers/CurrencyController.cs b/src/Presentation/SmartStore.Web/Administration/Controllers/CurrencyController.cs index 181071a2d2..e20b59013c 100644 --- a/src/Presentation/SmartStore.Web/Administration/Controllers/CurrencyController.cs +++ b/src/Presentation/SmartStore.Web/Administration/Controllers/CurrencyController.cs @@ -239,18 +239,25 @@ public ActionResult Save(FormCollection formValues) [HttpPost, GridAction(EnableCustomBinding = true)] public ActionResult List(GridCommand command) { - if (!_services.Permissions.Authorize(StandardPermissionProvider.ManageCurrencies)) - return AccessDeniedView(); + var model = new GridModel(); + + if (_services.Permissions.Authorize(StandardPermissionProvider.ManageCurrencies)) + { + var currencies = _currencyService.GetAllCurrencies(true); + + model.Data = currencies.Select(x => x.ToModel()); + model.Total = currencies.Count(); + } + else + { + model.Data = Enumerable.Empty(); + + NotifyAccessDenied(); + } - var currencies = _currencyService.GetAllCurrencies(true); - var gridModel = new GridModel - { - Data = currencies.Select(x => x.ToModel()), - Total = currencies.Count() - }; return new JsonResult { - Data = gridModel + Data = model }; } diff --git a/src/Presentation/SmartStore.Web/Administration/Controllers/CustomerController.cs b/src/Presentation/SmartStore.Web/Administration/Controllers/CustomerController.cs index 892bbaf5c6..0a91c9860f 100644 --- a/src/Presentation/SmartStore.Web/Administration/Controllers/CustomerController.cs +++ b/src/Presentation/SmartStore.Web/Administration/Controllers/CustomerController.cs @@ -396,28 +396,37 @@ public ActionResult List() [HttpPost, GridAction(EnableCustomBinding = true)] public ActionResult CustomerList(GridCommand command, CustomerListModel model, [ModelBinderAttribute(typeof(CommaSeparatedModelBinder))] int[] searchCustomerRoleIds) { - //we use own own binder for searchCustomerRoleIds property - if (!_permissionService.Authorize(StandardPermissionProvider.ManageCustomers)) - return AccessDeniedView(); + // we use own own binder for searchCustomerRoleIds property + var gridModel = new GridModel(); + + if (_permissionService.Authorize(StandardPermissionProvider.ManageCustomers)) + { + var searchDayOfBirth = 0; + var searchMonthOfBirth = 0; + + if (!String.IsNullOrWhiteSpace(model.SearchDayOfBirth)) + searchDayOfBirth = Convert.ToInt32(model.SearchDayOfBirth); + + if (!String.IsNullOrWhiteSpace(model.SearchMonthOfBirth)) + searchMonthOfBirth = Convert.ToInt32(model.SearchMonthOfBirth); + + var customers = _customerService.GetAllCustomers(null, null, + searchCustomerRoleIds, model.SearchEmail, model.SearchUsername, + model.SearchFirstName, model.SearchLastName, + searchDayOfBirth, searchMonthOfBirth, + model.SearchCompany, model.SearchPhone, model.SearchZipPostalCode, + false, null, command.Page - 1, command.PageSize); + + gridModel.Data = customers.Select(PrepareCustomerModelForList); + gridModel.Total = customers.TotalCount; + } + else + { + gridModel.Data = Enumerable.Empty(); + + NotifyAccessDenied(); + } - var searchDayOfBirth = 0; - int searchMonthOfBirth = 0; - if (!String.IsNullOrWhiteSpace(model.SearchDayOfBirth)) - searchDayOfBirth = Convert.ToInt32(model.SearchDayOfBirth); - if (!String.IsNullOrWhiteSpace(model.SearchMonthOfBirth)) - searchMonthOfBirth = Convert.ToInt32(model.SearchMonthOfBirth); - - var customers = _customerService.GetAllCustomers(null, null, - searchCustomerRoleIds, model.SearchEmail, model.SearchUsername, - model.SearchFirstName, model.SearchLastName, - searchDayOfBirth, searchMonthOfBirth, - model.SearchCompany, model.SearchPhone, model.SearchZipPostalCode, - false, null, command.Page - 1, command.PageSize); - var gridModel = new GridModel - { - Data = customers.Select(PrepareCustomerModelForList), - Total = customers.TotalCount - }; return new JsonResult { Data = gridModel @@ -1519,17 +1528,15 @@ public ActionResult AddressEdit(CustomerAddressModel model) [HttpPost, GridAction(EnableCustomBinding = true)] public ActionResult OrderList(int customerId, GridCommand command) { - if (!_permissionService.Authorize(StandardPermissionProvider.ManageCustomers)) - return AccessDeniedView(); + var model = new GridModel(); - var orders = _orderService.SearchOrders(0, customerId, - null, null, null, null, null, null, null, null, 0, int.MaxValue); + if (_permissionService.Authorize(StandardPermissionProvider.ManageCustomers)) + { + var orders = _orderService.SearchOrders(0, customerId, null, null, null, null, null, null, null, null, 0, int.MaxValue); - var model = new GridModel - { - Data = orders.PagedForCommand(command) - .Select(order => - { + model.Data = orders.PagedForCommand(command) + .Select(order => + { var store = _storeService.GetStoreById(order.StoreId); var orderModel = new CustomerModel.OrderModel() { @@ -1538,13 +1545,20 @@ public ActionResult OrderList(int customerId, GridCommand command) PaymentStatus = order.PaymentStatus.GetLocalizedEnum(_localizationService, _workContext), ShippingStatus = order.ShippingStatus.GetLocalizedEnum(_localizationService, _workContext), OrderTotal = _priceFormatter.FormatPrice(order.OrderTotal, true, false), - StoreName = store != null ? store.Name : "Unknown", + StoreName = store != null ? store.Name : "".NaIfEmpty(), CreatedOn = _dateTimeHelper.ConvertToUserTime(order.CreatedOnUtc, DateTimeKind.Utc), }; - return orderModel; - }), - Total = orders.Count - }; + return orderModel; + }); + + model.Total = orders.Count; + } + else + { + model.Data = Enumerable.Empty(); + + NotifyAccessDenied(); + } return new JsonResult { @@ -1596,9 +1610,8 @@ public ActionResult ReportBestCustomersByOrderTotalList(GridCommand command, Bes PaymentStatus? paymentStatus = model.PaymentStatusId > 0 ? (PaymentStatus?)(model.PaymentStatusId) : null; ShippingStatus? shippingStatus = model.ShippingStatusId > 0 ? (ShippingStatus?)(model.ShippingStatusId) : null; + var items = _customerReportService.GetBestCustomersReport(startDateValue, endDateValue, orderStatus, paymentStatus, shippingStatus, 1); - var items = _customerReportService.GetBestCustomersReport(startDateValue, endDateValue, - orderStatus, paymentStatus, shippingStatus, 1); var gridModel = new GridModel { Data = items.Select(x => @@ -1609,23 +1622,25 @@ public ActionResult ReportBestCustomersByOrderTotalList(GridCommand command, Bes OrderTotal = _priceFormatter.FormatPrice(x.OrderTotal, true, false), OrderCount = x.OrderCount, }; + var customer = _customerService.GetCustomerById(x.CustomerId); if (customer != null) { - m.CustomerName = customer.IsGuest() - ? _localizationService.GetResource("Admin.Customers.Guest") - : customer.Email; + m.CustomerName = customer.IsGuest() ? T("Admin.Customers.Guest").Text : customer.Email; } + return m; }), Total = items.Count }; + return new JsonResult { Data = gridModel }; } - [GridAction(EnableCustomBinding = true)] + + [GridAction(EnableCustomBinding = true)] public ActionResult ReportBestCustomersByNumberOfOrdersList(GridCommand command, BestCustomersReportModel model) { DateTime? startDateValue = (model.StartDate == null) ? null @@ -1638,26 +1653,25 @@ public ActionResult ReportBestCustomersByNumberOfOrdersList(GridCommand command, PaymentStatus? paymentStatus = model.PaymentStatusId > 0 ? (PaymentStatus?)(model.PaymentStatusId) : null; ShippingStatus? shippingStatus = model.ShippingStatusId > 0 ? (ShippingStatus?)(model.ShippingStatusId) : null; + var items = _customerReportService.GetBestCustomersReport(startDateValue, endDateValue, orderStatus, paymentStatus, shippingStatus, 2); - var items = _customerReportService.GetBestCustomersReport(startDateValue, endDateValue, - orderStatus, paymentStatus, shippingStatus, 2); var gridModel = new GridModel { Data = items.Select(x => { - var m = new BestCustomerReportLineModel() + var m = new BestCustomerReportLineModel { CustomerId = x.CustomerId, OrderTotal = _priceFormatter.FormatPrice(x.OrderTotal, true, false), OrderCount = x.OrderCount, }; + var customer = _customerService.GetCustomerById(x.CustomerId); if (customer != null) { - m.CustomerName = customer.IsGuest() - ? _localizationService.GetResource("Admin.Customers.Guest") - : customer.Email; + m.CustomerName = customer.IsGuest() ? T("Admin.Customers.Guest").Text : customer.Email; } + return m; }), Total = items.Count @@ -1674,15 +1688,18 @@ public ActionResult ReportRegisteredCustomers() var model = GetReportRegisteredCustomersModel(); return PartialView(model); } - [GridAction(EnableCustomBinding = true)] + + [GridAction(EnableCustomBinding = true)] public ActionResult ReportRegisteredCustomersList(GridCommand command) { var model = GetReportRegisteredCustomersModel(); - var gridModel = new GridModel + + var gridModel = new GridModel { Data = model, Total = model.Count }; + return new JsonResult { Data = gridModel @@ -1699,16 +1716,17 @@ public ActionResult GetCartList(int customerId, int cartTypeId) var customer = _customerService.GetCustomerById(customerId); var cart = customer.GetCartItems((ShoppingCartType)cartTypeId); - var gridModel = new GridModel() + var gridModel = new GridModel { Data = cart.Select(sci => { decimal taxRate; var store = _storeService.GetStoreById(sci.Item.StoreId); - var sciModel = new ShoppingCartItemModel() + + var sciModel = new ShoppingCartItemModel { Id = sci.Item.Id, - Store = store != null ? store.Name : "Unknown", + Store = store != null ? store.Name : "".NaIfEmpty(), ProductId = sci.Item.ProductId, Quantity = sci.Item.Quantity, ProductName = sci.Item.Product.Name, @@ -1722,6 +1740,7 @@ public ActionResult GetCartList(int customerId, int cartTypeId) }), Total = cart.Count }; + return new JsonResult { Data = gridModel @@ -1736,11 +1755,12 @@ public ActionResult GetCartList(int customerId, int cartTypeId) public JsonResult ListActivityLog(GridCommand command, int customerId) { var activityLog = _customerActivityService.GetAllActivities(null, null, customerId, 0, command.Page - 1, command.PageSize); + var gridModel = new GridModel { Data = activityLog.Select(x => { - var m = new CustomerModel.ActivityLogModel() + var m = new CustomerModel.ActivityLogModel { Id = x.Id, ActivityLogTypeName = x.ActivityLogType.Name, @@ -1748,11 +1768,11 @@ public JsonResult ListActivityLog(GridCommand command, int customerId) CreatedOn = _dateTimeHelper.ConvertToUserTime(x.CreatedOnUtc, DateTimeKind.Utc) }; return m; - }), Total = activityLog.TotalCount }; - return new JsonResult { Data = gridModel }; ; + + return new JsonResult { Data = gridModel }; } #endregion diff --git a/src/Presentation/SmartStore.Web/Administration/Controllers/CustomerRoleController.cs b/src/Presentation/SmartStore.Web/Administration/Controllers/CustomerRoleController.cs index 7cc7fa5575..6bb2d10b47 100644 --- a/src/Presentation/SmartStore.Web/Administration/Controllers/CustomerRoleController.cs +++ b/src/Presentation/SmartStore.Web/Administration/Controllers/CustomerRoleController.cs @@ -102,18 +102,25 @@ public ActionResult List() [HttpPost, GridAction(EnableCustomBinding = true)] public ActionResult List(GridCommand command) { - if (!_permissionService.Authorize(StandardPermissionProvider.ManageCustomerRoles)) - return AccessDeniedView(); - - var customerRoles = _customerService.GetAllCustomerRoles(true); - var gridModel = new GridModel + var model = new GridModel(); + + if (_permissionService.Authorize(StandardPermissionProvider.ManageCustomerRoles)) { - Data = customerRoles.Select(x => x.ToModel()), - Total = customerRoles.Count() - }; + var customerRoles = _customerService.GetAllCustomerRoles(true); + + model.Data = customerRoles.Select(x => x.ToModel()); + model.Total = customerRoles.Count(); + } + else + { + model.Data = Enumerable.Empty(); + + NotifyAccessDenied(); + } + return new JsonResult { - Data = gridModel + Data = model }; } diff --git a/src/Presentation/SmartStore.Web/Administration/Controllers/DiscountController.cs b/src/Presentation/SmartStore.Web/Administration/Controllers/DiscountController.cs index 6e18b8ec06..c9ab6e4496 100644 --- a/src/Presentation/SmartStore.Web/Administration/Controllers/DiscountController.cs +++ b/src/Presentation/SmartStore.Web/Administration/Controllers/DiscountController.cs @@ -138,7 +138,6 @@ private void PrepareDiscountModel(DiscountModel model, Discount discount) #region Discounts - //list public ActionResult Index() { return RedirectToAction("List"); @@ -161,22 +160,28 @@ public ActionResult List() [HttpPost, GridAction(EnableCustomBinding = true)] public ActionResult List(GridCommand command) { - if (!_services.Permissions.Authorize(StandardPermissionProvider.ManageDiscounts)) - return AccessDeniedView(); + var model = new GridModel(); + + if (_services.Permissions.Authorize(StandardPermissionProvider.ManageDiscounts)) + { + var discounts = _discountService.GetAllDiscounts(null, null, true); + + model.Data = discounts.Select(x => x.ToModel()); + model.Total = discounts.Count(); + } + else + { + model.Data = Enumerable.Empty(); + + NotifyAccessDenied(); + } - var discounts = _discountService.GetAllDiscounts(null, null, true); - var gridModel = new GridModel - { - Data = discounts.Select(x => x.ToModel()), - Total = discounts.Count() - }; return new JsonResult { - Data = gridModel + Data = model }; } - //create public ActionResult Create() { if (!_services.Permissions.Authorize(StandardPermissionProvider.ManageDiscounts)) @@ -212,7 +217,6 @@ public ActionResult Create(DiscountModel model, bool continueEditing) return View(model); } - //edit public ActionResult Edit(int id) { if (!_services.Permissions.Authorize(StandardPermissionProvider.ManageDiscounts)) @@ -281,7 +285,6 @@ public ActionResult Edit(DiscountModel model, bool continueEditing) return View(model); } - //delete [HttpPost, ActionName("Delete")] public ActionResult DeleteConfirmed(int id) { @@ -386,28 +389,31 @@ public ActionResult DeleteDiscountRequirement(int discountRequirementId, int dis [HttpPost, GridAction(EnableCustomBinding = true)] public ActionResult UsageHistoryList(int discountId, GridCommand command) { - if (!_services.Permissions.Authorize(StandardPermissionProvider.ManageDiscounts)) - return AccessDeniedView(); + var model = new GridModel(); - var discount = _discountService.GetDiscountById(discountId); - if (discount == null) - throw new ArgumentException("No discount found with the specified id"); + if (_services.Permissions.Authorize(StandardPermissionProvider.ManageDiscounts)) + { + var discount = _discountService.GetDiscountById(discountId); + + var discountHistories = _discountService.GetAllDiscountUsageHistory(discount.Id, null, command.Page - 1, command.PageSize); + + model.Data = discountHistories.Select(x => new DiscountModel.DiscountUsageHistoryModel + { + Id = x.Id, + DiscountId = x.DiscountId, + OrderId = x.OrderId, + CreatedOn = _dateTimeHelper.ConvertToUserTime(x.CreatedOnUtc, DateTimeKind.Utc) + }); + + model.Total = discountHistories.TotalCount; + } + else + { + model.Data = Enumerable.Empty(); + + NotifyAccessDenied(); + } - var duh = _discountService.GetAllDiscountUsageHistory(discount.Id, null, command.Page - 1, command.PageSize); - var model = new GridModel - { - Data = duh.Select(x => - { - return new DiscountModel.DiscountUsageHistoryModel - { - Id = x.Id, - DiscountId = x.DiscountId, - OrderId = x.OrderId, - CreatedOn = _dateTimeHelper.ConvertToUserTime(x.CreatedOnUtc, DateTimeKind.Utc) - }; - }), - Total = duh.TotalCount - }; return new JsonResult { Data = model @@ -417,16 +423,13 @@ public ActionResult UsageHistoryList(int discountId, GridCommand command) [GridAction(EnableCustomBinding = true)] public ActionResult UsageHistoryDelete(int discountId, int id, GridCommand command) { - if (!_services.Permissions.Authorize(StandardPermissionProvider.ManageDiscounts)) - return AccessDeniedView(); + if (_services.Permissions.Authorize(StandardPermissionProvider.ManageDiscounts)) + { + var discountHistory = _discountService.GetDiscountUsageHistoryById(id); + + _discountService.DeleteDiscountUsageHistory(discountHistory); + } - var discount = _discountService.GetDiscountById(discountId); - if (discount == null) - throw new ArgumentException("No discount found with the specified id"); - - var duh = _discountService.GetDiscountUsageHistoryById(id); - if (duh != null) - _discountService.DeleteDiscountUsageHistory(duh); return UsageHistoryList(discountId, command); } diff --git a/src/Presentation/SmartStore.Web/Administration/Controllers/EmailAccountController.cs b/src/Presentation/SmartStore.Web/Administration/Controllers/EmailAccountController.cs index c883d5f266..2586a826cb 100644 --- a/src/Presentation/SmartStore.Web/Administration/Controllers/EmailAccountController.cs +++ b/src/Presentation/SmartStore.Web/Administration/Controllers/EmailAccountController.cs @@ -78,24 +78,32 @@ public ActionResult List(string id) [HttpPost, GridAction(EnableCustomBinding = true)] public ActionResult List(GridCommand command) { - if (!_permissionService.Authorize(StandardPermissionProvider.ManageEmailAccounts)) - return AccessDeniedView(); + var model = new GridModel(); - var emailAccountModels = _emailAccountService.GetAllEmailAccounts() - .Select(x => x.ToModel()) - .ToList(); - foreach (var eam in emailAccountModels) - eam.IsDefaultEmailAccount = eam.Id == _emailAccountSettings.DefaultEmailAccountId; + if (_permissionService.Authorize(StandardPermissionProvider.ManageEmailAccounts)) + { + var emailAccountModels = _emailAccountService.GetAllEmailAccounts() + .Select(x => x.ToModel()) + .ToList(); - var gridModel = new GridModel - { - Data = emailAccountModels, - Total = emailAccountModels.Count() - }; + foreach (var eam in emailAccountModels) + { + eam.IsDefaultEmailAccount = eam.Id == _emailAccountSettings.DefaultEmailAccountId; + } + + model.Data = emailAccountModels; + model.Total = emailAccountModels.Count(); + } + else + { + model.Data = Enumerable.Empty(); + + NotifyAccessDenied(); + } return new JsonResult { - Data = gridModel + Data = model }; } diff --git a/src/Presentation/SmartStore.Web/Administration/Controllers/ExportController.cs b/src/Presentation/SmartStore.Web/Administration/Controllers/ExportController.cs index 2e719959ec..39579caa57 100644 --- a/src/Presentation/SmartStore.Web/Administration/Controllers/ExportController.cs +++ b/src/Presentation/SmartStore.Web/Administration/Controllers/ExportController.cs @@ -823,11 +823,17 @@ public ActionResult Preview(int id) [HttpPost, GridAction(EnableCustomBinding = true)] public ActionResult PreviewList(GridCommand command, int id, int totalRecords) { + if (_services.Permissions.Authorize(StandardPermissionProvider.ManageExports)) + { + NotifyAccessDenied(); + + return new JsonResult { Data = Enumerable.Empty() }; + } + ExportProfile profile = null; Provider provider = null; - if (_services.Permissions.Authorize(StandardPermissionProvider.ManageExports) && - (profile = _exportService.GetExportProfileById(id)) != null && + if ((profile = _exportService.GetExportProfileById(id)) != null && (provider = _exportService.LoadProvider(profile.ProviderSystemName)) != null && !provider.Metadata.IsHidden) { @@ -984,7 +990,7 @@ public ActionResult PreviewList(GridCommand command, int id, int totalRecords) return new JsonResult { Data = gridData }; } - return new EmptyResult(); + return new JsonResult { Data = Enumerable.Empty() }; } [HttpPost] diff --git a/src/Presentation/SmartStore.Web/Administration/Controllers/GiftCardController.cs b/src/Presentation/SmartStore.Web/Administration/Controllers/GiftCardController.cs index ea3eff5cd1..f52756dd84 100644 --- a/src/Presentation/SmartStore.Web/Administration/Controllers/GiftCardController.cs +++ b/src/Presentation/SmartStore.Web/Administration/Controllers/GiftCardController.cs @@ -94,27 +94,37 @@ public ActionResult List() [GridAction(EnableCustomBinding = true)] public ActionResult GiftCardList(GridCommand command, GiftCardListModel model) { - if (!_services.Permissions.Authorize(StandardPermissionProvider.ManageGiftCards)) - return AccessDeniedView(); + var gridModel = new GridModel(); + + if (_services.Permissions.Authorize(StandardPermissionProvider.ManageGiftCards)) + { + bool? isGiftCardActivated = null; + + if (model.ActivatedId == 1) + isGiftCardActivated = true; + else if (model.ActivatedId == 2) + isGiftCardActivated = false; + + var giftCards = _giftCardService.GetAllGiftCards(null, null, null, isGiftCardActivated, model.CouponCode); + + gridModel.Data = giftCards.PagedForCommand(command).Select(x => + { + var m = x.ToModel(); + m.RemainingAmountStr = _priceFormatter.FormatPrice(x.GetGiftCardRemainingAmount(), true, false); + m.AmountStr = _priceFormatter.FormatPrice(x.Amount, true, false); + m.CreatedOn = _dateTimeHelper.ConvertToUserTime(x.CreatedOnUtc, DateTimeKind.Utc); + return m; + }); + + gridModel.Total = giftCards.Count(); + } + else + { + gridModel.Data = Enumerable.Empty(); + + NotifyAccessDenied(); + } - bool? isGiftCardActivated = null; - if (model.ActivatedId == 1) - isGiftCardActivated = true; - else if (model.ActivatedId == 2) - isGiftCardActivated = false; - var giftCards = _giftCardService.GetAllGiftCards(null, null, null, isGiftCardActivated, model.CouponCode); - var gridModel = new GridModel - { - Data = giftCards.PagedForCommand(command).Select(x => - { - var m = x.ToModel(); - m.RemainingAmountStr = _priceFormatter.FormatPrice(x.GetGiftCardRemainingAmount(), true, false); - m.AmountStr = _priceFormatter.FormatPrice(x.Amount, true, false); - m.CreatedOn = _dateTimeHelper.ConvertToUserTime(x.CreatedOnUtc, DateTimeKind.Utc); - return m; - }), - Total = giftCards.Count() - }; return new JsonResult { Data = gridModel @@ -274,46 +284,48 @@ public ActionResult DeleteConfirmed(int id) var giftCard = _giftCardService.GetGiftCardById(id); if (giftCard == null) - //No gift card found with the specified id return RedirectToAction("List"); _giftCardService.DeleteGiftCard(giftCard); - //activity log _customerActivityService.InsertActivity("DeleteGiftCard", _services.Localization.GetResource("ActivityLog.DeleteGiftCard"), giftCard.GiftCardCouponCode); NotifySuccess(_services.Localization.GetResource("Admin.GiftCards.Deleted")); return RedirectToAction("List"); } - //Gif card usage history [HttpPost, GridAction(EnableCustomBinding = true)] public ActionResult UsageHistoryList(int giftCardId, GridCommand command) { - if (!_services.Permissions.Authorize(StandardPermissionProvider.ManageGiftCards)) - return AccessDeniedView(); - - var giftCard = _giftCardService.GetGiftCardById(giftCardId); - if (giftCard == null) - throw new ArgumentException("No gift card found with the specified id"); - - var usageHistoryModel = giftCard.GiftCardUsageHistory.OrderByDescending(gcuh => gcuh.CreatedOnUtc) - .Select(x => - { - return new GiftCardModel.GiftCardUsageHistoryModel() - { - Id = x.Id, - OrderId = x.UsedWithOrderId, - UsedValue = _priceFormatter.FormatPrice(x.UsedValue, true, false), - CreatedOn = _dateTimeHelper.ConvertToUserTime(x.CreatedOnUtc, DateTimeKind.Utc) - }; - }) - .ToList(); - var model = new GridModel - { - Data = usageHistoryModel.PagedForCommand(command), - Total = usageHistoryModel.Count - }; + var model = new GridModel(); + + if (_services.Permissions.Authorize(StandardPermissionProvider.ManageGiftCards)) + { + var giftCard = _giftCardService.GetGiftCardById(giftCardId); + + var usageHistoryModel = giftCard.GiftCardUsageHistory + .OrderByDescending(gcuh => gcuh.CreatedOnUtc) + .Select(x => + { + return new GiftCardModel.GiftCardUsageHistoryModel() + { + Id = x.Id, + OrderId = x.UsedWithOrderId, + UsedValue = _priceFormatter.FormatPrice(x.UsedValue, true, false), + CreatedOn = _dateTimeHelper.ConvertToUserTime(x.CreatedOnUtc, DateTimeKind.Utc) + }; + }) + .ToList(); + + model.Data = usageHistoryModel.PagedForCommand(command); + model.Total = usageHistoryModel.Count; + } + else + { + model.Data = Enumerable.Empty(); + + NotifyAccessDenied(); + } return new JsonResult { From 619e8dcb4426c7503ce455b9d6be10b0e7bf08b8 Mon Sep 17 00:00:00 2001 From: Marcus Gesing Date: Wed, 6 Jan 2016 12:19:09 +0100 Subject: [PATCH 215/707] Faulty permission handling in ajax grid actions (no message, infinite loading icon)(part 2) --- .../Controllers/WebApiController.cs | 2 +- .../Controllers/LanguageController.cs | 192 +- .../Controllers/LogController.cs | 78 +- .../Controllers/ManufacturerController.cs | 160 +- .../Controllers/MeasureController.cs | 198 +- .../Controllers/MessageTemplateController.cs | 20 +- .../Controllers/NewsController.cs | 138 +- .../NewsLetterSubscriptionController.cs | 70 +- .../Controllers/OnlineCustomerController.cs | 48 +- .../Controllers/OrderController.cs | 331 +-- .../Controllers/PollController.cs | 172 +- .../Controllers/ProductAttributeController.cs | 26 +- .../Controllers/ProductController.cs | 1766 +++++++++-------- .../Controllers/ProductReviewController.cs | 45 +- .../Controllers/QueuedEmailController.cs | 64 +- .../Controllers/RecurringPaymentController.cs | 81 +- .../Controllers/ReturnRequestController.cs | 38 +- .../Controllers/SettingController.cs | 173 +- .../Controllers/ShippingController.cs | 27 +- .../Controllers/ShoppingCartController.cs | 200 +- .../SpecificationAttributeController.cs | 96 +- .../Controllers/StoreController.cs | 35 +- .../Controllers/TaxController.cs | 83 +- .../Controllers/TopicController.cs | 27 +- .../Controllers/UrlRecordController.cs | 32 +- 25 files changed, 2200 insertions(+), 1902 deletions(-) diff --git a/src/Plugins/SmartStore.WebApi/Controllers/WebApiController.cs b/src/Plugins/SmartStore.WebApi/Controllers/WebApiController.cs index 808387b270..4fb254bbff 100644 --- a/src/Plugins/SmartStore.WebApi/Controllers/WebApiController.cs +++ b/src/Plugins/SmartStore.WebApi/Controllers/WebApiController.cs @@ -97,7 +97,7 @@ public ActionResult SaveGeneralSettings(WebApiConfigModel model) public ActionResult GridUserData(GridCommand command) { if (!HasPermission()) - return new JsonResult { Data = new GridModel { Data = new List() }}; + return new JsonResult { Data = new GridModel { Data = new List() } }; var model = _webApiPluginService.GetGridModel(command.Page - 1, command.PageSize); diff --git a/src/Presentation/SmartStore.Web/Administration/Controllers/LanguageController.cs b/src/Presentation/SmartStore.Web/Administration/Controllers/LanguageController.cs index e546998d03..02587df34f 100644 --- a/src/Presentation/SmartStore.Web/Administration/Controllers/LanguageController.cs +++ b/src/Presentation/SmartStore.Web/Administration/Controllers/LanguageController.cs @@ -60,7 +60,8 @@ public LanguageController(ILanguageService languageService, } #endregion - #region Utilities + + #region Utilities [NonAction] private void PrepareFlagsModel(LanguageModel model) @@ -123,18 +124,25 @@ public ActionResult List() [HttpPost, GridAction(EnableCustomBinding = true)] public ActionResult List(GridCommand command) { - if (!_permissionService.Authorize(StandardPermissionProvider.ManageLanguages)) - return AccessDeniedView(); + var model = new GridModel(); + + if (_permissionService.Authorize(StandardPermissionProvider.ManageLanguages)) + { + var languages = _languageService.GetAllLanguages(true); + + model.Data = languages.Select(x => x.ToModel()); + model.Total = languages.Count(); + } + else + { + model.Data = Enumerable.Empty(); + + NotifyAccessDenied(); + } - var languages = _languageService.GetAllLanguages(true); - var gridModel = new GridModel - { - Data = languages.Select(x => x.ToModel()), - Total = languages.Count() - }; return new JsonResult { - Data = gridModel + Data = model }; } @@ -329,31 +337,37 @@ public ActionResult Resources(int languageId) [HttpPost, GridAction(EnableCustomBinding = true)] public ActionResult Resources(int languageId, GridCommand command) { - if (!_permissionService.Authorize(StandardPermissionProvider.ManageLanguages)) - return AccessDeniedView(); + var model = new GridModel(); - var language = _languageService.GetLanguageById(languageId); + if (_permissionService.Authorize(StandardPermissionProvider.ManageLanguages)) + { + var language = _languageService.GetLanguageById(languageId); + + var resources = _localizationService + .GetResourceValues(languageId, true) + .OrderBy(x => x.Key) + .Where(x => x.Key != "!!___EOF___!!" && x.Value != null) + .Select(x => new LanguageResourceModel + { + LanguageId = languageId, + LanguageName = language.Name, + Id = x.Value.Item1, + Name = x.Key, + Value = x.Value.Item2.EmptyNull(), + }) + .ForCommand(command) + .ToList(); + + model.Data = resources.PagedForCommand(command); + model.Total = resources.Count; + } + else + { + model.Data = Enumerable.Empty(); - var resources = _localizationService - .GetResourceValues(languageId, true) - .OrderBy(x => x.Key) - .Where(x => x.Key != "!!___EOF___!!" && x.Value != null) - .Select(x => new LanguageResourceModel - { - LanguageId = languageId, - LanguageName = language.Name, - Id = x.Value.Item1, - Name = x.Key, - Value = x.Value.Item2.EmptyNull(), - }) - .ForCommand(command) - .ToList(); + NotifyAccessDenied(); + } - var model = new GridModel - { - Data = resources.PagedForCommand(command), - Total = resources.Count - }; return new JsonResult { Data = model @@ -363,36 +377,36 @@ public ActionResult Resources(int languageId, GridCommand command) [GridAction(EnableCustomBinding = true)] public ActionResult ResourceUpdate(LanguageResourceModel model, GridCommand command) { - if (!_permissionService.Authorize(StandardPermissionProvider.ManageLanguages)) - return AccessDeniedView(); + if (_permissionService.Authorize(StandardPermissionProvider.ManageLanguages)) + { + if (model.Name != null) + model.Name = model.Name.Trim(); + if (model.Value != null) + model.Value = model.Value.Trim(); - if (model.Name != null) - model.Name = model.Name.Trim(); - if (model.Value != null) - model.Value = model.Value.Trim(); + if (!ModelState.IsValid) + { + var modelStateErrors = this.ModelState.Values.SelectMany(x => x.Errors).Select(x => x.ErrorMessage); + return Content(modelStateErrors.FirstOrDefault()); + } - if (!ModelState.IsValid) - { - //display the first model error - var modelStateErrors = this.ModelState.Values.SelectMany(x => x.Errors).Select(x => x.ErrorMessage); - return Content(modelStateErrors.FirstOrDefault()); - } + var resource = _localizationService.GetLocaleStringResourceById(model.Id); + // if the resourceName changed, ensure it isn't being used by another resource + if (!resource.ResourceName.Equals(model.Name, StringComparison.InvariantCultureIgnoreCase)) + { + var res = _localizationService.GetLocaleStringResourceByName(model.Name, model.LanguageId, false); + if (res != null && res.Id != resource.Id) + { + return Content(T("Admin.Configuration.Languages.Resources.NameAlreadyExists", res.ResourceName)); + } + } - var resource = _localizationService.GetLocaleStringResourceById(model.Id); - // if the resourceName changed, ensure it isn't being used by another resource - if (!resource.ResourceName.Equals(model.Name, StringComparison.InvariantCultureIgnoreCase)) - { - var res = _localizationService.GetLocaleStringResourceByName(model.Name, model.LanguageId, false); - if (res != null && res.Id != resource.Id) - { - return Content(string.Format(_localizationService.GetResource("Admin.Configuration.Languages.Resources.NameAlreadyExists"), res.ResourceName)); - } - } + resource.ResourceName = model.Name; + resource.ResourceValue = model.Value; + resource.IsTouched = true; - resource.ResourceName = model.Name; - resource.ResourceValue = model.Value; - resource.IsTouched = true; - _localizationService.UpdateLocaleStringResource(resource); + _localizationService.UpdateLocaleStringResource(resource); + } return Resources(model.LanguageId, command); } @@ -400,47 +414,47 @@ public ActionResult ResourceUpdate(LanguageResourceModel model, GridCommand comm [GridAction(EnableCustomBinding = true)] public ActionResult ResourceAdd(int id, LanguageResourceModel model, GridCommand command) { - if (!_permissionService.Authorize(StandardPermissionProvider.ManageLanguages)) - return AccessDeniedView(); + if (_permissionService.Authorize(StandardPermissionProvider.ManageLanguages)) + { + if (model.Name != null) + model.Name = model.Name.Trim(); + if (model.Value != null) + model.Value = model.Value.Trim(); - if (model.Name != null) - model.Name = model.Name.Trim(); - if (model.Value != null) - model.Value = model.Value.Trim(); + if (!ModelState.IsValid) + { + var modelStateErrors = this.ModelState.Values.SelectMany(x => x.Errors).Select(x => x.ErrorMessage); + return Content(modelStateErrors.FirstOrDefault()); + } - if (!ModelState.IsValid) - { - //display the first model error - var modelStateErrors = this.ModelState.Values.SelectMany(x => x.Errors).Select(x => x.ErrorMessage); - return Content(modelStateErrors.FirstOrDefault()); - } + var res = _localizationService.GetLocaleStringResourceByName(model.Name, model.LanguageId, false); + if (res == null) + { + var resource = new LocaleStringResource { LanguageId = id }; + resource.ResourceName = model.Name; + resource.ResourceValue = model.Value; + resource.IsTouched = true; + + _localizationService.InsertLocaleStringResource(resource); + } + else + { + return Content(T("Admin.Configuration.Languages.Resources.NameAlreadyExists", model.Name)); + } + } - var res = _localizationService.GetLocaleStringResourceByName(model.Name, model.LanguageId, false); - if (res == null) - { - var resource = new LocaleStringResource { LanguageId = id }; - resource.ResourceName = model.Name; - resource.ResourceValue = model.Value; - resource.IsTouched = true; - _localizationService.InsertLocaleStringResource(resource); - } - else - { - return Content(string.Format(_localizationService.GetResource("Admin.Configuration.Languages.Resources.NameAlreadyExists"), model.Name)); - } return Resources(id, command); } [GridAction(EnableCustomBinding = true)] public ActionResult ResourceDelete(int id, int languageId, GridCommand command) { - if (!_permissionService.Authorize(StandardPermissionProvider.ManageLanguages)) - return AccessDeniedView(); + if (_permissionService.Authorize(StandardPermissionProvider.ManageLanguages)) + { + var resource = _localizationService.GetLocaleStringResourceById(id); - var resource = _localizationService.GetLocaleStringResourceById(id); - if (resource == null) - throw new ArgumentException("No resource found with the specified id"); - _localizationService.DeleteLocaleStringResource(resource); + _localizationService.DeleteLocaleStringResource(resource); + } return Resources(languageId, command); } diff --git a/src/Presentation/SmartStore.Web/Administration/Controllers/LogController.cs b/src/Presentation/SmartStore.Web/Administration/Controllers/LogController.cs index 8b82d5d894..9fb8db0105 100644 --- a/src/Presentation/SmartStore.Web/Administration/Controllers/LogController.cs +++ b/src/Presentation/SmartStore.Web/Administration/Controllers/LogController.cs @@ -64,49 +64,55 @@ public ActionResult List() [GridAction(EnableCustomBinding = true)] public ActionResult LogList(GridCommand command, LogListModel model) { - if (!_permissionService.Authorize(StandardPermissionProvider.ManageSystemLog)) - return AccessDeniedView(); - - DateTime? createdOnFromValue = (model.CreatedOnFrom == null) ? null - : (DateTime?)_dateTimeHelper.ConvertToUtcTime(model.CreatedOnFrom.Value, _dateTimeHelper.CurrentTimeZone); - - DateTime? createdToFromValue = (model.CreatedOnTo == null) ? null - : (DateTime?)_dateTimeHelper.ConvertToUtcTime(model.CreatedOnTo.Value, _dateTimeHelper.CurrentTimeZone).AddDays(1); - - LogLevel? logLevel = model.LogLevelId > 0 ? (LogLevel?)(model.LogLevelId) : null; - - - var logItems = Logger.GetAllLogs(createdOnFromValue, createdToFromValue, model.Message, - logLevel, command.Page - 1, command.PageSize, model.MinFrequency); - - var gridModel = new GridModel - { - Data = logItems.Select(x => - { - var logModel = new LogModel() - { - Id = x.Id, - LogLevelHint = s_logLevelHintMap[x.LogLevel], - LogLevel = x.LogLevel.GetLocalizedEnum(_localizationService, _workContext), - ShortMessage = x.ShortMessage, - FullMessage = x.FullMessage, - IpAddress = x.IpAddress, - CustomerId = x.CustomerId, - CustomerEmail = x.Customer != null ? x.Customer.Email : null, - PageUrl = x.PageUrl, - ReferrerUrl = x.ReferrerUrl, - CreatedOn = _dateTimeHelper.ConvertToUserTime(x.CreatedOnUtc, DateTimeKind.Utc), + var gridModel = new GridModel(); + + if (_permissionService.Authorize(StandardPermissionProvider.ManageSystemLog)) + { + DateTime? createdOnFromValue = (model.CreatedOnFrom == null) ? null + : (DateTime?)_dateTimeHelper.ConvertToUtcTime(model.CreatedOnFrom.Value, _dateTimeHelper.CurrentTimeZone); + + DateTime? createdToFromValue = (model.CreatedOnTo == null) ? null + : (DateTime?)_dateTimeHelper.ConvertToUtcTime(model.CreatedOnTo.Value, _dateTimeHelper.CurrentTimeZone).AddDays(1); + + LogLevel? logLevel = model.LogLevelId > 0 ? (LogLevel?)(model.LogLevelId) : null; + + var logItems = Logger.GetAllLogs(createdOnFromValue, createdToFromValue, model.Message, + logLevel, command.Page - 1, command.PageSize, model.MinFrequency); + + gridModel.Data = logItems.Select(x => + { + var logModel = new LogModel + { + Id = x.Id, + LogLevelHint = s_logLevelHintMap[x.LogLevel], + LogLevel = x.LogLevel.GetLocalizedEnum(_localizationService, _workContext), + ShortMessage = x.ShortMessage, + FullMessage = x.FullMessage, + IpAddress = x.IpAddress, + CustomerId = x.CustomerId, + CustomerEmail = x.Customer != null ? x.Customer.Email : null, + PageUrl = x.PageUrl, + ReferrerUrl = x.ReferrerUrl, + CreatedOn = _dateTimeHelper.ConvertToUserTime(x.CreatedOnUtc, DateTimeKind.Utc), Frequency = x.Frequency, ContentHash = x.ContentHash - }; + }; if (x.UpdatedOnUtc.HasValue) logModel.UpdatedOn = _dateTimeHelper.ConvertToUserTime(x.UpdatedOnUtc.Value, DateTimeKind.Utc); return logModel; - }), - Total = logItems.TotalCount - }; + }); + + gridModel.Total = logItems.TotalCount; + } + else + { + gridModel.Data = Enumerable.Empty(); + + NotifyAccessDenied(); + } + return new JsonResult { Data = gridModel diff --git a/src/Presentation/SmartStore.Web/Administration/Controllers/ManufacturerController.cs b/src/Presentation/SmartStore.Web/Administration/Controllers/ManufacturerController.cs index e107a81fac..5f345fcb42 100644 --- a/src/Presentation/SmartStore.Web/Administration/Controllers/ManufacturerController.cs +++ b/src/Presentation/SmartStore.Web/Administration/Controllers/ManufacturerController.cs @@ -254,16 +254,21 @@ public ActionResult List() [HttpPost, GridAction(EnableCustomBinding = true)] public ActionResult List(GridCommand command, ManufacturerListModel model) { - if (!_permissionService.Authorize(StandardPermissionProvider.ManageCatalog)) - return AccessDeniedView(); + var gridModel = new GridModel(); - var manufacturers = _manufacturerService.GetAllManufacturers(model.SearchManufacturerName, command.Page - 1, command.PageSize, true); + if (_permissionService.Authorize(StandardPermissionProvider.ManageCatalog)) + { + var manufacturers = _manufacturerService.GetAllManufacturers(model.SearchManufacturerName, command.Page - 1, command.PageSize, true); - var gridModel = new GridModel - { - Data = manufacturers.Select(x => x.ToModel()), - Total = manufacturers.TotalCount - }; + gridModel.Data = manufacturers.Select(x => x.ToModel()); + gridModel.Total = manufacturers.TotalCount; + } + else + { + gridModel.Data = Enumerable.Empty(); + + NotifyAccessDenied(); + } return new JsonResult { @@ -441,35 +446,43 @@ public ActionResult Delete(int id) [HttpPost, GridAction(EnableCustomBinding = true)] public ActionResult ProductList(GridCommand command, int manufacturerId) { - if (!_permissionService.Authorize(StandardPermissionProvider.ManageCatalog)) - return AccessDeniedView(); + var model = new GridModel(); + + if (_permissionService.Authorize(StandardPermissionProvider.ManageCatalog)) + { + var productManufacturers = _manufacturerService.GetProductManufacturersByManufacturerId(manufacturerId, command.Page - 1, command.PageSize, true); - var productManufacturers = _manufacturerService.GetProductManufacturersByManufacturerId(manufacturerId, - command.Page - 1, command.PageSize, true); + var productIds = productManufacturers.Select(x => x.ProductId).ToArray(); + var products = _productService.GetProductsByIds(productIds); - var model = new GridModel - { - Data = productManufacturers - .Select(x => - { - var product = _productService.GetProductById(x.ProductId); + model.Data = productManufacturers + .Select(x => + { + var product = products.FirstOrDefault(y => y.Id == x.ProductId); + + return new ManufacturerModel.ManufacturerProductModel + { + Id = x.Id, + ManufacturerId = x.ManufacturerId, + ProductId = x.ProductId, + ProductName = product.Name, + Sku = product.Sku, + ProductTypeName = product.GetProductTypeLabel(_localizationService), + ProductTypeLabelHint = product.ProductTypeLabelHint, + Published = product.Published, + IsFeaturedProduct = x.IsFeaturedProduct, + DisplayOrder1 = x.DisplayOrder + }; + }); - return new ManufacturerModel.ManufacturerProductModel() - { - Id = x.Id, - ManufacturerId = x.ManufacturerId, - ProductId = x.ProductId, - ProductName = product.Name, - Sku = product.Sku, - ProductTypeName = product.GetProductTypeLabel(_localizationService), - ProductTypeLabelHint = product.ProductTypeLabelHint, - Published = product.Published, - IsFeaturedProduct = x.IsFeaturedProduct, - DisplayOrder1 = x.DisplayOrder - }; - }), - Total = productManufacturers.TotalCount - }; + model.Total = productManufacturers.TotalCount; + } + else + { + model.Data = Enumerable.Empty(); + + NotifyAccessDenied(); + } return new JsonResult { @@ -480,16 +493,15 @@ public ActionResult ProductList(GridCommand command, int manufacturerId) [GridAction(EnableCustomBinding = true)] public ActionResult ProductUpdate(GridCommand command, ManufacturerModel.ManufacturerProductModel model) { - if (!_permissionService.Authorize(StandardPermissionProvider.ManageCatalog)) - return AccessDeniedView(); + var productManufacturer = _manufacturerService.GetProductManufacturerById(model.Id); - var productManufacturer = _manufacturerService.GetProductManufacturerById(model.Id); - if (productManufacturer == null) - throw new ArgumentException("No product manufacturer mapping found with the specified id"); + if (_permissionService.Authorize(StandardPermissionProvider.ManageCatalog)) + { + productManufacturer.IsFeaturedProduct = model.IsFeaturedProduct; + productManufacturer.DisplayOrder = model.DisplayOrder1; - productManufacturer.IsFeaturedProduct = model.IsFeaturedProduct; - productManufacturer.DisplayOrder = model.DisplayOrder1; - _manufacturerService.UpdateProductManufacturer(productManufacturer); + _manufacturerService.UpdateProductManufacturer(productManufacturer); + } return ProductList(command, productManufacturer.ManufacturerId); } @@ -497,15 +509,13 @@ public ActionResult ProductUpdate(GridCommand command, ManufacturerModel.Manufac [GridAction(EnableCustomBinding = true)] public ActionResult ProductDelete(int id, GridCommand command) { - if (!_permissionService.Authorize(StandardPermissionProvider.ManageCatalog)) - return AccessDeniedView(); - - var productManufacturer = _manufacturerService.GetProductManufacturerById(id); - if (productManufacturer == null) - throw new ArgumentException("No product manufacturer mapping found with the specified id"); + var productManufacturer = _manufacturerService.GetProductManufacturerById(id); + var manufacturerId = productManufacturer.ManufacturerId; - var manufacturerId = productManufacturer.ManufacturerId; - _manufacturerService.DeleteProductManufacturer(productManufacturer); + if (_permissionService.Authorize(StandardPermissionProvider.ManageCatalog)) + { + _manufacturerService.DeleteProductManufacturer(productManufacturer); + } return ProductList(command, manufacturerId); } @@ -560,35 +570,43 @@ public ActionResult ProductAddPopup(int manufacturerId) [HttpPost, GridAction(EnableCustomBinding = true)] public ActionResult ProductAddPopupList(GridCommand command, ManufacturerModel.AddManufacturerProductModel model) { - if (!_permissionService.Authorize(StandardPermissionProvider.ManageCatalog)) - return AccessDeniedView(); + var gridModel = new GridModel(); - var gridModel = new GridModel(); + if (_permissionService.Authorize(StandardPermissionProvider.ManageCatalog)) + { + var ctx = new ProductSearchContext(); - var ctx = new ProductSearchContext(); + if (model.SearchCategoryId > 0) + ctx.CategoryIds.Add(model.SearchCategoryId); - if (model.SearchCategoryId > 0) - ctx.CategoryIds.Add(model.SearchCategoryId); + ctx.ManufacturerId = model.SearchManufacturerId; + ctx.Keywords = model.SearchProductName; + ctx.LanguageId = _workContext.WorkingLanguage.Id; + ctx.OrderBy = ProductSortingEnum.Position; + ctx.PageIndex = command.Page - 1; + ctx.PageSize = command.PageSize; + ctx.ShowHidden = true; + ctx.ProductType = model.SearchProductTypeId > 0 ? (ProductType?)model.SearchProductTypeId : null; - ctx.ManufacturerId = model.SearchManufacturerId; - ctx.Keywords = model.SearchProductName; - ctx.LanguageId = _workContext.WorkingLanguage.Id; - ctx.OrderBy = ProductSortingEnum.Position; - ctx.PageIndex = command.Page - 1; - ctx.PageSize = command.PageSize; - ctx.ShowHidden = true; - ctx.ProductType = model.SearchProductTypeId > 0 ? (ProductType?)model.SearchProductTypeId : null; + var products = _productService.SearchProducts(ctx); - var products = _productService.SearchProducts(ctx); + gridModel.Data = products.Select(x => + { + var productModel = x.ToModel(); + productModel.ProductTypeName = x.GetProductTypeLabel(_localizationService); + + return productModel; + }); - gridModel.Data = products.Select(x => + gridModel.Total = products.TotalCount; + } + else { - var productModel = x.ToModel(); - productModel.ProductTypeName = x.GetProductTypeLabel(_localizationService); + gridModel.Data = Enumerable.Empty(); + + NotifyAccessDenied(); + } - return productModel; - }); - gridModel.Total = products.TotalCount; return new JsonResult { Data = gridModel diff --git a/src/Presentation/SmartStore.Web/Administration/Controllers/MeasureController.cs b/src/Presentation/SmartStore.Web/Administration/Controllers/MeasureController.cs index ec1265db77..f8b33e6102 100644 --- a/src/Presentation/SmartStore.Web/Administration/Controllers/MeasureController.cs +++ b/src/Presentation/SmartStore.Web/Administration/Controllers/MeasureController.cs @@ -79,20 +79,29 @@ public ActionResult Weights(string id) [HttpPost, GridAction(EnableCustomBinding = true)] public ActionResult Weights(GridCommand command) { - if (!_permissionService.Authorize(StandardPermissionProvider.ManageMeasures)) - return AccessDeniedView(); + var model = new GridModel(); - var weightsModel = _measureService.GetAllMeasureWeights() - .Select(x => x.ToModel()) - .ForCommand(command) - .ToList(); - foreach (var wm in weightsModel) - wm.IsPrimaryWeight = wm.Id == _measureSettings.BaseWeightId; - var model = new GridModel - { - Data = weightsModel, - Total = weightsModel.Count - }; + if (_permissionService.Authorize(StandardPermissionProvider.ManageMeasures)) + { + var weightsModel = _measureService.GetAllMeasureWeights() + .Select(x => x.ToModel()) + .ForCommand(command) + .ToList(); + + foreach (var wm in weightsModel) + { + wm.IsPrimaryWeight = wm.Id == _measureSettings.BaseWeightId; + } + + model.Data = weightsModel; + model.Total = weightsModel.Count; + } + else + { + model.Data = Enumerable.Empty(); + + NotifyAccessDenied(); + } return new JsonResult { @@ -100,22 +109,22 @@ public ActionResult Weights(GridCommand command) }; } - [GridAction(EnableCustomBinding=true)] + [GridAction(EnableCustomBinding = true)] public ActionResult WeightUpdate(MeasureWeightModel model, GridCommand command) { - if (!_permissionService.Authorize(StandardPermissionProvider.ManageMeasures)) - return AccessDeniedView(); - - if (!ModelState.IsValid) - { - //display the first model error - var modelStateErrors = this.ModelState.Values.SelectMany(x => x.Errors).Select(x => x.ErrorMessage); - return Content(modelStateErrors.FirstOrDefault()); - } + if (_permissionService.Authorize(StandardPermissionProvider.ManageMeasures)) + { + if (!ModelState.IsValid) + { + var modelStateErrors = this.ModelState.Values.SelectMany(x => x.Errors).Select(x => x.ErrorMessage); + return Content(modelStateErrors.FirstOrDefault()); + } - var weight = _measureService.GetMeasureWeightById(model.Id); - weight = model.ToEntity(weight); - _measureService.UpdateMeasureWeight(weight); + var weight = _measureService.GetMeasureWeightById(model.Id); + weight = model.ToEntity(weight); + + _measureService.UpdateMeasureWeight(weight); + } return Weights(command); } @@ -123,19 +132,19 @@ public ActionResult WeightUpdate(MeasureWeightModel model, GridCommand command) [GridAction(EnableCustomBinding = true)] public ActionResult WeightAdd([Bind(Exclude="Id")] MeasureWeightModel model, GridCommand command) { - if (!_permissionService.Authorize(StandardPermissionProvider.ManageMeasures)) - return AccessDeniedView(); + if (_permissionService.Authorize(StandardPermissionProvider.ManageMeasures)) + { + if (!ModelState.IsValid) + { + var modelStateErrors = this.ModelState.Values.SelectMany(x => x.Errors).Select(x => x.ErrorMessage); + return Content(modelStateErrors.FirstOrDefault()); + } - if (!ModelState.IsValid) - { - //display the first model error - var modelStateErrors = this.ModelState.Values.SelectMany(x => x.Errors).Select(x => x.ErrorMessage); - return Content(modelStateErrors.FirstOrDefault()); - } + var weight = new MeasureWeight(); + weight = model.ToEntity(weight); - var weight = new MeasureWeight(); - weight = model.ToEntity(weight); - _measureService.InsertMeasureWeight(weight); + _measureService.InsertMeasureWeight(weight); + } return Weights(command); } @@ -143,17 +152,17 @@ public ActionResult WeightAdd([Bind(Exclude="Id")] MeasureWeightModel model, Gri [GridAction(EnableCustomBinding = true)] public ActionResult WeightDelete(int id, GridCommand command) { - if (!_permissionService.Authorize(StandardPermissionProvider.ManageMeasures)) - return AccessDeniedView(); - - var weight = _measureService.GetMeasureWeightById(id); - if (weight == null) - throw new ArgumentException("No weight found with the specified id"); + if (_permissionService.Authorize(StandardPermissionProvider.ManageMeasures)) + { + var weight = _measureService.GetMeasureWeightById(id); - if (weight.Id == _measureSettings.BaseWeightId) - return Content(_localizationService.GetResource("Admin.Configuration.Measures.Weights.CantDeletePrimary")); + if (weight.Id == _measureSettings.BaseWeightId) + { + return Content(T("Admin.Configuration.Measures.Weights.CantDeletePrimary")); + } - _measureService.DeleteMeasureWeight(weight); + _measureService.DeleteMeasureWeight(weight); + } return Weights(command); } @@ -195,20 +204,29 @@ public ActionResult Dimensions(string id) [HttpPost, GridAction(EnableCustomBinding = true)] public ActionResult Dimensions(GridCommand command) { - if (!_permissionService.Authorize(StandardPermissionProvider.ManageMeasures)) - return AccessDeniedView(); + var model = new GridModel(); - var dimensionsModel = _measureService.GetAllMeasureDimensions() - .Select(x => x.ToModel()) - .ForCommand(command) - .ToList(); - foreach (var wm in dimensionsModel) - wm.IsPrimaryDimension = wm.Id == _measureSettings.BaseDimensionId; - var model = new GridModel - { - Data = dimensionsModel, - Total = dimensionsModel.Count - }; + if (_permissionService.Authorize(StandardPermissionProvider.ManageMeasures)) + { + var dimensionsModel = _measureService.GetAllMeasureDimensions() + .Select(x => x.ToModel()) + .ForCommand(command) + .ToList(); + + foreach (var wm in dimensionsModel) + { + wm.IsPrimaryDimension = wm.Id == _measureSettings.BaseDimensionId; + } + + model.Data = dimensionsModel; + model.Total = dimensionsModel.Count; + } + else + { + model.Data = Enumerable.Empty(); + + NotifyAccessDenied(); + } return new JsonResult { @@ -219,19 +237,19 @@ public ActionResult Dimensions(GridCommand command) [GridAction(EnableCustomBinding = true)] public ActionResult DimensionUpdate(MeasureDimensionModel model, GridCommand command) { - if (!_permissionService.Authorize(StandardPermissionProvider.ManageMeasures)) - return AccessDeniedView(); + if (_permissionService.Authorize(StandardPermissionProvider.ManageMeasures)) + { + if (!ModelState.IsValid) + { + var modelStateErrors = this.ModelState.Values.SelectMany(x => x.Errors).Select(x => x.ErrorMessage); + return Content(modelStateErrors.FirstOrDefault()); + } - if (!ModelState.IsValid) - { - //display the first model error - var modelStateErrors = this.ModelState.Values.SelectMany(x => x.Errors).Select(x => x.ErrorMessage); - return Content(modelStateErrors.FirstOrDefault()); - } + var dimension = _measureService.GetMeasureDimensionById(model.Id); + dimension = model.ToEntity(dimension); - var dimension = _measureService.GetMeasureDimensionById(model.Id); - dimension = model.ToEntity(dimension); - _measureService.UpdateMeasureDimension(dimension); + _measureService.UpdateMeasureDimension(dimension); + } return Dimensions(command); } @@ -239,19 +257,19 @@ public ActionResult DimensionUpdate(MeasureDimensionModel model, GridCommand com [GridAction(EnableCustomBinding = true)] public ActionResult DimensionAdd([Bind(Exclude="Id")] MeasureDimensionModel model, GridCommand command) { - if (!_permissionService.Authorize(StandardPermissionProvider.ManageMeasures)) - return AccessDeniedView(); + if (_permissionService.Authorize(StandardPermissionProvider.ManageMeasures)) + { + if (!ModelState.IsValid) + { + var modelStateErrors = this.ModelState.Values.SelectMany(x => x.Errors).Select(x => x.ErrorMessage); + return Content(modelStateErrors.FirstOrDefault()); + } - if (!ModelState.IsValid) - { - //display the first model error - var modelStateErrors = this.ModelState.Values.SelectMany(x => x.Errors).Select(x => x.ErrorMessage); - return Content(modelStateErrors.FirstOrDefault()); - } + var dimension = new MeasureDimension(); + dimension = model.ToEntity(dimension); - var dimension = new MeasureDimension(); - dimension = model.ToEntity(dimension); - _measureService.InsertMeasureDimension(dimension); + _measureService.InsertMeasureDimension(dimension); + } return Dimensions(command); } @@ -259,17 +277,17 @@ public ActionResult DimensionAdd([Bind(Exclude="Id")] MeasureDimensionModel mode [GridAction(EnableCustomBinding = true)] public ActionResult DimensionDelete(int id, GridCommand command) { - if (!_permissionService.Authorize(StandardPermissionProvider.ManageMeasures)) - return AccessDeniedView(); - - var dimension = _measureService.GetMeasureDimensionById(id); - if (dimension == null) - throw new ArgumentException("No dimension found with the specified id"); + if (_permissionService.Authorize(StandardPermissionProvider.ManageMeasures)) + { + var dimension = _measureService.GetMeasureDimensionById(id); - if (dimension.Id == _measureSettings.BaseDimensionId) - return Content(_localizationService.GetResource("Admin.Configuration.Measures.Dimensions.CantDeletePrimary")); + if (dimension.Id == _measureSettings.BaseDimensionId) + { + return Content(T("Admin.Configuration.Measures.Dimensions.CantDeletePrimary")); + } - _measureService.DeleteMeasureDimension(dimension); + _measureService.DeleteMeasureDimension(dimension); + } return Dimensions(command); } diff --git a/src/Presentation/SmartStore.Web/Administration/Controllers/MessageTemplateController.cs b/src/Presentation/SmartStore.Web/Administration/Controllers/MessageTemplateController.cs index be6c73a92b..eb0b111b06 100644 --- a/src/Presentation/SmartStore.Web/Administration/Controllers/MessageTemplateController.cs +++ b/src/Presentation/SmartStore.Web/Administration/Controllers/MessageTemplateController.cs @@ -162,15 +162,21 @@ public ActionResult List() [HttpPost, GridAction(EnableCustomBinding = true)] public ActionResult List(GridCommand command, MessageTemplateListModel model) { - if (!_permissionService.Authorize(StandardPermissionProvider.ManageMessageTemplates)) - return AccessDeniedView(); + var gridModel = new GridModel(); - var messageTemplates = _messageTemplateService.GetAllMessageTemplates(model.SearchStoreId); - var gridModel = new GridModel + if (_permissionService.Authorize(StandardPermissionProvider.ManageMessageTemplates)) { - Data = messageTemplates.Select(x => x.ToModel()), - Total = messageTemplates.Count - }; + var messageTemplates = _messageTemplateService.GetAllMessageTemplates(model.SearchStoreId); + + gridModel.Data = messageTemplates.Select(x => x.ToModel()); + gridModel.Total = messageTemplates.Count; + } + else + { + gridModel.Data = Enumerable.Empty(); + + NotifyAccessDenied(); + } return new JsonResult { diff --git a/src/Presentation/SmartStore.Web/Administration/Controllers/NewsController.cs b/src/Presentation/SmartStore.Web/Administration/Controllers/NewsController.cs index 2ac51b9184..2d12ecc9d6 100644 --- a/src/Presentation/SmartStore.Web/Administration/Controllers/NewsController.cs +++ b/src/Presentation/SmartStore.Web/Administration/Controllers/NewsController.cs @@ -115,26 +115,38 @@ public ActionResult List() [HttpPost, GridAction(EnableCustomBinding = true)] public ActionResult List(GridCommand command, NewsItemListModel model) { - if (!_permissionService.Authorize(StandardPermissionProvider.ManageNews)) - return AccessDeniedView(); + var gridModel = new GridModel(); + + if (_permissionService.Authorize(StandardPermissionProvider.ManageNews)) + { + var news = _newsService.GetAllNews(0, model.SearchStoreId, command.Page - 1, command.PageSize, true); + + gridModel.Data = news.Select(x => + { + var m = x.ToModel(); + + if (x.StartDateUtc.HasValue) + m.StartDate = _dateTimeHelper.ConvertToUserTime(x.StartDateUtc.Value, DateTimeKind.Utc); + + if (x.EndDateUtc.HasValue) + m.EndDate = _dateTimeHelper.ConvertToUserTime(x.EndDateUtc.Value, DateTimeKind.Utc); + + m.CreatedOn = _dateTimeHelper.ConvertToUserTime(x.CreatedOnUtc, DateTimeKind.Utc); + m.LanguageName = x.Language.Name; + m.Comments = x.ApprovedCommentCount + x.NotApprovedCommentCount; + + return m; + }); + + gridModel.Total = news.TotalCount; + } + else + { + gridModel.Data = Enumerable.Empty(); + + NotifyAccessDenied(); + } - var news = _newsService.GetAllNews(0, model.SearchStoreId, command.Page - 1, command.PageSize, true); - var gridModel = new GridModel - { - Data = news.Select(x => - { - var m = x.ToModel(); - if (x.StartDateUtc.HasValue) - m.StartDate = _dateTimeHelper.ConvertToUserTime(x.StartDateUtc.Value, DateTimeKind.Utc); - if (x.EndDateUtc.HasValue) - m.EndDate = _dateTimeHelper.ConvertToUserTime(x.EndDateUtc.Value, DateTimeKind.Utc); - m.CreatedOn = _dateTimeHelper.ConvertToUserTime(x.CreatedOnUtc, DateTimeKind.Utc); - m.LanguageName = x.Language.Name; - m.Comments = x.ApprovedCommentCount + x.NotApprovedCommentCount; - return m; - }), - Total = news.TotalCount - }; return new JsonResult { Data = gridModel @@ -297,47 +309,54 @@ public ActionResult Comments(int? filterByNewsItemId) [HttpPost, GridAction(EnableCustomBinding = true)] public ActionResult Comments(int? filterByNewsItemId, GridCommand command) { - if (!_permissionService.Authorize(StandardPermissionProvider.ManageNews)) - return AccessDeniedView(); + var gridModel = new GridModel(); - IList comments; - if (filterByNewsItemId.HasValue) - { - //filter comments by news item - var newsItem = _newsService.GetNewsById(filterByNewsItemId.Value); - comments = newsItem.NewsComments.OrderBy(bc => bc.CreatedOnUtc).ToList(); - } - else - { - //load all news comments - comments = _customerContentService.GetAllCustomerContent(0, null); - } + if (_permissionService.Authorize(StandardPermissionProvider.ManageNews)) + { + IList comments; + if (filterByNewsItemId.HasValue) + { + //filter comments by news item + var newsItem = _newsService.GetNewsById(filterByNewsItemId.Value); + comments = newsItem.NewsComments.OrderBy(bc => bc.CreatedOnUtc).ToList(); + } + else + { + //load all news comments + comments = _customerContentService.GetAllCustomerContent(0, null); + } - var gridModel = new GridModel - { - Data = comments.PagedForCommand(command).Select(newsComment => - { - var commentModel = new NewsCommentModel(); + gridModel.Data = comments.PagedForCommand(command).Select(newsComment => + { + var commentModel = new NewsCommentModel(); var customer = _customerService.GetCustomerById(newsComment.CustomerId); - commentModel.Id = newsComment.Id; - commentModel.NewsItemId = newsComment.NewsItemId; - commentModel.NewsItemTitle = newsComment.NewsItem.Title; - commentModel.CustomerId = newsComment.CustomerId; - commentModel.IpAddress = newsComment.IpAddress; - commentModel.CreatedOn = _dateTimeHelper.ConvertToUserTime(newsComment.CreatedOnUtc, DateTimeKind.Utc); - commentModel.CommentTitle = newsComment.CommentTitle; - commentModel.CommentText = Core.Html.HtmlUtils.FormatText(newsComment.CommentText, false, true, false, false, false, false); + commentModel.Id = newsComment.Id; + commentModel.NewsItemId = newsComment.NewsItemId; + commentModel.NewsItemTitle = newsComment.NewsItem.Title; + commentModel.CustomerId = newsComment.CustomerId; + commentModel.IpAddress = newsComment.IpAddress; + commentModel.CreatedOn = _dateTimeHelper.ConvertToUserTime(newsComment.CreatedOnUtc, DateTimeKind.Utc); + commentModel.CommentTitle = newsComment.CommentTitle; + commentModel.CommentText = Core.Html.HtmlUtils.FormatText(newsComment.CommentText, false, true, false, false, false, false); if (customer == null) commentModel.CustomerName = "".NaIfEmpty(); else commentModel.CustomerName = customer.GetFullName(); - return commentModel; - }), - Total = comments.Count, - }; + return commentModel; + }); + + gridModel.Total = comments.Count; + } + else + { + gridModel.Data = Enumerable.Empty(); + + NotifyAccessDenied(); + } + return new JsonResult { Data = gridModel @@ -347,17 +366,16 @@ public ActionResult Comments(int? filterByNewsItemId, GridCommand command) [GridAction(EnableCustomBinding = true)] public ActionResult CommentDelete(int? filterByNewsItemId, int id, GridCommand command) { - if (!_permissionService.Authorize(StandardPermissionProvider.ManageNews)) - return AccessDeniedView(); - - var comment = _customerContentService.GetCustomerContentById(id) as NewsComment; - if (comment == null) - throw new ArgumentException("No comment found with the specified id"); + if (_permissionService.Authorize(StandardPermissionProvider.ManageNews)) + { + var comment = _customerContentService.GetCustomerContentById(id) as NewsComment; - var newsItem = comment.NewsItem; - _customerContentService.DeleteCustomerContent(comment); - //update totals - _newsService.UpdateCommentTotals(newsItem); + var newsItem = comment.NewsItem; + _customerContentService.DeleteCustomerContent(comment); + + //update totals + _newsService.UpdateCommentTotals(newsItem); + } return Comments(filterByNewsItemId, command); } diff --git a/src/Presentation/SmartStore.Web/Administration/Controllers/NewsLetterSubscriptionController.cs b/src/Presentation/SmartStore.Web/Administration/Controllers/NewsLetterSubscriptionController.cs index e8e92184a2..9c688979ea 100644 --- a/src/Presentation/SmartStore.Web/Administration/Controllers/NewsLetterSubscriptionController.cs +++ b/src/Presentation/SmartStore.Web/Administration/Controllers/NewsLetterSubscriptionController.cs @@ -68,7 +68,7 @@ public ActionResult List() var store = _storeService.GetStoreById(x.StoreId); m.CreatedOn = _dateTimeHelper.ConvertToUserTime(x.CreatedOnUtc, DateTimeKind.Utc); - m.StoreName = store != null ? store.Name : "Unknown"; + m.StoreName = store != null ? store.Name : "".NaIfEmpty(); return m; }), @@ -80,26 +80,33 @@ public ActionResult List() [HttpPost, GridAction(EnableCustomBinding = true)] public ActionResult SubscriptionList(GridCommand command, NewsLetterSubscriptionListModel model) { - if (!_permissionService.Authorize(StandardPermissionProvider.ManageNewsletterSubscribers)) - return AccessDeniedView(); + var gridModel = new GridModel(); - var newsletterSubscriptions = _newsLetterSubscriptionService.GetAllNewsLetterSubscriptions( - model.SearchEmail, command.Page - 1, command.PageSize, true, model.StoreId); + if (_permissionService.Authorize(StandardPermissionProvider.ManageNewsletterSubscribers)) + { + var newsletterSubscriptions = _newsLetterSubscriptionService.GetAllNewsLetterSubscriptions( + model.SearchEmail, command.Page - 1, command.PageSize, true, model.StoreId); - var gridModel = new GridModel - { - Data = newsletterSubscriptions.Select(x => + gridModel.Data = newsletterSubscriptions.Select(x => { var m = x.ToModel(); var store = _storeService.GetStoreById(x.StoreId); m.CreatedOn = _dateTimeHelper.ConvertToUserTime(x.CreatedOnUtc, DateTimeKind.Utc); - m.StoreName = store != null ? store.Name : "Unknown"; + m.StoreName = store != null ? store.Name : "".NaIfEmpty(); return m; - }), - Total = newsletterSubscriptions.TotalCount - }; + }); + + gridModel.Total = newsletterSubscriptions.TotalCount; + } + else + { + gridModel.Data = Enumerable.Empty(); + + NotifyAccessDenied(); + } + return new JsonResult { Data = gridModel @@ -109,39 +116,36 @@ public ActionResult SubscriptionList(GridCommand command, NewsLetterSubscription [GridAction(EnableCustomBinding = true)] public ActionResult SubscriptionUpdate(NewsLetterSubscriptionModel model, GridCommand command) { - if (!_permissionService.Authorize(StandardPermissionProvider.ManageNewsletterSubscribers)) - return AccessDeniedView(); - - if (!ModelState.IsValid) - { - //display the first model error - var modelStateErrors = this.ModelState.Values.SelectMany(x => x.Errors).Select(x => x.ErrorMessage); - return Content(modelStateErrors.FirstOrDefault()); - } + if (_permissionService.Authorize(StandardPermissionProvider.ManageNewsletterSubscribers)) + { + if (!ModelState.IsValid) + { + var modelStateErrors = this.ModelState.Values.SelectMany(x => x.Errors).Select(x => x.ErrorMessage); + return Content(modelStateErrors.FirstOrDefault()); + } - var subscription = _newsLetterSubscriptionService.GetNewsLetterSubscriptionById(model.Id); - subscription.Email = model.Email; - subscription.Active = model.Active; + var subscription = _newsLetterSubscriptionService.GetNewsLetterSubscriptionById(model.Id); + subscription.Email = model.Email; + subscription.Active = model.Active; - _newsLetterSubscriptionService.UpdateNewsLetterSubscription(subscription); + _newsLetterSubscriptionService.UpdateNewsLetterSubscription(subscription); + } var listModel = new NewsLetterSubscriptionListModel(); PrepareNewsLetterSubscriptionListModel(listModel); - return SubscriptionList(command, listModel); + return SubscriptionList(command, listModel); } [GridAction(EnableCustomBinding = true)] public ActionResult SubscriptionDelete(int id, GridCommand command) { - if (!_permissionService.Authorize(StandardPermissionProvider.ManageNewsletterSubscribers)) - return AccessDeniedView(); - - var subscription = _newsLetterSubscriptionService.GetNewsLetterSubscriptionById(id); - if (subscription == null) - throw new ArgumentException("No subscription found with the specified id"); + if (_permissionService.Authorize(StandardPermissionProvider.ManageNewsletterSubscribers)) + { + var subscription = _newsLetterSubscriptionService.GetNewsLetterSubscriptionById(id); - _newsLetterSubscriptionService.DeleteNewsLetterSubscription(subscription); + _newsLetterSubscriptionService.DeleteNewsLetterSubscription(subscription); + } var listModel = new NewsLetterSubscriptionListModel(); PrepareNewsLetterSubscriptionListModel(listModel); diff --git a/src/Presentation/SmartStore.Web/Administration/Controllers/OnlineCustomerController.cs b/src/Presentation/SmartStore.Web/Administration/Controllers/OnlineCustomerController.cs index 222bb0863e..3aca0ddd54 100644 --- a/src/Presentation/SmartStore.Web/Administration/Controllers/OnlineCustomerController.cs +++ b/src/Presentation/SmartStore.Web/Administration/Controllers/OnlineCustomerController.cs @@ -81,27 +81,35 @@ public ActionResult List() [HttpPost, GridAction(EnableCustomBinding = true)] public ActionResult List(GridCommand command) { - if (!_permissionService.Authorize(StandardPermissionProvider.ManageCustomers)) - return AccessDeniedView(); + var model = new GridModel(); + + if (_permissionService.Authorize(StandardPermissionProvider.ManageCustomers)) + { + var lastActivityFrom = DateTime.UtcNow.AddMinutes(-_customerSettings.OnlineCustomerMinutes); + var customers = _customerService.GetOnlineCustomers(lastActivityFrom, null, command.Page - 1, command.PageSize); + + model.Data = customers.Select(x => + { + return new OnlineCustomerModel + { + Id = x.Id, + CustomerInfo = x.IsRegistered() ? x.Email : T("Admin.Customers.Guest").Text, + LastIpAddress = x.LastIpAddress, + Location = _geoCountryLookup.LookupCountryName(x.LastIpAddress), + LastActivityDate = _dateTimeHelper.ConvertToUserTime(x.LastActivityDateUtc, DateTimeKind.Utc), + LastVisitedPage = x.GetAttribute(SystemCustomerAttributeNames.LastVisitedPage) + }; + }); + + model.Total = customers.TotalCount; + } + else + { + model.Data = Enumerable.Empty(); + + NotifyAccessDenied(); + } - var customers = _customerService.GetOnlineCustomers(DateTime.UtcNow.AddMinutes(-_customerSettings.OnlineCustomerMinutes), - null, command.Page - 1, command.PageSize); - var model = new GridModel - { - Data = customers.Select(x => - { - return new OnlineCustomerModel() - { - Id = x.Id, - CustomerInfo = x.IsRegistered() ? x.Email : _localizationService.GetResource("Admin.Customers.Guest"), - LastIpAddress = x.LastIpAddress, - Location = _geoCountryLookup.LookupCountryName(x.LastIpAddress), - LastActivityDate = _dateTimeHelper.ConvertToUserTime(x.LastActivityDateUtc, DateTimeKind.Utc), - LastVisitedPage = x.GetAttribute(SystemCustomerAttributeNames.LastVisitedPage) - }; - }), - Total = customers.TotalCount - }; return new JsonResult { Data = model diff --git a/src/Presentation/SmartStore.Web/Administration/Controllers/OrderController.cs b/src/Presentation/SmartStore.Web/Administration/Controllers/OrderController.cs index f7adf8147d..911d14b44b 100644 --- a/src/Presentation/SmartStore.Web/Administration/Controllers/OrderController.cs +++ b/src/Presentation/SmartStore.Web/Administration/Controllers/OrderController.cs @@ -809,57 +809,65 @@ public ActionResult List(OrderListModel model) [GridAction(EnableCustomBinding = true)] public ActionResult OrderList(GridCommand command, OrderListModel model) { - if (!_permissionService.Authorize(StandardPermissionProvider.ManageOrders)) - return AccessDeniedView(); + var gridModel = new GridModel(); - DateTime? startDateValue = (model.StartDate == null) ? null : (DateTime?)_dateTimeHelper.ConvertToUtcTime(model.StartDate.Value, _dateTimeHelper.CurrentTimeZone); - DateTime? endDateValue = (model.EndDate == null) ? null : (DateTime?)_dateTimeHelper.ConvertToUtcTime(model.EndDate.Value, _dateTimeHelper.CurrentTimeZone).AddDays(1); + if (_permissionService.Authorize(StandardPermissionProvider.ManageOrders)) + { + DateTime? startDateValue = (model.StartDate == null) ? null : (DateTime?)_dateTimeHelper.ConvertToUtcTime(model.StartDate.Value, _dateTimeHelper.CurrentTimeZone); + DateTime? endDateValue = (model.EndDate == null) ? null : (DateTime?)_dateTimeHelper.ConvertToUtcTime(model.EndDate.Value, _dateTimeHelper.CurrentTimeZone).AddDays(1); - var orderStatusIds = model.OrderStatusIds.ToIntArray(); - var paymentStatusIds = model.PaymentStatusIds.ToIntArray(); - var shippingStatusIds = model.ShippingStatusIds.ToIntArray(); + var orderStatusIds = model.OrderStatusIds.ToIntArray(); + var paymentStatusIds = model.PaymentStatusIds.ToIntArray(); + var shippingStatusIds = model.ShippingStatusIds.ToIntArray(); - var orders = _orderService.SearchOrders(model.StoreId, 0, startDateValue, endDateValue, orderStatusIds, paymentStatusIds, shippingStatusIds, - model.CustomerEmail, model.OrderGuid, model.OrderNumber, command.Page - 1, command.PageSize, model.CustomerName); + var orders = _orderService.SearchOrders(model.StoreId, 0, startDateValue, endDateValue, orderStatusIds, paymentStatusIds, shippingStatusIds, + model.CustomerEmail, model.OrderGuid, model.OrderNumber, command.Page - 1, command.PageSize, model.CustomerName); - var gridModel = new GridModel - { - Data = orders.Select(x => - { + gridModel.Data = orders.Select(x => + { var store = _storeService.GetStoreById(x.StoreId); - return new OrderModel - { - Id = x.Id, - OrderNumber = x.GetOrderNumber(), + return new OrderModel + { + Id = x.Id, + OrderNumber = x.GetOrderNumber(), StoreName = (store != null ? store.Name : "".NaIfEmpty()), - OrderTotal = _priceFormatter.FormatPrice(x.OrderTotal, true, false), - OrderStatus = x.OrderStatus.GetLocalizedEnum(_localizationService, _workContext), - PaymentStatus = x.PaymentStatus.GetLocalizedEnum(_localizationService, _workContext), - ShippingStatus = x.ShippingStatus.GetLocalizedEnum(_localizationService, _workContext), + OrderTotal = _priceFormatter.FormatPrice(x.OrderTotal, true, false), + OrderStatus = x.OrderStatus.GetLocalizedEnum(_localizationService, _workContext), + PaymentStatus = x.PaymentStatus.GetLocalizedEnum(_localizationService, _workContext), + ShippingStatus = x.ShippingStatus.GetLocalizedEnum(_localizationService, _workContext), CustomerName = x.BillingAddress.GetFullName(), CustomerEmail = x.BillingAddress.Email, - CreatedOn = _dateTimeHelper.ConvertToUserTime(x.CreatedOnUtc, DateTimeKind.Utc), + CreatedOn = _dateTimeHelper.ConvertToUserTime(x.CreatedOnUtc, DateTimeKind.Utc), HasNewPaymentNotification = x.HasNewPaymentNotification - }; - }), - Total = orders.TotalCount - }; + }; + }); + + gridModel.Total = orders.TotalCount; + + //summary report + //implemented as a workaround described here: http://www.telerik.com/community/forums/aspnet-mvc/grid/gridmodel-aggregates-how-to-use.aspx + var reportSummary = _orderReportService.GetOrderAverageReportLine(model.StoreId, orderStatusIds, + paymentStatusIds, shippingStatusIds, startDateValue, endDateValue, model.CustomerEmail); + + var profit = _orderReportService.ProfitReport(model.StoreId, orderStatusIds, + paymentStatusIds, shippingStatusIds, startDateValue, endDateValue, model.CustomerEmail); + + var aggregator = new OrderModel + { + aggregatorprofit = _priceFormatter.FormatPrice(profit, true, false), + aggregatortax = _priceFormatter.FormatPrice(reportSummary.SumTax, true, false), + aggregatortotal = _priceFormatter.FormatPrice(reportSummary.SumOrders, true, false) + }; + + gridModel.Aggregates = aggregator; + } + else + { + gridModel.Data = Enumerable.Empty(); + + NotifyAccessDenied(); + } - //summary report - //implemented as a workaround described here: http://www.telerik.com/community/forums/aspnet-mvc/grid/gridmodel-aggregates-how-to-use.aspx - var reportSummary = _orderReportService.GetOrderAverageReportLine(model.StoreId, orderStatusIds, - paymentStatusIds, shippingStatusIds, startDateValue, endDateValue, model.CustomerEmail); - - var profit = _orderReportService.ProfitReport(model.StoreId, orderStatusIds, - paymentStatusIds, shippingStatusIds, startDateValue, endDateValue, model.CustomerEmail); - - var aggregator = new OrderModel() - { - aggregatorprofit = _priceFormatter.FormatPrice(profit, true, false), - aggregatortax = _priceFormatter.FormatPrice(reportSummary.SumTax, true, false), - aggregatortotal = _priceFormatter.FormatPrice(reportSummary.SumOrders, true, false) - }; - gridModel.Aggregates = aggregator; return new JsonResult { Data = gridModel @@ -1676,36 +1684,46 @@ public ActionResult AddProductToOrder(int orderId) [HttpPost, GridAction(EnableCustomBinding = true)] public ActionResult AddProductToOrder(GridCommand command, OrderModel.AddOrderProductModel model) { - if (!_permissionService.Authorize(StandardPermissionProvider.ManageOrders)) - return AccessDeniedView(); + var gridModel = new GridModel(); - var gridModel = new GridModel(); - var searchContext = new ProductSearchContext() + if (_permissionService.Authorize(StandardPermissionProvider.ManageOrders)) { - CategoryIds = new List() { model.SearchCategoryId }, - ManufacturerId = model.SearchManufacturerId, - Keywords = model.SearchProductName, - PageIndex = command.Page - 1, - PageSize = command.PageSize, - ShowHidden = true, - ProductType = model.SearchProductTypeId > 0 ? (ProductType?)model.SearchProductTypeId : null - }; + var searchContext = new ProductSearchContext + { + CategoryIds = new List { model.SearchCategoryId }, + ManufacturerId = model.SearchManufacturerId, + Keywords = model.SearchProductName, + PageIndex = command.Page - 1, + PageSize = command.PageSize, + ShowHidden = true, + ProductType = model.SearchProductTypeId > 0 ? (ProductType?)model.SearchProductTypeId : null + }; - var products = _productService.SearchProducts(searchContext); - gridModel.Data = products.Select(x => - { - var productModel = new OrderModel.AddOrderProductModel.ProductModel - { - Id = x.Id, - Name = x.Name, - Sku = x.Sku, - ProductTypeName = x.GetProductTypeLabel(_localizationService), - ProductTypeLabelHint = x.ProductTypeLabelHint - }; + var products = _productService.SearchProducts(searchContext); + + gridModel.Data = products.Select(x => + { + var productModel = new OrderModel.AddOrderProductModel.ProductModel + { + Id = x.Id, + Name = x.Name, + Sku = x.Sku, + ProductTypeName = x.GetProductTypeLabel(_localizationService), + ProductTypeLabelHint = x.ProductTypeLabelHint + }; + + return productModel; + }); + + gridModel.Total = products.TotalCount; + } + else + { + gridModel.Data = Enumerable.Empty(); + + NotifyAccessDenied(); + } - return productModel; - }); - gridModel.Total = products.TotalCount; return new JsonResult { Data = gridModel @@ -1983,23 +2001,29 @@ public ActionResult ShipmentList() [GridAction(EnableCustomBinding = true)] public ActionResult ShipmentListSelect(GridCommand command, ShipmentListModel model) { - if (!_permissionService.Authorize(StandardPermissionProvider.ManageOrders)) - return AccessDeniedView(); + var gridModel = new GridModel(); - DateTime? startDateValue = (model.StartDate == null) ? null - : (DateTime?)_dateTimeHelper.ConvertToUtcTime(model.StartDate.Value, _dateTimeHelper.CurrentTimeZone); + if (_permissionService.Authorize(StandardPermissionProvider.ManageOrders)) + { + DateTime? startDateValue = (model.StartDate == null) ? null + : (DateTime?)_dateTimeHelper.ConvertToUtcTime(model.StartDate.Value, _dateTimeHelper.CurrentTimeZone); - DateTime? endDateValue = (model.EndDate == null) ? null - :(DateTime?)_dateTimeHelper.ConvertToUtcTime(model.EndDate.Value, _dateTimeHelper.CurrentTimeZone).AddDays(1); + DateTime? endDateValue = (model.EndDate == null) ? null + : (DateTime?)_dateTimeHelper.ConvertToUtcTime(model.EndDate.Value, _dateTimeHelper.CurrentTimeZone).AddDays(1); + + //load shipments + var shipments = _shipmentService.GetAllShipments(model.TrackingNumber, startDateValue, endDateValue, command.Page - 1, command.PageSize); + + gridModel.Data = shipments.Select(shipment => PrepareShipmentModel(shipment, false, false)); + gridModel.Total = shipments.TotalCount; + } + else + { + gridModel.Data = Enumerable.Empty(); + + NotifyAccessDenied(); + } - //load shipments - var shipments = _shipmentService.GetAllShipments(model.TrackingNumber, startDateValue, endDateValue, - command.Page - 1, command.PageSize); - var gridModel = new GridModel - { - Data = shipments.Select(shipment => PrepareShipmentModel(shipment, false, false)), - Total = shipments.TotalCount - }; return new JsonResult { Data = gridModel @@ -2009,24 +2033,29 @@ public ActionResult ShipmentListSelect(GridCommand command, ShipmentListModel mo [HttpPost, GridAction(EnableCustomBinding = true)] public ActionResult ShipmentsSelect(int orderId, GridCommand command) { - if (!_permissionService.Authorize(StandardPermissionProvider.ManageOrders)) - return AccessDeniedView(); + var model = new GridModel(); - var order = _orderService.GetOrderById(orderId); - if (order == null) - throw new ArgumentException("No order found with the specified id"); + if (_permissionService.Authorize(StandardPermissionProvider.ManageOrders)) + { + var order = _orderService.GetOrderById(orderId); - //shipments - var shipmentModels = new List(); - var shipments = order.Shipments.OrderBy(s => s.CreatedOnUtc).ToList(); - foreach (var shipment in shipments) - shipmentModels.Add(PrepareShipmentModel(shipment, false, false)); + var shipmentModels = new List(); + var shipments = order.Shipments.OrderBy(s => s.CreatedOnUtc).ToList(); - var model = new GridModel - { - Data = shipmentModels, - Total = shipmentModels.Count - }; + foreach (var shipment in shipments) + { + shipmentModels.Add(PrepareShipmentModel(shipment, false, false)); + } + + model.Data = shipmentModels; + model.Total = shipmentModels.Count; + } + else + { + model.Data = Enumerable.Empty(); + + NotifyAccessDenied(); + } return new JsonResult { @@ -2311,37 +2340,40 @@ public ActionResult PdfPackagingSlips(bool all, string selectedIds = null) [HttpPost, GridAction(EnableCustomBinding = true)] public ActionResult OrderNotesSelect(int orderId, GridCommand command) { - if (!_permissionService.Authorize(StandardPermissionProvider.ManageOrders)) - return AccessDeniedView(); + var model = new GridModel(); - var order = _orderService.GetOrderById(orderId); - if (order == null) - throw new ArgumentException("No order found with the specified id"); + if (_permissionService.Authorize(StandardPermissionProvider.ManageOrders)) + { + var order = _orderService.GetOrderById(orderId); - var orderNoteModels = new List(); + var orderNoteModels = new List(); - foreach (var orderNote in order.OrderNotes.OrderByDescending(on => on.CreatedOnUtc)) - { - orderNoteModels.Add(new OrderModel.OrderNote - { - Id = orderNote.Id, - OrderId = orderNote.OrderId, - DisplayToCustomer = orderNote.DisplayToCustomer, - Note = orderNote.FormatOrderNoteText(), - CreatedOn = _dateTimeHelper.ConvertToUserTime(orderNote.CreatedOnUtc, DateTimeKind.Utc) - }); - } + foreach (var orderNote in order.OrderNotes.OrderByDescending(on => on.CreatedOnUtc)) + { + orderNoteModels.Add(new OrderModel.OrderNote + { + Id = orderNote.Id, + OrderId = orderNote.OrderId, + DisplayToCustomer = orderNote.DisplayToCustomer, + Note = orderNote.FormatOrderNoteText(), + CreatedOn = _dateTimeHelper.ConvertToUserTime(orderNote.CreatedOnUtc, DateTimeKind.Utc) + }); + } - var model = new GridModel - { - Data = orderNoteModels, - Total = orderNoteModels.Count - }; + model.Data = orderNoteModels; + model.Total = orderNoteModels.Count; - if (order.HasNewPaymentNotification) + if (order.HasNewPaymentNotification) + { + order.HasNewPaymentNotification = false; + _orderService.UpdateOrder(order); + } + } + else { - order.HasNewPaymentNotification = false; - _orderService.UpdateOrder(order); + model.Data = Enumerable.Empty(); + + NotifyAccessDenied(); } return new JsonResult @@ -2385,17 +2417,13 @@ public ActionResult OrderNoteAdd(int orderId, bool displayToCustomer, string mes [GridAction(EnableCustomBinding = true)] public ActionResult OrderNoteDelete(int orderId, int orderNoteId, GridCommand command) { - if (!_permissionService.Authorize(StandardPermissionProvider.ManageOrders)) - return AccessDeniedView(); - - var order = _orderService.GetOrderById(orderId); - if (order == null) - throw new ArgumentException("No order found with the specified id"); + if (_permissionService.Authorize(StandardPermissionProvider.ManageOrders)) + { + var order = _orderService.GetOrderById(orderId); + var orderNote = order.OrderNotes.Where(on => on.Id == orderNoteId).FirstOrDefault(); - var orderNote = order.OrderNotes.Where(on => on.Id == orderNoteId).FirstOrDefault(); - if (orderNote == null) - throw new ArgumentException("No order note found with the specified id"); - _orderService.DeleteOrderNote(orderNote); + _orderService.DeleteOrderNote(orderNote); + } return OrderNotesSelect(orderId, command); } @@ -2433,12 +2461,14 @@ protected IList GetBestsellersBriefReportModel(int r return model; } - public ActionResult BestsellersBriefReportByQuantity() + + public ActionResult BestsellersBriefReportByQuantity() { var model = GetBestsellersBriefReportModel(5, 1); return PartialView(model); } - [GridAction(EnableCustomBinding = true)] + + [GridAction(EnableCustomBinding = true)] public ActionResult BestsellersBriefReportByQuantityList(GridCommand command) { var model = GetBestsellersBriefReportModel(5, 1); @@ -2452,12 +2482,14 @@ public ActionResult BestsellersBriefReportByQuantityList(GridCommand command) Data = gridModel }; } - public ActionResult BestsellersBriefReportByAmount() + + public ActionResult BestsellersBriefReportByAmount() { var model = GetBestsellersBriefReportModel(5, 2); return PartialView(model); } - [GridAction(EnableCustomBinding = true)] + + [GridAction(EnableCustomBinding = true)] public ActionResult BestsellersBriefReportByAmountList(GridCommand command) { var model = GetBestsellersBriefReportModel(5, 2); @@ -2496,27 +2528,29 @@ public ActionResult BestsellersReport() return View(model); } - [GridAction(EnableCustomBinding = true)] + + [GridAction(EnableCustomBinding = true)] public ActionResult BestsellersReportList(GridCommand command, BestsellersReportModel model) { DateTime? startDateValue = (model.StartDate == null) ? null - : (DateTime?)_dateTimeHelper.ConvertToUtcTime(model.StartDate.Value, _dateTimeHelper.CurrentTimeZone); + : (DateTime?)_dateTimeHelper.ConvertToUtcTime(model.StartDate.Value, _dateTimeHelper.CurrentTimeZone); DateTime? endDateValue = (model.EndDate == null) ? null - : (DateTime?)_dateTimeHelper.ConvertToUtcTime(model.EndDate.Value, _dateTimeHelper.CurrentTimeZone).AddDays(1); + : (DateTime?)_dateTimeHelper.ConvertToUtcTime(model.EndDate.Value, _dateTimeHelper.CurrentTimeZone).AddDays(1); OrderStatus? orderStatus = model.OrderStatusId > 0 ? (OrderStatus?)(model.OrderStatusId) : null; PaymentStatus? paymentStatus = model.PaymentStatusId > 0 ? (PaymentStatus?)(model.PaymentStatusId) : null; var items = _orderReportService.BestSellersReport(0, startDateValue, endDateValue, orderStatus, paymentStatus, null, model.BillingCountryId, 100, 2, true); + var gridModel = new GridModel { Data = items.Select(x => { var product = _productService.GetProductById(x.ProductId); - var m = new BestsellersReportLineModel() + var m = new BestsellersReportLineModel { ProductId = x.ProductId, TotalAmount = _priceFormatter.FormatPrice(x.TotalAmount, true, false), @@ -2533,6 +2567,7 @@ public ActionResult BestsellersReportList(GridCommand command, BestsellersReport }), Total = items.Count }; + return new JsonResult { Data = gridModel @@ -2546,17 +2581,18 @@ public ActionResult NeverSoldReport() var model = new NeverSoldReportModel(); return View(model); } - [GridAction(EnableCustomBinding = true)] + + [GridAction(EnableCustomBinding = true)] public ActionResult NeverSoldReportList(GridCommand command, NeverSoldReportModel model) { DateTime? startDateValue = (model.StartDate == null) ? null - : (DateTime?)_dateTimeHelper.ConvertToUtcTime(model.StartDate.Value, _dateTimeHelper.CurrentTimeZone); + : (DateTime?)_dateTimeHelper.ConvertToUtcTime(model.StartDate.Value, _dateTimeHelper.CurrentTimeZone); DateTime? endDateValue = (model.EndDate == null) ? null - : (DateTime?)_dateTimeHelper.ConvertToUtcTime(model.EndDate.Value, _dateTimeHelper.CurrentTimeZone).AddDays(1); + : (DateTime?)_dateTimeHelper.ConvertToUtcTime(model.EndDate.Value, _dateTimeHelper.CurrentTimeZone).AddDays(1); - var items = _orderReportService.ProductsNeverSold(startDateValue, endDateValue, - command.Page - 1, command.PageSize, true); + var items = _orderReportService.ProductsNeverSold(startDateValue, endDateValue, command.Page - 1, command.PageSize, true); + var gridModel = new GridModel { Data = items.Select(x => @@ -2572,6 +2608,7 @@ public ActionResult NeverSoldReportList(GridCommand command, NeverSoldReportMode }), Total = items.TotalCount }; + return new JsonResult { Data = gridModel @@ -2680,13 +2717,15 @@ protected virtual IList GetOrderIncompleteReport return model; } - [ChildActionOnly] + + [ChildActionOnly] public ActionResult OrderIncompleteReport() { var model = GetOrderIncompleteReportModel(); return PartialView(model); } - [GridAction(EnableCustomBinding = true)] + + [GridAction(EnableCustomBinding = true)] public ActionResult OrderIncompleteReportList(GridCommand command) { var model = GetOrderIncompleteReportModel(); diff --git a/src/Presentation/SmartStore.Web/Administration/Controllers/PollController.cs b/src/Presentation/SmartStore.Web/Administration/Controllers/PollController.cs index c6c6abac89..efbf8ad4ad 100644 --- a/src/Presentation/SmartStore.Web/Administration/Controllers/PollController.cs +++ b/src/Presentation/SmartStore.Web/Administration/Controllers/PollController.cs @@ -103,24 +103,36 @@ public ActionResult List() [HttpPost, GridAction(EnableCustomBinding = true)] public ActionResult List(GridCommand command) { - if (!_permissionService.Authorize(StandardPermissionProvider.ManagePolls)) - return AccessDeniedView(); + var gridModel = new GridModel(); + + if (_permissionService.Authorize(StandardPermissionProvider.ManagePolls)) + { + var polls = _pollService.GetPolls(0, false, command.Page - 1, command.PageSize, true); + + gridModel.Data = polls.Select(x => + { + var m = x.ToModel(); + + if (x.StartDateUtc.HasValue) + m.StartDate = _dateTimeHelper.ConvertToUserTime(x.StartDateUtc.Value, DateTimeKind.Utc); + + if (x.EndDateUtc.HasValue) + m.EndDate = _dateTimeHelper.ConvertToUserTime(x.EndDateUtc.Value, DateTimeKind.Utc); + + m.LanguageName = x.Language.Name; + + return m; + }); + + gridModel.Total = polls.TotalCount; + } + else + { + gridModel.Data = Enumerable.Empty(); + + NotifyAccessDenied(); + } - var polls = _pollService.GetPolls(0, false, command.Page - 1, command.PageSize, true); - var gridModel = new GridModel - { - Data = polls.Select(x => - { - var m = x.ToModel(); - if (x.StartDateUtc.HasValue) - m.StartDate = _dateTimeHelper.ConvertToUserTime(x.StartDateUtc.Value, DateTimeKind.Utc); - if (x.EndDateUtc.HasValue) - m.EndDate = _dateTimeHelper.ConvertToUserTime(x.EndDateUtc.Value, DateTimeKind.Utc); - m.LanguageName = x.Language.Name; - return m; - }), - Total = polls.TotalCount - }; return new JsonResult { Data = gridModel @@ -245,30 +257,35 @@ public ActionResult DeleteConfirmed(int id) [HttpPost, GridAction(EnableCustomBinding = true)] public ActionResult PollAnswers(int pollId, GridCommand command) { - if (!_permissionService.Authorize(StandardPermissionProvider.ManagePolls)) - return AccessDeniedView(); + var model = new GridModel(); - var poll = _pollService.GetPollById(pollId); - if (poll == null) - throw new ArgumentException("No poll found with the specified id", "pollId"); + if (_permissionService.Authorize(StandardPermissionProvider.ManagePolls)) + { + var poll = _pollService.GetPollById(pollId); + + var answers = poll.PollAnswers.OrderBy(x => x.DisplayOrder).ToList(); + + model.Data = answers.Select(x => + { + return new PollAnswerModel + { + Id = x.Id, + PollId = x.PollId, + Name = x.Name, + NumberOfVotes = x.NumberOfVotes, + DisplayOrder1 = x.DisplayOrder + }; + }); + + model.Total = answers.Count; + } + else + { + model.Data = Enumerable.Empty(); - var answers = poll.PollAnswers.OrderBy(x=>x.DisplayOrder).ToList(); + NotifyAccessDenied(); + } - var model = new GridModel - { - Data = answers.Select(x => - { - return new PollAnswerModel() - { - Id = x.Id, - PollId = x.PollId, - Name = x.Name, - NumberOfVotes = x.NumberOfVotes, - DisplayOrder1 = x.DisplayOrder - }; - }), - Total = answers.Count - }; return new JsonResult { Data = model @@ -279,23 +296,21 @@ public ActionResult PollAnswers(int pollId, GridCommand command) [GridAction(EnableCustomBinding = true)] public ActionResult PollAnswerUpdate(PollAnswerModel model, GridCommand command) { - if (!_permissionService.Authorize(StandardPermissionProvider.ManagePolls)) - return AccessDeniedView(); - - if (!ModelState.IsValid) - { - //display the first model error - var modelStateErrors = this.ModelState.Values.SelectMany(x => x.Errors).Select(x => x.ErrorMessage); - return Content(modelStateErrors.FirstOrDefault()); - } + var pollAnswer = _pollService.GetPollAnswerById(model.Id); - var pollAnswer = _pollService.GetPollAnswerById(model.Id); - if (pollAnswer == null) - throw new ArgumentException("No poll answer found with the specified id", "id"); + if (_permissionService.Authorize(StandardPermissionProvider.ManagePolls)) + { + if (!ModelState.IsValid) + { + var modelStateErrors = this.ModelState.Values.SelectMany(x => x.Errors).Select(x => x.ErrorMessage); + return Content(modelStateErrors.FirstOrDefault()); + } + + pollAnswer.Name = model.Name; + pollAnswer.DisplayOrder = model.DisplayOrder1; - pollAnswer.Name = model.Name; - pollAnswer.DisplayOrder = model.DisplayOrder1; - _pollService.UpdatePoll(pollAnswer.Poll); + _pollService.UpdatePoll(pollAnswer.Poll); + } return PollAnswers(pollAnswer.PollId, command); } @@ -303,44 +318,39 @@ public ActionResult PollAnswerUpdate(PollAnswerModel model, GridCommand command) [GridAction(EnableCustomBinding = true)] public ActionResult PollAnswerAdd(int pollId, PollAnswerModel model, GridCommand command) { - if (!_permissionService.Authorize(StandardPermissionProvider.ManagePolls)) - return AccessDeniedView(); - - if (!ModelState.IsValid) - { - //display the first model error - var modelStateErrors = this.ModelState.Values.SelectMany(x => x.Errors).Select(x => x.ErrorMessage); - return Content(modelStateErrors.FirstOrDefault()); - } + if (_permissionService.Authorize(StandardPermissionProvider.ManagePolls)) + { + if (!ModelState.IsValid) + { + var modelStateErrors = this.ModelState.Values.SelectMany(x => x.Errors).Select(x => x.ErrorMessage); + return Content(modelStateErrors.FirstOrDefault()); + } - var poll = _pollService.GetPollById(pollId); - if (poll == null) - throw new ArgumentException("No poll found with the specified id", "pollId"); + var poll = _pollService.GetPollById(pollId); - poll.PollAnswers.Add(new PollAnswer - { - Name = model.Name, - DisplayOrder = model.DisplayOrder1 - }); - _pollService.UpdatePoll(poll); + poll.PollAnswers.Add(new PollAnswer + { + Name = model.Name, + DisplayOrder = model.DisplayOrder1 + }); + + _pollService.UpdatePoll(poll); + } - return PollAnswers(poll.Id, command); + return PollAnswers(pollId, command); } [GridAction(EnableCustomBinding = true)] public ActionResult PollAnswerDelete(int id, GridCommand command) { - if (!_permissionService.Authorize(StandardPermissionProvider.ManagePolls)) - return AccessDeniedView(); - - var pollAnswer = _pollService.GetPollAnswerById(id); - if (pollAnswer == null) - throw new ArgumentException("No poll answer found with the specified id", "id"); - - int pollId = pollAnswer.PollId; - _pollService.DeletePollAnswer(pollAnswer); + var pollAnswer = _pollService.GetPollAnswerById(id); + var pollId = pollAnswer.PollId; + if (_permissionService.Authorize(StandardPermissionProvider.ManagePolls)) + { + _pollService.DeletePollAnswer(pollAnswer); + } return PollAnswers(pollId, command); } diff --git a/src/Presentation/SmartStore.Web/Administration/Controllers/ProductAttributeController.cs b/src/Presentation/SmartStore.Web/Administration/Controllers/ProductAttributeController.cs index 9381bd50ee..ea2a6ae606 100644 --- a/src/Presentation/SmartStore.Web/Administration/Controllers/ProductAttributeController.cs +++ b/src/Presentation/SmartStore.Web/Administration/Controllers/ProductAttributeController.cs @@ -91,29 +91,35 @@ public ActionResult List() [HttpPost, GridAction(EnableCustomBinding = true)] public ActionResult List(GridCommand command) { - if (!_permissionService.Authorize(StandardPermissionProvider.ManageCatalog)) - return AccessDeniedView(); + var gridModel = new GridModel(); + + if (_permissionService.Authorize(StandardPermissionProvider.ManageCatalog)) + { + var productAttributes = _productAttributeService.GetAllProductAttributes(); + + gridModel.Data = productAttributes.Select(x => x.ToModel()); + gridModel.Total = productAttributes.Count(); + } + else + { + gridModel.Data = Enumerable.Empty(); + + NotifyAccessDenied(); + } - var productAttributes = _productAttributeService.GetAllProductAttributes(); - var gridModel = new GridModel - { - Data = productAttributes.Select(x => x.ToModel()), - Total = productAttributes.Count() - }; return new JsonResult { Data = gridModel }; } - //create public ActionResult Create() { if (!_permissionService.Authorize(StandardPermissionProvider.ManageCatalog)) return AccessDeniedView(); var model = new ProductAttributeModel(); - //locales + AddLocales(_languageService, model.Locales); return View(model); } diff --git a/src/Presentation/SmartStore.Web/Administration/Controllers/ProductController.cs b/src/Presentation/SmartStore.Web/Administration/Controllers/ProductController.cs index e1f0748bfc..1371b0d5c8 100644 --- a/src/Presentation/SmartStore.Web/Administration/Controllers/ProductController.cs +++ b/src/Presentation/SmartStore.Web/Administration/Controllers/ProductController.cs @@ -895,67 +895,74 @@ public ActionResult List(ProductListModel model) return View(model); } - [HttpPost, GridAction(EnableCustomBinding = true)] - public ActionResult ProductList(GridCommand command, ProductListModel model) - { - if (!_permissionService.Authorize(StandardPermissionProvider.ManageCatalog)) - return AccessDeniedView(); + [HttpPost, GridAction(EnableCustomBinding = true)] + public ActionResult ProductList(GridCommand command, ProductListModel model) + { + var gridModel = new GridModel(); - var gridModel = new GridModel(); - var searchContext = new ProductSearchContext - { - ManufacturerId = model.SearchManufacturerId, - StoreId = model.SearchStoreId, - Keywords = model.SearchProductName, - SearchSku = !_catalogSettings.SuppressSkuSearch, - LanguageId = _workContext.WorkingLanguage.Id, - OrderBy = ProductSortingEnum.Position, - PageIndex = command.Page - 1, - PageSize = command.PageSize, - ShowHidden = true, - ProductType = (model.SearchProductTypeId > 0 ? (ProductType?)model.SearchProductTypeId : null), - WithoutCategories = model.SearchWithoutCategories, - WithoutManufacturers = model.SearchWithoutManufacturers, - IsPublished = model.SearchIsPublished, - HomePageProducts = model.SearchHomePageProducts - }; + if (_permissionService.Authorize(StandardPermissionProvider.ManageCatalog)) + { + var searchContext = new ProductSearchContext + { + ManufacturerId = model.SearchManufacturerId, + StoreId = model.SearchStoreId, + Keywords = model.SearchProductName, + SearchSku = !_catalogSettings.SuppressSkuSearch, + LanguageId = _workContext.WorkingLanguage.Id, + OrderBy = ProductSortingEnum.Position, + PageIndex = command.Page - 1, + PageSize = command.PageSize, + ShowHidden = true, + ProductType = (model.SearchProductTypeId > 0 ? (ProductType?)model.SearchProductTypeId : null), + WithoutCategories = model.SearchWithoutCategories, + WithoutManufacturers = model.SearchWithoutManufacturers, + IsPublished = model.SearchIsPublished, + HomePageProducts = model.SearchHomePageProducts + }; - if (model.SearchCategoryId > 0) - searchContext.CategoryIds.Add(model.SearchCategoryId); + if (model.SearchCategoryId > 0) + searchContext.CategoryIds.Add(model.SearchCategoryId); - if (command.SortDescriptors != null && command.SortDescriptors.Count > 0) - { - var sort = command.SortDescriptors.First(); - if (sort.Member == "Name") - { - searchContext.OrderBy = (sort.SortDirection == ListSortDirection.Ascending ? ProductSortingEnum.NameAsc : ProductSortingEnum.NameDesc); - } - else if (sort.Member == "Price") - { - searchContext.OrderBy = (sort.SortDirection == ListSortDirection.Ascending ? ProductSortingEnum.PriceAsc : ProductSortingEnum.PriceDesc); - } - else if (sort.Member == "CreatedOn") + if (command.SortDescriptors != null && command.SortDescriptors.Count > 0) { - searchContext.OrderBy = (sort.SortDirection == ListSortDirection.Ascending ? ProductSortingEnum.CreatedOnAsc : ProductSortingEnum.CreatedOn); + var sort = command.SortDescriptors.First(); + if (sort.Member == "Name") + { + searchContext.OrderBy = (sort.SortDirection == ListSortDirection.Ascending ? ProductSortingEnum.NameAsc : ProductSortingEnum.NameDesc); + } + else if (sort.Member == "Price") + { + searchContext.OrderBy = (sort.SortDirection == ListSortDirection.Ascending ? ProductSortingEnum.PriceAsc : ProductSortingEnum.PriceDesc); + } + else if (sort.Member == "CreatedOn") + { + searchContext.OrderBy = (sort.SortDirection == ListSortDirection.Ascending ? ProductSortingEnum.CreatedOnAsc : ProductSortingEnum.CreatedOn); + } } - } - var products = _productService.SearchProducts(searchContext); + var products = _productService.SearchProducts(searchContext); - gridModel.Data = products.Select(x => - { - var productModel = x.ToModel(); - productModel.FullDescription = ""; // Perf - PrepareProductPictureThumbnailModel(productModel, x); + gridModel.Data = products.Select(x => + { + var productModel = x.ToModel(); + productModel.FullDescription = ""; // Perf + PrepareProductPictureThumbnailModel(productModel, x); - productModel.ProductTypeName = x.GetProductTypeLabel(_localizationService); - productModel.UpdatedOn = _dateTimeHelper.ConvertToUserTime(x.UpdatedOnUtc, DateTimeKind.Utc); - productModel.CreatedOn = _dateTimeHelper.ConvertToUserTime(x.CreatedOnUtc, DateTimeKind.Utc); + productModel.ProductTypeName = x.GetProductTypeLabel(_localizationService); + productModel.UpdatedOn = _dateTimeHelper.ConvertToUserTime(x.UpdatedOnUtc, DateTimeKind.Utc); + productModel.CreatedOn = _dateTimeHelper.ConvertToUserTime(x.CreatedOnUtc, DateTimeKind.Utc); - return productModel; - }); + return productModel; + }); + + gridModel.Total = products.TotalCount; + } + else + { + gridModel.Data = Enumerable.Empty(); - gridModel.Total = products.TotalCount; + NotifyAccessDenied(); + } return new JsonResult { @@ -1288,30 +1295,35 @@ public ActionResult CopyProduct(ProductModel model) [HttpPost, GridAction(EnableCustomBinding = true)] public ActionResult ProductCategoryList(GridCommand command, int productId) { - if (!_permissionService.Authorize(StandardPermissionProvider.ManageCatalog)) - return AccessDeniedView(); + var model = new GridModel(); - var productCategories = _categoryService.GetProductCategoriesByProductId(productId, true); - var productCategoriesModel = productCategories - .Select(x => - { - return new ProductModel.ProductCategoryModel() - { - Id = x.Id, - Category = _categoryService.GetCategoryById(x.CategoryId).GetCategoryBreadCrumb(_categoryService), - ProductId = x.ProductId, - CategoryId = x.CategoryId, - IsFeaturedProduct = x.IsFeaturedProduct, - DisplayOrder = x.DisplayOrder - }; - }) - .ToList(); + if (_permissionService.Authorize(StandardPermissionProvider.ManageCatalog)) + { + var productCategories = _categoryService.GetProductCategoriesByProductId(productId, true); + var productCategoriesModel = productCategories + .Select(x => + { + return new ProductModel.ProductCategoryModel() + { + Id = x.Id, + Category = _categoryService.GetCategoryById(x.CategoryId).GetCategoryBreadCrumb(_categoryService), + ProductId = x.ProductId, + CategoryId = x.CategoryId, + IsFeaturedProduct = x.IsFeaturedProduct, + DisplayOrder = x.DisplayOrder + }; + }) + .ToList(); - var model = new GridModel - { - Data = productCategoriesModel, - Total = productCategoriesModel.Count - }; + model.Data = productCategoriesModel; + model.Total = productCategoriesModel.Count; + } + else + { + model.Data = Enumerable.Empty(); + + NotifyAccessDenied(); + } return new JsonResult { @@ -1322,23 +1334,23 @@ public ActionResult ProductCategoryList(GridCommand command, int productId) [GridAction(EnableCustomBinding = true)] public ActionResult ProductCategoryInsert(GridCommand command, ProductModel.ProductCategoryModel model) { - if (!_permissionService.Authorize(StandardPermissionProvider.ManageCatalog)) - return AccessDeniedView(); + if (_permissionService.Authorize(StandardPermissionProvider.ManageCatalog)) + { + var productCategory = new ProductCategory + { + ProductId = model.ProductId, + CategoryId = Int32.Parse(model.Category), //use Category property (not CategoryId) because appropriate property is stored in it + IsFeaturedProduct = model.IsFeaturedProduct, + DisplayOrder = model.DisplayOrder + }; - var productCategory = new ProductCategory() - { - ProductId = model.ProductId, - CategoryId = Int32.Parse(model.Category), //use Category property (not CategoryId) because appropriate property is stored in it - IsFeaturedProduct = model.IsFeaturedProduct, - DisplayOrder = model.DisplayOrder - }; - _categoryService.InsertProductCategory(productCategory); + _categoryService.InsertProductCategory(productCategory); - - var mru = new MostRecentlyUsedList(_workContext.CurrentCustomer.GetAttribute(SystemCustomerAttributeNames.MostRecentlyUsedCategories), - model.Category, _catalogSettings.MostRecentlyUsedCategoriesMaxSize); + var mru = new MostRecentlyUsedList(_workContext.CurrentCustomer.GetAttribute(SystemCustomerAttributeNames.MostRecentlyUsedCategories), + model.Category, _catalogSettings.MostRecentlyUsedCategoriesMaxSize); - _genericAttributeService.SaveAttribute(_workContext.CurrentCustomer, SystemCustomerAttributeNames.MostRecentlyUsedCategories, mru.ToString()); + _genericAttributeService.SaveAttribute(_workContext.CurrentCustomer, SystemCustomerAttributeNames.MostRecentlyUsedCategories, mru.ToString()); + } return ProductCategoryList(command, model.ProductId); } @@ -1346,27 +1358,25 @@ public ActionResult ProductCategoryInsert(GridCommand command, ProductModel.Prod [GridAction(EnableCustomBinding = true)] public ActionResult ProductCategoryUpdate(GridCommand command, ProductModel.ProductCategoryModel model) { - if (!_permissionService.Authorize(StandardPermissionProvider.ManageCatalog)) - return AccessDeniedView(); + var productCategory = _categoryService.GetProductCategoryById(model.Id); - var productCategory = _categoryService.GetProductCategoryById(model.Id); - if (productCategory == null) - throw new ArgumentException("No product category mapping found with the specified id"); - - bool categoryChanged = (Int32.Parse(model.Category) != productCategory.CategoryId); + if (_permissionService.Authorize(StandardPermissionProvider.ManageCatalog)) + { + var categoryChanged = (Int32.Parse(model.Category) != productCategory.CategoryId); - //use Category property (not CategoryId) because appropriate property is stored in it - productCategory.CategoryId = Int32.Parse(model.Category); - productCategory.IsFeaturedProduct = model.IsFeaturedProduct; - productCategory.DisplayOrder = model.DisplayOrder; - _categoryService.UpdateProductCategory(productCategory); + //use Category property (not CategoryId) because appropriate property is stored in it + productCategory.CategoryId = Int32.Parse(model.Category); + productCategory.IsFeaturedProduct = model.IsFeaturedProduct; + productCategory.DisplayOrder = model.DisplayOrder; + _categoryService.UpdateProductCategory(productCategory); - if (categoryChanged) - { - var mru = new MostRecentlyUsedList(_workContext.CurrentCustomer.GetAttribute(SystemCustomerAttributeNames.MostRecentlyUsedCategories), - model.Category, _catalogSettings.MostRecentlyUsedCategoriesMaxSize); + if (categoryChanged) + { + var mru = new MostRecentlyUsedList(_workContext.CurrentCustomer.GetAttribute(SystemCustomerAttributeNames.MostRecentlyUsedCategories), + model.Category, _catalogSettings.MostRecentlyUsedCategoriesMaxSize); - _genericAttributeService.SaveAttribute(_workContext.CurrentCustomer, SystemCustomerAttributeNames.MostRecentlyUsedCategories, mru.ToString()); + _genericAttributeService.SaveAttribute(_workContext.CurrentCustomer, SystemCustomerAttributeNames.MostRecentlyUsedCategories, mru.ToString()); + } } return ProductCategoryList(command, productCategory.ProductId); @@ -1375,15 +1385,13 @@ public ActionResult ProductCategoryUpdate(GridCommand command, ProductModel.Prod [GridAction(EnableCustomBinding = true)] public ActionResult ProductCategoryDelete(int id, GridCommand command) { - if (!_permissionService.Authorize(StandardPermissionProvider.ManageCatalog)) - return AccessDeniedView(); - - var productCategory = _categoryService.GetProductCategoryById(id); - if (productCategory == null) - throw new ArgumentException("No product category mapping found with the specified id"); + var productCategory = _categoryService.GetProductCategoryById(id); + var productId = productCategory.ProductId; - var productId = productCategory.ProductId; - _categoryService.DeleteProductCategory(productCategory); + if (_permissionService.Authorize(StandardPermissionProvider.ManageCatalog)) + { + _categoryService.DeleteProductCategory(productCategory); + } return ProductCategoryList(command, productId); } @@ -1395,30 +1403,35 @@ public ActionResult ProductCategoryDelete(int id, GridCommand command) [HttpPost, GridAction(EnableCustomBinding = true)] public ActionResult ProductManufacturerList(GridCommand command, int productId) { - if (!_permissionService.Authorize(StandardPermissionProvider.ManageCatalog)) - return AccessDeniedView(); + var model = new GridModel(); - var productManufacturers = _manufacturerService.GetProductManufacturersByProductId(productId, true); - var productManufacturersModel = productManufacturers - .Select(x => - { - return new ProductModel.ProductManufacturerModel() - { - Id = x.Id, - Manufacturer = _manufacturerService.GetManufacturerById(x.ManufacturerId).Name, - ProductId = x.ProductId, - ManufacturerId = x.ManufacturerId, - IsFeaturedProduct = x.IsFeaturedProduct, - DisplayOrder = x.DisplayOrder - }; - }) - .ToList(); + if (_permissionService.Authorize(StandardPermissionProvider.ManageCatalog)) + { + var productManufacturers = _manufacturerService.GetProductManufacturersByProductId(productId, true); + var productManufacturersModel = productManufacturers + .Select(x => + { + return new ProductModel.ProductManufacturerModel + { + Id = x.Id, + Manufacturer = _manufacturerService.GetManufacturerById(x.ManufacturerId).Name, + ProductId = x.ProductId, + ManufacturerId = x.ManufacturerId, + IsFeaturedProduct = x.IsFeaturedProduct, + DisplayOrder = x.DisplayOrder + }; + }) + .ToList(); - var model = new GridModel - { - Data = productManufacturersModel, - Total = productManufacturersModel.Count - }; + model.Data = productManufacturersModel; + model.Total = productManufacturersModel.Count; + } + else + { + model.Data = Enumerable.Empty(); + + NotifyAccessDenied(); + } return new JsonResult { @@ -1429,22 +1442,23 @@ public ActionResult ProductManufacturerList(GridCommand command, int productId) [GridAction(EnableCustomBinding = true)] public ActionResult ProductManufacturerInsert(GridCommand command, ProductModel.ProductManufacturerModel model) { - if (!_permissionService.Authorize(StandardPermissionProvider.ManageCatalog)) - return AccessDeniedView(); + if (_permissionService.Authorize(StandardPermissionProvider.ManageCatalog)) + { + var productManufacturer = new ProductManufacturer + { + ProductId = model.ProductId, + ManufacturerId = Int32.Parse(model.Manufacturer), //use Manufacturer property (not ManufacturerId) because appropriate property is stored in it + IsFeaturedProduct = model.IsFeaturedProduct, + DisplayOrder = model.DisplayOrder + }; - var productManufacturer = new ProductManufacturer() - { - ProductId = model.ProductId, - ManufacturerId = Int32.Parse(model.Manufacturer), //use Manufacturer property (not ManufacturerId) because appropriate property is stored in it - IsFeaturedProduct = model.IsFeaturedProduct, - DisplayOrder = model.DisplayOrder - }; - _manufacturerService.InsertProductManufacturer(productManufacturer); + _manufacturerService.InsertProductManufacturer(productManufacturer); - var mru = new MostRecentlyUsedList(_workContext.CurrentCustomer.GetAttribute(SystemCustomerAttributeNames.MostRecentlyUsedManufacturers), - model.Manufacturer, _catalogSettings.MostRecentlyUsedManufacturersMaxSize); + var mru = new MostRecentlyUsedList(_workContext.CurrentCustomer.GetAttribute(SystemCustomerAttributeNames.MostRecentlyUsedManufacturers), + model.Manufacturer, _catalogSettings.MostRecentlyUsedManufacturersMaxSize); - _genericAttributeService.SaveAttribute(_workContext.CurrentCustomer, SystemCustomerAttributeNames.MostRecentlyUsedManufacturers, mru.ToString()); + _genericAttributeService.SaveAttribute(_workContext.CurrentCustomer, SystemCustomerAttributeNames.MostRecentlyUsedManufacturers, mru.ToString()); + } return ProductManufacturerList(command, model.ProductId); } @@ -1452,27 +1466,26 @@ public ActionResult ProductManufacturerInsert(GridCommand command, ProductModel. [GridAction(EnableCustomBinding = true)] public ActionResult ProductManufacturerUpdate(GridCommand command, ProductModel.ProductManufacturerModel model) { - if (!_permissionService.Authorize(StandardPermissionProvider.ManageCatalog)) - return AccessDeniedView(); + var productManufacturer = _manufacturerService.GetProductManufacturerById(model.Id); - var productManufacturer = _manufacturerService.GetProductManufacturerById(model.Id); - if (productManufacturer == null) - throw new ArgumentException("No product manufacturer mapping found with the specified id"); + if (_permissionService.Authorize(StandardPermissionProvider.ManageCatalog)) + { + var manufacturerChanged = (Int32.Parse(model.Manufacturer) != productManufacturer.ManufacturerId); - bool manufacturerChanged = (Int32.Parse(model.Manufacturer) != productManufacturer.ManufacturerId); + //use Manufacturer property (not ManufacturerId) because appropriate property is stored in it + productManufacturer.ManufacturerId = Int32.Parse(model.Manufacturer); + productManufacturer.IsFeaturedProduct = model.IsFeaturedProduct; + productManufacturer.DisplayOrder = model.DisplayOrder; - //use Manufacturer property (not ManufacturerId) because appropriate property is stored in it - productManufacturer.ManufacturerId = Int32.Parse(model.Manufacturer); - productManufacturer.IsFeaturedProduct = model.IsFeaturedProduct; - productManufacturer.DisplayOrder = model.DisplayOrder; - _manufacturerService.UpdateProductManufacturer(productManufacturer); + _manufacturerService.UpdateProductManufacturer(productManufacturer); - if (manufacturerChanged) - { - var mru = new MostRecentlyUsedList(_workContext.CurrentCustomer.GetAttribute(SystemCustomerAttributeNames.MostRecentlyUsedManufacturers), - model.Manufacturer, _catalogSettings.MostRecentlyUsedManufacturersMaxSize); + if (manufacturerChanged) + { + var mru = new MostRecentlyUsedList(_workContext.CurrentCustomer.GetAttribute(SystemCustomerAttributeNames.MostRecentlyUsedManufacturers), + model.Manufacturer, _catalogSettings.MostRecentlyUsedManufacturersMaxSize); - _genericAttributeService.SaveAttribute(_workContext.CurrentCustomer, SystemCustomerAttributeNames.MostRecentlyUsedManufacturers, mru.ToString()); + _genericAttributeService.SaveAttribute(_workContext.CurrentCustomer, SystemCustomerAttributeNames.MostRecentlyUsedManufacturers, mru.ToString()); + } } return ProductManufacturerList(command, productManufacturer.ProductId); @@ -1481,15 +1494,13 @@ public ActionResult ProductManufacturerUpdate(GridCommand command, ProductModel. [GridAction(EnableCustomBinding = true)] public ActionResult ProductManufacturerDelete(int id, GridCommand command) { - if (!_permissionService.Authorize(StandardPermissionProvider.ManageCatalog)) - return AccessDeniedView(); + var productManufacturer = _manufacturerService.GetProductManufacturerById(id); + var productId = productManufacturer.ProductId; - var productManufacturer = _manufacturerService.GetProductManufacturerById(id); - if (productManufacturer == null) - throw new ArgumentException("No product manufacturer mapping found with the specified id"); - - var productId = productManufacturer.ProductId; - _manufacturerService.DeleteProductManufacturer(productManufacturer); + if (_permissionService.Authorize(StandardPermissionProvider.ManageCatalog)) + { + _manufacturerService.DeleteProductManufacturer(productManufacturer); + } return ProductManufacturerList(command, productId); } @@ -1501,34 +1512,39 @@ public ActionResult ProductManufacturerDelete(int id, GridCommand command) [HttpPost, GridAction(EnableCustomBinding = true)] public ActionResult RelatedProductList(GridCommand command, int productId) { - if (!_permissionService.Authorize(StandardPermissionProvider.ManageCatalog)) - return AccessDeniedView(); + var model = new GridModel(); - var relatedProducts = _productService.GetRelatedProductsByProductId1(productId, true); - var relatedProductsModel = relatedProducts - .Select(x => - { - var product2 = _productService.GetProductById(x.ProductId2); + if (_permissionService.Authorize(StandardPermissionProvider.ManageCatalog)) + { + var relatedProducts = _productService.GetRelatedProductsByProductId1(productId, true); + var relatedProductsModel = relatedProducts + .Select(x => + { + var product2 = _productService.GetProductById(x.ProductId2); - return new ProductModel.RelatedProductModel() - { - Id = x.Id, - ProductId2 = x.ProductId2, - Product2Name = product2.Name, - ProductTypeName = product2.GetProductTypeLabel(_localizationService), - ProductTypeLabelHint = product2.ProductTypeLabelHint, - DisplayOrder = x.DisplayOrder, - Product2Sku = product2.Sku, - Product2Published = product2.Published - }; - }) - .ToList(); + return new ProductModel.RelatedProductModel() + { + Id = x.Id, + ProductId2 = x.ProductId2, + Product2Name = product2.Name, + ProductTypeName = product2.GetProductTypeLabel(_localizationService), + ProductTypeLabelHint = product2.ProductTypeLabelHint, + DisplayOrder = x.DisplayOrder, + Product2Sku = product2.Sku, + Product2Published = product2.Published + }; + }) + .ToList(); - var model = new GridModel - { - Data = relatedProductsModel, - Total = relatedProductsModel.Count - }; + model.Data = relatedProductsModel; + model.Total = relatedProductsModel.Count; + } + else + { + model.Data = Enumerable.Empty(); + + NotifyAccessDenied(); + } return new JsonResult { @@ -1539,15 +1555,13 @@ public ActionResult RelatedProductList(GridCommand command, int productId) [GridAction(EnableCustomBinding = true)] public ActionResult RelatedProductUpdate(GridCommand command, ProductModel.RelatedProductModel model) { - if (!_permissionService.Authorize(StandardPermissionProvider.ManageCatalog)) - return AccessDeniedView(); - - var relatedProduct = _productService.GetRelatedProductById(model.Id); - if (relatedProduct == null) - throw new ArgumentException("No related product found with the specified id"); + var relatedProduct = _productService.GetRelatedProductById(model.Id); - relatedProduct.DisplayOrder = model.DisplayOrder; - _productService.UpdateRelatedProduct(relatedProduct); + if (_permissionService.Authorize(StandardPermissionProvider.ManageCatalog)) + { + relatedProduct.DisplayOrder = model.DisplayOrder; + _productService.UpdateRelatedProduct(relatedProduct); + } return RelatedProductList(command, relatedProduct.ProductId1); } @@ -1555,15 +1569,13 @@ public ActionResult RelatedProductUpdate(GridCommand command, ProductModel.Relat [GridAction(EnableCustomBinding = true)] public ActionResult RelatedProductDelete(int id, GridCommand command) { - if (!_permissionService.Authorize(StandardPermissionProvider.ManageCatalog)) - return AccessDeniedView(); - - var relatedProduct = _productService.GetRelatedProductById(id); - if (relatedProduct == null) - throw new ArgumentException("No related product found with the specified id"); + var relatedProduct = _productService.GetRelatedProductById(id); + var productId = relatedProduct.ProductId1; - var productId = relatedProduct.ProductId1; - _productService.DeleteRelatedProduct(relatedProduct); + if (_permissionService.Authorize(StandardPermissionProvider.ManageCatalog)) + { + _productService.DeleteRelatedProduct(relatedProduct); + } return RelatedProductList(command, productId); } @@ -1623,36 +1635,45 @@ public ActionResult RelatedProductAddPopup(int productId) [HttpPost, GridAction(EnableCustomBinding = true)] public ActionResult RelatedProductAddPopupList(GridCommand command, ProductModel.AddRelatedProductModel model) { - if (!_permissionService.Authorize(StandardPermissionProvider.ManageCatalog)) - return AccessDeniedView(); + var gridModel = new GridModel(); - var gridModel = new GridModel(); + if (_permissionService.Authorize(StandardPermissionProvider.ManageCatalog)) + { + var ctx = new ProductSearchContext(); - var ctx = new ProductSearchContext(); + if (model.SearchCategoryId > 0) + ctx.CategoryIds.Add(model.SearchCategoryId); - if (model.SearchCategoryId > 0) - ctx.CategoryIds.Add(model.SearchCategoryId); + ctx.ManufacturerId = model.SearchManufacturerId; + ctx.StoreId = model.SearchStoreId; + ctx.Keywords = model.SearchProductName; + ctx.SearchSku = !_catalogSettings.SuppressSkuSearch; + ctx.LanguageId = _workContext.WorkingLanguage.Id; + ctx.OrderBy = ProductSortingEnum.Position; + ctx.PageIndex = command.Page - 1; + ctx.PageSize = command.PageSize; + ctx.ShowHidden = true; + ctx.ProductType = model.SearchProductTypeId > 0 ? (ProductType?)model.SearchProductTypeId : null; - ctx.ManufacturerId = model.SearchManufacturerId; - ctx.StoreId = model.SearchStoreId; - ctx.Keywords = model.SearchProductName; - ctx.SearchSku = !_catalogSettings.SuppressSkuSearch; - ctx.LanguageId = _workContext.WorkingLanguage.Id; - ctx.OrderBy = ProductSortingEnum.Position; - ctx.PageIndex = command.Page - 1; - ctx.PageSize = command.PageSize; - ctx.ShowHidden = true; - ctx.ProductType = model.SearchProductTypeId > 0 ? (ProductType?)model.SearchProductTypeId : null; + var products = _productService.SearchProducts(ctx); - var products = _productService.SearchProducts(ctx); - gridModel.Data = products.Select(x => + gridModel.Data = products.Select(x => + { + var productModel = x.ToModel(); + productModel.ProductTypeName = x.GetProductTypeLabel(_localizationService); + + return productModel; + }); + + gridModel.Total = products.TotalCount; + } + else { - var productModel = x.ToModel(); - productModel.ProductTypeName = x.GetProductTypeLabel(_localizationService); + gridModel.Data = Enumerable.Empty(); + + NotifyAccessDenied(); + } - return productModel; - }); - gridModel.Total = products.TotalCount; return new JsonResult { Data = gridModel @@ -1732,33 +1753,38 @@ public ActionResult CreateAllMutuallyRelatedProducts(int productId) [HttpPost, GridAction(EnableCustomBinding = true)] public ActionResult CrossSellProductList(GridCommand command, int productId) { - if (!_permissionService.Authorize(StandardPermissionProvider.ManageCatalog)) - return AccessDeniedView(); + var model = new GridModel(); - var crossSellProducts = _productService.GetCrossSellProductsByProductId1(productId, true); - var crossSellProductsModel = crossSellProducts - .Select(x => - { - var product2 = _productService.GetProductById(x.ProductId2); + if (_permissionService.Authorize(StandardPermissionProvider.ManageCatalog)) + { + var crossSellProducts = _productService.GetCrossSellProductsByProductId1(productId, true); + var crossSellProductsModel = crossSellProducts + .Select(x => + { + var product2 = _productService.GetProductById(x.ProductId2); - return new ProductModel.CrossSellProductModel() - { - Id = x.Id, - ProductId2 = x.ProductId2, - Product2Name = product2.Name, - ProductTypeName = product2.GetProductTypeLabel(_localizationService), - ProductTypeLabelHint = product2.ProductTypeLabelHint, - Product2Sku = product2.Sku, - Product2Published = product2.Published - }; - }) - .ToList(); + return new ProductModel.CrossSellProductModel + { + Id = x.Id, + ProductId2 = x.ProductId2, + Product2Name = product2.Name, + ProductTypeName = product2.GetProductTypeLabel(_localizationService), + ProductTypeLabelHint = product2.ProductTypeLabelHint, + Product2Sku = product2.Sku, + Product2Published = product2.Published + }; + }) + .ToList(); - var model = new GridModel - { - Data = crossSellProductsModel, - Total = crossSellProductsModel.Count - }; + model.Data = crossSellProductsModel; + model.Total = crossSellProductsModel.Count; + } + else + { + model.Data = Enumerable.Empty(); + + NotifyAccessDenied(); + } return new JsonResult { @@ -1769,15 +1795,13 @@ public ActionResult CrossSellProductList(GridCommand command, int productId) [GridAction(EnableCustomBinding = true)] public ActionResult CrossSellProductDelete(int id, GridCommand command) { - if (!_permissionService.Authorize(StandardPermissionProvider.ManageCatalog)) - return AccessDeniedView(); - - var crossSellProduct = _productService.GetCrossSellProductById(id); - if (crossSellProduct == null) - throw new ArgumentException("No cross-sell product found with the specified id"); + var crossSellProduct = _productService.GetCrossSellProductById(id); + var productId = crossSellProduct.ProductId1; - var productId = crossSellProduct.ProductId1; - _productService.DeleteCrossSellProduct(crossSellProduct); + if (_permissionService.Authorize(StandardPermissionProvider.ManageCatalog)) + { + _productService.DeleteCrossSellProduct(crossSellProduct); + } return CrossSellProductList(command, productId); } @@ -1837,37 +1861,45 @@ public ActionResult CrossSellProductAddPopup(int productId) [HttpPost, GridAction(EnableCustomBinding = true)] public ActionResult CrossSellProductAddPopupList(GridCommand command, ProductModel.AddCrossSellProductModel model) { - if (!_permissionService.Authorize(StandardPermissionProvider.ManageCatalog)) - return AccessDeniedView(); + var gridModel = new GridModel(); - var gridModel = new GridModel(); + if (_permissionService.Authorize(StandardPermissionProvider.ManageCatalog)) + { + var ctx = new ProductSearchContext(); - var ctx = new ProductSearchContext(); + if (model.SearchCategoryId > 0) + ctx.CategoryIds.Add(model.SearchCategoryId); - if (model.SearchCategoryId > 0) - ctx.CategoryIds.Add(model.SearchCategoryId); + ctx.ManufacturerId = model.SearchManufacturerId; + ctx.StoreId = model.SearchStoreId; + ctx.Keywords = model.SearchProductName; + ctx.SearchSku = !_catalogSettings.SuppressSkuSearch; + ctx.LanguageId = _workContext.WorkingLanguage.Id; + ctx.OrderBy = ProductSortingEnum.Position; + ctx.PageIndex = command.Page - 1; + ctx.PageSize = command.PageSize; + ctx.ShowHidden = true; + ctx.ProductType = model.SearchProductTypeId > 0 ? (ProductType?)model.SearchProductTypeId : null; - ctx.ManufacturerId = model.SearchManufacturerId; - ctx.StoreId = model.SearchStoreId; - ctx.Keywords = model.SearchProductName; - ctx.SearchSku = !_catalogSettings.SuppressSkuSearch; - ctx.LanguageId = _workContext.WorkingLanguage.Id; - ctx.OrderBy = ProductSortingEnum.Position; - ctx.PageIndex = command.Page - 1; - ctx.PageSize = command.PageSize; - ctx.ShowHidden = true; - ctx.ProductType = model.SearchProductTypeId > 0 ? (ProductType?)model.SearchProductTypeId : null; + var products = _productService.SearchProducts(ctx); - var products = _productService.SearchProducts(ctx); + gridModel.Data = products.Select(x => + { + var productModel = x.ToModel(); + productModel.ProductTypeName = x.GetProductTypeLabel(_localizationService); + + return productModel; + }); - gridModel.Data = products.Select(x => + gridModel.Total = products.TotalCount; + } + else { - var productModel = x.ToModel(); - productModel.ProductTypeName = x.GetProductTypeLabel(_localizationService); + gridModel.Data = Enumerable.Empty(); + + NotifyAccessDenied(); + } - return productModel; - }); - gridModel.Total = products.TotalCount; return new JsonResult { Data = gridModel @@ -1946,38 +1978,43 @@ public ActionResult CreateAllMutuallyCrossSellProducts(int productId) [HttpPost, GridAction(EnableCustomBinding = true)] public ActionResult AssociatedProductList(GridCommand command, int productId) { - if (!_permissionService.Authorize(StandardPermissionProvider.ManageCatalog)) - return AccessDeniedView(); + var model = new GridModel(); - var searchContext = new ProductSearchContext() + if (_permissionService.Authorize(StandardPermissionProvider.ManageCatalog)) { - ParentGroupedProductId = productId, - PageSize = int.MaxValue, - ShowHidden = true - }; - - var associatedProducts = _productService.SearchProducts(searchContext); - var associatedProductsModel = associatedProducts - .Select(x => + var searchContext = new ProductSearchContext { - return new ProductModel.AssociatedProductModel() + ParentGroupedProductId = productId, + PageSize = int.MaxValue, + ShowHidden = true + }; + + var associatedProducts = _productService.SearchProducts(searchContext); + var associatedProductsModel = associatedProducts + .Select(x => { - Id = x.Id, - ProductName = x.Name, - ProductTypeName = x.GetProductTypeLabel(_localizationService), - ProductTypeLabelHint = x.ProductTypeLabelHint, - DisplayOrder = x.DisplayOrder, - Sku = x.Sku, - Published = x.Published - }; - }) - .ToList(); + return new ProductModel.AssociatedProductModel + { + Id = x.Id, + ProductName = x.Name, + ProductTypeName = x.GetProductTypeLabel(_localizationService), + ProductTypeLabelHint = x.ProductTypeLabelHint, + DisplayOrder = x.DisplayOrder, + Sku = x.Sku, + Published = x.Published + }; + }) + .ToList(); - var model = new GridModel + model.Data = associatedProductsModel; + model.Total = associatedProductsModel.Count; + } + else { - Data = associatedProductsModel, - Total = associatedProductsModel.Count - }; + model.Data = Enumerable.Empty(); + + NotifyAccessDenied(); + } return new JsonResult { @@ -1988,15 +2025,13 @@ public ActionResult AssociatedProductList(GridCommand command, int productId) [GridAction(EnableCustomBinding = true)] public ActionResult AssociatedProductUpdate(GridCommand command, ProductModel.AssociatedProductModel model) { - if (!_permissionService.Authorize(StandardPermissionProvider.ManageCatalog)) - return AccessDeniedView(); - var associatedProduct = _productService.GetProductById(model.Id); - if (associatedProduct == null) - throw new ArgumentException("No associated product found with the specified id"); - associatedProduct.DisplayOrder = model.DisplayOrder; - _productService.UpdateProduct(associatedProduct); + if (_permissionService.Authorize(StandardPermissionProvider.ManageCatalog)) + { + associatedProduct.DisplayOrder = model.DisplayOrder; + _productService.UpdateProduct(associatedProduct); + } return AssociatedProductList(command, associatedProduct.ParentGroupedProductId); } @@ -2004,19 +2039,16 @@ public ActionResult AssociatedProductUpdate(GridCommand command, ProductModel.As [GridAction(EnableCustomBinding = true)] public ActionResult AssociatedProductDelete(int id, GridCommand command) { - if (!_permissionService.Authorize(StandardPermissionProvider.ManageCatalog)) - return AccessDeniedView(); - var product = _productService.GetProductById(id); - if (product == null) - throw new ArgumentException("No associated product found with the specified id"); - var originalParentGroupedProductId = product.ParentGroupedProductId; - product.ParentGroupedProductId = 0; - _productService.UpdateProduct(product); - - return AssociatedProductList(command, originalParentGroupedProductId); + if (_permissionService.Authorize(StandardPermissionProvider.ManageCatalog)) + { + product.ParentGroupedProductId = 0; + _productService.UpdateProduct(product); + } + + return AssociatedProductList(command, originalParentGroupedProductId); } public ActionResult AssociatedProductAddPopup(int productId) @@ -2057,33 +2089,41 @@ public ActionResult AssociatedProductAddPopup(int productId) [HttpPost, GridAction(EnableCustomBinding = true)] public ActionResult AssociatedProductAddPopupList(GridCommand command, ProductModel.AddAssociatedProductModel model) { - if (!_permissionService.Authorize(StandardPermissionProvider.ManageCatalog)) - return AccessDeniedView(); + var gridModel = new GridModel(); - var searchContext = new ProductSearchContext() - { - CategoryIds = new List() { model.SearchCategoryId }, - ManufacturerId = model.SearchManufacturerId, - StoreId = model.SearchStoreId, - Keywords = model.SearchProductName, - SearchSku = !_catalogSettings.SuppressSkuSearch, - PageIndex = command.Page - 1, - PageSize = command.PageSize, - ShowHidden = true, - ProductType = model.SearchProductTypeId > 0 ? (ProductType?)model.SearchProductTypeId : null - }; + if (_permissionService.Authorize(StandardPermissionProvider.ManageCatalog)) + { + var searchContext = new ProductSearchContext + { + CategoryIds = new List() { model.SearchCategoryId }, + ManufacturerId = model.SearchManufacturerId, + StoreId = model.SearchStoreId, + Keywords = model.SearchProductName, + SearchSku = !_catalogSettings.SuppressSkuSearch, + PageIndex = command.Page - 1, + PageSize = command.PageSize, + ShowHidden = true, + ProductType = model.SearchProductTypeId > 0 ? (ProductType?)model.SearchProductTypeId : null + }; + + var products = _productService.SearchProducts(searchContext); - var products = _productService.SearchProducts(searchContext); + gridModel.Data = products.Select(x => + { + var productModel = x.ToModel(); + productModel.ProductTypeName = x.GetProductTypeLabel(_localizationService); - var gridModel = new GridModel(); - gridModel.Data = products.Select(x => + return productModel; + }); + + gridModel.Total = products.TotalCount; + } + else { - var productModel = x.ToModel(); - productModel.ProductTypeName = x.GetProductTypeLabel(_localizationService); + gridModel.Data = Enumerable.Empty(); - return productModel; - }); - gridModel.Total = products.TotalCount; + NotifyAccessDenied(); + } return new JsonResult { @@ -2222,34 +2262,39 @@ private void SaveFilteredAttributes(ProductBundleItem bundleItem, FormCollection [HttpPost, GridAction(EnableCustomBinding = true)] public ActionResult BundleItemList(GridCommand command, int productId) { - if (!_permissionService.Authorize(StandardPermissionProvider.ManageCatalog)) - return AccessDeniedView(); + var model = new GridModel(); - var bundleItems = _productService.GetBundleItems(productId, true).Select(x => x.Item); + if (_permissionService.Authorize(StandardPermissionProvider.ManageCatalog)) + { + var bundleItems = _productService.GetBundleItems(productId, true).Select(x => x.Item); - var bundleItemsModel = bundleItems.Select(x => - { - return new ProductModel.BundleItemModel() + var bundleItemsModel = bundleItems.Select(x => { - Id = x.Id, - ProductId = x.Product.Id, - ProductName = x.Product.Name, - ProductTypeName = x.Product.GetProductTypeLabel(_localizationService), - ProductTypeLabelHint = x.Product.ProductTypeLabelHint, - Sku = x.Product.Sku, - Quantity = x.Quantity, - Discount = x.Discount, - DisplayOrder = x.DisplayOrder, - Visible = x.Visible, - Published = x.Published - }; - }).ToList(); + return new ProductModel.BundleItemModel + { + Id = x.Id, + ProductId = x.Product.Id, + ProductName = x.Product.Name, + ProductTypeName = x.Product.GetProductTypeLabel(_localizationService), + ProductTypeLabelHint = x.Product.ProductTypeLabelHint, + Sku = x.Product.Sku, + Quantity = x.Quantity, + Discount = x.Discount, + DisplayOrder = x.DisplayOrder, + Visible = x.Visible, + Published = x.Published + }; + }).ToList(); - var model = new GridModel() + model.Data = bundleItemsModel; + model.Total = bundleItemsModel.Count; + } + else { - Data = bundleItemsModel, - Total = bundleItemsModel.Count - }; + model.Data = Enumerable.Empty(); + + NotifyAccessDenied(); + } return new JsonResult { Data = model }; } @@ -2257,15 +2302,12 @@ public ActionResult BundleItemList(GridCommand command, int productId) [GridAction(EnableCustomBinding = true)] public ActionResult BundleItemDelete(int id, GridCommand command) { - if (!_permissionService.Authorize(StandardPermissionProvider.ManageCatalog)) - return AccessDeniedView(); - var bundleItem = _productService.GetBundleItemById(id); - if (bundleItem == null) - throw new ArgumentException("No product bundle item found with the specified id"); - - _productService.DeleteBundleItem(bundleItem); + if (_permissionService.Authorize(StandardPermissionProvider.ManageCatalog)) + { + _productService.DeleteBundleItem(bundleItem); + } return BundleItemList(command, bundleItem.BundleProductId); } @@ -2369,34 +2411,42 @@ public ActionResult BundleItemAddPopup(string btnId, string formId, ProductModel [HttpPost, GridAction(EnableCustomBinding = true)] public ActionResult BundleItemAddPopupList(GridCommand command, ProductModel.AddBundleItemModel model) { - if (!_permissionService.Authorize(StandardPermissionProvider.ManageCatalog)) - return AccessDeniedView(); + var gridModel = new GridModel(); - var searchContext = new ProductSearchContext() - { - CategoryIds = new List() { model.SearchCategoryId }, - ManufacturerId = model.SearchManufacturerId, - StoreId = model.SearchStoreId, - Keywords = model.SearchProductName, - SearchSku = !_catalogSettings.SuppressSkuSearch, - PageIndex = command.Page - 1, - PageSize = command.PageSize, - ShowHidden = true, - ProductType = model.SearchProductTypeId > 0 ? (ProductType?)model.SearchProductTypeId : null - }; + if (_permissionService.Authorize(StandardPermissionProvider.ManageCatalog)) + { + var searchContext = new ProductSearchContext + { + CategoryIds = new List { model.SearchCategoryId }, + ManufacturerId = model.SearchManufacturerId, + StoreId = model.SearchStoreId, + Keywords = model.SearchProductName, + SearchSku = !_catalogSettings.SuppressSkuSearch, + PageIndex = command.Page - 1, + PageSize = command.PageSize, + ShowHidden = true, + ProductType = model.SearchProductTypeId > 0 ? (ProductType?)model.SearchProductTypeId : null + }; - var products = _productService.SearchProducts(searchContext); + var products = _productService.SearchProducts(searchContext); - var gridModel = new GridModel(); - gridModel.Data = products.Select(x => + gridModel.Data = products.Select(x => + { + var productModel = x.ToModel(); + productModel.ProductTypeName = x.GetProductTypeLabel(_localizationService); + productModel.ProductSelectCheckboxClass = (!x.CanBeBundleItem() ? " hide" : ""); + + return productModel; + }); + + gridModel.Total = products.TotalCount; + } + else { - var productModel = x.ToModel(); - productModel.ProductTypeName = x.GetProductTypeLabel(_localizationService); - productModel.ProductSelectCheckboxClass = (!x.CanBeBundleItem() ? " hide" : ""); + gridModel.Data = Enumerable.Empty(); - return productModel; - }); - gridModel.Total = products.TotalCount; + NotifyAccessDenied(); + } return new JsonResult { @@ -2498,29 +2548,34 @@ public ActionResult ProductPictureAdd(int pictureId, int displayOrder, int produ [HttpPost, GridAction(EnableCustomBinding = true)] public ActionResult ProductPictureList(GridCommand command, int productId) { - if (!_permissionService.Authorize(StandardPermissionProvider.ManageCatalog)) - return AccessDeniedView(); + var model = new GridModel(); - var productPictures = _productService.GetProductPicturesByProductId(productId); - var productPicturesModel = productPictures - .Select(x => - { - return new ProductModel.ProductPictureModel() - { - Id = x.Id, - ProductId = x.ProductId, - PictureId = x.PictureId, - PictureUrl = _pictureService.GetPictureUrl(x.PictureId), - DisplayOrder = x.DisplayOrder - }; - }) - .ToList(); + if (_permissionService.Authorize(StandardPermissionProvider.ManageCatalog)) + { + var productPictures = _productService.GetProductPicturesByProductId(productId); + var productPicturesModel = productPictures + .Select(x => + { + return new ProductModel.ProductPictureModel + { + Id = x.Id, + ProductId = x.ProductId, + PictureId = x.PictureId, + PictureUrl = _pictureService.GetPictureUrl(x.PictureId), + DisplayOrder = x.DisplayOrder + }; + }) + .ToList(); - var model = new GridModel - { - Data = productPicturesModel, - Total = productPicturesModel.Count - }; + model.Data = productPicturesModel; + model.Total = productPicturesModel.Count; + } + else + { + model.Data = Enumerable.Empty(); + + NotifyAccessDenied(); + } return new JsonResult { @@ -2531,15 +2586,13 @@ public ActionResult ProductPictureList(GridCommand command, int productId) [GridAction(EnableCustomBinding = true)] public ActionResult ProductPictureUpdate(ProductModel.ProductPictureModel model, GridCommand command) { - if (!_permissionService.Authorize(StandardPermissionProvider.ManageCatalog)) - return AccessDeniedView(); + var productPicture = _productService.GetProductPictureById(model.Id); - var productPicture = _productService.GetProductPictureById(model.Id); - if (productPicture == null) - throw new ArgumentException("No product picture found with the specified id"); - - productPicture.DisplayOrder = model.DisplayOrder; - _productService.UpdateProductPicture(productPicture); + if (_permissionService.Authorize(StandardPermissionProvider.ManageCatalog)) + { + productPicture.DisplayOrder = model.DisplayOrder; + _productService.UpdateProductPicture(productPicture); + } return ProductPictureList(command, productPicture.ProductId); } @@ -2547,18 +2600,16 @@ public ActionResult ProductPictureUpdate(ProductModel.ProductPictureModel model, [GridAction(EnableCustomBinding = true)] public ActionResult ProductPictureDelete(int id, GridCommand command) { - if (!_permissionService.Authorize(StandardPermissionProvider.ManageCatalog)) - return AccessDeniedView(); + var productPicture = _productService.GetProductPictureById(id); + var productId = productPicture.ProductId; - var productPicture = _productService.GetProductPictureById(id); - if (productPicture == null) - throw new ArgumentException("No product picture found with the specified id"); - - var productId = productPicture.ProductId; - _productService.DeleteProductPicture(productPicture); + if (_permissionService.Authorize(StandardPermissionProvider.ManageCatalog)) + { + _productService.DeleteProductPicture(productPicture); - var picture = _pictureService.GetPictureById(productPicture.PictureId); - _pictureService.DeletePicture(picture); + var picture = _pictureService.GetPictureById(productPicture.PictureId); + _pictureService.DeletePicture(picture); + } return ProductPictureList(command, productId); } @@ -2589,51 +2640,56 @@ public ActionResult ProductSpecificationAttributeAdd(int specificationAttributeO [HttpPost, GridAction(EnableCustomBinding = true)] public ActionResult ProductSpecAttrList(GridCommand command, int productId) { - if (!_permissionService.Authorize(StandardPermissionProvider.ManageCatalog)) - return AccessDeniedView(); - - var productrSpecs = _specificationAttributeService.GetProductSpecificationAttributesByProductId(productId); + var model = new GridModel(); - var productrSpecsModel = productrSpecs - .Select(x => - { - var psaModel = new ProductSpecificationAttributeModel() - { - Id = x.Id, - SpecificationAttributeName = x.SpecificationAttributeOption.SpecificationAttribute.Name, - SpecificationAttributeOptionName = x.SpecificationAttributeOption.Name, - SpecificationAttributeOptionAttributeId = x.SpecificationAttributeOption.SpecificationAttributeId, - SpecificationAttributeOptionId = x.SpecificationAttributeOptionId, - AllowFiltering = x.AllowFiltering, - ShowOnProductPage = x.ShowOnProductPage, - DisplayOrder = x.DisplayOrder - }; - return psaModel; - }) - .ToList(); + if (_permissionService.Authorize(StandardPermissionProvider.ManageCatalog)) + { + var productrSpecs = _specificationAttributeService.GetProductSpecificationAttributesByProductId(productId); - foreach(var attr in productrSpecsModel) { + var productrSpecsModel = productrSpecs + .Select(x => + { + var psaModel = new ProductSpecificationAttributeModel + { + Id = x.Id, + SpecificationAttributeName = x.SpecificationAttributeOption.SpecificationAttribute.Name, + SpecificationAttributeOptionName = x.SpecificationAttributeOption.Name, + SpecificationAttributeOptionAttributeId = x.SpecificationAttributeOption.SpecificationAttributeId, + SpecificationAttributeOptionId = x.SpecificationAttributeOptionId, + AllowFiltering = x.AllowFiltering, + ShowOnProductPage = x.ShowOnProductPage, + DisplayOrder = x.DisplayOrder + }; + return psaModel; + }) + .ToList(); - var options = _specificationAttributeService.GetSpecificationAttributeOptionsBySpecificationAttribute(attr.SpecificationAttributeOptionAttributeId); + foreach (var attr in productrSpecsModel) + { + var options = _specificationAttributeService.GetSpecificationAttributeOptionsBySpecificationAttribute(attr.SpecificationAttributeOptionAttributeId); - foreach(var option in options) { + foreach (var option in options) + { + attr.SpecificationAttributeOptions.Add(new ProductSpecificationAttributeModel.SpecificationAttributeOption + { + id = option.Id, + name = option.Name, + text = option.Name + }); + } - attr.SpecificationAttributeOptions.Add(new ProductSpecificationAttributeModel.SpecificationAttributeOption() - { - id = option.Id, - name = option.Name, - text = option.Name - }); - } + attr.SpecificationAttributeOptionsJsonString = JsonConvert.SerializeObject(attr.SpecificationAttributeOptions); + } - attr.SpecificationAttributeOptionsJsonString = JsonConvert.SerializeObject(attr.SpecificationAttributeOptions); - } + model.Data = productrSpecsModel; + model.Total = productrSpecsModel.Count; + } + else + { + model.Data = Enumerable.Empty(); - var model = new GridModel - { - Data = productrSpecsModel, - Total = productrSpecsModel.Count - }; + NotifyAccessDenied(); + } return new JsonResult { @@ -2642,17 +2698,17 @@ public ActionResult ProductSpecAttrList(GridCommand command, int productId) } [GridAction(EnableCustomBinding = true)] - public ActionResult ProductSpecAttrUpdate(int psaId, ProductSpecificationAttributeModel model, - GridCommand command) + public ActionResult ProductSpecAttrUpdate(int psaId, ProductSpecificationAttributeModel model, GridCommand command) { - if (!_permissionService.Authorize(StandardPermissionProvider.ManageCatalog)) - return AccessDeniedView(); + var psa = _specificationAttributeService.GetProductSpecificationAttributeById(psaId); - var psa = _specificationAttributeService.GetProductSpecificationAttributeById(psaId); - psa.AllowFiltering = model.AllowFiltering; - psa.ShowOnProductPage = model.ShowOnProductPage; - psa.DisplayOrder = model.DisplayOrder; - _specificationAttributeService.UpdateProductSpecificationAttribute(psa); + if (_permissionService.Authorize(StandardPermissionProvider.ManageCatalog)) + { + psa.AllowFiltering = model.AllowFiltering; + psa.ShowOnProductPage = model.ShowOnProductPage; + psa.DisplayOrder = model.DisplayOrder; + _specificationAttributeService.UpdateProductSpecificationAttribute(psa); + } return ProductSpecAttrList(command, psa.ProductId); } @@ -2660,15 +2716,13 @@ public ActionResult ProductSpecAttrUpdate(int psaId, ProductSpecificationAttribu [GridAction(EnableCustomBinding = true)] public ActionResult ProductSpecAttrDelete(int psaId, GridCommand command) { - if (!_permissionService.Authorize(StandardPermissionProvider.ManageCatalog)) - return AccessDeniedView(); - - var psa = _specificationAttributeService.GetProductSpecificationAttributeById(psaId); - if (psa == null) - throw new ArgumentException("No specification attribute found with the specified id"); + var psa = _specificationAttributeService.GetProductSpecificationAttributeById(psaId); + var productId = psa.ProductId; - var productId = psa.ProductId; - _specificationAttributeService.DeleteProductSpecificationAttribute(psa); + if (_permissionService.Authorize(StandardPermissionProvider.ManageCatalog)) + { + _specificationAttributeService.DeleteProductSpecificationAttribute(psa); + } return ProductSpecAttrList(command, productId); } @@ -2688,28 +2742,33 @@ public ActionResult ProductTags() [HttpPost, GridAction(EnableCustomBinding = true)] public ActionResult ProductTags(GridCommand command) { - if (!_permissionService.Authorize(StandardPermissionProvider.ManageCatalog)) - return AccessDeniedView(); + var model = new GridModel(); + + if (_permissionService.Authorize(StandardPermissionProvider.ManageCatalog)) + { + var tags = _productTagService.GetAllProductTags() + .OrderByDescending(x => _productTagService.GetProductCount(x.Id, 0)) + .Select(x => + { + return new ProductTagModel + { + Id = x.Id, + Name = x.Name, + ProductCount = _productTagService.GetProductCount(x.Id, 0) + }; + }) + .ForCommand(command); + + model.Data = tags.PagedForCommand(command); + model.Total = tags.Count(); + } + else + { + model.Data = Enumerable.Empty(); + + NotifyAccessDenied(); + } - var tags = _productTagService.GetAllProductTags() - //order by product count - .OrderByDescending(x => _productTagService.GetProductCount(x.Id, 0)) - .Select(x => - { - return new ProductTagModel() - { - Id = x.Id, - Name = x.Name, - ProductCount = _productTagService.GetProductCount(x.Id, 0) - }; - }) - .ForCommand(command); - - var model = new GridModel - { - Data = tags.PagedForCommand(command), - Total = tags.Count() - }; return new JsonResult { Data = model @@ -2719,13 +2778,12 @@ public ActionResult ProductTags(GridCommand command) [GridAction(EnableCustomBinding = true)] public ActionResult ProductTagDelete(int id, GridCommand command) { - if (!_permissionService.Authorize(StandardPermissionProvider.ManageCatalog)) - return AccessDeniedView(); + if (_permissionService.Authorize(StandardPermissionProvider.ManageCatalog)) + { + var tag = _productTagService.GetProductTagById(id); - var tag = _productTagService.GetProductTagById(id); - if (tag == null) - throw new ArgumentException("No product tag found with the specified id"); - _productTagService.DeleteProductTag(tag); + _productTagService.DeleteProductTag(tag); + } return ProductTags(command); } @@ -2799,21 +2857,29 @@ public ActionResult LowStockReport() [HttpPost, GridAction(EnableCustomBinding = true)] public ActionResult LowStockReportList(GridCommand command) { - if (!_permissionService.Authorize(StandardPermissionProvider.ManageCatalog)) - return AccessDeniedView(); + var model = new GridModel(); - var allProducts = _productService.GetLowStockProducts(); - var model = new GridModel() + if (_permissionService.Authorize(StandardPermissionProvider.ManageCatalog)) { - Data = allProducts.PagedForCommand(command).Select(x => + var allProducts = _productService.GetLowStockProducts(); + + model.Data = allProducts.PagedForCommand(command).Select(x => { var productModel = x.ToModel(); productModel.ProductTypeName = x.GetProductTypeLabel(_localizationService); return productModel; - }), - Total = allProducts.Count - }; + }); + + model.Total = allProducts.Count; + } + else + { + model.Data = Enumerable.Empty(); + + NotifyAccessDenied(); + } + return new JsonResult { Data = model @@ -2860,47 +2926,54 @@ public ActionResult BulkEdit() [HttpPost, GridAction(EnableCustomBinding = true)] public ActionResult BulkEditSelect(GridCommand command, BulkEditListModel model) { - if (!_permissionService.Authorize(StandardPermissionProvider.ManageCatalog)) - return AccessDeniedView(); + var gridModel = new GridModel(); - var searchContext = new ProductSearchContext + if (_permissionService.Authorize(StandardPermissionProvider.ManageCatalog)) { - StoreId = model.SearchStoreId, - ManufacturerId = model.SearchManufacturerId, - Keywords = model.SearchProductName, - SearchSku = !_catalogSettings.SuppressSkuSearch, - PageIndex = command.Page - 1, - PageSize = command.PageSize, - ShowHidden = true, - ProductType = model.SearchProductTypeId > 0 ? (ProductType?)model.SearchProductTypeId : null - }; + var searchContext = new ProductSearchContext + { + StoreId = model.SearchStoreId, + ManufacturerId = model.SearchManufacturerId, + Keywords = model.SearchProductName, + SearchSku = !_catalogSettings.SuppressSkuSearch, + PageIndex = command.Page - 1, + PageSize = command.PageSize, + ShowHidden = true, + ProductType = model.SearchProductTypeId > 0 ? (ProductType?)model.SearchProductTypeId : null + }; - if (model.SearchCategoryId > 0) - searchContext.CategoryIds.Add(model.SearchCategoryId); + if (model.SearchCategoryId > 0) + searchContext.CategoryIds.Add(model.SearchCategoryId); - var products = _productService.SearchProducts(searchContext); - var gridModel = new GridModel(); + var products = _productService.SearchProducts(searchContext); - gridModel.Data = products.Select(x => - { - var productModel = new BulkEditProductModel() + gridModel.Data = products.Select(x => { - Id = x.Id, - Name = x.Name, - ProductTypeName = x.GetProductTypeLabel(_localizationService), - ProductTypeLabelHint = x.ProductTypeLabelHint, - Sku = x.Sku, - OldPrice = x.OldPrice, - Price = x.Price, - ManageInventoryMethod = x.ManageInventoryMethod.GetLocalizedEnum(_localizationService, _workContext.WorkingLanguage.Id), - StockQuantity = x.StockQuantity, - Published = x.Published - }; + var productModel = new BulkEditProductModel + { + Id = x.Id, + Name = x.Name, + ProductTypeName = x.GetProductTypeLabel(_localizationService), + ProductTypeLabelHint = x.ProductTypeLabelHint, + Sku = x.Sku, + OldPrice = x.OldPrice, + Price = x.Price, + ManageInventoryMethod = x.ManageInventoryMethod.GetLocalizedEnum(_localizationService, _workContext.WorkingLanguage.Id), + StockQuantity = x.StockQuantity, + Published = x.Published + }; - return productModel; - }); + return productModel; + }); + + gridModel.Total = products.TotalCount; + } + else + { + gridModel.Data = Enumerable.Empty(); - gridModel.Total = products.TotalCount; + NotifyAccessDenied(); + } return new JsonResult { @@ -2915,39 +2988,39 @@ public ActionResult BulkEditSave(GridCommand command, [Bind(Prefix = "deleted")]IEnumerable deletedProducts, BulkEditListModel model) { - if (!_permissionService.Authorize(StandardPermissionProvider.ManageCatalog)) - return AccessDeniedView(); - - if (updatedProducts != null) + if (_permissionService.Authorize(StandardPermissionProvider.ManageCatalog)) { - foreach (var pModel in updatedProducts) + if (updatedProducts != null) { - //update - var product = _productService.GetProductById(pModel.Id); - if (product != null) + foreach (var pModel in updatedProducts) { - product.Sku = pModel.Sku; - product.Price = pModel.Price; - product.OldPrice = pModel.OldPrice; - product.StockQuantity = pModel.StockQuantity; - product.Published = pModel.Published; + var product = _productService.GetProductById(pModel.Id); + if (product != null) + { + product.Sku = pModel.Sku; + product.Price = pModel.Price; + product.OldPrice = pModel.OldPrice; + product.StockQuantity = pModel.StockQuantity; + product.Published = pModel.Published; - _productService.UpdateProduct(product); + _productService.UpdateProduct(product); + } } } - } - if (deletedProducts != null) - { - foreach (var pModel in deletedProducts) + if (deletedProducts != null) { - var product = _productService.GetProductById(pModel.Id); - if (product != null) + foreach (var pModel in deletedProducts) { - _productService.DeleteProduct(product); + var product = _productService.GetProductById(pModel.Id); + if (product != null) + { + _productService.DeleteProduct(product); + } } } } + return BulkEditSelect(command, model); } @@ -2958,64 +3031,67 @@ public ActionResult BulkEditSave(GridCommand command, [HttpPost, GridAction(EnableCustomBinding = true)] public ActionResult TierPriceList(GridCommand command, int productId) { - if (!_permissionService.Authorize(StandardPermissionProvider.ManageCatalog)) - return AccessDeniedView(); - - var product = _productService.GetProductById(productId); - if (product == null) - throw new ArgumentException("No product variant found with the specified id"); + var model = new GridModel(); - var allStores = _services.StoreService.GetAllStores(); - var allCustomerRoles = _customerService.GetAllCustomerRoles(true); - string allRolesString = T("Admin.Catalog.Products.TierPrices.Fields.CustomerRole.AllRoles"); - string allStoresString = T("Admin.Common.StoresAll"); - string deletedString = "[{0}]".FormatInvariant(T("Admin.Common.Deleted")); + if (_permissionService.Authorize(StandardPermissionProvider.ManageCatalog)) + { + var product = _productService.GetProductById(productId); - var tierPricesModel = product.TierPrices - .OrderBy(x => x.StoreId) - .ThenBy(x => x.Quantity) - .ThenBy(x => x.CustomerRoleId) - .Select(x => - { - var tierPriceModel = new ProductModel.TierPriceModel + var allStores = _services.StoreService.GetAllStores(); + var allCustomerRoles = _customerService.GetAllCustomerRoles(true); + string allRolesString = T("Admin.Catalog.Products.TierPrices.Fields.CustomerRole.AllRoles"); + string allStoresString = T("Admin.Common.StoresAll"); + string deletedString = "[{0}]".FormatInvariant(T("Admin.Common.Deleted")); + + var tierPricesModel = product.TierPrices + .OrderBy(x => x.StoreId) + .ThenBy(x => x.Quantity) + .ThenBy(x => x.CustomerRoleId) + .Select(x => { - Id = x.Id, - StoreId = x.StoreId, - ProductId = x.ProductId, - CustomerRoleId = x.CustomerRoleId ?? 0, - Quantity = x.Quantity, - Price1 = x.Price - }; + var tierPriceModel = new ProductModel.TierPriceModel + { + Id = x.Id, + StoreId = x.StoreId, + ProductId = x.ProductId, + CustomerRoleId = x.CustomerRoleId ?? 0, + Quantity = x.Quantity, + Price1 = x.Price + }; - if (x.CustomerRoleId.HasValue) - { - var role = allCustomerRoles.FirstOrDefault(r => r.Id == x.CustomerRoleId.Value); - tierPriceModel.CustomerRole = (role == null ? allRolesString : role.Name); - } - else - { - tierPriceModel.CustomerRole = allRolesString; - } + if (x.CustomerRoleId.HasValue) + { + var role = allCustomerRoles.FirstOrDefault(r => r.Id == x.CustomerRoleId.Value); + tierPriceModel.CustomerRole = (role == null ? allRolesString : role.Name); + } + else + { + tierPriceModel.CustomerRole = allRolesString; + } - if (x.StoreId > 0) - { - var store = allStores.FirstOrDefault(s => s.Id == x.StoreId); - tierPriceModel.Store = (store == null ? deletedString : store.Name); - } - else - { - tierPriceModel.Store = allStoresString; - } + if (x.StoreId > 0) + { + var store = allStores.FirstOrDefault(s => s.Id == x.StoreId); + tierPriceModel.Store = (store == null ? deletedString : store.Name); + } + else + { + tierPriceModel.Store = allStoresString; + } - return tierPriceModel; - }) - .ToList(); + return tierPriceModel; + }) + .ToList(); - var model = new GridModel + model.Data = tierPricesModel; + model.Total = tierPricesModel.Count; + } + else { - Data = tierPricesModel, - Total = tierPricesModel.Count - }; + model.Data = Enumerable.Empty(); + + NotifyAccessDenied(); + } return new JsonResult { @@ -3026,27 +3102,26 @@ public ActionResult TierPriceList(GridCommand command, int productId) [GridAction(EnableCustomBinding = true)] public ActionResult TierPriceInsert(GridCommand command, ProductModel.TierPriceModel model) { - if (!_permissionService.Authorize(StandardPermissionProvider.ManageCatalog)) - return AccessDeniedView(); + if (_permissionService.Authorize(StandardPermissionProvider.ManageCatalog)) + { + var product = _productService.GetProductById(model.ProductId); - var product = _productService.GetProductById(model.ProductId); - if (product == null) - throw new ArgumentException("No product found with the specified id"); + var tierPrice = new TierPrice + { + ProductId = model.ProductId, + // use Store property (not Store propertyId) because appropriate property is stored in it + StoreId = model.Store.ToInt(), + // use CustomerRole property (not CustomerRoleId) because appropriate property is stored in it + CustomerRoleId = model.CustomerRole.IsNumeric() && Int32.Parse(model.CustomerRole) != 0 ? Int32.Parse(model.CustomerRole) : (int?)null, + Quantity = model.Quantity, + Price = model.Price1 + }; - var tierPrice = new TierPrice() - { - ProductId = model.ProductId, - // use Store property (not Store propertyId) because appropriate property is stored in it - StoreId = model.Store.ToInt(), - // use CustomerRole property (not CustomerRoleId) because appropriate property is stored in it - CustomerRoleId = model.CustomerRole.IsNumeric() && Int32.Parse(model.CustomerRole) != 0 ? Int32.Parse(model.CustomerRole) : (int?)null, - Quantity = model.Quantity, - Price = model.Price1 - }; - _productService.InsertTierPrice(tierPrice); + _productService.InsertTierPrice(tierPrice); - //update "HasTierPrices" property - _productService.UpdateHasTierPricesProperty(product); + //update "HasTierPrices" property + _productService.UpdateHasTierPricesProperty(product); + } return TierPriceList(command, model.ProductId); } @@ -3054,20 +3129,19 @@ public ActionResult TierPriceInsert(GridCommand command, ProductModel.TierPriceM [GridAction(EnableCustomBinding = true)] public ActionResult TierPriceUpdate(GridCommand command, ProductModel.TierPriceModel model) { - if (!_permissionService.Authorize(StandardPermissionProvider.ManageCatalog)) - return AccessDeniedView(); - var tierPrice = _productService.GetTierPriceById(model.Id); - if (tierPrice == null) - throw new ArgumentException("No tier price found with the specified id"); - //use Store property (not Store propertyId) because appropriate property is stored in it - tierPrice.StoreId = model.Store.ToInt(); - //use CustomerRole property (not CustomerRoleId) because appropriate property is stored in it - tierPrice.CustomerRoleId = model.CustomerRole.IsNumeric() && Int32.Parse(model.CustomerRole) != 0 ? Int32.Parse(model.CustomerRole) : (int?)null; - tierPrice.Quantity = model.Quantity; - tierPrice.Price = model.Price1; - _productService.UpdateTierPrice(tierPrice); + if (_permissionService.Authorize(StandardPermissionProvider.ManageCatalog)) + { + //use Store property (not Store propertyId) because appropriate property is stored in it + tierPrice.StoreId = model.Store.ToInt(); + //use CustomerRole property (not CustomerRoleId) because appropriate property is stored in it + tierPrice.CustomerRoleId = model.CustomerRole.IsNumeric() && Int32.Parse(model.CustomerRole) != 0 ? Int32.Parse(model.CustomerRole) : (int?)null; + tierPrice.Quantity = model.Quantity; + tierPrice.Price = model.Price1; + + _productService.UpdateTierPrice(tierPrice); + } return TierPriceList(command, tierPrice.ProductId); } @@ -3075,22 +3149,18 @@ public ActionResult TierPriceUpdate(GridCommand command, ProductModel.TierPriceM [GridAction(EnableCustomBinding = true)] public ActionResult TierPriceDelete(int id, GridCommand command) { - if (!_permissionService.Authorize(StandardPermissionProvider.ManageCatalog)) - return AccessDeniedView(); - var tierPrice = _productService.GetTierPriceById(id); - if (tierPrice == null) - throw new ArgumentException("No tier price found with the specified id"); - var productId = tierPrice.ProductId; - var product = _productService.GetProductById(productId); - if (product == null) - throw new ArgumentException("No product found with the specified id"); - _productService.DeleteTierPrice(tierPrice); + if (_permissionService.Authorize(StandardPermissionProvider.ManageCatalog)) + { + var product = _productService.GetProductById(productId); + + _productService.DeleteTierPrice(tierPrice); - //update "HasTierPrices" property - _productService.UpdateHasTierPricesProperty(product); + //update "HasTierPrices" property + _productService.UpdateHasTierPricesProperty(product); + } return TierPriceList(command, productId); } @@ -3102,40 +3172,45 @@ public ActionResult TierPriceDelete(int id, GridCommand command) [HttpPost, GridAction(EnableCustomBinding = true)] public ActionResult ProductVariantAttributeList(GridCommand command, int productId) { - if (!_permissionService.Authorize(StandardPermissionProvider.ManageCatalog)) - return AccessDeniedView(); + var model = new GridModel(); - var productVariantAttributes = _productAttributeService.GetProductVariantAttributesByProductId(productId); - var productVariantAttributesModel = productVariantAttributes - .Select(x => - { - var pvaModel = new ProductModel.ProductVariantAttributeModel() + if (_permissionService.Authorize(StandardPermissionProvider.ManageCatalog)) + { + var productVariantAttributes = _productAttributeService.GetProductVariantAttributesByProductId(productId); + var productVariantAttributesModel = productVariantAttributes + .Select(x => { - Id = x.Id, - ProductId = x.ProductId, - ProductAttribute = _productAttributeService.GetProductAttributeById(x.ProductAttributeId).Name, - ProductAttributeId = x.ProductAttributeId, - TextPrompt = x.TextPrompt, - IsRequired = x.IsRequired, - AttributeControlType = x.AttributeControlType.GetLocalizedEnum(_localizationService, _workContext), - AttributeControlTypeId = x.AttributeControlTypeId, - DisplayOrder1 = x.DisplayOrder - }; + var pvaModel = new ProductModel.ProductVariantAttributeModel + { + Id = x.Id, + ProductId = x.ProductId, + ProductAttribute = _productAttributeService.GetProductAttributeById(x.ProductAttributeId).Name, + ProductAttributeId = x.ProductAttributeId, + TextPrompt = x.TextPrompt, + IsRequired = x.IsRequired, + AttributeControlType = x.AttributeControlType.GetLocalizedEnum(_localizationService, _workContext), + AttributeControlTypeId = x.AttributeControlTypeId, + DisplayOrder1 = x.DisplayOrder + }; - if (x.ShouldHaveValues()) - { - pvaModel.ViewEditUrl = Url.Action("EditAttributeValues", "Product", new { productVariantAttributeId = x.Id }); - pvaModel.ViewEditText = string.Format(_localizationService.GetResource("Admin.Catalog.Products.ProductVariantAttributes.Attributes.Values.ViewLink"), x.ProductVariantAttributeValues != null ? x.ProductVariantAttributeValues.Count : 0); - } - return pvaModel; - }) - .ToList(); + if (x.ShouldHaveValues()) + { + pvaModel.ViewEditUrl = Url.Action("EditAttributeValues", "Product", new { productVariantAttributeId = x.Id }); + pvaModel.ViewEditText = string.Format(_localizationService.GetResource("Admin.Catalog.Products.ProductVariantAttributes.Attributes.Values.ViewLink"), x.ProductVariantAttributeValues != null ? x.ProductVariantAttributeValues.Count : 0); + } + return pvaModel; + }) + .ToList(); - var model = new GridModel + model.Data = productVariantAttributesModel; + model.Total = productVariantAttributesModel.Count; + } + else { - Data = productVariantAttributesModel, - Total = productVariantAttributesModel.Count - }; + model.Data = Enumerable.Empty(); + + NotifyAccessDenied(); + } return new JsonResult { @@ -3146,19 +3221,20 @@ public ActionResult ProductVariantAttributeList(GridCommand command, int product [GridAction(EnableCustomBinding = true)] public ActionResult ProductVariantAttributeInsert(GridCommand command, ProductModel.ProductVariantAttributeModel model) { - if (!_permissionService.Authorize(StandardPermissionProvider.ManageCatalog)) - return AccessDeniedView(); - - var pva = new ProductVariantAttribute() + if (_permissionService.Authorize(StandardPermissionProvider.ManageCatalog)) { - ProductId = model.ProductId, - ProductAttributeId = Int32.Parse(model.ProductAttribute), //use ProductAttribute property (not ProductAttributeId) because appropriate property is stored in it - TextPrompt = model.TextPrompt, - IsRequired = model.IsRequired, - AttributeControlTypeId = Int32.Parse(model.AttributeControlType), //use AttributeControlType property (not AttributeControlTypeId) because appropriate property is stored in it - DisplayOrder = model.DisplayOrder1 - }; - _productAttributeService.InsertProductVariantAttribute(pva); + var pva = new ProductVariantAttribute + { + ProductId = model.ProductId, + ProductAttributeId = Int32.Parse(model.ProductAttribute), //use ProductAttribute property (not ProductAttributeId) because appropriate property is stored in it + TextPrompt = model.TextPrompt, + IsRequired = model.IsRequired, + AttributeControlTypeId = Int32.Parse(model.AttributeControlType), //use AttributeControlType property (not AttributeControlTypeId) because appropriate property is stored in it + DisplayOrder = model.DisplayOrder1 + }; + + _productAttributeService.InsertProductVariantAttribute(pva); + } return ProductVariantAttributeList(command, model.ProductId); } @@ -3166,21 +3242,20 @@ public ActionResult ProductVariantAttributeInsert(GridCommand command, ProductMo [GridAction(EnableCustomBinding = true)] public ActionResult ProductVariantAttributeUpdate(GridCommand command, ProductModel.ProductVariantAttributeModel model) { - if (!_permissionService.Authorize(StandardPermissionProvider.ManageCatalog)) - return AccessDeniedView(); - var pva = _productAttributeService.GetProductVariantAttributeById(model.Id); - if (pva == null) - throw new ArgumentException("No product variant attribute found with the specified id"); - //use ProductAttribute property (not ProductAttributeId) because appropriate property is stored in it - pva.ProductAttributeId = Int32.Parse(model.ProductAttribute); - pva.TextPrompt = model.TextPrompt; - pva.IsRequired = model.IsRequired; - //use AttributeControlType property (not AttributeControlTypeId) because appropriate property is stored in it - pva.AttributeControlTypeId = Int32.Parse(model.AttributeControlType); - pva.DisplayOrder = model.DisplayOrder1; - _productAttributeService.UpdateProductVariantAttribute(pva); + if (_permissionService.Authorize(StandardPermissionProvider.ManageCatalog)) + { + //use ProductAttribute property (not ProductAttributeId) because appropriate property is stored in it + pva.ProductAttributeId = Int32.Parse(model.ProductAttribute); + pva.TextPrompt = model.TextPrompt; + pva.IsRequired = model.IsRequired; + //use AttributeControlType property (not AttributeControlTypeId) because appropriate property is stored in it + pva.AttributeControlTypeId = Int32.Parse(model.AttributeControlType); + pva.DisplayOrder = model.DisplayOrder1; + + _productAttributeService.UpdateProductVariantAttribute(pva); + } return ProductVariantAttributeList(command, pva.ProductId); } @@ -3188,16 +3263,13 @@ public ActionResult ProductVariantAttributeUpdate(GridCommand command, ProductMo [GridAction(EnableCustomBinding = true)] public ActionResult ProductVariantAttributeDelete(int id, GridCommand command) { - if (!_permissionService.Authorize(StandardPermissionProvider.ManageCatalog)) - return AccessDeniedView(); - var pva = _productAttributeService.GetProductVariantAttributeById(id); - if (pva == null) - throw new ArgumentException("No product variant attribute found with the specified id"); - var productId = pva.ProductId; - _productAttributeService.DeleteProductVariantAttribute(pva); + if (_permissionService.Authorize(StandardPermissionProvider.ManageCatalog)) + { + _productAttributeService.DeleteProductVariantAttribute(pva); + } return ProductVariantAttributeList(command, productId); } @@ -3254,22 +3326,19 @@ public ActionResult EditAttributeValues(int productVariantAttributeId) [HttpPost, GridAction(EnableCustomBinding = true)] public ActionResult ProductAttributeValueList(int productVariantAttributeId, GridCommand command) { - if (!_permissionService.Authorize(StandardPermissionProvider.ManageCatalog)) - return AccessDeniedView(); + var gridModel = new GridModel(); - var pva = _productAttributeService.GetProductVariantAttributeById(productVariantAttributeId); - if (pva == null) - throw new ArgumentException("No product variant attribute found with the specified id"); + if (_permissionService.Authorize(StandardPermissionProvider.ManageCatalog)) + { + var pva = _productAttributeService.GetProductVariantAttributeById(productVariantAttributeId); - var values = _productAttributeService.GetProductVariantAttributeValues(productVariantAttributeId); + var values = _productAttributeService.GetProductVariantAttributeValues(productVariantAttributeId); - var gridModel = new GridModel - { - Data = values.Select(x => + gridModel.Data = values.Select(x => { var linkedProduct = _productService.GetProductById(x.LinkedProductId); - var model = new ProductModel.ProductVariantAttributeValueModel() + var model = new ProductModel.ProductVariantAttributeValueModel { Id = x.Id, ProductVariantAttributeId = x.ProductVariantAttributeId, @@ -3300,9 +3369,17 @@ public ActionResult ProductAttributeValueList(int productVariantAttributeId, Gri } return model; - }), - Total = values.Count() - }; + }); + + gridModel.Total = values.Count(); + } + else + { + gridModel.Data = Enumerable.Empty(); + + NotifyAccessDenied(); + } + return new JsonResult { Data = gridModel @@ -3493,14 +3570,12 @@ public ActionResult ProductAttributeValueEditPopup(string btnId, string formId, [GridAction(EnableCustomBinding = true)] public ActionResult ProductAttributeValueDelete(int pvavId, int productVariantAttributeId, GridCommand command) { - if (!_permissionService.Authorize(StandardPermissionProvider.ManageCatalog)) - return AccessDeniedView(); - - var pvav = _productAttributeService.GetProductVariantAttributeValueById(pvavId); - if (pvav == null) - throw new ArgumentException("No product variant attribute value found with the specified id"); + if (_permissionService.Authorize(StandardPermissionProvider.ManageCatalog)) + { + var pvav = _productAttributeService.GetProductVariantAttributeValueById(pvavId); - _productAttributeService.DeleteProductVariantAttributeValue(pvav); + _productAttributeService.DeleteProductVariantAttributeValue(pvav); + } return ProductAttributeValueList(productVariantAttributeId, command); } @@ -3543,33 +3618,41 @@ public ActionResult ProductAttributeValueLinkagePopup() [HttpPost, GridAction(EnableCustomBinding = true)] public ActionResult ProductAttributeValueLinkagePopupList(GridCommand command, ProductModel.ProductVariantAttributeValueModel.AddProductLinkageModel model) { - if (!_permissionService.Authorize(StandardPermissionProvider.ManageCatalog)) - return AccessDeniedView(); + var gridModel = new GridModel(); - var searchContext = new ProductSearchContext() - { - CategoryIds = new List() { model.SearchCategoryId }, - ManufacturerId = model.SearchManufacturerId, - StoreId = model.SearchStoreId, - Keywords = model.SearchProductName, - SearchSku = !_catalogSettings.SuppressSkuSearch, - PageIndex = command.Page - 1, - PageSize = command.PageSize, - ShowHidden = true, - ProductType = model.SearchProductTypeId > 0 ? (ProductType?)model.SearchProductTypeId : null - }; + if (_permissionService.Authorize(StandardPermissionProvider.ManageCatalog)) + { + var searchContext = new ProductSearchContext + { + CategoryIds = new List { model.SearchCategoryId }, + ManufacturerId = model.SearchManufacturerId, + StoreId = model.SearchStoreId, + Keywords = model.SearchProductName, + SearchSku = !_catalogSettings.SuppressSkuSearch, + PageIndex = command.Page - 1, + PageSize = command.PageSize, + ShowHidden = true, + ProductType = model.SearchProductTypeId > 0 ? (ProductType?)model.SearchProductTypeId : null + }; + + var products = _productService.SearchProducts(searchContext); + + gridModel.Data = products.Select(x => + { + var productModel = x.ToModel(); + productModel.ProductTypeName = x.GetProductTypeLabel(_localizationService); - var products = _productService.SearchProducts(searchContext); + return productModel; + }); - var gridModel = new GridModel(); - gridModel.Data = products.Select(x => + gridModel.Total = products.TotalCount; + } + else { - var productModel = x.ToModel(); - productModel.ProductTypeName = x.GetProductTypeLabel(_localizationService); + gridModel.Data = Enumerable.Empty(); - return productModel; - }); - gridModel.Total = products.TotalCount; + NotifyAccessDenied(); + } return new JsonResult { @@ -3704,65 +3787,69 @@ private void PrepareDeliveryTimes(ProductVariantAttributeCombinationModel model, [HttpPost, GridAction(EnableCustomBinding = true)] public ActionResult ProductVariantAttributeCombinationList(GridCommand command, int productId) { - if (!_permissionService.Authorize(StandardPermissionProvider.ManageCatalog)) - return AccessDeniedView(); + var model = new GridModel(); - // TODO: Replace ProductModel.ProductVariantAttributeCombinationModel by AddProductVariantAttributeCombinationModel - // when there's no grid-inline-editing anymore. + if (_permissionService.Authorize(StandardPermissionProvider.ManageCatalog)) + { + // TODO: Replace ProductModel.ProductVariantAttributeCombinationModel by AddProductVariantAttributeCombinationModel + // when there's no grid-inline-editing anymore. - var product = _productService.GetProductById(productId); - if (product == null) - throw new ArgumentException("No product found with the specified id"); + var product = _productService.GetProductById(productId); - var allCombinations = _productAttributeService.GetAllProductVariantAttributeCombinations(product.Id, command.Page - 1, command.PageSize); + var allCombinations = _productAttributeService.GetAllProductVariantAttributeCombinations(product.Id, command.Page - 1, command.PageSize); - var productUrlTitle = _localizationService.GetResource("Common.OpenInShop"); - var productSeName = product.GetSeName(); + var productUrlTitle = _localizationService.GetResource("Common.OpenInShop"); + var productSeName = product.GetSeName(); - var productVariantAttributesModel = allCombinations.Select(x => - { - var pvacModel = x.ToModel(); - PrepareProductAttributeCombinationModel(pvacModel, x, product, true); + var productVariantAttributesModel = allCombinations.Select(x => + { + var pvacModel = x.ToModel(); + PrepareProductAttributeCombinationModel(pvacModel, x, product, true); - pvacModel.ProductUrl = _productAttributeParser.GetProductUrlWithAttributes(x.AttributesXml, product.Id, productSeName); - pvacModel.ProductUrlTitle = productUrlTitle; + pvacModel.ProductUrl = _productAttributeParser.GetProductUrlWithAttributes(x.AttributesXml, product.Id, productSeName); + pvacModel.ProductUrlTitle = productUrlTitle; - try - { - var firstAttribute = _productAttributeParser.DeserializeProductVariantAttributes(x.AttributesXml).FirstOrDefault(); - - var attribute = x.Product.ProductVariantAttributes.FirstOrDefault(y => y.Id == firstAttribute.Key); - var attributeValue = attribute.ProductVariantAttributeValues.FirstOrDefault(y => y.Id == int.Parse(firstAttribute.Value.First())); + try + { + var firstAttribute = _productAttributeParser.DeserializeProductVariantAttributes(x.AttributesXml).FirstOrDefault(); - pvacModel.DisplayOrder = attributeValue.DisplayOrder; - } - catch (Exception exc) - { - exc.Dump(); - } + var attribute = x.Product.ProductVariantAttributes.FirstOrDefault(y => y.Id == firstAttribute.Key); + var attributeValue = attribute.ProductVariantAttributeValues.FirstOrDefault(y => y.Id == int.Parse(firstAttribute.Value.First())); - //if (x.IsDefaultCombination) - // pvacModel.AttributesXml = "{0}".FormatWith(pvacModel.AttributesXml); + pvacModel.DisplayOrder = attributeValue.DisplayOrder; + } + catch (Exception exc) + { + exc.Dump(); + } - //warnings - var warnings = _shoppingCartService.GetShoppingCartItemAttributeWarnings( - _workContext.CurrentCustomer, - ShoppingCartType.ShoppingCart, - x.Product, - x.AttributesXml, - combination: x); - - pvacModel.Warnings.AddRange(warnings); + //if (x.IsDefaultCombination) + // pvacModel.AttributesXml = "{0}".FormatWith(pvacModel.AttributesXml); + + //warnings + var warnings = _shoppingCartService.GetShoppingCartItemAttributeWarnings( + _workContext.CurrentCustomer, + ShoppingCartType.ShoppingCart, + x.Product, + x.AttributesXml, + combination: x); - return pvacModel; - }) - .OrderBy(x => x.DisplayOrder).ToList(); + pvacModel.Warnings.AddRange(warnings); - var model = new GridModel + return pvacModel; + }) + .OrderBy(x => x.DisplayOrder) + .ToList(); + + model.Data = productVariantAttributesModel; + model.Total = allCombinations.TotalCount; + } + else { - Data = productVariantAttributesModel, - Total = allCombinations.TotalCount, - }; + model.Data = Enumerable.Empty(); + + NotifyAccessDenied(); + } return new JsonResult { @@ -3773,19 +3860,16 @@ public ActionResult ProductVariantAttributeCombinationList(GridCommand command, [GridAction(EnableCustomBinding = true)] public ActionResult ProductVariantAttributeCombinationDelete(int id, GridCommand command) { - if (!_permissionService.Authorize(StandardPermissionProvider.ManageCatalog)) - return AccessDeniedView(); - var pvac = _productAttributeService.GetProductVariantAttributeCombinationById(id); - if (pvac == null) - throw new ArgumentException("No product variant attribute combination found with the specified id"); - var productId = pvac.ProductId; - _productAttributeService.DeleteProductVariantAttributeCombination(pvac); + if (_permissionService.Authorize(StandardPermissionProvider.ManageCatalog)) + { + _productAttributeService.DeleteProductVariantAttributeCombination(pvac); - var product = _productService.GetProductById(productId); - _productService.UpdateLowestAttributeCombinationPriceProperty(product); + var product = _productService.GetProductById(productId); + _productService.UpdateLowestAttributeCombinationPriceProperty(product); + } return ProductVariantAttributeCombinationList(command, productId); } diff --git a/src/Presentation/SmartStore.Web/Administration/Controllers/ProductReviewController.cs b/src/Presentation/SmartStore.Web/Administration/Controllers/ProductReviewController.cs index 9858dc1745..dff5a6de80 100644 --- a/src/Presentation/SmartStore.Web/Administration/Controllers/ProductReviewController.cs +++ b/src/Presentation/SmartStore.Web/Administration/Controllers/ProductReviewController.cs @@ -109,34 +109,40 @@ public ActionResult List() [HttpPost, GridAction(EnableCustomBinding = true)] public ActionResult List(GridCommand command, ProductReviewListModel model) { - if (!_permissionService.Authorize(StandardPermissionProvider.ManageCatalog)) - return AccessDeniedView(); + var gridModel = new GridModel(); - DateTime? createdOnFromValue = (model.CreatedOnFrom == null) ? null - : (DateTime?)_dateTimeHelper.ConvertToUtcTime(model.CreatedOnFrom.Value, _dateTimeHelper.CurrentTimeZone); + if (_permissionService.Authorize(StandardPermissionProvider.ManageCatalog)) + { + DateTime? createdOnFromValue = (model.CreatedOnFrom == null) ? null + : (DateTime?)_dateTimeHelper.ConvertToUtcTime(model.CreatedOnFrom.Value, _dateTimeHelper.CurrentTimeZone); - DateTime? createdToFromValue = (model.CreatedOnTo == null) ? null - : (DateTime?)_dateTimeHelper.ConvertToUtcTime(model.CreatedOnTo.Value, _dateTimeHelper.CurrentTimeZone).AddDays(1); + DateTime? createdToFromValue = (model.CreatedOnTo == null) ? null + : (DateTime?)_dateTimeHelper.ConvertToUtcTime(model.CreatedOnTo.Value, _dateTimeHelper.CurrentTimeZone).AddDays(1); + + var productReviews = _customerContentService.GetAllCustomerContent(0, null, createdOnFromValue, createdToFromValue); + + gridModel.Data = productReviews.PagedForCommand(command).Select(x => + { + var m = new ProductReviewModel(); + PrepareProductReviewModel(m, x, false, true); + return m; + }); + + gridModel.Total = productReviews.Count; + } + else + { + gridModel.Data = Enumerable.Empty(); + + NotifyAccessDenied(); + } - var productReviews = _customerContentService.GetAllCustomerContent(0, null, - createdOnFromValue, createdToFromValue); - var gridModel = new GridModel - { - Data = productReviews.PagedForCommand(command).Select(x => - { - var m = new ProductReviewModel(); - PrepareProductReviewModel(m, x, false, true); - return m; - }), - Total = productReviews.Count, - }; return new JsonResult { Data = gridModel }; } - //edit public ActionResult Edit(int id) { if (!_permissionService.Authorize(StandardPermissionProvider.ManageCatalog)) @@ -186,7 +192,6 @@ public ActionResult Edit(ProductReviewModel model, bool continueEditing) return View(model); } - //delete [HttpPost, ActionName("Delete")] public ActionResult DeleteConfirmed(int id) { diff --git a/src/Presentation/SmartStore.Web/Administration/Controllers/QueuedEmailController.cs b/src/Presentation/SmartStore.Web/Administration/Controllers/QueuedEmailController.cs index 58057c2d80..6bc007e811 100644 --- a/src/Presentation/SmartStore.Web/Administration/Controllers/QueuedEmailController.cs +++ b/src/Presentation/SmartStore.Web/Administration/Controllers/QueuedEmailController.cs @@ -53,41 +53,47 @@ public ActionResult List() [GridAction(EnableCustomBinding = true)] public ActionResult QueuedEmailList(GridCommand command, QueuedEmailListModel model) { - if (!_permissionService.Authorize(StandardPermissionProvider.ManageMessageQueue)) - return AccessDeniedView(); + var gridModel = new GridModel(); - DateTime? startDateValue = (model.SearchStartDate == null) ? null : (DateTime?)_dateTimeHelper.ConvertToUtcTime(model.SearchStartDate.Value, _dateTimeHelper.CurrentTimeZone); - DateTime? endDateValue = (model.SearchEndDate == null) ? null : (DateTime?)_dateTimeHelper.ConvertToUtcTime(model.SearchEndDate.Value, _dateTimeHelper.CurrentTimeZone).AddDays(1); - - var q = new SearchEmailsQuery + if (_permissionService.Authorize(StandardPermissionProvider.ManageMessageQueue)) { - EndTime = endDateValue, - From = model.SearchFromEmail, - MaxSendTries = model.SearchMaxSentTries, - OrderByLatest = true, - PageIndex = command.Page - 1, - PageSize = command.PageSize, - SendManually = model.SearchSendManually, - StartTime = startDateValue, - To = model.SearchToEmail, - UnsentOnly = model.SearchLoadNotSent - }; - var queuedEmails = _queuedEmailService.SearchEmails(q); + DateTime? startDateValue = (model.SearchStartDate == null) ? null : (DateTime?)_dateTimeHelper.ConvertToUtcTime(model.SearchStartDate.Value, _dateTimeHelper.CurrentTimeZone); + DateTime? endDateValue = (model.SearchEndDate == null) ? null : (DateTime?)_dateTimeHelper.ConvertToUtcTime(model.SearchEndDate.Value, _dateTimeHelper.CurrentTimeZone).AddDays(1); - var gridModel = new GridModel - { - Data = queuedEmails.Select(x => + var q = new SearchEmailsQuery + { + EndTime = endDateValue, + From = model.SearchFromEmail, + MaxSendTries = model.SearchMaxSentTries, + OrderByLatest = true, + PageIndex = command.Page - 1, + PageSize = command.PageSize, + SendManually = model.SearchSendManually, + StartTime = startDateValue, + To = model.SearchToEmail, + UnsentOnly = model.SearchLoadNotSent + }; + var queuedEmails = _queuedEmailService.SearchEmails(q); + + gridModel.Data = queuedEmails.Select(x => { - var m = x.ToModel(); - m.CreatedOn = _dateTimeHelper.ConvertToUserTime(x.CreatedOnUtc, DateTimeKind.Utc); + var m = x.ToModel(); + m.CreatedOn = _dateTimeHelper.ConvertToUserTime(x.CreatedOnUtc, DateTimeKind.Utc); - if (x.SentOnUtc.HasValue) - m.SentOn = _dateTimeHelper.ConvertToUserTime(x.SentOnUtc.Value, DateTimeKind.Utc); + if (x.SentOnUtc.HasValue) + m.SentOn = _dateTimeHelper.ConvertToUserTime(x.SentOnUtc.Value, DateTimeKind.Utc); - return m; - }), - Total = queuedEmails.TotalCount - }; + return m; + }); + + gridModel.Total = queuedEmails.TotalCount; + } + else + { + gridModel.Data = Enumerable.Empty(); + + NotifyAccessDenied(); + } return new JsonResult { diff --git a/src/Presentation/SmartStore.Web/Administration/Controllers/RecurringPaymentController.cs b/src/Presentation/SmartStore.Web/Administration/Controllers/RecurringPaymentController.cs index 39d549fc08..0f4b15968e 100644 --- a/src/Presentation/SmartStore.Web/Administration/Controllers/RecurringPaymentController.cs +++ b/src/Presentation/SmartStore.Web/Administration/Controllers/RecurringPaymentController.cs @@ -113,7 +113,6 @@ private void PrepareRecurringPaymentHistoryModel(RecurringPaymentModel.Recurring #region Recurring payment - //list public ActionResult Index() { return RedirectToAction("List"); @@ -131,27 +130,34 @@ public ActionResult List() [HttpPost, GridAction(EnableCustomBinding = true)] public ActionResult List(GridCommand command) { - if (!_permissionService.Authorize(StandardPermissionProvider.ManageOrders)) - return AccessDeniedView(); + var gridModel = new GridModel(); + + if (_permissionService.Authorize(StandardPermissionProvider.ManageOrders)) + { + var payments = _orderService.SearchRecurringPayments(0, 0, 0, null, true); + + gridModel.Data = payments.PagedForCommand(command).Select(x => + { + var m = new RecurringPaymentModel(); + PrepareRecurringPaymentModel(m, x, false); + return m; + }); + + gridModel.Total = payments.Count; + } + else + { + gridModel.Data = Enumerable.Empty(); + + NotifyAccessDenied(); + } - var payments = _orderService.SearchRecurringPayments(0, 0, 0, null, true); - var gridModel = new GridModel - { - Data = payments.PagedForCommand(command).Select(x => - { - var m = new RecurringPaymentModel(); - PrepareRecurringPaymentModel(m, x, false); - return m; - }), - Total = payments.Count, - }; return new JsonResult { Data = gridModel }; } - //edit public ActionResult Edit(int id) { if (!_permissionService.Authorize(StandardPermissionProvider.ManageOrders)) @@ -189,7 +195,6 @@ public ActionResult Edit(RecurringPaymentModel model, bool continueEditing) return continueEditing ? RedirectToAction("Edit", payment.Id) : RedirectToAction("List"); } - //delete [HttpPost, ActionName("Delete")] public ActionResult DeleteConfirmed(int id) { @@ -214,26 +219,30 @@ public ActionResult DeleteConfirmed(int id) [HttpPost, GridAction(EnableCustomBinding = true)] public ActionResult HistoryList(int recurringPaymentId, GridCommand command) { - if (!_permissionService.Authorize(StandardPermissionProvider.ManageOrders)) - return AccessDeniedView(); - - var payment = _orderService.GetRecurringPaymentById(recurringPaymentId); - if (payment == null) - throw new ArgumentException("No recurring payment found with the specified id"); - - var historyModel = payment.RecurringPaymentHistory.OrderBy(x => x.CreatedOnUtc) - .Select(x => - { - var m = new RecurringPaymentModel.RecurringPaymentHistoryModel(); - PrepareRecurringPaymentHistoryModel(m, x); - return m; - }) - .ToList(); - var model = new GridModel - { - Data = historyModel, - Total = historyModel.Count - }; + var model = new GridModel(); + + if (_permissionService.Authorize(StandardPermissionProvider.ManageOrders)) + { + var payment = _orderService.GetRecurringPaymentById(recurringPaymentId); + + var historyModel = payment.RecurringPaymentHistory.OrderBy(x => x.CreatedOnUtc) + .Select(x => + { + var m = new RecurringPaymentModel.RecurringPaymentHistoryModel(); + PrepareRecurringPaymentHistoryModel(m, x); + return m; + }) + .ToList(); + + model.Data = historyModel; + model.Total = historyModel.Count; + } + else + { + model.Data = Enumerable.Empty(); + + NotifyAccessDenied(); + } return new JsonResult { diff --git a/src/Presentation/SmartStore.Web/Administration/Controllers/ReturnRequestController.cs b/src/Presentation/SmartStore.Web/Administration/Controllers/ReturnRequestController.cs index 1180d71fc7..f210fef4fd 100644 --- a/src/Presentation/SmartStore.Web/Administration/Controllers/ReturnRequestController.cs +++ b/src/Presentation/SmartStore.Web/Administration/Controllers/ReturnRequestController.cs @@ -171,7 +171,6 @@ private bool PrepareReturnRequestModel(ReturnRequestModel model, ReturnRequest r #region Methods - //list public ActionResult Index() { return RedirectToAction("List"); @@ -191,26 +190,31 @@ public ActionResult List() [HttpPost, GridAction(EnableCustomBinding = true)] public ActionResult List(GridCommand command, ReturnRequestListModel model) { - if (!_permissionService.Authorize(StandardPermissionProvider.ManageReturnRequests)) - return AccessDeniedView(); + var gridModel = new GridModel(); - var data = new List(); + if (_permissionService.Authorize(StandardPermissionProvider.ManageReturnRequests)) + { + var data = new List(); - var returnRequests = _orderService.SearchReturnRequests(model.SearchStoreId, 0, 0, model.SearchReturnRequestStatus, - command.Page - 1, command.PageSize, model.SearchId ?? 0); + var returnRequests = _orderService.SearchReturnRequests(model.SearchStoreId, 0, 0, model.SearchReturnRequestStatus, + command.Page - 1, command.PageSize, model.SearchId ?? 0); - foreach (var rr in returnRequests) - { - var m = new ReturnRequestModel(); - if (PrepareReturnRequestModel(m, rr, false)) - data.Add(m); - } + foreach (var rr in returnRequests) + { + var m = new ReturnRequestModel(); + if (PrepareReturnRequestModel(m, rr, false)) + data.Add(m); + } - var gridModel = new GridModel + gridModel.Data = data; + gridModel.Total = returnRequests.TotalCount; + } + else { - Data = data, - Total = returnRequests.TotalCount, - }; + gridModel.Data = Enumerable.Empty(); + + NotifyAccessDenied(); + } return new JsonResult { @@ -218,7 +222,6 @@ public ActionResult List(GridCommand command, ReturnRequestListModel model) }; } - //edit public ActionResult Edit(int id) { if (!_permissionService.Authorize(StandardPermissionProvider.ManageReturnRequests)) @@ -300,7 +303,6 @@ public ActionResult NotifyCustomer(ReturnRequestModel model) return RedirectToAction("Edit", returnRequest.Id); } - //delete [HttpPost, ActionName("Delete")] public ActionResult DeleteConfirmed(int id) { diff --git a/src/Presentation/SmartStore.Web/Administration/Controllers/SettingController.cs b/src/Presentation/SmartStore.Web/Administration/Controllers/SettingController.cs index 086be63a26..85ea07067b 100644 --- a/src/Presentation/SmartStore.Web/Administration/Controllers/SettingController.cs +++ b/src/Presentation/SmartStore.Web/Administration/Controllers/SettingController.cs @@ -1532,44 +1532,49 @@ public ActionResult AllSettings() [HttpPost, GridAction(EnableCustomBinding = true)] public ActionResult AllSettings(GridCommand command) { - if (!_services.Permissions.Authorize(StandardPermissionProvider.ManageSettings)) - return AccessDeniedView(); + var model = new GridModel(); - var stores = _services.StoreService.GetAllStores(); - string allStoresString = _services.Localization.GetResource("Admin.Common.StoresAll"); - - var settings = _services.Settings - .GetAllSettings() - .Select(x => - { - var settingModel = new SettingModel() - { - Id = x.Id, - Name = x.Name, - Value = x.Value, - StoreId = x.StoreId - }; + if (_services.Permissions.Authorize(StandardPermissionProvider.ManageSettings)) + { + var stores = _services.StoreService.GetAllStores(); + string allStoresString = _services.Localization.GetResource("Admin.Common.StoresAll"); - if (x.StoreId == 0) - { - settingModel.Store = allStoresString; - } - else + var settings = _services.Settings + .GetAllSettings() + .Select(x => { - var store = stores.FirstOrDefault(s => s.Id == x.StoreId); - settingModel.Store = store != null ? store.Name : "Unknown"; - } - - return settingModel; - }) - .ForCommand(command) - .ToList(); - - var model = new GridModel - { - Data = settings.PagedForCommand(command), - Total = settings.Count - }; + var settingModel = new SettingModel() + { + Id = x.Id, + Name = x.Name, + Value = x.Value, + StoreId = x.StoreId + }; + + if (x.StoreId == 0) + { + settingModel.Store = allStoresString; + } + else + { + var store = stores.FirstOrDefault(s => s.Id == x.StoreId); + settingModel.Store = store != null ? store.Name : "".NaIfEmpty(); + } + + return settingModel; + }) + .ForCommand(command) + .ToList(); + + model.Data = settings.PagedForCommand(command); + model.Total = settings.Count; + } + else + { + model.Data = Enumerable.Empty(); + + NotifyAccessDenied(); + } return new JsonResult { @@ -1580,80 +1585,76 @@ public ActionResult AllSettings(GridCommand command) [GridAction(EnableCustomBinding = true)] public ActionResult SettingUpdate(SettingModel model, GridCommand command) { - if (!_services.Permissions.Authorize(StandardPermissionProvider.ManageSettings)) - return AccessDeniedView(); - - if (model.Name != null) - model.Name = model.Name.Trim(); - if (model.Value != null) - model.Value = model.Value.Trim(); + if (_services.Permissions.Authorize(StandardPermissionProvider.ManageSettings)) + { + if (model.Name != null) + model.Name = model.Name.Trim(); + if (model.Value != null) + model.Value = model.Value.Trim(); - if (!ModelState.IsValid) - { - //display the first model error - var modelStateErrors = this.ModelState.Values.SelectMany(x => x.Errors).Select(x => x.ErrorMessage); - return Content(modelStateErrors.FirstOrDefault()); - } + if (!ModelState.IsValid) + { + var modelStateErrors = this.ModelState.Values.SelectMany(x => x.Errors).Select(x => x.ErrorMessage); + return Content(modelStateErrors.FirstOrDefault()); + } - var setting = _services.Settings.GetSettingById(model.Id); - if (setting == null) - return Content(_services.Localization.GetResource("Admin.Configuration.Settings.NoneWithThatId")); + var setting = _services.Settings.GetSettingById(model.Id); + if (setting == null) + return Content(T("Admin.Configuration.Settings.NoneWithThatId")); - var storeId = model.Store.ToInt(); //use Store property (not StoreId) because appropriate property is stored in it + var storeId = model.Store.ToInt(); //use Store property (not StoreId) because appropriate property is stored in it - if (!setting.Name.Equals(model.Name, StringComparison.InvariantCultureIgnoreCase) || - setting.StoreId != storeId) - { - //setting name or store has been changed - _services.Settings.DeleteSetting(setting); - } + if (!setting.Name.Equals(model.Name, StringComparison.InvariantCultureIgnoreCase) || setting.StoreId != storeId) + { + //setting name or store has been changed + _services.Settings.DeleteSetting(setting); + } - _services.Settings.SetSetting(model.Name, model.Value, storeId); + _services.Settings.SetSetting(model.Name, model.Value, storeId); - //activity log - _customerActivityService.InsertActivity("EditSettings", _services.Localization.GetResource("ActivityLog.EditSettings")); + //activity log + _customerActivityService.InsertActivity("EditSettings", T("ActivityLog.EditSettings")); + } return AllSettings(command); } [GridAction(EnableCustomBinding = true)] public ActionResult SettingAdd([Bind(Exclude = "Id")] SettingModel model, GridCommand command) { - if (!_services.Permissions.Authorize(StandardPermissionProvider.ManageSettings)) - return AccessDeniedView(); - - if (model.Name != null) - model.Name = model.Name.Trim(); - if (model.Value != null) - model.Value = model.Value.Trim(); + if (_services.Permissions.Authorize(StandardPermissionProvider.ManageSettings)) + { + if (model.Name != null) + model.Name = model.Name.Trim(); + if (model.Value != null) + model.Value = model.Value.Trim(); - if (!ModelState.IsValid) - { - //display the first model error - var modelStateErrors = this.ModelState.Values.SelectMany(x => x.Errors).Select(x => x.ErrorMessage); - return Content(modelStateErrors.FirstOrDefault()); - } + if (!ModelState.IsValid) + { + var modelStateErrors = this.ModelState.Values.SelectMany(x => x.Errors).Select(x => x.ErrorMessage); + return Content(modelStateErrors.FirstOrDefault()); + } - var storeId = model.Store.ToInt(); //use Store property (not StoreId) because appropriate property is stored in it - _services.Settings.SetSetting(model.Name, model.Value, storeId); + var storeId = model.Store.ToInt(); //use Store property (not StoreId) because appropriate property is stored in it + _services.Settings.SetSetting(model.Name, model.Value, storeId); - //activity log - _customerActivityService.InsertActivity("AddNewSetting", _services.Localization.GetResource("ActivityLog.AddNewSetting"), model.Name); + //activity log + _customerActivityService.InsertActivity("AddNewSetting", T("ActivityLog.AddNewSetting", model.Name)); + } return AllSettings(command); } [GridAction(EnableCustomBinding = true)] public ActionResult SettingDelete(int id, GridCommand command) { - if (!_services.Permissions.Authorize(StandardPermissionProvider.ManageSettings)) - return AccessDeniedView(); + if (_services.Permissions.Authorize(StandardPermissionProvider.ManageSettings)) + { + var setting = _services.Settings.GetSettingById(id); - var setting = _services.Settings.GetSettingById(id); - if (setting == null) - throw new ArgumentException("No setting found with the specified id"); - _services.Settings.DeleteSetting(setting); + _services.Settings.DeleteSetting(setting); - //activity log - _customerActivityService.InsertActivity("DeleteSetting", _services.Localization.GetResource("ActivityLog.DeleteSetting"), setting.Name); + //activity log + _customerActivityService.InsertActivity("DeleteSetting", T("ActivityLog.DeleteSetting", setting.Name)); + } return AllSettings(command); } diff --git a/src/Presentation/SmartStore.Web/Administration/Controllers/ShippingController.cs b/src/Presentation/SmartStore.Web/Administration/Controllers/ShippingController.cs index a63f02506f..887b5dabbc 100644 --- a/src/Presentation/SmartStore.Web/Administration/Controllers/ShippingController.cs +++ b/src/Presentation/SmartStore.Web/Administration/Controllers/ShippingController.cs @@ -149,19 +149,24 @@ public ActionResult Methods() [HttpPost, GridAction(EnableCustomBinding = true)] public ActionResult Methods(GridCommand command) { - if (!_services.Permissions.Authorize(StandardPermissionProvider.ManageShippingSettings)) - return AccessDeniedView(); + var model = new GridModel(); - var shippingMethodsModel = _shippingService.GetAllShippingMethods() - .Select(x => x.ToModel()) - .ForCommand(command) - .ToList(); + if (_services.Permissions.Authorize(StandardPermissionProvider.ManageShippingSettings)) + { + var shippingMethodsModel = _shippingService.GetAllShippingMethods() + .Select(x => x.ToModel()) + .ForCommand(command) + .ToList(); - var model = new GridModel - { - Data = shippingMethodsModel, - Total = shippingMethodsModel.Count - }; + model.Data = shippingMethodsModel; + model.Total = shippingMethodsModel.Count; + } + else + { + model.Data = Enumerable.Empty(); + + NotifyAccessDenied(); + } return new JsonResult { diff --git a/src/Presentation/SmartStore.Web/Administration/Controllers/ShoppingCartController.cs b/src/Presentation/SmartStore.Web/Administration/Controllers/ShoppingCartController.cs index b6868c18ce..fccebd040d 100644 --- a/src/Presentation/SmartStore.Web/Administration/Controllers/ShoppingCartController.cs +++ b/src/Presentation/SmartStore.Web/Administration/Controllers/ShoppingCartController.cs @@ -65,28 +65,32 @@ public ActionResult CurrentCarts() [HttpPost, GridAction(EnableCustomBinding = true)] public ActionResult CurrentCarts(GridCommand command) { - if (!_permissionService.Authorize(StandardPermissionProvider.ManageOrders)) - return AccessDeniedView(); - - var customers = _customerService.GetAllCustomers(null, null, null, null, null, - null, null, 0, 0, null, null, null, true, ShoppingCartType.ShoppingCart, - command.Page - 1, command.PageSize); + var gridModel = new GridModel(); + + if (_permissionService.Authorize(StandardPermissionProvider.ManageOrders)) + { + var customers = _customerService.GetAllCustomers(null, null, null, null, null, null, null, + 0, 0, null, null, null, true, ShoppingCartType.ShoppingCart, command.Page - 1, command.PageSize); + + gridModel.Data = customers.Select(x => + { + return new ShoppingCartModel + { + CustomerId = x.Id, + CustomerEmail = x.IsGuest() ? T("Admin.Customers.Guest").Text : x.Email, + TotalItems = x.CountProductsInCart(ShoppingCartType.ShoppingCart) + }; + }); + + gridModel.Total = customers.TotalCount; + } + else + { + gridModel.Data = Enumerable.Empty(); + + NotifyAccessDenied(); + } - var gridModel = new GridModel - { - Data = customers.Select(x => - { - return new ShoppingCartModel() - { - CustomerId = x.Id, - CustomerEmail = x.IsGuest() ? - _localizationService.GetResource("Admin.Customers.Guest") : - x.Email, - TotalItems = x.CountProductsInCart(ShoppingCartType.ShoppingCart) - }; - }), - Total = customers.TotalCount - }; return new JsonResult { Data = gridModel @@ -96,35 +100,43 @@ public ActionResult CurrentCarts(GridCommand command) [GridAction(EnableCustomBinding = true)] public ActionResult GetCartDetails(int customerId) { - if (!_permissionService.Authorize(StandardPermissionProvider.ManageOrders)) - return AccessDeniedView(); + var gridModel = new GridModel(); - var customer = _customerService.GetCustomerById(customerId); - var cart = customer.GetCartItems(ShoppingCartType.ShoppingCart); + if (_permissionService.Authorize(StandardPermissionProvider.ManageOrders)) + { + var customer = _customerService.GetCustomerById(customerId); + var cart = customer.GetCartItems(ShoppingCartType.ShoppingCart); - var gridModel = new GridModel() - { - Data = cart.Select(sci => - { - decimal taxRate; + gridModel.Data = cart.Select(sci => + { + decimal taxRate; var store = _storeService.GetStoreById(sci.Item.StoreId); - var sciModel = new ShoppingCartItemModel() - { - Id = sci.Item.Id, - Store = store != null ? store.Name : "Unknown", + + var sciModel = new ShoppingCartItemModel + { + Id = sci.Item.Id, + Store = store != null ? store.Name : "".NaIfEmpty(), ProductId = sci.Item.ProductId, - Quantity = sci.Item.Quantity, + Quantity = sci.Item.Quantity, ProductName = sci.Item.Product.Name, ProductTypeName = sci.Item.Product.GetProductTypeLabel(_localizationService), ProductTypeLabelHint = sci.Item.Product.ProductTypeLabelHint, - UnitPrice = _priceFormatter.FormatPrice(_taxService.GetProductPrice(sci.Item.Product, _priceCalculationService.GetUnitPrice(sci, true), out taxRate)), - Total = _priceFormatter.FormatPrice(_taxService.GetProductPrice(sci.Item.Product, _priceCalculationService.GetSubTotal(sci, true), out taxRate)), - UpdatedOn = _dateTimeHelper.ConvertToUserTime(sci.Item.UpdatedOnUtc, DateTimeKind.Utc) - }; - return sciModel; - }), - Total = cart.Count - }; + UnitPrice = _priceFormatter.FormatPrice(_taxService.GetProductPrice(sci.Item.Product, _priceCalculationService.GetUnitPrice(sci, true), out taxRate)), + Total = _priceFormatter.FormatPrice(_taxService.GetProductPrice(sci.Item.Product, _priceCalculationService.GetSubTotal(sci, true), out taxRate)), + UpdatedOn = _dateTimeHelper.ConvertToUserTime(sci.Item.UpdatedOnUtc, DateTimeKind.Utc) + }; + return sciModel; + }); + + gridModel.Total = cart.Count; + } + else + { + gridModel.Data = Enumerable.Empty(); + + NotifyAccessDenied(); + } + return new JsonResult { Data = gridModel @@ -144,28 +156,32 @@ public ActionResult CurrentWishlists() [HttpPost, GridAction(EnableCustomBinding = true)] public ActionResult CurrentWishlists(GridCommand command) { - if (!_permissionService.Authorize(StandardPermissionProvider.ManageOrders)) - return AccessDeniedView(); - - var customers = _customerService.GetAllCustomers(null, null, null, null, null, - null, null, 0, 0, null, null, null, - true, ShoppingCartType.Wishlist, command.Page - 1, command.PageSize); + var gridModel = new GridModel(); + + if (_permissionService.Authorize(StandardPermissionProvider.ManageOrders)) + { + var customers = _customerService.GetAllCustomers(null, null, null, null, null, null, null, + 0, 0, null, null, null, true, ShoppingCartType.Wishlist, command.Page - 1, command.PageSize); + + gridModel.Data = customers.Select(x => + { + return new ShoppingCartModel + { + CustomerId = x.Id, + CustomerEmail = x.IsGuest() ? T("Admin.Customers.Guest").Text : x.Email, + TotalItems = x.CountProductsInCart(ShoppingCartType.Wishlist) + }; + }); + + gridModel.Total = customers.TotalCount; + } + else + { + gridModel.Data = Enumerable.Empty(); + + NotifyAccessDenied(); + } - var gridModel = new GridModel - { - Data = customers.Select(x => - { - return new ShoppingCartModel() - { - CustomerId = x.Id, - CustomerEmail = x.IsGuest() ? - _localizationService.GetResource("Admin.Customers.Guest") : - x.Email, - TotalItems = x.CountProductsInCart(ShoppingCartType.Wishlist) - }; - }), - Total = customers.TotalCount - }; return new JsonResult { Data = gridModel @@ -175,35 +191,43 @@ public ActionResult CurrentWishlists(GridCommand command) [GridAction(EnableCustomBinding = true)] public ActionResult GetWishlistDetails(int customerId) { - if (!_permissionService.Authorize(StandardPermissionProvider.ManageOrders)) - return AccessDeniedView(); + var gridModel = new GridModel(); - var customer = _customerService.GetCustomerById(customerId); - var cart = customer.GetCartItems(ShoppingCartType.Wishlist); + if (_permissionService.Authorize(StandardPermissionProvider.ManageOrders)) + { + var customer = _customerService.GetCustomerById(customerId); + var cart = customer.GetCartItems(ShoppingCartType.Wishlist); - var gridModel = new GridModel() - { - Data = cart.Select(sci => - { - decimal taxRate; - var store = _storeService.GetStoreById(sci.Item.StoreId); - var sciModel = new ShoppingCartItemModel() - { - Id = sci.Item.Id, - Store = store != null ? store.Name : "Unknown", - ProductId = sci.Item.ProductId, - Quantity = sci.Item.Quantity, + gridModel.Data = cart.Select(sci => + { + decimal taxRate; + var store = _storeService.GetStoreById(sci.Item.StoreId); + + var sciModel = new ShoppingCartItemModel + { + Id = sci.Item.Id, + Store = store != null ? store.Name : "".NaIfEmpty(), + ProductId = sci.Item.ProductId, + Quantity = sci.Item.Quantity, ProductName = sci.Item.Product.Name, ProductTypeName = sci.Item.Product.GetProductTypeLabel(_localizationService), ProductTypeLabelHint = sci.Item.Product.ProductTypeLabelHint, - UnitPrice = _priceFormatter.FormatPrice(_taxService.GetProductPrice(sci.Item.Product, _priceCalculationService.GetUnitPrice(sci, true), out taxRate)), - Total = _priceFormatter.FormatPrice(_taxService.GetProductPrice(sci.Item.Product, _priceCalculationService.GetSubTotal(sci, true), out taxRate)), - UpdatedOn = _dateTimeHelper.ConvertToUserTime(sci.Item.UpdatedOnUtc, DateTimeKind.Utc) - }; - return sciModel; - }), - Total = cart.Count - }; + UnitPrice = _priceFormatter.FormatPrice(_taxService.GetProductPrice(sci.Item.Product, _priceCalculationService.GetUnitPrice(sci, true), out taxRate)), + Total = _priceFormatter.FormatPrice(_taxService.GetProductPrice(sci.Item.Product, _priceCalculationService.GetSubTotal(sci, true), out taxRate)), + UpdatedOn = _dateTimeHelper.ConvertToUserTime(sci.Item.UpdatedOnUtc, DateTimeKind.Utc) + }; + return sciModel; + }); + + gridModel.Total = cart.Count; + } + else + { + gridModel.Data = Enumerable.Empty(); + + NotifyAccessDenied(); + } + return new JsonResult { Data = gridModel diff --git a/src/Presentation/SmartStore.Web/Administration/Controllers/SpecificationAttributeController.cs b/src/Presentation/SmartStore.Web/Administration/Controllers/SpecificationAttributeController.cs index 92877bbb9b..a15ca73afc 100644 --- a/src/Presentation/SmartStore.Web/Administration/Controllers/SpecificationAttributeController.cs +++ b/src/Presentation/SmartStore.Web/Administration/Controllers/SpecificationAttributeController.cs @@ -121,28 +121,31 @@ public ActionResult List() [HttpPost, GridAction(EnableCustomBinding = true)] public ActionResult List(GridCommand command) { - if (!_permissionService.Authorize(StandardPermissionProvider.ManageCatalog)) - return AccessDeniedView(); - - var optionsText = _localizationService.GetResource("Admin.Catalog.Attributes.SpecificationAttributes.Options"); - - var data = _specificationAttributeService.GetSpecificationAttributes() - .Expand(x => x.SpecificationAttributeOptions) - .ForCommand(command) - .Select(x => - { - var model = x.ToModel(); - model.OptionCount = x.SpecificationAttributeOptions.Count; - - return model; - }) - .ToList(); + var gridModel = new GridModel(); - var gridModel = new GridModel + if (_permissionService.Authorize(StandardPermissionProvider.ManageCatalog)) + { + var data = _specificationAttributeService.GetSpecificationAttributes() + .Expand(x => x.SpecificationAttributeOptions) + .ForCommand(command) + .Select(x => + { + var model = x.ToModel(); + model.OptionCount = x.SpecificationAttributeOptions.Count; + + return model; + }) + .ToList(); + + gridModel.Data = data.PagedForCommand(command); + gridModel.Total = data.Count; + } + else { - Data = data.PagedForCommand(command), - Total = data.Count - }; + gridModel.Data = Enumerable.Empty(); + + NotifyAccessDenied(); + } return new JsonResult { @@ -150,7 +153,6 @@ public ActionResult List(GridCommand command) }; } - //create public ActionResult Create() { if (!_permissionService.Authorize(StandardPermissionProvider.ManageCatalog)) @@ -185,7 +187,6 @@ public ActionResult Create(SpecificationAttributeModel model, bool continueEditi return View(model); } - //edit public ActionResult Edit(int id) { if (!_permissionService.Authorize(StandardPermissionProvider.ManageCatalog)) @@ -233,7 +234,6 @@ public ActionResult Edit(SpecificationAttributeModel model, bool continueEditing return View(model); } - //delete [HttpPost, ActionName("Delete")] public ActionResult DeleteConfirmed(int id) { @@ -289,35 +289,31 @@ public ActionResult ProductMappingEdit(int specificationAttributeId, string fiel #region Specification attribute options - //list [HttpPost, GridAction(EnableCustomBinding = true)] public ActionResult OptionList(int specificationAttributeId, GridCommand command) { - if (!_permissionService.Authorize(StandardPermissionProvider.ManageCatalog)) - return AccessDeniedView(); + var gridModel = new GridModel(); + + if (_permissionService.Authorize(StandardPermissionProvider.ManageCatalog)) + { + var options = _specificationAttributeService.GetSpecificationAttributeOptionsBySpecificationAttribute(specificationAttributeId); + + gridModel.Data = options.Select(x => x.ToModel()); + gridModel.Total = options.Count(); + } + else + { + gridModel.Data = Enumerable.Empty(); + + NotifyAccessDenied(); + } - var options = _specificationAttributeService.GetSpecificationAttributeOptionsBySpecificationAttribute(specificationAttributeId); - var gridModel = new GridModel - { - Data = options.Select(x => - { - var model = x.ToModel(); - //locales - //AddLocales(_languageService, model.Locales, (locale, languageId) => - //{ - // locale.Name = x.GetLocalized(y => y.Name, languageId, false, false); - //}); - return model; - }), - Total = options.Count() - }; return new JsonResult { Data = gridModel }; } - //create public ActionResult OptionCreatePopup(int specificationAttributeId) { if (!_permissionService.Authorize(StandardPermissionProvider.ManageCatalog)) @@ -367,7 +363,6 @@ public ActionResult OptionCreatePopup(string btnId, string formId, Specification return View(model); } - //edit public ActionResult OptionEditPopup(int id) { if (!_permissionService.Authorize(StandardPermissionProvider.ManageCatalog)) @@ -414,23 +409,19 @@ public ActionResult OptionEditPopup(string btnId, string formId, SpecificationAt return View(model); } - //delete [GridAction(EnableCustomBinding = true)] public ActionResult OptionDelete(int optionId, int specificationAttributeId, GridCommand command) { - if (!_permissionService.Authorize(StandardPermissionProvider.ManageCatalog)) - return AccessDeniedView(); - - var sao = _specificationAttributeService.GetSpecificationAttributeOptionById(optionId); - if (sao == null) - throw new ArgumentException("No specification attribute option found with the specified id"); + if (_permissionService.Authorize(StandardPermissionProvider.ManageCatalog)) + { + var sao = _specificationAttributeService.GetSpecificationAttributeOptionById(optionId); - _specificationAttributeService.DeleteSpecificationAttributeOption(sao); + _specificationAttributeService.DeleteSpecificationAttributeOption(sao); + } return OptionList(specificationAttributeId, command); } - //ajax [AcceptVerbs(HttpVerbs.Get)] public ActionResult GetOptionsByAttributeId(string attributeId) @@ -468,7 +459,6 @@ public ActionResult SetAttributeValue(string pk, string value, string name, Form } } - #endregion } } diff --git a/src/Presentation/SmartStore.Web/Administration/Controllers/StoreController.cs b/src/Presentation/SmartStore.Web/Administration/Controllers/StoreController.cs index 78a441460e..38df324a4c 100644 --- a/src/Presentation/SmartStore.Web/Administration/Controllers/StoreController.cs +++ b/src/Presentation/SmartStore.Web/Administration/Controllers/StoreController.cs @@ -81,27 +81,32 @@ from m in stores [HttpPost, GridAction(EnableCustomBinding = true)] public ActionResult List(GridCommand command) { - if (!_permissionService.Authorize(StandardPermissionProvider.ManageStores)) - return AccessDeniedView(); + var gridModel = new GridModel(); - var storeModels = _storeService.GetAllStores() - .Select(x => - { - var model = x.ToModel(); + if (_permissionService.Authorize(StandardPermissionProvider.ManageStores)) + { + var storeModels = _storeService.GetAllStores() + .Select(x => + { + var model = x.ToModel(); - PrepareStoreModel(model, x); + PrepareStoreModel(model, x); - model.Hosts = model.Hosts.EmptyNull().Replace(",", "
    "); + model.Hosts = model.Hosts.EmptyNull().Replace(",", "
    "); - return model; - }) - .ToList(); + return model; + }) + .ToList(); - var gridModel = new GridModel + gridModel.Data = storeModels; + gridModel.Total = storeModels.Count(); + } + else { - Data = storeModels, - Total = storeModels.Count() - }; + gridModel.Data = Enumerable.Empty(); + + NotifyAccessDenied(); + } return new JsonResult { diff --git a/src/Presentation/SmartStore.Web/Administration/Controllers/TaxController.cs b/src/Presentation/SmartStore.Web/Administration/Controllers/TaxController.cs index b78404407d..a694f7df48 100644 --- a/src/Presentation/SmartStore.Web/Administration/Controllers/TaxController.cs +++ b/src/Presentation/SmartStore.Web/Administration/Controllers/TaxController.cs @@ -116,18 +116,24 @@ public ActionResult Categories() [HttpPost, GridAction(EnableCustomBinding = true)] public ActionResult Categories(GridCommand command) { - if (!_permissionService.Authorize(StandardPermissionProvider.ManageTaxSettings)) - return AccessDeniedView(); + var model = new GridModel(); - var categoriesModel = _taxCategoryService.GetAllTaxCategories() - .Select(x => x.ToModel()) - .ForCommand(command) - .ToList(); - var model = new GridModel - { - Data = categoriesModel, - Total = categoriesModel.Count - }; + if (_permissionService.Authorize(StandardPermissionProvider.ManageTaxSettings)) + { + var categoriesModel = _taxCategoryService.GetAllTaxCategories() + .Select(x => x.ToModel()) + .ForCommand(command) + .ToList(); + + model.Data = categoriesModel; + model.Total = categoriesModel.Count; + } + else + { + model.Data = Enumerable.Empty(); + + NotifyAccessDenied(); + } return new JsonResult { @@ -138,19 +144,19 @@ public ActionResult Categories(GridCommand command) [GridAction(EnableCustomBinding = true)] public ActionResult CategoryUpdate(TaxCategoryModel model, GridCommand command) { - if (!_permissionService.Authorize(StandardPermissionProvider.ManageTaxSettings)) - return AccessDeniedView(); + if (_permissionService.Authorize(StandardPermissionProvider.ManageTaxSettings)) + { + if (!ModelState.IsValid) + { + var modelStateErrors = this.ModelState.Values.SelectMany(x => x.Errors).Select(x => x.ErrorMessage); + return Content(modelStateErrors.FirstOrDefault()); + } - if (!ModelState.IsValid) - { - //display the first model error - var modelStateErrors = this.ModelState.Values.SelectMany(x => x.Errors).Select(x => x.ErrorMessage); - return Content(modelStateErrors.FirstOrDefault()); - } + var taxCategory = _taxCategoryService.GetTaxCategoryById(model.Id); + taxCategory = model.ToEntity(taxCategory); - var taxCategory = _taxCategoryService.GetTaxCategoryById(model.Id); - taxCategory = model.ToEntity(taxCategory); - _taxCategoryService.UpdateTaxCategory(taxCategory); + _taxCategoryService.UpdateTaxCategory(taxCategory); + } return Categories(command); } @@ -158,19 +164,19 @@ public ActionResult CategoryUpdate(TaxCategoryModel model, GridCommand command) [GridAction(EnableCustomBinding = true)] public ActionResult CategoryAdd([Bind(Exclude = "Id")] TaxCategoryModel model, GridCommand command) { - if (!_permissionService.Authorize(StandardPermissionProvider.ManageTaxSettings)) - return AccessDeniedView(); + if (_permissionService.Authorize(StandardPermissionProvider.ManageTaxSettings)) + { + if (!ModelState.IsValid) + { + var modelStateErrors = this.ModelState.Values.SelectMany(x => x.Errors).Select(x => x.ErrorMessage); + return Content(modelStateErrors.FirstOrDefault()); + } - if (!ModelState.IsValid) - { - //display the first model error - var modelStateErrors = this.ModelState.Values.SelectMany(x => x.Errors).Select(x => x.ErrorMessage); - return Content(modelStateErrors.FirstOrDefault()); - } + var taxCategory = new TaxCategory(); + taxCategory = model.ToEntity(taxCategory); - var taxCategory = new TaxCategory(); - taxCategory = model.ToEntity(taxCategory); - _taxCategoryService.InsertTaxCategory(taxCategory); + _taxCategoryService.InsertTaxCategory(taxCategory); + } return Categories(command); } @@ -178,13 +184,12 @@ public ActionResult CategoryAdd([Bind(Exclude = "Id")] TaxCategoryModel model, G [GridAction(EnableCustomBinding = true)] public ActionResult CategoryDelete(int id, GridCommand command) { - if (!_permissionService.Authorize(StandardPermissionProvider.ManageTaxSettings)) - return AccessDeniedView(); + if (_permissionService.Authorize(StandardPermissionProvider.ManageTaxSettings)) + { + var taxCategory = _taxCategoryService.GetTaxCategoryById(id); - var taxCategory = _taxCategoryService.GetTaxCategoryById(id); - if (taxCategory == null) - throw new ArgumentException("No tax category found with the specified id"); - _taxCategoryService.DeleteTaxCategory(taxCategory); + _taxCategoryService.DeleteTaxCategory(taxCategory); + } return Categories(command); } diff --git a/src/Presentation/SmartStore.Web/Administration/Controllers/TopicController.cs b/src/Presentation/SmartStore.Web/Administration/Controllers/TopicController.cs index 29f29762c6..03b4a60c62 100644 --- a/src/Presentation/SmartStore.Web/Administration/Controllers/TopicController.cs +++ b/src/Presentation/SmartStore.Web/Administration/Controllers/TopicController.cs @@ -137,20 +137,29 @@ public ActionResult List() [HttpPost, GridAction(EnableCustomBinding = true)] public ActionResult List(GridCommand command, TopicListModel model) { - if (!_permissionService.Authorize(StandardPermissionProvider.ManageTopics)) - return AccessDeniedView(); + var gridModel = new GridModel(); - var topics = _topicService.GetAllTopics(model.SearchStoreId); - var gridModel = new GridModel - { - Data = topics.Select(x => { + if (_permissionService.Authorize(StandardPermissionProvider.ManageTopics)) + { + var topics = _topicService.GetAllTopics(model.SearchStoreId); + + gridModel.Data = topics.Select(x => + { var item = x.ToModel(); // otherwise maxJsonLength could be exceeded item.Body = ""; return item; - }), - Total = topics.Count - }; + }); + + gridModel.Total = topics.Count; + } + else + { + gridModel.Data = Enumerable.Empty(); + + NotifyAccessDenied(); + } + return new JsonResult { MaxJsonLength = int.MaxValue, diff --git a/src/Presentation/SmartStore.Web/Administration/Controllers/UrlRecordController.cs b/src/Presentation/SmartStore.Web/Administration/Controllers/UrlRecordController.cs index c088c0805d..d51b32bb19 100644 --- a/src/Presentation/SmartStore.Web/Administration/Controllers/UrlRecordController.cs +++ b/src/Presentation/SmartStore.Web/Administration/Controllers/UrlRecordController.cs @@ -107,20 +107,19 @@ public ActionResult List(string entityName, int? entityId) [HttpPost, GridAction(EnableCustomBinding = true)] public ActionResult List(GridCommand command, UrlRecordListModel model) { - if (!_services.Permissions.Authorize(StandardPermissionProvider.ManageUrlRecords)) - return AccessDeniedView(); + var gridModel = new GridModel(); - var allLanguages = _languageService.GetAllLanguages(true); - var defaultLanguageName = T("Admin.System.SeNames.Language.Standard"); + if (_services.Permissions.Authorize(StandardPermissionProvider.ManageUrlRecords)) + { + var allLanguages = _languageService.GetAllLanguages(true); + var defaultLanguageName = T("Admin.System.SeNames.Language.Standard"); - var urlRecords = _urlRecordService.GetAllUrlRecords(command.Page - 1, command.PageSize, - model.SeName, model.EntityName, model.EntityId, model.LanguageId, model.IsActive); + var urlRecords = _urlRecordService.GetAllUrlRecords(command.Page - 1, command.PageSize, + model.SeName, model.EntityName, model.EntityId, model.LanguageId, model.IsActive); - var slugsPerEntity = _urlRecordService.CountSlugsPerEntity(urlRecords.Select(x => x.Id).Distinct().ToArray()); + var slugsPerEntity = _urlRecordService.CountSlugsPerEntity(urlRecords.Select(x => x.Id).Distinct().ToArray()); - var gridModel = new GridModel - { - Data = urlRecords.Select(x => + gridModel.Data = urlRecords.Select(x => { string languageName; @@ -141,9 +140,16 @@ public ActionResult List(GridCommand command, UrlRecordListModel model) urlRecordModel.SlugsPerEntity = (slugsPerEntity.ContainsKey(x.Id) ? slugsPerEntity[x.Id] : 0); return urlRecordModel; - }), - Total = urlRecords.TotalCount - }; + }); + + gridModel.Total = urlRecords.TotalCount; + } + else + { + gridModel.Data = Enumerable.Empty(); + + NotifyAccessDenied(); + } return new JsonResult { From 1fa83bdc2017f11dd20ee50efd901e4336aceabe Mon Sep 17 00:00:00 2001 From: Marcus Gesing Date: Wed, 6 Jan 2016 12:57:00 +0100 Subject: [PATCH 216/707] Localized some hard-coded strings --- .../201512151526290_ImportFramework.cs | 9 +++++++ .../Controllers/ByTotalController.cs | 6 +++-- .../Controllers/FixedRateController.cs | 2 +- .../Providers/ByTotalProvider.cs | 27 ++++++++++--------- .../Providers/FixedRateProvider.cs | 25 +++++++++-------- .../ByWeightShippingComputationMethod.cs | 23 ++++++++++------ .../Controllers/ShippingByWeightController.cs | 6 +++-- .../Controllers/TaxByRegionController.cs | 4 +-- 8 files changed, 64 insertions(+), 38 deletions(-) diff --git a/src/Libraries/SmartStore.Data/Migrations/201512151526290_ImportFramework.cs b/src/Libraries/SmartStore.Data/Migrations/201512151526290_ImportFramework.cs index 7de4cc953b..35b6497ae1 100644 --- a/src/Libraries/SmartStore.Data/Migrations/201512151526290_ImportFramework.cs +++ b/src/Libraries/SmartStore.Data/Migrations/201512151526290_ImportFramework.cs @@ -76,6 +76,7 @@ public void MigrateLocaleResources(LocaleResourcesBuilder builder) "Legt die Anzahl der zu berspringenden Datenstze fest."); builder.AddOrUpdate("Common.Unknown", "Unknown", "Unbekannt"); + builder.AddOrUpdate("Common.Unavailable", "Unavailable", "Nicht verfgbar"); builder.AddOrUpdate("Common.Language", "Language", "Sprache"); builder.AddOrUpdate("Admin.Common.ImportFile", "Import file", "Importdatei"); builder.AddOrUpdate("Admin.Common.ImportFiles", "Import files", "Importdateien"); @@ -303,6 +304,14 @@ public void MigrateLocaleResources(LocaleResourcesBuilder builder) builder.AddOrUpdate("Admin.Configuration.Countries.States.CantDeleteWithAddresses", "The state\\province cannot be deleted because it has associated addresses.", "Das Bundesland\\Region kann nicht gelscht werden, weil ihm Adressen zugeordnet sind."); + + builder.AddOrUpdate("Admin.Configuration.Shipping.Methods.NoMethodsLoaded", + "No shipping methods could be loaded.", + "Es konnten keine Versandarten geladen werden."); + + builder.AddOrUpdate("Admin.System.Warnings.NoShipmentItems", + "No shipment items", + "Keine Versand-Artikel"); } } } diff --git a/src/Plugins/SmartStore.Shipping/Controllers/ByTotalController.cs b/src/Plugins/SmartStore.Shipping/Controllers/ByTotalController.cs index 1bf1f643b1..5c5e03f8ab 100644 --- a/src/Plugins/SmartStore.Shipping/Controllers/ByTotalController.cs +++ b/src/Plugins/SmartStore.Shipping/Controllers/ByTotalController.cs @@ -43,7 +43,7 @@ public ActionResult Configure() var shippingMethods = _shippingService.GetAllShippingMethods(); if (shippingMethods.Count == 0) { - return Content("No shipping methods can be loaded"); + return Content(T("Admin.Configuration.Shipping.Methods.NoMethodsLoaded")); } var model = new ByTotalListModel(); @@ -100,10 +100,11 @@ public ActionResult RateUpdate(ByTotalModel model, GridCommand command) { if (!ModelState.IsValid) { - return new JsonResult { Data = "error" }; + return new JsonResult { Data = T("Admin.Common.UnknownError").Text }; } var shippingByTotalRecord = _shippingByTotalService.GetShippingByTotalRecordById(model.Id); + shippingByTotalRecord.Zip = model.Zip == "*" ? null : model.Zip; shippingByTotalRecord.From = model.From; shippingByTotalRecord.To = model.To; @@ -112,6 +113,7 @@ public ActionResult RateUpdate(ByTotalModel model, GridCommand command) shippingByTotalRecord.ShippingChargePercentage = model.ShippingChargePercentage; shippingByTotalRecord.BaseCharge = model.BaseCharge; shippingByTotalRecord.MaxCharge = model.MaxCharge; + _shippingByTotalService.UpdateShippingByTotalRecord(shippingByTotalRecord); return RatesList(command); diff --git a/src/Plugins/SmartStore.Shipping/Controllers/FixedRateController.cs b/src/Plugins/SmartStore.Shipping/Controllers/FixedRateController.cs index f0e510f3b7..353bafe59d 100644 --- a/src/Plugins/SmartStore.Shipping/Controllers/FixedRateController.cs +++ b/src/Plugins/SmartStore.Shipping/Controllers/FixedRateController.cs @@ -29,7 +29,7 @@ public ActionResult Configure() { var shippingMethods = _shippingService.GetAllShippingMethods(); if (shippingMethods.Count == 0) - return Content("No shipping methods can be loaded"); + return Content(T("Admin.Configuration.Shipping.Methods.NoMethodsLoaded")); var tmp = new List(); foreach (var shippingMethod in shippingMethods) diff --git a/src/Plugins/SmartStore.Shipping/Providers/ByTotalProvider.cs b/src/Plugins/SmartStore.Shipping/Providers/ByTotalProvider.cs index 882a576f15..82ec989cf4 100644 --- a/src/Plugins/SmartStore.Shipping/Providers/ByTotalProvider.cs +++ b/src/Plugins/SmartStore.Shipping/Providers/ByTotalProvider.cs @@ -1,20 +1,20 @@ using System; -using System.Data.Entity.Migrations; using System.Web.Routing; using SmartStore.Core; using SmartStore.Core.Domain.Shipping; +using SmartStore.Core.Localization; +using SmartStore.Core.Logging; using SmartStore.Core.Plugins; -using SmartStore.Shipping.Services; using SmartStore.Services.Catalog; using SmartStore.Services.Configuration; using SmartStore.Services.Localization; -using SmartStore.Core.Logging; using SmartStore.Services.Shipping; using SmartStore.Services.Shipping.Tracking; +using SmartStore.Shipping.Services; namespace SmartStore.Shipping { - [SystemName("Shipping.ByTotal")] + [SystemName("Shipping.ByTotal")] [FriendlyName("Shipping by total")] [DisplayOrder(1)] public class ByTotalProvider : IShippingRateComputationMethod, IConfigurable @@ -28,7 +28,6 @@ public class ByTotalProvider : IShippingRateComputationMethod, IConfigurable private readonly ISettingService _settingService; private readonly ILocalizationService _localizationService; - /// /// Ctor /// @@ -56,14 +55,18 @@ public ByTotalProvider(IShippingService shippingService, this._logger = logger; this._settingService = settingService; this._localizationService = localizationService; - } - #region Properties + T = NullLocalizer.Instance; + } - /// - /// Gets a shipping rate computation method type - /// - public ShippingRateComputationMethodType ShippingRateComputationMethodType + #region Properties + + public Localizer T { get; set; } + + /// + /// Gets a shipping rate computation method type + /// + public ShippingRateComputationMethodType ShippingRateComputationMethodType { get { @@ -158,7 +161,7 @@ public GetShippingOptionResponse GetShippingOptions(GetShippingOptionRequest get if (getShippingOptionRequest.Items == null || getShippingOptionRequest.Items.Count == 0) { - response.AddError("No shipment items"); + response.AddError(T("Admin.System.Warnings.NoShipmentItems")); return response; } diff --git a/src/Plugins/SmartStore.Shipping/Providers/FixedRateProvider.cs b/src/Plugins/SmartStore.Shipping/Providers/FixedRateProvider.cs index a4ae31c94e..cc303cee6e 100644 --- a/src/Plugins/SmartStore.Shipping/Providers/FixedRateProvider.cs +++ b/src/Plugins/SmartStore.Shipping/Providers/FixedRateProvider.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.Web.Routing; using SmartStore.Core.Domain.Shipping; +using SmartStore.Core.Localization; using SmartStore.Core.Plugins; using SmartStore.Services.Configuration; using SmartStore.Services.Localization; @@ -10,27 +11,29 @@ namespace SmartStore.Shipping { - /// - /// Fixed rate shipping computation provider - /// - [SystemName("Shipping.FixedRate")] + /// + /// Fixed rate shipping computation provider + /// + [SystemName("Shipping.FixedRate")] [FriendlyName("Fixed Rate Shipping")] [DisplayOrder(0)] public class FixedRateProvider : IShippingRateComputationMethod, IConfigurable { private readonly ISettingService _settingService; private readonly IShippingService _shippingService; - private readonly ILocalizationService _localizationService; public FixedRateProvider(ISettingService settingService, - IShippingService shippingService, ILocalizationService localizationService) + IShippingService shippingService) { this._settingService = settingService; this._shippingService = shippingService; - _localizationService = localizationService; - } - - private decimal GetRate(int shippingMethodId) + + T = NullLocalizer.Instance; + } + + public Localizer T { get; set; } + + private decimal GetRate(int shippingMethodId) { string key = string.Format("ShippingRateComputationMethod.FixedRate.Rate.ShippingMethodId{0}", shippingMethodId); decimal rate = this._settingService.GetSettingByKey(key); @@ -51,7 +54,7 @@ public GetShippingOptionResponse GetShippingOptions(GetShippingOptionRequest get if (getShippingOptionRequest.Items == null || getShippingOptionRequest.Items.Count == 0) { - response.AddError("No shipment items"); + response.AddError(T("Admin.System.Warnings.NoShipmentItems")); return response; } diff --git a/src/Plugins/SmartStore.ShippingByWeight/ByWeightShippingComputationMethod.cs b/src/Plugins/SmartStore.ShippingByWeight/ByWeightShippingComputationMethod.cs index 0c59828d2a..40334476a9 100644 --- a/src/Plugins/SmartStore.ShippingByWeight/ByWeightShippingComputationMethod.cs +++ b/src/Plugins/SmartStore.ShippingByWeight/ByWeightShippingComputationMethod.cs @@ -3,15 +3,16 @@ using System.Web.Routing; using SmartStore.Core; using SmartStore.Core.Domain.Shipping; +using SmartStore.Core.Localization; using SmartStore.Core.Plugins; -using SmartStore.ShippingByWeight.Data; -using SmartStore.ShippingByWeight.Data.Migrations; -using SmartStore.ShippingByWeight.Services; using SmartStore.Services; using SmartStore.Services.Catalog; using SmartStore.Services.Localization; using SmartStore.Services.Shipping; using SmartStore.Services.Shipping.Tracking; +using SmartStore.ShippingByWeight.Data; +using SmartStore.ShippingByWeight.Data.Migrations; +using SmartStore.ShippingByWeight.Services; namespace SmartStore.ShippingByWeight { @@ -32,6 +33,7 @@ public class ByWeightShippingComputationMethod : BasePlugin, IShippingRateComput #endregion #region Ctor + public ByWeightShippingComputationMethod(IShippingService shippingService, IStoreContext storeContext, IShippingByWeightService shippingByWeightService, @@ -51,12 +53,17 @@ public ByWeightShippingComputationMethod(IShippingService shippingService, this._localizationService = localizationService; this._priceFormatter = priceFormatter; this._services = services; - } - #endregion - #region Utilities + T = NullLocalizer.Instance; + } + + public Localizer T { get; set; } + + #endregion + + #region Utilities - private decimal? GetRate(decimal subTotal, decimal weight, int shippingMethodId, int storeId, int countryId, string zip) + private decimal? GetRate(decimal subTotal, decimal weight, int shippingMethodId, int storeId, int countryId, string zip) { decimal? shippingTotal = null; @@ -120,7 +127,7 @@ public GetShippingOptionResponse GetShippingOptions(GetShippingOptionRequest get if (getShippingOptionRequest.Items == null || getShippingOptionRequest.Items.Count == 0) { - response.AddError("No shipment items"); + response.AddError(T("Admin.System.Warnings.NoShipmentItems")); return response; } diff --git a/src/Plugins/SmartStore.ShippingByWeight/Controllers/ShippingByWeightController.cs b/src/Plugins/SmartStore.ShippingByWeight/Controllers/ShippingByWeightController.cs index aaa92a955f..383d77dfa2 100644 --- a/src/Plugins/SmartStore.ShippingByWeight/Controllers/ShippingByWeightController.cs +++ b/src/Plugins/SmartStore.ShippingByWeight/Controllers/ShippingByWeightController.cs @@ -50,8 +50,10 @@ public ShippingByWeightController( public ActionResult Configure() { var shippingMethods = _shippingService.GetAllShippingMethods(); - if (shippingMethods.Count == 0) - return Content("No shipping methods can be loaded"); + if (shippingMethods.Count == 0) + { + return Content(T("Admin.Configuration.Shipping.Methods.NoMethodsLoaded")); + } var model = new ShippingByWeightListModel(); var countries = _countryService.GetAllCountries(true); diff --git a/src/Plugins/SmartStore.Tax/Controllers/TaxByRegionController.cs b/src/Plugins/SmartStore.Tax/Controllers/TaxByRegionController.cs index 53bc5628e7..ca43d31f14 100644 --- a/src/Plugins/SmartStore.Tax/Controllers/TaxByRegionController.cs +++ b/src/Plugins/SmartStore.Tax/Controllers/TaxByRegionController.cs @@ -70,7 +70,7 @@ public ActionResult Configure() var tc = _taxCategoryService.GetTaxCategoryById(x.TaxCategoryId); m.TaxCategoryName = (tc != null) ? tc.Name : ""; var c = _countryService.GetCountryById(x.CountryId); - m.CountryName = (c != null) ? c.Name : "Unavailable"; + m.CountryName = (c != null) ? c.Name : T("Common.Unavailable").Text; var s = _stateProvinceService.GetStateProvinceById(x.StateProvinceId); m.StateProvinceName = (s != null) ? s.Name : "*"; m.Zip = (!String.IsNullOrEmpty(x.Zip)) ? x.Zip : "*"; @@ -99,7 +99,7 @@ public ActionResult RatesList(GridCommand command) var tc = _taxCategoryService.GetTaxCategoryById(x.TaxCategoryId); m.TaxCategoryName = (tc != null) ? tc.Name : ""; var c = _countryService.GetCountryById(x.CountryId); - m.CountryName = (c != null) ? c.Name : "Unavailable"; + m.CountryName = (c != null) ? c.Name : T("Common.Unavailable").Text; var s = _stateProvinceService.GetStateProvinceById(x.StateProvinceId); m.StateProvinceName = (s != null) ? s.Name : "*"; m.Zip = (!String.IsNullOrEmpty(x.Zip)) ? x.Zip : "*"; From 07432d249b21eb3b5f8e089bb20ef63d322ea786 Mon Sep 17 00:00:00 2001 From: Marcus Gesing Date: Thu, 7 Jan 2016 11:52:49 +0100 Subject: [PATCH 217/707] GMC feed: Supporting fields multipack, bundle, adult, energy efficiency class and custom label (0 to 4) --- changelog.md | 1 + .../201512151526290_ImportFramework.cs | 4 + .../FeedGoogleMerchantCenterController.cs | 31 +++- .../Data/GoogleProductRecordMap.cs | 10 +- .../201601061649324_IsBundle.Designer.cs | 29 ++++ .../Migrations/201601061649324_IsBundle.cs | 34 ++++ .../Migrations/201601061649324_IsBundle.resx | 126 +++++++++++++++ .../Description.txt | 2 +- .../Domain/GoogleProductRecord.cs | 13 +- .../SmartStore.GoogleMerchantCenter/Events.cs | 39 ++--- .../Extensions/MiscExtensions.cs | 13 +- .../Localization/resources.de-de.xml | 84 +++++++--- .../Localization/resources.en-us.xml | 84 +++++++--- .../Models/FeedGoogleMerchantCenterModel.cs | 53 +++++-- .../Models/ProfileConfigurationModel.cs | 4 - .../Providers/GmcXmlExportProvider.cs | 59 ++++++- .../Services/GoogleFeedService.cs | 54 ++++++- .../SmartStore.GoogleMerchantCenter.csproj | 7 + .../FeedGoogleMerchantCenter/Configure.cshtml | 146 ++++++++++++++---- .../ProductEditTab.cshtml | 97 +++++++++++- .../ProfileConfiguration.cshtml | 15 +- .../changelog.md | 7 + 22 files changed, 748 insertions(+), 164 deletions(-) create mode 100644 src/Plugins/SmartStore.GoogleMerchantCenter/Data/Migrations/201601061649324_IsBundle.Designer.cs create mode 100644 src/Plugins/SmartStore.GoogleMerchantCenter/Data/Migrations/201601061649324_IsBundle.cs create mode 100644 src/Plugins/SmartStore.GoogleMerchantCenter/Data/Migrations/201601061649324_IsBundle.resx diff --git a/changelog.md b/changelog.md index 2308726b85..f6fa16e556 100644 --- a/changelog.md +++ b/changelog.md @@ -32,6 +32,7 @@ * #840 Activity log: Have option to exclude search engine activity * #841 Activity log for deleting an order * More settings to control creation of SEO names +* GMC feed: Supporting fields multipack, bundle, adult, energy efficiency class and custom label (0 to 4) ### Improvements * (Perf) Implemented static caches for URL aliases and localized properties. Increases app startup and request speed by up to 30%. diff --git a/src/Libraries/SmartStore.Data/Migrations/201512151526290_ImportFramework.cs b/src/Libraries/SmartStore.Data/Migrations/201512151526290_ImportFramework.cs index 35b6497ae1..7f2dec3086 100644 --- a/src/Libraries/SmartStore.Data/Migrations/201512151526290_ImportFramework.cs +++ b/src/Libraries/SmartStore.Data/Migrations/201512151526290_ImportFramework.cs @@ -312,6 +312,10 @@ public void MigrateLocaleResources(LocaleResourcesBuilder builder) builder.AddOrUpdate("Admin.System.Warnings.NoShipmentItems", "No shipment items", "Keine Versand-Artikel"); + + builder.AddOrUpdate("Admin.System.Warnings.DigitsOnly", + "Please enter digits only.", + "Bitte nur Ziffern eingeben."); } } } diff --git a/src/Plugins/SmartStore.GoogleMerchantCenter/Controllers/FeedGoogleMerchantCenterController.cs b/src/Plugins/SmartStore.GoogleMerchantCenter/Controllers/FeedGoogleMerchantCenterController.cs index 74b368fe98..6c37461c87 100644 --- a/src/Plugins/SmartStore.GoogleMerchantCenter/Controllers/FeedGoogleMerchantCenterController.cs +++ b/src/Plugins/SmartStore.GoogleMerchantCenter/Controllers/FeedGoogleMerchantCenterController.cs @@ -36,21 +36,31 @@ public ActionResult ProductEditTab(int productId) var culture = CultureInfo.InvariantCulture; var model = new GoogleProductModel { ProductId = productId }; var entity = _googleFeedService.GetGoogleProductRecord(productId); + string notSpecified = T("Common.Unspecified"); if (entity != null) { model.Taxonomy = entity.Taxonomy; model.Gender = entity.Gender; model.AgeGroup = entity.AgeGroup; + model.IsAdult = entity.IsAdult; model.Color = entity.Color; model.Size = entity.Size; model.Material = entity.Material; model.Pattern = entity.Pattern; - model.Exporting = entity.Export; + model.Export2 = entity.Export; + model.Multipack2 = entity.Multipack; + model.IsBundle = entity.IsBundle; + model.EnergyEfficiencyClass = entity.EnergyEfficiencyClass; + model.CustomLabel0 = entity.CustomLabel0; + model.CustomLabel1 = entity.CustomLabel1; + model.CustomLabel2 = entity.CustomLabel2; + model.CustomLabel3 = entity.CustomLabel3; + model.CustomLabel4 = entity.CustomLabel4; } else { - model.Exporting = true; + model.Export2 = true; } ViewBag.DefaultCategory = ""; @@ -58,8 +68,13 @@ public ActionResult ProductEditTab(int productId) ViewBag.DefaultSize = ""; ViewBag.DefaultMaterial = ""; ViewBag.DefaultPattern = ""; - ViewBag.DefaultGender = T("Common.Auto"); - ViewBag.DefaultAgeGroup = T("Common.Auto"); + ViewBag.DefaultGender = notSpecified; + ViewBag.DefaultAgeGroup = notSpecified; + ViewBag.DefaultIsAdult = ""; + ViewBag.DefaultMultipack2 = ""; + ViewBag.DefaultIsBundle = ""; + ViewBag.DefaultEnergyEfficiencyClass = notSpecified; + ViewBag.DefaultCustomLabel = ""; // we do not have export profile context here, so we simply use the first profile var profile = _exportService.GetExportProfilesBySystemName(GmcXmlExportProvider.SystemName).FirstOrDefault(); @@ -99,6 +114,11 @@ public ActionResult ProductEditTab(int productId) new SelectListItem { Value = "kids", Text = T("Plugins.Feed.Froogle.AgeGroupKids") }, }; + ViewBag.AvailableEnergyEfficiencyClasses = T("Plugins.Feed.Froogle.EnergyEfficiencyClasses").Text + .SplitSafe(",") + .Select(x => new SelectListItem { Value = x, Text = x }) + .ToList(); + var result = PartialView(model); result.ViewData.TemplateInfo = new TemplateInfo { HtmlFieldPrefix = "CustomProperties[GMC]" }; return result; @@ -114,8 +134,9 @@ public ActionResult Configure() { var model = new FeedGoogleMerchantCenterModel(); - model.AvailableGoogleCategories = _googleFeedService.GetTaxonomyList(); model.GridPageSize = _adminAreaSettings.GridPageSize; + model.AvailableGoogleCategories = _googleFeedService.GetTaxonomyList(); + model.EnergyEfficiencyClasses = T("Plugins.Feed.Froogle.EnergyEfficiencyClasses").Text.SplitSafe(","); return View(model); } diff --git a/src/Plugins/SmartStore.GoogleMerchantCenter/Data/GoogleProductRecordMap.cs b/src/Plugins/SmartStore.GoogleMerchantCenter/Data/GoogleProductRecordMap.cs index 5b4e0817ab..98aaec1aa4 100644 --- a/src/Plugins/SmartStore.GoogleMerchantCenter/Data/GoogleProductRecordMap.cs +++ b/src/Plugins/SmartStore.GoogleMerchantCenter/Data/GoogleProductRecordMap.cs @@ -9,6 +9,14 @@ public GoogleProductRecordMap() { this.ToTable("GoogleProduct"); this.HasKey(x => x.Id); - } + + this.Property(x => x.EnergyEfficiencyClass).HasMaxLength(50); + + this.Property(x => x.CustomLabel0).HasMaxLength(100); + this.Property(x => x.CustomLabel1).HasMaxLength(100); + this.Property(x => x.CustomLabel2).HasMaxLength(100); + this.Property(x => x.CustomLabel3).HasMaxLength(100); + this.Property(x => x.CustomLabel4).HasMaxLength(100); + } } } \ No newline at end of file diff --git a/src/Plugins/SmartStore.GoogleMerchantCenter/Data/Migrations/201601061649324_IsBundle.Designer.cs b/src/Plugins/SmartStore.GoogleMerchantCenter/Data/Migrations/201601061649324_IsBundle.Designer.cs new file mode 100644 index 0000000000..652bba012c --- /dev/null +++ b/src/Plugins/SmartStore.GoogleMerchantCenter/Data/Migrations/201601061649324_IsBundle.Designer.cs @@ -0,0 +1,29 @@ +// +namespace SmartStore.GoogleMerchantCenter.Data.Migrations +{ + using System.CodeDom.Compiler; + using System.Data.Entity.Migrations; + using System.Data.Entity.Migrations.Infrastructure; + using System.Resources; + + [GeneratedCode("EntityFramework.Migrations", "6.1.3-40302")] + public sealed partial class IsBundle : IMigrationMetadata + { + private readonly ResourceManager Resources = new ResourceManager(typeof(IsBundle)); + + string IMigrationMetadata.Id + { + get { return "201601061649324_IsBundle"; } + } + + string IMigrationMetadata.Source + { + get { return null; } + } + + string IMigrationMetadata.Target + { + get { return Resources.GetString("Target"); } + } + } +} diff --git a/src/Plugins/SmartStore.GoogleMerchantCenter/Data/Migrations/201601061649324_IsBundle.cs b/src/Plugins/SmartStore.GoogleMerchantCenter/Data/Migrations/201601061649324_IsBundle.cs new file mode 100644 index 0000000000..bc8af7c35e --- /dev/null +++ b/src/Plugins/SmartStore.GoogleMerchantCenter/Data/Migrations/201601061649324_IsBundle.cs @@ -0,0 +1,34 @@ +namespace SmartStore.GoogleMerchantCenter.Data.Migrations +{ + using System; + using System.Data.Entity.Migrations; + + public partial class IsBundle : DbMigration + { + public override void Up() + { + AddColumn("dbo.GoogleProduct", "Multipack", c => c.Int(nullable: false)); + AddColumn("dbo.GoogleProduct", "IsBundle", c => c.Boolean()); + AddColumn("dbo.GoogleProduct", "IsAdult", c => c.Boolean()); + AddColumn("dbo.GoogleProduct", "EnergyEfficiencyClass", c => c.String(maxLength: 50)); + AddColumn("dbo.GoogleProduct", "CustomLabel0", c => c.String(maxLength: 100)); + AddColumn("dbo.GoogleProduct", "CustomLabel1", c => c.String(maxLength: 100)); + AddColumn("dbo.GoogleProduct", "CustomLabel2", c => c.String(maxLength: 100)); + AddColumn("dbo.GoogleProduct", "CustomLabel3", c => c.String(maxLength: 100)); + AddColumn("dbo.GoogleProduct", "CustomLabel4", c => c.String(maxLength: 100)); + } + + public override void Down() + { + DropColumn("dbo.GoogleProduct", "CustomLabel4"); + DropColumn("dbo.GoogleProduct", "CustomLabel3"); + DropColumn("dbo.GoogleProduct", "CustomLabel2"); + DropColumn("dbo.GoogleProduct", "CustomLabel1"); + DropColumn("dbo.GoogleProduct", "CustomLabel0"); + DropColumn("dbo.GoogleProduct", "EnergyEfficiencyClass"); + DropColumn("dbo.GoogleProduct", "IsAdult"); + DropColumn("dbo.GoogleProduct", "IsBundle"); + DropColumn("dbo.GoogleProduct", "Multipack"); + } + } +} diff --git a/src/Plugins/SmartStore.GoogleMerchantCenter/Data/Migrations/201601061649324_IsBundle.resx b/src/Plugins/SmartStore.GoogleMerchantCenter/Data/Migrations/201601061649324_IsBundle.resx new file mode 100644 index 0000000000..ebf95a7c54 --- /dev/null +++ b/src/Plugins/SmartStore.GoogleMerchantCenter/Data/Migrations/201601061649324_IsBundle.resx @@ -0,0 +1,126 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + H4sIAAAAAAAEAM2a227jNhCG7wv0HQRdtUDW8iEF2sDeReIki6BxHETJ3tPS2FGXIlWSCuy+Wi/6SH2Fjs6iJNuSHQe9s0fkNwdS1K+x//37n/GXtU+NNxDS42xiDnp90wDmcNdjq4kZquWnX80vn3/8YXzj+mvjWzZuFI3DmUxOzFelggvLks4r+ET2fM8RXPKl6jnct4jLrWG//5s1GFiACBNZhjF+CpnyfIi/4NcpZw4EKiR0xl2gMrXjFTumGg/EBxkQByam7ROhbMUF9L5yvqIwA+G8EqamwBSI3jVRxDQuqUcwNhvo0jQIY1wRhZFfvEiwleBsZQdoIPR5EwCOWxIqIc3oohjeNrn+MErOKiZmKCeUivsdgYNRWi2rOv2gmpt5NbGeN1h3tYmyjms6MZMaPgruho56AocL1zSqfi+mVERzWlQfp3ms10A9M/bMPcu317A37PV7/TNjGlIVCpgwCJUg9Mx4DBfUc36HzTP/DmzCQkrL6WGCeE0zoAnDCECozRMs06TvMEdLn2dVJ+bTSnOSGtwxNRqaxgM6JwsK+e4p1SvO8iswEESB+0gU5sciBsT1r3mv+EoLt9/lbswzWXPG/U1GwZ2Pt7VpzMj6HthKvU5M/Ggat94a3MySkl+Yh6cATlIi3OsIM3VBnNzN5Qq+Ch4GJ3c05ZSfPh3b+wtO7mSGG1DgQXdyR+kmP7mfOwV+vAuKu+N0vuQzD/GMzT1dcU6BsM534lRAdBDM2YtyMhY+qOAZH4KdYS+B+36wm3XAhTo2vxke1B4+n78fd2DdyauQuRRq4eybduliAB1n3eDpvNrcLJee46Hk2UwpkXLHlvql/x4nS/xkvScLoP0dvgb9d3Y2+Ehnw490NvpIZ+fv7GxsFYKsLtNQFitUUyCatNp88Qc4KhoCa9Ug2VDppqpNpp71JBMXNqjtQhDvhiK8REw3KbvmlPLgCzFvJWo+U/3WFtk/npEgwOqWXgNSi2En7wDTT3Z3KewnDMuRDYo4jzb3hAqOrKByNZIGLtx6QqroPWNBovWdun5t2I6l2rIMmeMdq1EVtsXiZJOjz6m4aPGa1LiYFSdF8W+xHj5OjksDedzNrxA1SvwuRygRDbIa5Vbos23SfNfsklAuQ0rm9qxCLZdRhbU9KZPDZU5ma08p1G6ZU1jbk1I5W8akpvaMRKyWEYmlPaFQomVKYe2w6pnU1NY8M7bnaFJS24TlCx14hVzUaIW5w5ppilFbOu1Ke6IuG8tE/Up7YqYdy6zM1mFfFNpR2xiFucsKZAJSX4DM2oWUakodlBo71KhZZWolax7SYa9oolLbK9qVg4iDrcTBgcThVuLwQOJoK3F0IPF8K/G8iTi2Kg/J6qPaqj2rK+2nqg7YpaiqQ3LvubKqKKhxqmb2d1dr8iYZYhpYqjfPjaSNvZF4PCYCwv6TTiluWlUMmBHmLUGqpENnDvuDYaUd+/9pjVpSurR7f/TDO45eVOC9PcWOL9u1JmPs5cgWI3sjkcwUP/lk/XOZ1r2NeBSq2io8Cqa1A48ilVt+R4Gqbb2jYJXW3VGshvbccbxqC27hdd+lTe23SPKo92q/HQzT22+H5FZrvR1yG1cbb5VA2i2U1oQ7gLCzIZdtolpLruOt3NB/a0TH3ZyD2YMTsocnZI9OyD4/jt2tVVZv03TufrVtfiUKCc+ABccMk/C1gQf3x+qqbWyVfzkfX4P0VgUi+h2dgRPJoQKajbljS54tDuZdjigbUj1ZQBE82MilUN6SOAovOyBl3Pf8RmgY3bL+Atw7Ng9VEKpLKcFfUK1VMrZ2+4+bgHrM43kQfZPvkQKG6UVn85xdhR5187hv64fiNkS0k1LVhVHZKlJfq01OeuCsJSgt3zUEkcxh6hn8gCJMzplN3uCQ2F4k3MOKOJtMfG+H7F8Ivezja4+sBPFlyijmR/8GsaK/g3z+D2Zr4jJAIgAA + + + dbo + + \ No newline at end of file diff --git a/src/Plugins/SmartStore.GoogleMerchantCenter/Description.txt b/src/Plugins/SmartStore.GoogleMerchantCenter/Description.txt index 043c9f3476..55dfd4845a 100644 --- a/src/Plugins/SmartStore.GoogleMerchantCenter/Description.txt +++ b/src/Plugins/SmartStore.GoogleMerchantCenter/Description.txt @@ -1,7 +1,7 @@ FriendlyName: Google Merchant Center (GMC) feed SystemName: SmartStore.GoogleMerchantCenter Group: Marketing -Version: 2.2.0.4 +Version: 2.2.0.5 MinAppVersion: 2.2.0 Author: SmartStore AG DisplayOrder: 1 diff --git a/src/Plugins/SmartStore.GoogleMerchantCenter/Domain/GoogleProductRecord.cs b/src/Plugins/SmartStore.GoogleMerchantCenter/Domain/GoogleProductRecord.cs index cca0f73827..7064e84880 100644 --- a/src/Plugins/SmartStore.GoogleMerchantCenter/Domain/GoogleProductRecord.cs +++ b/src/Plugins/SmartStore.GoogleMerchantCenter/Domain/GoogleProductRecord.cs @@ -29,5 +29,16 @@ public GoogleProductRecord() public DateTime UpdatedOnUtc { get; set; } public bool Export { get; set; } - } + + public int Multipack { get; set; } + public bool? IsBundle { get; set; } + public bool? IsAdult { get; set; } + public string EnergyEfficiencyClass { get; set; } + + public string CustomLabel0 { get; set; } + public string CustomLabel1 { get; set; } + public string CustomLabel2 { get; set; } + public string CustomLabel3 { get; set; } + public string CustomLabel4 { get; set; } + } } \ No newline at end of file diff --git a/src/Plugins/SmartStore.GoogleMerchantCenter/Events.cs b/src/Plugins/SmartStore.GoogleMerchantCenter/Events.cs index 3673c52c20..ea0bd90c3a 100644 --- a/src/Plugins/SmartStore.GoogleMerchantCenter/Events.cs +++ b/src/Plugins/SmartStore.GoogleMerchantCenter/Events.cs @@ -10,8 +10,7 @@ namespace SmartStore.GoogleMerchantCenter { public class Events : IConsumer, - IConsumer/*, - IConsumer*/ + IConsumer { private readonly IGoogleFeedService _googleService; @@ -25,6 +24,7 @@ public void HandleEvent(TabStripCreated eventMessage) if (eventMessage.TabStripName == "product-edit") { var productId = ((TabbableModel)eventMessage.Model).Id; + eventMessage.ItemFactory.Add().Text("GMC") .Name("tab-gmc") .Icon("fa fa-google fa-lg fa-fw") @@ -34,30 +34,6 @@ public void HandleEvent(TabStripCreated eventMessage) } } - //public void HandleEvent(RowExportingEvent eventMessage) - //{ - // if (eventMessage.EntityType != ExportEntityType.Product) - // return; - - // var row = eventMessage.Row; - // var product = eventMessage.Row.Entity as Product; - - // if (product == null) - // return; - - // var gmc = _googleService.GetGoogleProductRecord(product.Id); - // if (gmc == null) - // return; - - // row["_GMC_AgeGroup"] = gmc.AgeGroup; - // row["_GMC_Color"] = gmc.Color; - // row["_GMC_Gender"] = gmc.Gender; - // row["_GMC_Size"] = gmc.Size; - // row["_GMC_Taxonomy"] = gmc.Taxonomy; - // row["_GMC_Material"] = gmc.Material; - // row["_GMC_Pattern"] = gmc.Pattern; - //} - public void HandleEvent(ModelBoundEvent eventMessage) { if (!eventMessage.BoundModel.CustomProperties.ContainsKey("GMC")) @@ -88,8 +64,17 @@ public void HandleEvent(ModelBoundEvent eventMessage) entity.Taxonomy = model.Taxonomy; entity.Material = model.Material; entity.Pattern = model.Pattern; - entity.Export = model.Exporting; + entity.Export = model.Export2; entity.UpdatedOnUtc = utcNow; + entity.Multipack = model.Multipack2 ?? 0; + entity.IsBundle = model.IsBundle; + entity.IsAdult = model.IsAdult; + entity.EnergyEfficiencyClass = model.EnergyEfficiencyClass; + entity.CustomLabel0 = model.CustomLabel0; + entity.CustomLabel1 = model.CustomLabel1; + entity.CustomLabel2 = model.CustomLabel2; + entity.CustomLabel3 = model.CustomLabel3; + entity.CustomLabel4 = model.CustomLabel4; entity.IsTouched = entity.IsTouched(); diff --git a/src/Plugins/SmartStore.GoogleMerchantCenter/Extensions/MiscExtensions.cs b/src/Plugins/SmartStore.GoogleMerchantCenter/Extensions/MiscExtensions.cs index c140111c1e..5a8dd0168d 100644 --- a/src/Plugins/SmartStore.GoogleMerchantCenter/Extensions/MiscExtensions.cs +++ b/src/Plugins/SmartStore.GoogleMerchantCenter/Extensions/MiscExtensions.cs @@ -9,7 +9,7 @@ public static string XEditableLink(this HtmlHelper hlp, string fieldName, string { string displayText = null; - if (fieldName == "Gender" || fieldName == "AgeGroup" || fieldName == "Exporting") + if (fieldName == "Gender" || fieldName == "AgeGroup" || fieldName == "Export2" || fieldName == "IsBundle" || fieldName == "IsAdult") displayText = "<#= {0}Localize #>".FormatInvariant(fieldName); else displayText = "<#= {0} #>".FormatInvariant(fieldName); @@ -22,12 +22,15 @@ public static string XEditableLink(this HtmlHelper hlp, string fieldName, string return skeleton.FormatInvariant(fieldName, fieldName.ToLower(), type, displayText); } - public static bool IsTouched(this GoogleProductRecord product) + public static bool IsTouched(this GoogleProductRecord p) { - if (product != null) + if (p != null) { - return product.Taxonomy.HasValue() || product.Gender.HasValue() || product.AgeGroup.HasValue() || product.Color.HasValue() || - product.Size.HasValue() || product.Material.HasValue() || product.Pattern.HasValue() || product.ItemGroupId.HasValue() || !product.Export; + return + p.Taxonomy.HasValue() || p.Gender.HasValue() || p.AgeGroup.HasValue() || p.Color.HasValue() || + p.Size.HasValue() || p.Material.HasValue() || p.Pattern.HasValue() || p.ItemGroupId.HasValue() || + !p.Export || p.Multipack != 0 || p.IsBundle.HasValue || p.IsAdult.HasValue || p.EnergyEfficiencyClass.HasValue() || + p.CustomLabel0.HasValue() || p.CustomLabel1.HasValue() || p.CustomLabel2.HasValue() || p.CustomLabel3.HasValue() || p.CustomLabel4.HasValue(); } return false; } diff --git a/src/Plugins/SmartStore.GoogleMerchantCenter/Localization/resources.de-de.xml b/src/Plugins/SmartStore.GoogleMerchantCenter/Localization/resources.de-de.xml index e4aa14c576..17b90e856c 100644 --- a/src/Plugins/SmartStore.GoogleMerchantCenter/Localization/resources.de-de.xml +++ b/src/Plugins/SmartStore.GoogleMerchantCenter/Localization/resources.de-de.xml @@ -37,24 +37,9 @@ Google-Kategorie - - Geschlecht - - - Altersgruppe - - - Farbe - - - Größe - - - Material - - - Muster - + + Legt die dem Artikel entsprechende Google-Kategorie fest. Zwingend erforderlich. + Zusätzliche Bilder @@ -148,12 +133,6 @@ Muster oder grafisches Druckdesign eines Produktes. Angabe ist z.B. bei Bekleidung sinnvoll. - - Nur online zu kaufen - - - Legt fest, ob Produkte nur online erworben werden können. Aktivieren Sie diese Option nicht, falls Produkte auch in Ihrem Ladengeschäft erhältlich sind. - Leer @@ -196,4 +175,61 @@ Legt fest, ob der Grundpreis eines Produktes exportiert werden soll. + + Multipack + + + Anzahl identischer Produkte in einem händlerdefinierten Multipack. Muss größer 1 sein. + + + Bundle + + + Händlerdefiniertes Produktpaket bestehend aus einem Haupt- und mehreren Zubehörartikel bzw. Add-ons. + + + Nicht jugendfrei + + + Produkt, welches nur für erwachsene Nutzer bestimmt ist. + + + Energieeffizienz + + + Die Energieeffizienzklasse des Produktes gemäß EU-Richtlinie 2010/30/EU. Mögliche Werte sind G, F, E, D, C, B, A, A+, A++, A+++. + + + A+++,A++,A+,A,B,C,D,E,F,G + + + Label 0 + + + Benutzerdefiniertes Label 0. Dient der individuellen Gruppierung von Produkten. + + + Label 1 + + + Benutzerdefiniertes Label 1. Dient der individuellen Gruppierung von Produkten. + + + Label 2 + + + Benutzerdefiniertes Label 2. Dient der individuellen Gruppierung von Produkten. + + + Label 3 + + + Benutzerdefiniertes Label 3. Dient der individuellen Gruppierung von Produkten. + + + Label 4 + + + Benutzerdefiniertes Label 4. Dient der individuellen Gruppierung von Produkten. + \ No newline at end of file diff --git a/src/Plugins/SmartStore.GoogleMerchantCenter/Localization/resources.en-us.xml b/src/Plugins/SmartStore.GoogleMerchantCenter/Localization/resources.en-us.xml index a80721be22..3b75a8c306 100644 --- a/src/Plugins/SmartStore.GoogleMerchantCenter/Localization/resources.en-us.xml +++ b/src/Plugins/SmartStore.GoogleMerchantCenter/Localization/resources.en-us.xml @@ -37,24 +37,9 @@ Google Category - - Gender - - - Age group - - - Color - - - Size - - - Material - - - Pattern - + + Specifies the Google category corresponding to the product. Mandatory. + Additional images @@ -148,12 +133,6 @@ The pattern or graphic print featured on a product. Usefull for clothes for instance. - - Only online available - - - Check the box if products can only be purchased online. - Empty @@ -196,4 +175,61 @@ Activate this option if you want to export the base price of the product. + + Multipack + + + Number of identical products in a merchant defined multipack. Must be greater than 1. + + + Bundle + + + Merchant defined product package consisting of one main and several accessories or add-ons. + + + Adult + + + Product, which is intended only for adult users. + + + Energy efficiency + + + The energy efficiency class of the product in accordance with EU directive 2010/30/EU. Possible values are G, F, E, D, C, B, A, A +, A++, A+++. + + + A+++,A++,A+,A,B,C,D,E,F,G + + + Label 0 + + + Custom label 0 serves the individual grouping of products. + + + Label 1 + + + Custom label 1 serves the individual grouping of products. + + + Label 2 + + + Custom label 2 serves the individual grouping of products. + + + Label 3 + + + Custom label 3 serves the individual grouping of products. + + + Label 4 + + + Custom label 4 serves the individual grouping of products. + \ No newline at end of file diff --git a/src/Plugins/SmartStore.GoogleMerchantCenter/Models/FeedGoogleMerchantCenterModel.cs b/src/Plugins/SmartStore.GoogleMerchantCenter/Models/FeedGoogleMerchantCenterModel.cs index 0ec41770fe..36c5f02799 100644 --- a/src/Plugins/SmartStore.GoogleMerchantCenter/Models/FeedGoogleMerchantCenterModel.cs +++ b/src/Plugins/SmartStore.GoogleMerchantCenter/Models/FeedGoogleMerchantCenterModel.cs @@ -1,5 +1,6 @@ using System.ComponentModel; using System.ComponentModel.DataAnnotations; +using System.Text; using Newtonsoft.Json; using SmartStore.Core.Domain.Catalog; using SmartStore.Web.Framework; @@ -18,10 +19,12 @@ public string AvailableGoogleCategoriesAsJson { if (AvailableGoogleCategories != null && AvailableGoogleCategories.Length > 0) return JsonConvert.SerializeObject(AvailableGoogleCategories); - return ""; + return "[ ]"; } } + public string[] EnergyEfficiencyClasses { get; set; } + [SmartResourceDisplayName("Plugins.Feed.Froogle.SearchProductName")] public string SearchProductName { get; set; } @@ -29,7 +32,6 @@ public string AvailableGoogleCategoriesAsJson public string SearchIsTouched { get; set; } } - public class GoogleProductModel : ModelBase { public int TotalCount { get; set; } @@ -74,35 +76,66 @@ public string ProductTypeLabelHint [SmartResourceDisplayName("Plugins.Feed.Froogle.Products.GoogleCategory")] public string Taxonomy { get; set; } - [SmartResourceDisplayName("Plugins.Feed.Froogle.Products.Gender")] + [SmartResourceDisplayName("Plugins.Feed.Froogle.Gender")] public string Gender { get; set; } - [SmartResourceDisplayName("Plugins.Feed.Froogle.Products.AgeGroup")] + [SmartResourceDisplayName("Plugins.Feed.Froogle.AgeGroup")] public string AgeGroup { get; set; } - [SmartResourceDisplayName("Plugins.Feed.Froogle.Products.Color")] + [SmartResourceDisplayName("Plugins.Feed.Froogle.Color")] public string Color { get; set; } - [SmartResourceDisplayName("Plugins.Feed.Froogle.Products.Size")] + [SmartResourceDisplayName("Plugins.Feed.Froogle.Size")] public string Size { get; set; } - [SmartResourceDisplayName("Plugins.Feed.Froogle.Products.Material")] + [SmartResourceDisplayName("Plugins.Feed.Froogle.Material")] public string Material { get; set; } - [SmartResourceDisplayName("Plugins.Feed.Froogle.Products.Pattern")] + [SmartResourceDisplayName("Plugins.Feed.Froogle.Pattern")] public string Pattern { get; set; } [SmartResourceDisplayName("Common.Export")] public int Export { get; set; } [SmartResourceDisplayName("Common.Export")] - public bool Exporting + public bool Export2 { get { return Export != 0; } set { Export = (value ? 1 : 0); } } + [SmartResourceDisplayName("Plugins.Feed.Froogle.Multipack")] + public int Multipack { get; set; } + [SmartResourceDisplayName("Plugins.Feed.Froogle.Multipack")] + public int? Multipack2 + { + get { return Multipack > 0 ? Multipack : (int?)null; } + set { Multipack = (value ?? 0); } + } + + [SmartResourceDisplayName("Plugins.Feed.Froogle.IsBundle")] + public bool? IsBundle { get; set; } + + [SmartResourceDisplayName("Plugins.Feed.Froogle.IsAdult")] + public bool? IsAdult { get; set; } + + [SmartResourceDisplayName("Plugins.Feed.Froogle.EnergyEfficiencyClass")] + public string EnergyEfficiencyClass { get; set; } + + [SmartResourceDisplayName("Plugins.Feed.Froogle.CustomLabel0")] + public string CustomLabel0 { get; set; } + [SmartResourceDisplayName("Plugins.Feed.Froogle.CustomLabel1")] + public string CustomLabel1 { get; set; } + [SmartResourceDisplayName("Plugins.Feed.Froogle.CustomLabel2")] + public string CustomLabel2 { get; set; } + [SmartResourceDisplayName("Plugins.Feed.Froogle.CustomLabel3")] + public string CustomLabel3 { get; set; } + [SmartResourceDisplayName("Plugins.Feed.Froogle.CustomLabel4")] + public string CustomLabel4 { get; set; } + public string GenderLocalize { get; set; } public string AgeGroupLocalize { get; set; } - public string ExportingLocalize { get; set; } + public string Export2Localize { get; set; } + public string IsBundleLocalize { get; set; } + public string IsAdultLocalize { get; set; } } } \ No newline at end of file diff --git a/src/Plugins/SmartStore.GoogleMerchantCenter/Models/ProfileConfigurationModel.cs b/src/Plugins/SmartStore.GoogleMerchantCenter/Models/ProfileConfigurationModel.cs index 6b96944375..69d81d50dd 100644 --- a/src/Plugins/SmartStore.GoogleMerchantCenter/Models/ProfileConfigurationModel.cs +++ b/src/Plugins/SmartStore.GoogleMerchantCenter/Models/ProfileConfigurationModel.cs @@ -14,7 +14,6 @@ public class ProfileConfigurationModel public ProfileConfigurationModel() { Condition = "new"; - OnlineOnly = true; AdditionalImages = true; SpecialPrice = true; } @@ -66,9 +65,6 @@ public string AvailableGoogleCategoriesAsJson [SmartResourceDisplayName("Plugins.Feed.Froogle.Pattern")] public string Pattern { get; set; } - [SmartResourceDisplayName("Plugins.Feed.Froogle.OnlineOnly")] - public bool OnlineOnly { get; set; } - [SmartResourceDisplayName("Plugins.Feed.Froogle.ExpirationDays")] public int ExpirationDays { get; set; } diff --git a/src/Plugins/SmartStore.GoogleMerchantCenter/Providers/GmcXmlExportProvider.cs b/src/Plugins/SmartStore.GoogleMerchantCenter/Providers/GmcXmlExportProvider.cs index b43d2abe70..3a5cc536f6 100644 --- a/src/Plugins/SmartStore.GoogleMerchantCenter/Providers/GmcXmlExportProvider.cs +++ b/src/Plugins/SmartStore.GoogleMerchantCenter/Providers/GmcXmlExportProvider.cs @@ -157,6 +157,7 @@ protected override void Export(IExportExecuteContext context) { dynamic currency = context.Currency; string measureWeightSystemKey = ""; + var dateFormat = "yyyy-MM-ddTHH:mmZ"; var measureWeight = _measureService.GetMeasureWeightById(_measureSettings.BaseWeightId); @@ -287,9 +288,15 @@ protected override void Export(IExportExecuteContext context) writer.WriteElementString("g", "condition", _googleNamespace, condition); writer.WriteElementString("g", "availability", _googleNamespace, availability); + if (availability == "preorder" && entity.AvailableStartDateTimeUtc.HasValue && entity.AvailableStartDateTimeUtc.Value > DateTime.UtcNow) + { + var availabilityDate = entity.AvailableStartDateTimeUtc.Value.ToString(dateFormat); + + writer.WriteElementString("g", "availability_date", _googleNamespace, availabilityDate); + } + if (config.SpecialPrice && specialPrice.HasValue && entity.SpecialPriceStartDateTimeUtc.HasValue && entity.SpecialPriceEndDateTimeUtc.HasValue) { - var dateFormat = "yyyy-MM-ddTHH:mmZ"; var specialPriceDate = "{0}/{1}".FormatInvariant( entity.SpecialPriceStartDateTimeUtc.Value.ToString(dateFormat), entity.SpecialPriceEndDateTimeUtc.Value.ToString(dateFormat)); @@ -321,7 +328,6 @@ protected override void Export(IExportExecuteContext context) writer.WriteCData("pattern", gmc != null && gmc.Pattern.HasValue() ? gmc.Pattern : config.Pattern, "g", _googleNamespace); writer.WriteCData("item_group_id", gmc != null && gmc.ItemGroupId.HasValue() ? gmc.ItemGroupId : "", "g", _googleNamespace); - writer.WriteElementString("g", "online_only", _googleNamespace, config.OnlineOnly ? "y" : "n"); writer.WriteElementString("g", "identifier_exists", _googleNamespace, gtin.HasValue() || brand.HasValue() || mpn.HasValue() ? "TRUE" : "FALSE"); if (config.ExpirationDays > 0) @@ -360,11 +366,56 @@ protected override void Export(IExportExecuteContext context) } } + if (gmc != null && gmc.Multipack > 1) + { + writer.WriteElementString("g", "multipack", _googleNamespace, gmc.Multipack.ToString()); + } + + if (gmc != null && gmc.IsBundle.HasValue) + { + writer.WriteElementString("g", "is_bundle", _googleNamespace, gmc.IsBundle.Value ? "TRUE" : "FALSE"); + } + + if (gmc != null && gmc.IsAdult.HasValue) + { + writer.WriteElementString("g", "adult", _googleNamespace, gmc.IsAdult.Value ? "TRUE" : "FALSE"); + } + + if (gmc != null && gmc.EnergyEfficiencyClass.HasValue()) + { + writer.WriteElementString("g", "energy_efficiency_class", _googleNamespace, gmc.EnergyEfficiencyClass); + } + + if (gmc != null && gmc.CustomLabel0.HasValue()) + { + writer.WriteElementString("g", "custom_label_0", _googleNamespace, gmc.CustomLabel0); + } + + if (gmc != null && gmc.CustomLabel1.HasValue()) + { + writer.WriteElementString("g", "custom_label_1", _googleNamespace, gmc.CustomLabel1); + } + + if (gmc != null && gmc.CustomLabel2.HasValue()) + { + writer.WriteElementString("g", "custom_label_2", _googleNamespace, gmc.CustomLabel2); + } + + if (gmc != null && gmc.CustomLabel3.HasValue()) + { + writer.WriteElementString("g", "custom_label_3", _googleNamespace, gmc.CustomLabel3); + } + + if (gmc != null && gmc.CustomLabel4.HasValue()) + { + writer.WriteElementString("g", "custom_label_4", _googleNamespace, gmc.CustomLabel4); + } + ++context.RecordsSucceeded; } - catch (Exception exc) + catch (Exception exception) { - context.RecordException(exc, entity.Id); + context.RecordException(exception, entity.Id); } writer.WriteEndElement(); // item diff --git a/src/Plugins/SmartStore.GoogleMerchantCenter/Services/GoogleFeedService.cs b/src/Plugins/SmartStore.GoogleMerchantCenter/Services/GoogleFeedService.cs index 48d574215e..b5fab3af04 100644 --- a/src/Plugins/SmartStore.GoogleMerchantCenter/Services/GoogleFeedService.cs +++ b/src/Plugins/SmartStore.GoogleMerchantCenter/Services/GoogleFeedService.cs @@ -125,9 +125,36 @@ public void Upsert(int pk, string name, string value) case "Pattern": product.Pattern = value; break; - case "Exporting": + case "Export2": product.Export = value.ToBool(true); break; + case "Multipack2": + product.Multipack = value.ToInt(); + break; + case "IsBundle": + product.IsBundle = (value.IsEmpty() ? (bool?)null : value.ToBool()); + break; + case "IsAdult": + product.IsAdult = (value.IsEmpty() ? (bool?)null : value.ToBool()); + break; + case "EnergyEfficiencyClass": + product.EnergyEfficiencyClass = value; + break; + case "CustomLabel0": + product.CustomLabel0 = value; + break; + case "CustomLabel1": + product.CustomLabel1 = value; + break; + case "CustomLabel2": + product.CustomLabel2 = value; + break; + case "CustomLabel3": + product.CustomLabel3 = value; + break; + case "CustomLabel4": + product.CustomLabel4 = value; + break; } product.UpdatedOnUtc = utcNow; @@ -156,7 +183,8 @@ public GridModel GetGridModel(GridCommand command, string se string yes = T("Admin.Common.Yes"); string no = T("Admin.Common.No"); - // there's no way to share a context instance across repositories which makes GoogleProductObjectContext pretty useless here. + // there's no way to share a context instance across repositories in EF. + // so we have to fallback to pure SQL here to get the data paged and filtered. var whereClause = new StringBuilder("(NOT ([t2].[Deleted] = 1)) AND ([t2].[VisibleIndividually] = 1)"); @@ -181,11 +209,11 @@ public GridModel GetGridModel(GridCommand command, string se { // fastest possible paged data query sql = - "SELECT [TotalCount], [t3].[Id], [t3].[Name], [t3].[SKU], [t3].[ProductTypeId], [t3].[value] AS [Taxonomy], [t3].[value2] AS [Gender], [t3].[value3] AS [AgeGroup], [t3].[value4] AS [Color], [t3].[value5] AS [Size], [t3].[value6] AS [Material], [t3].[value7] AS [Pattern], [t3].[value8] AS [Export]" + + "SELECT [TotalCount], [t3].[Id], [t3].[Name], [t3].[SKU], [t3].[ProductTypeId], [t3].[value] AS [Taxonomy], [t3].[value2] AS [Gender], [t3].[value3] AS [AgeGroup], [t3].[value4] AS [Color], [t3].[value5] AS [Size], [t3].[value6] AS [Material], [t3].[value7] AS [Pattern], [t3].[value8] AS [Export], [t3].[value9] AS [Multipack], [t3].[value10] AS [IsBundle], [t3].[value11] AS [IsAdult], [t3].[value12] AS [EnergyEfficiencyClass], [t3].[value13] AS [CustomLabel0], [t3].[value14] AS [CustomLabel1], [t3].[value15] AS [CustomLabel2], [t3].[value16] AS [CustomLabel3], [t3].[value17] AS [CustomLabel4]" + " FROM (" + - " SELECT COUNT(id) OVER() [TotalCount], ROW_NUMBER() OVER (ORDER BY [t2].[Name]) AS [ROW_NUMBER], [t2].[Id], [t2].[Name], [t2].[SKU], [t2].[ProductTypeId], [t2].[value], [t2].[value2], [t2].[value3], [t2].[value4], [t2].[value5], [t2].[value6], [t2].[value7], [t2].[value8]" + + " SELECT COUNT(id) OVER() [TotalCount], ROW_NUMBER() OVER (ORDER BY [t2].[Name]) AS [ROW_NUMBER], [t2].[Id], [t2].[Name], [t2].[SKU], [t2].[ProductTypeId], [t2].[value], [t2].[value2], [t2].[value3], [t2].[value4], [t2].[value5], [t2].[value6], [t2].[value7], [t2].[value8], [t2].[value9], [t2].[value10], [t2].[value11], [t2].[value12], [t2].[value13], [t2].[value14], [t2].[value15], [t2].[value16], [t2].[value17]" + " FROM (" + - " SELECT [t0].[Id], [t0].[Name], [t0].[SKU], [t0].[ProductTypeId], [t1].[Taxonomy] AS [value], [t1].[Gender] AS [value2], [t1].[AgeGroup] AS [value3], [t1].[Color] AS [value4], [t1].[Size] AS [value5], [t1].[Material] AS [value6], [t1].[Pattern] AS [value7], COALESCE([t1].[Export],1) AS [value8], [t0].[Deleted], [t0].[VisibleIndividually], [t1].[IsTouched]" + + " SELECT [t0].[Id], [t0].[Name], [t0].[SKU], [t0].[ProductTypeId], [t1].[Taxonomy] AS [value], [t1].[Gender] AS [value2], [t1].[AgeGroup] AS [value3], [t1].[Color] AS [value4], [t1].[Size] AS [value5], [t1].[Material] AS [value6], [t1].[Pattern] AS [value7], COALESCE([t1].[Export],1) AS [value8], COALESCE([t1].[Multipack],0) AS [value9], [t1].[IsBundle] AS [value10], [t1].[IsAdult] AS [value11], [t1].[EnergyEfficiencyClass] AS [value12], [t1].[CustomLabel0] AS [value13], [t1].[CustomLabel1] AS [value14], [t1].[CustomLabel2] AS [value15], [t1].[CustomLabel3] AS [value16], [t1].[CustomLabel4] AS [value17], [t0].[Deleted], [t0].[VisibleIndividually], [t1].[IsTouched]" + " FROM [Product] AS [t0]" + " LEFT OUTER JOIN [GoogleProduct] AS [t1] ON [t0].[Id] = [t1].[ProductId]" + " ) AS [t2]" + @@ -198,9 +226,9 @@ public GridModel GetGridModel(GridCommand command, string se { // OFFSET... FETCH NEXT requires SQL Server 2012 or SQL CE 4 sql = - "SELECT [t2].[Id], [t2].[Name], [t2].[SKU], [t2].[ProductTypeId], [t2].[value] AS [Taxonomy], [t2].[value2] AS [Gender], [t2].[value3] AS [AgeGroup], [t2].[value4] AS [Color], [t2].[value5] AS [Size], [t2].[value6] AS [Material], [t2].[value7] AS [Pattern], [t2].[value8] AS [Export]" + + "SELECT [t2].[Id], [t2].[Name], [t2].[SKU], [t2].[ProductTypeId], [t2].[value] AS [Taxonomy], [t2].[value2] AS [Gender], [t2].[value3] AS [AgeGroup], [t2].[value4] AS [Color], [t2].[value5] AS [Size], [t2].[value6] AS [Material], [t2].[value7] AS [Pattern], [t2].[value8] AS [Export], [t2].[value9] AS [Multipack], [t2].[value10] AS [IsBundle], [t2].[value11] AS [IsAdult], [t2].[value12] AS [EnergyEfficiencyClass], [t2].[value13] AS [CustomLabel0], [t2].[value14] AS [CustomLabel1], [t2].[value15] AS [CustomLabel2], [t2].[value16] AS [CustomLabel3], [t2].[value17] AS [CustomLabel4]" + " FROM (" + - " SELECT [t0].[Id], [t0].[Name], [t0].[SKU], [t0].[ProductTypeId], [t1].[Taxonomy] AS [value], [t1].[Gender] AS [value2], [t1].[AgeGroup] AS [value3], [t1].[Color] AS [value4], [t1].[Size] AS [value5], [t1].[Material] AS [value6], [t1].[Pattern] AS [value7], COALESCE([t1].[Export],1) AS [value8], [t0].[Deleted], [t0].[VisibleIndividually], [t1].[IsTouched] AS [IsTouched]" + + " SELECT [t0].[Id], [t0].[Name], [t0].[SKU], [t0].[ProductTypeId], [t1].[Taxonomy] AS [value], [t1].[Gender] AS [value2], [t1].[AgeGroup] AS [value3], [t1].[Color] AS [value4], [t1].[Size] AS [value5], [t1].[Material] AS [value6], [t1].[Pattern] AS [value7], COALESCE([t1].[Export],1) AS [value8], COALESCE([t1].[Multipack],0) AS [value9], [t1].[IsBundle] AS [value10], [t1].[IsAdult] AS [value11], [t1].[EnergyEfficiencyClass] AS [value12], [t1].[CustomLabel0] AS [value13], [t1].[CustomLabel1] AS [value14], [t1].[CustomLabel2] AS [value15], [t1].[CustomLabel3] AS [value16], [t1].[CustomLabel4] AS [value17], [t0].[Deleted], [t0].[VisibleIndividually], [t1].[IsTouched] AS [IsTouched]" + " FROM [Product] AS [t0]" + " LEFT OUTER JOIN [GoogleProduct] AS [t1] ON [t0].[Id] = [t1].[ProductId]" + " ) AS [t2]" + @@ -232,7 +260,17 @@ public GridModel GetGridModel(GridCommand command, string se if (x.AgeGroup.HasValue()) x.AgeGroupLocalize = T("Plugins.Feed.Froogle.AgeGroup" + textInfo.ToTitleCase(x.AgeGroup)); - x.ExportingLocalize = (x.Export == 0 ? no : yes); + x.Export2Localize = (x.Export == 0 ? no : yes); + + if (x.IsBundle.HasValue) + x.IsBundleLocalize = (x.IsBundle.Value ? yes : no); + else + x.IsBundleLocalize = null; + + if (x.IsAdult.HasValue) + x.IsAdultLocalize = (x.IsAdult.Value ? yes : no); + else + x.IsAdultLocalize = null; }); model.Data = data; diff --git a/src/Plugins/SmartStore.GoogleMerchantCenter/SmartStore.GoogleMerchantCenter.csproj b/src/Plugins/SmartStore.GoogleMerchantCenter/SmartStore.GoogleMerchantCenter.csproj index aa2b7dca53..f027f7dd39 100644 --- a/src/Plugins/SmartStore.GoogleMerchantCenter/SmartStore.GoogleMerchantCenter.csproj +++ b/src/Plugins/SmartStore.GoogleMerchantCenter/SmartStore.GoogleMerchantCenter.csproj @@ -169,6 +169,10 @@ 201504211854125_IsActive.cs + + + 201601061649324_IsBundle.cs + @@ -218,6 +222,9 @@ 201504211854125_IsActive.cs + + 201601061649324_IsBundle.cs + diff --git a/src/Plugins/SmartStore.GoogleMerchantCenter/Views/FeedGoogleMerchantCenter/Configure.cshtml b/src/Plugins/SmartStore.GoogleMerchantCenter/Views/FeedGoogleMerchantCenter/Configure.cshtml index 6312648112..d91ec16571 100644 --- a/src/Plugins/SmartStore.GoogleMerchantCenter/Views/FeedGoogleMerchantCenter/Configure.cshtml +++ b/src/Plugins/SmartStore.GoogleMerchantCenter/Views/FeedGoogleMerchantCenter/Configure.cshtml @@ -3,7 +3,6 @@ @using SmartStore.GoogleMerchantCenter.Models; @using SmartStore.GoogleMerchantCenter.Providers; @using SmartStore.Web.Framework; -@using SmartStore.Web.Framework.Plugins; @using Telerik.Web.Mvc.UI; @using SmartStore.Web.Framework.UI; @@ -53,7 +52,8 @@ @Html.SmartLabelFor(m => m.SearchIsTouched) - @Html.DropDownList("SearchIsTouched", new List { + @Html.DropDownList("SearchIsTouched", new List + { new SelectListItem { Text = T("Common.Unspecified"), Value = "" }, new SelectListItem { Text = T("Plugins.Feed.Froogle.SearchIsTouched.Touched"), Value = "touched" }, new SelectListItem { Text = T("Plugins.Feed.Froogle.SearchIsTouched.Untouched"), Value = "untouched" } @@ -82,25 +82,56 @@ }) .Columns(c => { - c.Bound(x => x.ProductId).ReadOnly().Visible(false); + c.Bound(x => x.ProductId) + .ReadOnly() + .Visible(false); c.Bound(x => x.Name) - .ReadOnly().Visible(true).Width(420) + .ReadOnly().Visible(true) .Template(x => @Html.LabeledProductName(x.ProductId, x.Name, x.ProductTypeName, x.ProductTypeLabelHint)) .ClientTemplate(@Html.LabeledProductName("ProductId", "Name")); - c.Bound(x => x.SKU).ReadOnly().Visible(true); - c.Bound(x => x.Exporting).ClientTemplate(Html.XEditableLink("Exporting", "select2")); - c.Bound(x => x.Taxonomy).ClientTemplate(Html.XEditableLink("Taxonomy", "typeahead")); - c.Bound(x => x.Gender).ClientTemplate(Html.XEditableLink("Gender", "select2")).Width(100); - c.Bound(x => x.AgeGroup).ClientTemplate(Html.XEditableLink("AgeGroup", "select2")).Width(100); - c.Bound(x => x.Color).ClientTemplate(Html.XEditableLink("Color", "text")); - c.Bound(x => x.Size).ClientTemplate(Html.XEditableLink("Size", "text")); - c.Bound(x => x.Material).ClientTemplate(Html.XEditableLink("Material", "text")); - c.Bound(x => x.Pattern).ClientTemplate(Html.XEditableLink("Pattern", "text")); + c.Bound(x => x.SKU) + .ReadOnly() + .Visible(true); + c.Bound(x => x.Export2) + .ClientTemplate(Html.XEditableLink("Export2", "select2")); + c.Bound(x => x.Taxonomy) + .ClientTemplate(Html.XEditableLink("Taxonomy", "typeahead")); + c.Bound(x => x.Gender) + .ClientTemplate(Html.XEditableLink("Gender", "select2")); + c.Bound(x => x.AgeGroup) + .ClientTemplate(Html.XEditableLink("AgeGroup", "select2")); + c.Bound(x => x.IsAdult) + .ClientTemplate(Html.XEditableLink("IsAdult", "select2")); + c.Bound(x => x.Color) + .ClientTemplate(Html.XEditableLink("Color", "text")); + c.Bound(x => x.Size) + .ClientTemplate(Html.XEditableLink("Size", "text")); + c.Bound(x => x.Material) + .ClientTemplate(Html.XEditableLink("Material", "text")); + c.Bound(x => x.Pattern) + .ClientTemplate(Html.XEditableLink("Pattern", "text")); + c.Bound(x => x.Multipack2) + .ClientTemplate(Html.XEditableLink("Multipack2", "text")); + c.Bound(x => x.IsBundle) + .ClientTemplate(Html.XEditableLink("IsBundle", "select2")); + c.Bound(x => x.EnergyEfficiencyClass) + .ClientTemplate(Html.XEditableLink("EnergyEfficiencyClass", "select2")); + c.Bound(x => x.CustomLabel0) + .ClientTemplate(Html.XEditableLink("CustomLabel0", "text")); + c.Bound(x => x.CustomLabel1) + .ClientTemplate(Html.XEditableLink("CustomLabel1", "text")); + c.Bound(x => x.CustomLabel2) + .ClientTemplate(Html.XEditableLink("CustomLabel2", "text")); + c.Bound(x => x.CustomLabel3) + .ClientTemplate(Html.XEditableLink("CustomLabel3", "text")); + c.Bound(x => x.CustomLabel4) + .ClientTemplate(Html.XEditableLink("CustomLabel4", "text")); }) .ClientEvents(e => { e.OnDataBound("OnGridDataBound"); e.OnDataBinding("OnGridDataBinding"); + e.OnError("OnGridError"); }) .DataBinding(dataBinding => { @@ -127,6 +158,11 @@ return false; }); + function OnGridError(e) { + e.preventDefault(); + alert(e.XMLHttpRequest.responseText); + } + function OnGridDataBinding(e) { e.data = { searchProductName: $('#SearchProductName').val(), @@ -135,28 +171,32 @@ } function OnGridDataBound(e) { - var grid = $('#gmc-products-grid'), - options = { - emptytext: '@T("Plugins.Feed.Froogle.EmptyGridCell")', - url: '@Url.Action("GoogleProductEdit", "FeedGoogleMerchantCenter", new { Namespaces = "SmartStore.GoogleMerchantCenter.Controllers", area = GoogleMerchantCenterFeedPlugin.SystemName })' - }, - select2Options = { - placeholder: '@T("Plugins.Feed.Froogle.EmptyGridCell")', - minimumResultsForSearch: 20, - allowClear: true - }; + var grid = $('#gmc-products-grid'); + + var emptyCell = '@T("Plugins.Feed.Froogle.EmptyGridCell")'; + + var options = { + emptytext: emptyCell, + url: '@Url.Action("GoogleProductEdit", "FeedGoogleMerchantCenter", new { Namespaces = "SmartStore.GoogleMerchantCenter.Controllers", area = GoogleMerchantCenterFeedPlugin.SystemName })' + }; + var select2Options = { + placeholder: emptyCell, + minimumResultsForSearch: 20, + allowClear: true + }; + var boolSource = [ + { id: 'true', text: '@T("Admin.Common.Yes")' }, + { id: 'false', text: '@T("Admin.Common.No")' } + ]; - grid.find('a.edit-link-exporting').editable($.extend(options, { + grid.find('a.edit-link-export2').editable($.extend({}, options, { select2: { minimumResultsForSearch: 20 }, - source: [ - { id: 'true', text: '@T("Admin.Common.Yes")' }, - { id: 'false', text: '@T("Admin.Common.No")' } - ] + source: boolSource })); - grid.find('a.edit-link-gender').editable($.extend(options, { + grid.find('a.edit-link-gender').editable($.extend({}, options, { select2: select2Options, source: [ { id: 'male', text: '@T("Plugins.Feed.Froogle.GenderMale")' }, @@ -165,7 +205,7 @@ ] })); - grid.find('a.edit-link-agegroup').editable($.extend(options, { + grid.find('a.edit-link-agegroup').editable($.extend({}, options, { select2: select2Options, source: [ { id: 'adult', text: '@T("Plugins.Feed.Froogle.AgeGroupAdult").Text' }, @@ -173,6 +213,11 @@ ] })); + grid.find('a.edit-link-isadult').editable($.extend({}, options, { + select2: select2Options, + source: boolSource + })); + grid.find('a.edit-link-color').editable(options); grid.find('a.edit-link-size').editable(options); @@ -181,7 +226,46 @@ grid.find('a.edit-link-pattern').editable(options); - grid.find('a.edit-link-taxonomy').editable($.extend(options, { + grid.find('a.edit-link-multipack2').editable($.extend({}, options, { + validate: function(value) { + if (value.length !== 0) { + var regex = /^[0-9]+$/; + if (!regex.test(value)) { + return '@T("Admin.System.Warnings.DigitsOnly")'; + } + } + return null; + } + })); + + grid.find('a.edit-link-isbundle').editable($.extend({}, options, { + select2: select2Options, + source: boolSource + })); + + grid.find('a.edit-link-energyefficiencyclass').editable($.extend({}, options, { + select2: select2Options, + source: [ + @if (Model.EnergyEfficiencyClasses != null && Model.EnergyEfficiencyClasses.Length > 0) + { + foreach (var str in Model.EnergyEfficiencyClasses.Select(x => x.Replace("'", "\""))) + { + { id: '@str', text: '@str' }, + } + } + ] + })); + + grid.find('a.edit-link-customlabel0').editable(options); + grid.find('a.edit-link-customlabel1').editable(options); + grid.find('a.edit-link-customlabel2').editable(options); + grid.find('a.edit-link-customlabel3').editable(options); + grid.find('a.edit-link-customlabel4').editable(options); + + grid.find('a.edit-link-taxonomy').editable($.extend({}, options, { + select2: { + minimumResultsForSearch: 20 + }, source: @Html.Raw(Model.AvailableGoogleCategoriesAsJson) })); } diff --git a/src/Plugins/SmartStore.GoogleMerchantCenter/Views/FeedGoogleMerchantCenter/ProductEditTab.cshtml b/src/Plugins/SmartStore.GoogleMerchantCenter/Views/FeedGoogleMerchantCenter/ProductEditTab.cshtml index fa3273da09..c20ef9acd7 100644 --- a/src/Plugins/SmartStore.GoogleMerchantCenter/Views/FeedGoogleMerchantCenter/ProductEditTab.cshtml +++ b/src/Plugins/SmartStore.GoogleMerchantCenter/Views/FeedGoogleMerchantCenter/ProductEditTab.cshtml @@ -6,24 +6,24 @@ - } - + if (ViewBag.RefreshPage == true) + { + + } - +
    @@ -51,7 +49,7 @@ @Html.SmartLabelFor(model => model.SearchManufacturerId) @@ -59,7 +57,7 @@ @Html.SmartLabelFor(model => model.SearchProductTypeId) @@ -71,8 +69,9 @@
    @Html.SmartLabelFor(model => model.SearchProductName) @@ -43,7 +41,7 @@ @Html.SmartLabelFor(model => model.SearchCategoryId) - @Html.DropDownList("SearchCategoryId", Model.AvailableCategories, T("Admin.Common.All").Text) + @Html.DropDownList("SearchCategoryId", Model.AvailableCategories, T("Admin.Common.All"))
    - @Html.DropDownList("SearchManufacturerId", Model.AvailableManufacturers, T("Admin.Common.All").Text) + @Html.DropDownList("SearchManufacturerId", Model.AvailableManufacturers, T("Admin.Common.All"))
    - @Html.DropDownList("SearchProductTypeId", Model.AvailableProductTypes) + @Html.DropDownList("SearchProductTypeId", Model.AvailableProductTypes, T("Admin.Common.All"))
    -

    -

    + +

    +
    diff --git a/src/Presentation/SmartStore.Web/Administration/Views/Category/Tree.cshtml b/src/Presentation/SmartStore.Web/Administration/Views/Category/Tree.cshtml index 68162d1e32..1f3d747077 100644 --- a/src/Presentation/SmartStore.Web/Administration/Views/Category/Tree.cshtml +++ b/src/Presentation/SmartStore.Web/Administration/Views/Category/Tree.cshtml @@ -15,26 +15,29 @@ -@using (Html.BeginForm()) +@if (Model.AvailableStores.Count > 1) { - - - - - - - - - -
    - @Html.SmartLabelFor(model => model.SearchStoreId) - - @Html.DropDownList("SearchStoreId", Model.AvailableStores) -
    -   - - -
    + using (Html.BeginForm()) + { + + + + + + + + + +
    + @Html.SmartLabelFor(model => model.SearchStoreId) + + @Html.DropDownList("SearchStoreId", Model.AvailableStores, T("Admin.Common.All")) +
    +   + + +
    + } }

    diff --git a/src/Presentation/SmartStore.Web/Administration/Views/ContentSlider/Index.cshtml b/src/Presentation/SmartStore.Web/Administration/Views/ContentSlider/Index.cshtml index 51251e2491..e847170de8 100644 --- a/src/Presentation/SmartStore.Web/Administration/Views/ContentSlider/Index.cshtml +++ b/src/Presentation/SmartStore.Web/Administration/Views/ContentSlider/Index.cshtml @@ -120,24 +120,27 @@ - - - - - - - - - -
    - @Html.SmartLabelFor(model => model.SearchStoreId) - - @Html.DropDownList("SearchStoreId", Model.AvailableStores) -
    -   - - -
    + if (Model.AvailableStores.Count > 1) + { + + + + + + + + + +
    + @Html.SmartLabelFor(model => model.SearchStoreId) + + @Html.DropDownList("SearchStoreId", Model.AvailableStores, T("Admin.Common.All")) +
    +   + + +
    + }
    @@ -164,7 +167,7 @@ .Width(100) .Template(x => @Html.SymbolForBool(x.LimitedToStores)) .ClientTemplate(@Html.SymbolForBool("LimitedToStores")) - .Hidden(Model.StoreCount <= 1) + .Hidden(Model.AvailableStores.Count <= 1) .Centered(); columns.Bound(x => x.Published) .Width(100) diff --git a/src/Presentation/SmartStore.Web/Administration/Views/Customer/_ReportBestCustomersByNumberOfOrders.cshtml b/src/Presentation/SmartStore.Web/Administration/Views/Customer/_ReportBestCustomersByNumberOfOrders.cshtml index 98165844ae..919a1af379 100644 --- a/src/Presentation/SmartStore.Web/Administration/Views/Customer/_ReportBestCustomersByNumberOfOrders.cshtml +++ b/src/Presentation/SmartStore.Web/Administration/Views/Customer/_ReportBestCustomersByNumberOfOrders.cshtml @@ -1,59 +1,59 @@ @model BestCustomersReportModel - @using Telerik.Web.Mvc.UI - - - - - - - - - - - - - - - - - - - - - - - - - -
    - @Html.SmartLabelFor(model => model.StartDate) - - @Html.EditorFor(model => model.StartDate) -
    - @Html.SmartLabelFor(model => model.EndDate) - - @Html.EditorFor(model => Model.EndDate) -
    - @Html.SmartLabelFor(model => model.OrderStatusId) - - @Html.DropDownList("OrderStatusId", Model.AvailableOrderStatuses) -
    - @Html.SmartLabelFor(model => model.PaymentStatusId) - - @Html.DropDownList("PaymentStatusId", Model.AvailablePaymentStatuses) -
    - @Html.SmartLabelFor(model => model.ShippingStatusId) - - @Html.DropDownList("ShippingStatusId", Model.AvailableShippingStatuses) -
    -   - - -
    -

    -

    + + + + + + + + + + + + + + + + + + + + + + + + + +
    + @Html.SmartLabelFor(model => model.StartDate) + + @Html.EditorFor(model => model.StartDate) +
    + @Html.SmartLabelFor(model => model.EndDate) + + @Html.EditorFor(model => Model.EndDate) +
    + @Html.SmartLabelFor(model => model.OrderStatusId) + + @Html.DropDownList("OrderStatusId", Model.AvailableOrderStatuses, T("Admin.Common.All")) +
    + @Html.SmartLabelFor(model => model.PaymentStatusId) + + @Html.DropDownList("PaymentStatusId", Model.AvailablePaymentStatuses, T("Admin.Common.All")) +
    + @Html.SmartLabelFor(model => model.ShippingStatusId) + + @Html.DropDownList("ShippingStatusId", Model.AvailableShippingStatuses, T("Admin.Common.All")) +
    +   + + +
    + +

    +
    diff --git a/src/Presentation/SmartStore.Web/Administration/Views/Customer/_ReportBestCustomersByOrderTotal.cshtml b/src/Presentation/SmartStore.Web/Administration/Views/Customer/_ReportBestCustomersByOrderTotal.cshtml index 13c0f4570f..af0e21e9bb 100644 --- a/src/Presentation/SmartStore.Web/Administration/Views/Customer/_ReportBestCustomersByOrderTotal.cshtml +++ b/src/Presentation/SmartStore.Web/Administration/Views/Customer/_ReportBestCustomersByOrderTotal.cshtml @@ -4,7 +4,7 @@ @using (Html.BeginForm()) { - +
    @@ -34,7 +34,7 @@ @Html.SmartLabelFor(model => model.PaymentStatusId) @@ -42,7 +42,7 @@ @Html.SmartLabelFor(model => model.ShippingStatusId) @@ -54,8 +54,9 @@
    @Html.SmartLabelFor(model => model.StartDate) @@ -26,7 +26,7 @@ @Html.SmartLabelFor(model => model.OrderStatusId) - @Html.DropDownList("OrderStatusId", Model.AvailableOrderStatuses) + @Html.DropDownList("OrderStatusId", Model.AvailableOrderStatuses, T("Admin.Common.All"))
    - @Html.DropDownList("PaymentStatusId", Model.AvailablePaymentStatuses) + @Html.DropDownList("PaymentStatusId", Model.AvailablePaymentStatuses, T("Admin.Common.All"))
    - @Html.DropDownList("ShippingStatusId", Model.AvailableShippingStatuses) + @Html.DropDownList("ShippingStatusId", Model.AvailableShippingStatuses, T("Admin.Common.All"))
    -

    -

    + +

    +
    diff --git a/src/Presentation/SmartStore.Web/Administration/Views/GiftCard/List.cshtml b/src/Presentation/SmartStore.Web/Administration/Views/GiftCard/List.cshtml index fdcacfa7ea..96727f6ecb 100644 --- a/src/Presentation/SmartStore.Web/Administration/Views/GiftCard/List.cshtml +++ b/src/Presentation/SmartStore.Web/Administration/Views/GiftCard/List.cshtml @@ -1,9 +1,6 @@ @model GiftCardListModel @using Telerik.Web.Mvc.UI @{ - var gridPageSize = EngineContext.Current.Resolve().GridPageSize; - - //page title ViewBag.Title = T("Admin.GiftCards").Text; } @using (Html.BeginForm()) @@ -20,34 +17,36 @@ - - - - - - - - - - - + +
    - @Html.SmartLabelFor(model => model.ActivatedId) - - @Html.DropDownListFor(model => model.ActivatedId, Model.ActivatedList) -
    - @Html.SmartLabelFor(model => model.CouponCode) - - @Html.EditorFor(model => model.CouponCode) -
    + + + + + + + + + + + + - -
    + @Html.SmartLabelFor(model => model.ActivatedId) + + @Html.DropDownListFor(model => model.ActivatedId, Model.ActivatedList, T("Admin.Common.All")) +
    + @Html.SmartLabelFor(model => model.CouponCode) + + @Html.EditorFor(model => model.CouponCode) +
      - -
    -

    -

    + +
    + +

    +
    @@ -75,7 +74,7 @@ .HeaderTemplate("{0}".FormatWith(T("Admin.Common.Edit").Text)) .Filterable(false); }) - .Pageable(settings => settings.PageSize(gridPageSize).Position(GridPagerPosition.Both)) + .Pageable(settings => settings.PageSize(Model.GridPageSize).Position(GridPagerPosition.Both)) .DataBinding(dataBinding => dataBinding.Ajax().Select("GiftCardList", "GiftCard", Model)) .PreserveGridState() .EnableCustomBinding(true)) diff --git a/src/Presentation/SmartStore.Web/Administration/Views/Log/List.cshtml b/src/Presentation/SmartStore.Web/Administration/Views/Log/List.cshtml index fbd9a6d127..05d898f309 100644 --- a/src/Presentation/SmartStore.Web/Administration/Views/Log/List.cshtml +++ b/src/Presentation/SmartStore.Web/Administration/Views/Log/List.cshtml @@ -21,7 +21,8 @@ - + +
    diff --git a/src/Presentation/SmartStore.Web/Administration/Views/Manufacturer/List.cshtml b/src/Presentation/SmartStore.Web/Administration/Views/Manufacturer/List.cshtml index c5f8fccc99..112515ff69 100644 --- a/src/Presentation/SmartStore.Web/Administration/Views/Manufacturer/List.cshtml +++ b/src/Presentation/SmartStore.Web/Administration/Views/Manufacturer/List.cshtml @@ -19,23 +19,35 @@ @Html.Widget("admin_button_toolbar_after") -
    @Html.SmartLabelFor(model => model.CreatedOnFrom) @@ -51,7 +52,7 @@ @Html.SmartLabelFor(model => model.LogLevelId) - @Html.DropDownList("LogLevelId", Model.AvailableLogLevels) + @Html.DropDownList("LogLevelId", Model.AvailableLogLevels, T("Admin.Common.All"))
    - - - - - + +
    - @Html.SmartLabelFor(model => model.SearchManufacturerName) - - @Html.EditorFor(model => Model.SearchManufacturerName) -
    + + + + + @if (Model.AvailableStores.Count > 1) + { + + + + + } + - - + +
    + @Html.SmartLabelFor(model => model.SearchManufacturerName) + + @Html.EditorFor(model => Model.SearchManufacturerName) +
    + @Html.SmartLabelFor(model => model.SearchStoreId) + + @Html.DropDownListFor(model => model.SearchStoreId, Model.AvailableStores, T("Admin.Common.All")) +
      - -
    + +

    @@ -57,11 +69,9 @@ .HtmlAttributes(new { style = "text-align:center" }) .HeaderHtmlAttributes(new { style = "text-align:center" }); columns.Bound(x => x.Name) - .Template(x => Html.ActionLink(x.Name, "Edit", new { id = x.Id })) .ClientTemplate("\"><#= Name #>"); columns.Bound(x => x.Published) .Width(160) - .Template(item => @Html.SymbolForBool(item.Published)) .ClientTemplate(@Html.SymbolForBool("Published")) .Centered(); columns.Bound(x => x.DisplayOrder) @@ -69,8 +79,8 @@ .Centered(); columns.Bound(x => x.LimitedToStores) .Width(160) - .Template(item => @Html.SymbolForBool(item.LimitedToStores)) .ClientTemplate(@Html.SymbolForBool("LimitedToStores")) + .Hidden(Model.AvailableStores.Count <= 1) .Centered(); }) .Pageable(settings => settings.PageSize(Model.GridPageSize).Position(GridPagerPosition.Both)) @@ -129,7 +139,8 @@ function onDataBinding(e) { var searchModel = { - SearchManufacturerName: $('#@Html.FieldIdFor(model => model.SearchManufacturerName)').val() + SearchManufacturerName: $('#@Html.FieldIdFor(model => model.SearchManufacturerName)').val(), + SearchStoreId: $('#@Html.FieldIdFor(model => model.SearchStoreId)').val() }; e.data = searchModel; } diff --git a/src/Presentation/SmartStore.Web/Administration/Views/Manufacturer/ProductAddPopup.cshtml b/src/Presentation/SmartStore.Web/Administration/Views/Manufacturer/ProductAddPopup.cshtml index 15185b0812..d0864667b3 100644 --- a/src/Presentation/SmartStore.Web/Administration/Views/Manufacturer/ProductAddPopup.cshtml +++ b/src/Presentation/SmartStore.Web/Administration/Views/Manufacturer/ProductAddPopup.cshtml @@ -5,7 +5,6 @@ @{ var gridPageSize = EngineContext.Current.Resolve().GridPageSize; - //page title ViewBag.Title = T("Admin.Catalog.Manufacturers.Products.AddNew").Text; } @using Telerik.Web.Mvc.UI; @@ -17,17 +16,16 @@ - if (ViewBag.RefreshPage == true) - { - - } + if (ViewBag.RefreshPage == true) + { + + } - - +
    @@ -49,7 +47,7 @@ @Html.SmartLabelFor(model => model.SearchManufacturerId) @@ -57,7 +55,7 @@ @Html.SmartLabelFor(model => model.SearchProductTypeId) @@ -69,8 +67,9 @@
    @Html.SmartLabelFor(model => model.SearchProductName) @@ -41,7 +39,7 @@ @Html.SmartLabelFor(model => model.SearchCategoryId) - @Html.DropDownList("SearchCategoryId", Model.AvailableCategories, T("Admin.Common.All").Text) + @Html.DropDownList("SearchCategoryId", Model.AvailableCategories, T("Admin.Common.All"))
    - @Html.DropDownList("SearchManufacturerId", Model.AvailableManufacturers, T("Admin.Common.All").Text) + @Html.DropDownList("SearchManufacturerId", Model.AvailableManufacturers, T("Admin.Common.All"))
    - @Html.DropDownList("SearchProductTypeId", Model.AvailableProductTypes) + @Html.DropDownList("SearchProductTypeId", Model.AvailableProductTypes, T("Admin.Common.All"))
    -

    -

    + +

    + - - - - + @if (Model.AvailableStores.Count > 1) + { + + + + + }
    diff --git a/src/Presentation/SmartStore.Web/Administration/Views/MessageTemplate/List.cshtml b/src/Presentation/SmartStore.Web/Administration/Views/MessageTemplate/List.cshtml index 29c941466b..ed38d5c49c 100644 --- a/src/Presentation/SmartStore.Web/Administration/Views/MessageTemplate/List.cshtml +++ b/src/Presentation/SmartStore.Web/Administration/Views/MessageTemplate/List.cshtml @@ -16,26 +16,29 @@ - - - - - - - - - -
    - @Html.SmartLabelFor(model => model.SearchStoreId) - - @Html.DropDownList("SearchStoreId", Model.AvailableStores) -
    -   - - -
    +@if (Model.AvailableStores.Count > 1) +{ + + + + + + + + + +
    + @Html.SmartLabelFor(model => model.SearchStoreId) + + @Html.DropDownList("SearchStoreId", Model.AvailableStores, T("Admin.Common.All")) +
    +   + + +
    +}

    diff --git a/src/Presentation/SmartStore.Web/Administration/Views/News/List.cshtml b/src/Presentation/SmartStore.Web/Administration/Views/News/List.cshtml index dfcd240b18..aa82033bf7 100644 --- a/src/Presentation/SmartStore.Web/Administration/Views/News/List.cshtml +++ b/src/Presentation/SmartStore.Web/Administration/Views/News/List.cshtml @@ -25,26 +25,29 @@ - - - - - - - - - -
    - @Html.SmartLabelFor(model => model.SearchStoreId) - - @Html.DropDownList("SearchStoreId", Model.AvailableStores) -
    -   - - -
    +@if (Model.AvailableStores.Count > 1) +{ + + + + + + + + + +
    + @Html.SmartLabelFor(model => model.SearchStoreId) + + @Html.DropDownList("SearchStoreId", Model.AvailableStores, T("Admin.Common.All")) +
    +   + + +
    +}

    @@ -81,6 +84,7 @@ columns.Bound(x => x.LimitedToStores) .Template(item => @Html.SymbolForBool(item.LimitedToStores)) .ClientTemplate(@Html.SymbolForBool("LimitedToStores")) + .Hidden(Model.AvailableStores.Count <= 1) .Centered(); columns.Bound(x => x.CreatedOn); }) diff --git a/src/Presentation/SmartStore.Web/Administration/Views/NewsLetterSubscription/List.cshtml b/src/Presentation/SmartStore.Web/Administration/Views/NewsLetterSubscription/List.cshtml index 5953d03c49..da8b2d4fd5 100644 --- a/src/Presentation/SmartStore.Web/Administration/Views/NewsLetterSubscription/List.cshtml +++ b/src/Presentation/SmartStore.Web/Administration/Views/NewsLetterSubscription/List.cshtml @@ -24,14 +24,17 @@ @Html.EditorFor(model => Model.SearchEmail)
    - @Html.SmartLabelFor(model => model.StoreId) - - @Html.DropDownList("StoreId", Model.AvailableStores) -
    + @Html.SmartLabelFor(model => model.StoreId) + + @Html.DropDownList("StoreId", Model.AvailableStores, T("Admin.Common.All")) +
      @@ -64,6 +67,7 @@ .Centered() .Width(100); columns.Bound(x => x.StoreName) + .Hidden(Model.AvailableStores.Count <= 1) .ReadOnly(); columns.Bound(x => x.CreatedOn) .ReadOnly() diff --git a/src/Presentation/SmartStore.Web/Administration/Views/Order/AddProductToOrder.cshtml b/src/Presentation/SmartStore.Web/Administration/Views/Order/AddProductToOrder.cshtml index 574db39957..2c99ed1a86 100644 --- a/src/Presentation/SmartStore.Web/Administration/Views/Order/AddProductToOrder.cshtml +++ b/src/Presentation/SmartStore.Web/Administration/Views/Order/AddProductToOrder.cshtml @@ -2,7 +2,6 @@ @{ var gridPageSize = EngineContext.Current.Resolve().GridPageSize; - //page title ViewBag.Title = string.Format(T("Admin.Orders.Products.AddNew.Title1").Text, Model.OrderId); } @using Telerik.Web.Mvc.UI; @@ -19,7 +18,7 @@ @T("Admin.Orders.Products.AddNew.Note1") - +
    @@ -41,7 +40,7 @@ @Html.SmartLabelFor(model => model.SearchManufacturerId) @@ -49,7 +48,7 @@ @Html.SmartLabelFor(model => model.SearchProductTypeId) @@ -63,7 +62,9 @@
    @Html.SmartLabelFor(model => model.SearchProductName) @@ -33,7 +32,7 @@ @Html.SmartLabelFor(model => model.SearchCategoryId) - @Html.DropDownList("SearchCategoryId", Model.AvailableCategories, T("Admin.Common.All").Text) + @Html.DropDownList("SearchCategoryId", Model.AvailableCategories, T("Admin.Common.All"))
    - @Html.DropDownList("SearchManufacturerId", Model.AvailableManufacturers, T("Admin.Common.All").Text) + @Html.DropDownList("SearchManufacturerId", Model.AvailableManufacturers, T("Admin.Common.All"))
    - @Html.DropDownList("SearchProductTypeId", Model.AvailableProductTypes) + @Html.DropDownList("SearchProductTypeId", Model.AvailableProductTypes, T("Admin.Common.All"))
    +

    +
    diff --git a/src/Presentation/SmartStore.Web/Administration/Views/Order/BestsellersReport.cshtml b/src/Presentation/SmartStore.Web/Administration/Views/Order/BestsellersReport.cshtml index c6fb84b696..e035acfa1e 100644 --- a/src/Presentation/SmartStore.Web/Administration/Views/Order/BestsellersReport.cshtml +++ b/src/Presentation/SmartStore.Web/Administration/Views/Order/BestsellersReport.cshtml @@ -1,7 +1,6 @@ @model BestsellersReportModel @using Telerik.Web.Mvc.UI @{ - //page title ViewBag.Title = T("Admin.SalesReport.Bestsellers").Text; } @using (Html.BeginForm()) @@ -14,7 +13,8 @@
    - + +
    @@ -44,7 +44,7 @@ @Html.SmartLabelFor(model => model.PaymentStatusId) @@ -56,8 +56,9 @@
    @Html.SmartLabelFor(model => model.StartDate) @@ -36,7 +36,7 @@ @Html.SmartLabelFor(model => model.OrderStatusId) - @Html.DropDownList("OrderStatusId", Model.AvailableOrderStatuses) + @Html.DropDownList("OrderStatusId", Model.AvailableOrderStatuses, T("Admin.Common.All"))
    - @Html.DropDownList("PaymentStatusId", Model.AvailablePaymentStatuses) + @Html.DropDownList("PaymentStatusId", Model.AvailablePaymentStatuses, T("Admin.Common.All"))
    -

    -

    + +

    + - @if (Model.StoreCount > 1) + @if (Model.AvailableStores.Count > 1) {
    @@ -106,5 +107,4 @@ } - } \ No newline at end of file diff --git a/src/Presentation/SmartStore.Web/Administration/Views/Order/List.cshtml b/src/Presentation/SmartStore.Web/Administration/Views/Order/List.cshtml index 47e12fdb99..af55c9bde6 100644 --- a/src/Presentation/SmartStore.Web/Administration/Views/Order/List.cshtml +++ b/src/Presentation/SmartStore.Web/Administration/Views/Order/List.cshtml @@ -97,7 +97,7 @@ @Html.DropDownList("ShippingStatusIds", Model.AvailableShippingStatuses, null, new { multiple = "multiple" })
    @@ -176,7 +176,7 @@ columns.Bound(x => x.CustomerName); columns.Bound(x => x.CustomerEmail); columns.Bound(x => x.StoreName) - .Hidden(Model.StoreCount <= 1); + .Hidden(Model.AvailableStores.Count <= 1); columns.Bound(x => x.CreatedOn); columns.Bound(x => x.OrderTotal) .Width(180) diff --git a/src/Presentation/SmartStore.Web/Administration/Views/Product/AssociatedProductAddPopup.cshtml b/src/Presentation/SmartStore.Web/Administration/Views/Product/AssociatedProductAddPopup.cshtml index b5fd79b0e4..a46a602417 100644 --- a/src/Presentation/SmartStore.Web/Administration/Views/Product/AssociatedProductAddPopup.cshtml +++ b/src/Presentation/SmartStore.Web/Administration/Views/Product/AssociatedProductAddPopup.cshtml @@ -27,7 +27,7 @@ } - +
    @@ -49,23 +49,26 @@ @Html.SmartLabelFor(model => model.SearchManufacturerId) - - - - + @if (Model.AvailableStores.Count > 1) + { + + + + + } diff --git a/src/Presentation/SmartStore.Web/Administration/Views/Product/BulkEdit.cshtml b/src/Presentation/SmartStore.Web/Administration/Views/Product/BulkEdit.cshtml index 6eb786b6ba..ebdea889fa 100644 --- a/src/Presentation/SmartStore.Web/Administration/Views/Product/BulkEdit.cshtml +++ b/src/Presentation/SmartStore.Web/Administration/Views/Product/BulkEdit.cshtml @@ -3,7 +3,6 @@ @{ var allString = T("Admin.Common.All").Text; - //page title ViewBag.Title = T("Admin.Catalog.BulkEdit").Text; } @using (Html.BeginForm()) @@ -38,7 +37,7 @@ @Html.DropDownList("SearchProductTypeId", Model.AvailableProductTypes, allString) - @if (Model.StoreCount > 1) + @if (Model.AvailableStores.Count > 1) {
    @Html.SmartLabelFor(model => model.SearchProductName) @@ -41,7 +41,7 @@ @Html.SmartLabelFor(model => model.SearchCategoryId) - @Html.DropDownList("SearchCategoryId", Model.AvailableCategories, T("Admin.Common.All").Text) + @Html.DropDownList("SearchCategoryId", Model.AvailableCategories, T("Admin.Common.All"))
    - @Html.DropDownList("SearchManufacturerId", Model.AvailableManufacturers, T("Admin.Common.All").Text) -
    - @Html.SmartLabelFor(model => model.SearchStoreId) - - @Html.DropDownList("SearchStoreId", Model.AvailableStores) + @Html.DropDownList("SearchManufacturerId", Model.AvailableManufacturers, T("Admin.Common.All"))
    + @Html.SmartLabelFor(model => model.SearchStoreId) + + @Html.DropDownList("SearchStoreId", Model.AvailableStores, T("Admin.Common.All")) +
    @Html.SmartLabelFor(model => model.SearchProductTypeId) - @Html.DropDownList("SearchProductTypeId", Model.AvailableProductTypes) + @Html.DropDownList("SearchProductTypeId", Model.AvailableProductTypes, T("Admin.Common.All"))
    diff --git a/src/Presentation/SmartStore.Web/Administration/Views/Product/BundleItemAddPopup.cshtml b/src/Presentation/SmartStore.Web/Administration/Views/Product/BundleItemAddPopup.cshtml index b31b86f3a2..490d650ce4 100644 --- a/src/Presentation/SmartStore.Web/Administration/Views/Product/BundleItemAddPopup.cshtml +++ b/src/Presentation/SmartStore.Web/Administration/Views/Product/BundleItemAddPopup.cshtml @@ -47,7 +47,7 @@ } - +
    @@ -69,23 +69,26 @@ @Html.SmartLabelFor(model => model.SearchManufacturerId) - - - - + @if (Model.AvailableStores.Count > 1) + { + + + + + } diff --git a/src/Presentation/SmartStore.Web/Administration/Views/Product/CrossSellProductAddPopup.cshtml b/src/Presentation/SmartStore.Web/Administration/Views/Product/CrossSellProductAddPopup.cshtml index ac06795dec..31f0e00244 100644 --- a/src/Presentation/SmartStore.Web/Administration/Views/Product/CrossSellProductAddPopup.cshtml +++ b/src/Presentation/SmartStore.Web/Administration/Views/Product/CrossSellProductAddPopup.cshtml @@ -5,7 +5,6 @@ @{ var gridPageSize = EngineContext.Current.Resolve().GridPageSize; - //page title ViewBag.Title = T("Admin.Catalog.Products.CrossSells.AddNew").Text; } @using Telerik.Web.Mvc.UI; @@ -27,7 +26,7 @@ } -
    @Html.SmartLabelFor(model => model.SearchProductName) @@ -61,7 +61,7 @@ @Html.SmartLabelFor(model => model.SearchCategoryId) - @Html.DropDownList("SearchCategoryId", Model.AvailableCategories, T("Admin.Common.All").Text) + @Html.DropDownList("SearchCategoryId", Model.AvailableCategories, T("Admin.Common.All"))
    - @Html.DropDownList("SearchManufacturerId", Model.AvailableManufacturers, T("Admin.Common.All").Text) -
    - @Html.SmartLabelFor(model => model.SearchStoreId) - - @Html.DropDownList("SearchStoreId", Model.AvailableStores) + @Html.DropDownList("SearchManufacturerId", Model.AvailableManufacturers, T("Admin.Common.All"))
    + @Html.SmartLabelFor(model => model.SearchStoreId) + + @Html.DropDownList("SearchStoreId", Model.AvailableStores, T("Admin.Common.All")) +
    @Html.SmartLabelFor(model => model.SearchProductTypeId) - @Html.DropDownList("SearchProductTypeId", Model.AvailableProductTypes) + @Html.DropDownList("SearchProductTypeId", Model.AvailableProductTypes, T("Admin.Common.All"))
    +
    @@ -49,23 +48,26 @@ @Html.SmartLabelFor(model => model.SearchManufacturerId) - - - - + @if (Model.AvailableStores.Count > 1) + { + + + + + } diff --git a/src/Presentation/SmartStore.Web/Administration/Views/Product/List.cshtml b/src/Presentation/SmartStore.Web/Administration/Views/Product/List.cshtml index feb7fe9c84..1b18b8a636 100644 --- a/src/Presentation/SmartStore.Web/Administration/Views/Product/List.cshtml +++ b/src/Presentation/SmartStore.Web/Administration/Views/Product/List.cshtml @@ -44,7 +44,7 @@ @Html.DropDownListFor(model => model.SearchProductTypeId, Model.AvailableProductTypes, allString) - @if (Model.StoreCount > 1) + @if (Model.AvailableStores.Count > 1) { + + + + } + @if (Model.StoreCount > 1) + { + + + + + }
    @Html.SmartLabelFor(model => model.SearchProductName) @@ -41,7 +40,7 @@ @Html.SmartLabelFor(model => model.SearchCategoryId) - @Html.DropDownList("SearchCategoryId", Model.AvailableCategories, T("Admin.Common.All").Text) + @Html.DropDownList("SearchCategoryId", Model.AvailableCategories, T("Admin.Common.All"))
    - @Html.DropDownList("SearchManufacturerId", Model.AvailableManufacturers, T("Admin.Common.All").Text) -
    - @Html.SmartLabelFor(model => model.SearchStoreId) - - @Html.DropDownList("SearchStoreId", Model.AvailableStores) + @Html.DropDownList("SearchManufacturerId", Model.AvailableManufacturers, T("Admin.Common.All"))
    + @Html.SmartLabelFor(model => model.SearchStoreId) + + @Html.DropDownList("SearchStoreId", Model.AvailableStores, T("Admin.Common.All")) +
    @Html.SmartLabelFor(model => model.SearchProductTypeId) - @Html.DropDownList("SearchProductTypeId", Model.AvailableProductTypes) + @Html.DropDownList("SearchProductTypeId", Model.AvailableProductTypes, T("Admin.Common.All"))
    @@ -170,7 +170,7 @@ .Sortable(false) .Template(item => @Html.SymbolForBool(item.LimitedToStores)) .ClientTemplate(@Html.SymbolForBool("LimitedToStores")) - .Hidden(Model.StoreCount <= 1) + .Hidden(Model.AvailableStores.Count <= 1) .Centered(); columns.Bound(x => x.CreatedOn); columns.Bound(x => x.UpdatedOn) diff --git a/src/Presentation/SmartStore.Web/Administration/Views/Product/ProductAttributeValueLinkagePopup.cshtml b/src/Presentation/SmartStore.Web/Administration/Views/Product/ProductAttributeValueLinkagePopup.cshtml index 0ef7426f3c..62cde68c17 100644 --- a/src/Presentation/SmartStore.Web/Administration/Views/Product/ProductAttributeValueLinkagePopup.cshtml +++ b/src/Presentation/SmartStore.Web/Administration/Views/Product/ProductAttributeValueLinkagePopup.cshtml @@ -34,7 +34,7 @@ @Html.HiddenFor(model => model.ProductId) - +
    @@ -56,23 +56,26 @@ @Html.SmartLabelFor(model => model.SearchManufacturerId) - - - - + @if (Model.AvailableStores.Count > 1) + { + + + + + } diff --git a/src/Presentation/SmartStore.Web/Administration/Views/Product/RelatedProductAddPopup.cshtml b/src/Presentation/SmartStore.Web/Administration/Views/Product/RelatedProductAddPopup.cshtml index 7d5db715ca..a9a5b0b701 100644 --- a/src/Presentation/SmartStore.Web/Administration/Views/Product/RelatedProductAddPopup.cshtml +++ b/src/Presentation/SmartStore.Web/Administration/Views/Product/RelatedProductAddPopup.cshtml @@ -5,7 +5,6 @@ @{ var gridPageSize = EngineContext.Current.Resolve().GridPageSize; - //page title ViewBag.Title = T("Admin.Catalog.Products.RelatedProducts.AddNew").Text; } @using Telerik.Web.Mvc.UI; @@ -26,8 +25,7 @@ } - -
    @Html.SmartLabelFor(model => model.SearchProductName) @@ -48,7 +48,7 @@ @Html.SmartLabelFor(model => model.SearchCategoryId) - @Html.DropDownList("SearchCategoryId", Model.AvailableCategories, T("Admin.Common.All").Text) + @Html.DropDownList("SearchCategoryId", Model.AvailableCategories, T("Admin.Common.All"))
    - @Html.DropDownList("SearchManufacturerId", Model.AvailableManufacturers, T("Admin.Common.All").Text) -
    - @Html.SmartLabelFor(model => model.SearchStoreId) - - @Html.DropDownList("SearchStoreId", Model.AvailableStores) + @Html.DropDownList("SearchManufacturerId", Model.AvailableManufacturers, T("Admin.Common.All"))
    + @Html.SmartLabelFor(model => model.SearchStoreId) + + @Html.DropDownList("SearchStoreId", Model.AvailableStores, T("Admin.Common.All")) +
    @Html.SmartLabelFor(model => model.SearchProductTypeId) - @Html.DropDownList("SearchProductTypeId", Model.AvailableProductTypes) + @Html.DropDownList("SearchProductTypeId", Model.AvailableProductTypes, T("Admin.Common.All"))
    +
    @@ -49,23 +47,26 @@ @Html.SmartLabelFor(model => model.SearchManufacturerId) - - - - + @if (Model.AvailableStores.Count > 1) + { + + + + + } @@ -77,6 +78,7 @@
    @Html.SmartLabelFor(model => model.SearchProductName) @@ -41,7 +39,7 @@ @Html.SmartLabelFor(model => model.SearchCategoryId) - @Html.DropDownList("SearchCategoryId", Model.AvailableCategories, T("Admin.Common.All").Text) + @Html.DropDownList("SearchCategoryId", Model.AvailableCategories, T("Admin.Common.All"))
    - @Html.DropDownList("SearchManufacturerId", Model.AvailableManufacturers, T("Admin.Common.All").Text) -
    - @Html.SmartLabelFor(model => model.SearchStoreId) - - @Html.DropDownList("SearchStoreId", Model.AvailableStores) + @Html.DropDownList("SearchManufacturerId", Model.AvailableManufacturers, T("Admin.Common.All"))
    + @Html.SmartLabelFor(model => model.SearchStoreId) + + @Html.DropDownList("SearchStoreId", Model.AvailableStores, T("Admin.Common.All")) +
    @Html.SmartLabelFor(model => model.SearchProductTypeId) - @Html.DropDownList("SearchProductTypeId", Model.AvailableProductTypes) + @Html.DropDownList("SearchProductTypeId", Model.AvailableProductTypes, T("Admin.Common.All"))
    +

    diff --git a/src/Presentation/SmartStore.Web/Administration/Views/ReturnRequest/List.cshtml b/src/Presentation/SmartStore.Web/Administration/Views/ReturnRequest/List.cshtml index e8f2359885..c9a62c9b5c 100644 --- a/src/Presentation/SmartStore.Web/Administration/Views/ReturnRequest/List.cshtml +++ b/src/Presentation/SmartStore.Web/Administration/Views/ReturnRequest/List.cshtml @@ -13,83 +13,88 @@ -
    - - - - - - - - - - - - - +
    - @Html.SmartLabelFor(model => model.SearchId) - - @Html.EditorFor(model => Model.SearchId) -
    - @Html.SmartLabelFor(model => model.SearchStoreId) - - @Html.DropDownListFor(model => model.SearchStoreId, Model.AvailableStores) -
    - @Html.SmartLabelFor(model => model.SearchReturnRequestStatusId) - - @Html.DropDownListFor(model => model.SearchReturnRequestStatusId, Model.AvailableReturnRequestStatus) -
    + + + + + @if (Model.AvailableStores.Count > 1) + { + + + + + } + + + + + - - + +
    + @Html.SmartLabelFor(model => model.SearchId) + + @Html.EditorFor(model => Model.SearchId) +
    + @Html.SmartLabelFor(model => model.SearchStoreId) + + @Html.DropDownListFor(model => model.SearchStoreId, Model.AvailableStores, T("Admin.Common.All")) +
    + @Html.SmartLabelFor(model => model.SearchReturnRequestStatusId) + + @Html.DropDownListFor(model => model.SearchReturnRequestStatusId, Model.AvailableReturnRequestStatus, T("Admin.Common.All")) +
      - -
    + +
    +

    @(Html.Telerik().Grid() - .Name("returnrequests-grid") - .Columns(columns => - { + .Name("returnrequests-grid") + .Columns(columns => + { columns.Bound(x => x.Id) .Centered() .Width(80); columns.Bound(x => x.ProductName) .Template(x => @Html.LabeledProductName(x.ProductId, x.ProductName, x.ProductTypeName, x.ProductTypeLabelHint)) .ClientTemplate(@Html.LabeledProductName("ProductId", "ProductName")); - columns.Bound(x => x.Quantity) + columns.Bound(x => x.Quantity) .Width(80) - .Centered(); - columns.Bound(x => x.CustomerId) - .Template(x => Html.ActionLink(T("Admin.Common.View").Text, "Edit", "Customer", new { id = x.CustomerId }, new { })) + .Centered(); + columns.Bound(x => x.CustomerId) + .Template(x => Html.ActionLink(T("Admin.Common.View").Text, "Edit", "Customer", new { id = x.CustomerId }, new { })) .ClientTemplate("\"><#= CustomerFullName #>"); - columns.Bound(x => x.OrderId) + columns.Bound(x => x.OrderId) .Width(80) - .Centered() - .Template(x => Html.ActionLink(T("Admin.Common.View").Text, "Edit", "Order", new { id = x.OrderId }, new { })) + .Centered() + .Template(x => Html.ActionLink(T("Admin.Common.View").Text, "Edit", "Order", new { id = x.OrderId }, new { })) .ClientTemplate("\"><#= OrderId #>"); columns.Bound(x => x.ReturnRequestStatusStr) - .Width(180); - columns.Bound(x => x.CreatedOn) .Width(180); - columns.Bound(x => x.StoreName); - columns.Bound(x => x.Id) + columns.Bound(x => x.CreatedOn) + .Width(180); + columns.Bound(x => x.StoreName) + .Hidden(Model.AvailableStores.Count <= 1); + columns.Bound(x => x.Id) .Width(100) - .Centered() - .Template(x => Html.ActionLink(T("Admin.Common.Edit").Text, "Edit", new { id = x.Id })) - .ClientTemplate("\">" + T("Admin.Common.Edit").Text + "") - .Title(T("Admin.Common.Edit").Text); - }) + .Centered() + .Template(x => Html.ActionLink(T("Admin.Common.Edit").Text, "Edit", new { id = x.Id })) + .ClientTemplate("\">" + T("Admin.Common.Edit").Text + "") + .Title(T("Admin.Common.Edit").Text); + }) .Pageable(settings => settings.PageSize(Model.GridPageSize).Position(GridPagerPosition.Both)) - .DataBinding(dataBinding => dataBinding.Ajax().Select("List", "ReturnRequest")) + .DataBinding(dataBinding => dataBinding.Ajax().Select("List", "ReturnRequest")) .ClientEvents(events => events.OnDataBinding("returnRequestGrid_onDataBinding")) .PreserveGridState() - .EnableCustomBinding(true)) + .EnableCustomBinding(true))
    diff --git a/src/Presentation/SmartStore.Web/Administration/Views/Topic/List.cshtml b/src/Presentation/SmartStore.Web/Administration/Views/Topic/List.cshtml index 08de2f50ab..18fda90102 100644 --- a/src/Presentation/SmartStore.Web/Administration/Views/Topic/List.cshtml +++ b/src/Presentation/SmartStore.Web/Administration/Views/Topic/List.cshtml @@ -16,26 +16,29 @@ - - - - - - - - - -
    - @Html.SmartLabelFor(model => model.SearchStoreId) - - @Html.DropDownList("SearchStoreId", Model.AvailableStores) -
    -   - - -
    +@if (Model.AvailableStores.Count > 1) +{ + + + + + + + + + +
    + @Html.SmartLabelFor(model => model.SearchStoreId) + + @Html.DropDownList("SearchStoreId", Model.AvailableStores, T("Admin.Common.All")) +
    +   + + +
    +}

    From 49da71aa6d88631916c7e9bf681732af73ff0f24 Mon Sep 17 00:00:00 2001 From: Marcus Gesing Date: Thu, 7 Jan 2016 18:56:27 +0100 Subject: [PATCH 219/707] Updated Google Analytics admin instructions Bulk update of string resources may fail because of outdated EfRepository.AutoCommitEnabledInternal state --- .../Localization/LocalizationService.cs | 9 +-------- .../Importer/NewsLetterSubscriptionImporter.cs | 4 +--- .../Localization/resources.de-de.xml | 11 ++++++----- .../Localization/resources.en-us.xml | 12 ++++++------ 4 files changed, 14 insertions(+), 22 deletions(-) diff --git a/src/Libraries/SmartStore.Services/Localization/LocalizationService.cs b/src/Libraries/SmartStore.Services/Localization/LocalizationService.cs index 31f83eb7dc..8610072e92 100644 --- a/src/Libraries/SmartStore.Services/Localization/LocalizationService.cs +++ b/src/Libraries/SmartStore.Services/Localization/LocalizationService.cs @@ -437,7 +437,6 @@ public virtual void ImportResourcesFromXml( foreach (var xel in nodes.Cast()) { - string name = xel.GetAttribute("Name").TrimSafe(); string value = ""; var valueNode = xel.SelectSingleNode("Value"); @@ -488,13 +487,7 @@ public virtual void ImportResourcesFromXml( _lsrRepository.InsertRange(toAdd, 500); toAdd.Clear(); - _lsrRepository.AutoCommitEnabled = null; - toUpdate.Each(x => - { - _lsrRepository.Update(x); - }); - - _lsrRepository.Context.SaveChanges(); + _lsrRepository.UpdateRange(toUpdate); toUpdate.Clear(); //clear cache diff --git a/src/Libraries/SmartStore.Services/Messages/Importer/NewsLetterSubscriptionImporter.cs b/src/Libraries/SmartStore.Services/Messages/Importer/NewsLetterSubscriptionImporter.cs index 5bf83c4755..17f3c10ed0 100644 --- a/src/Libraries/SmartStore.Services/Messages/Importer/NewsLetterSubscriptionImporter.cs +++ b/src/Libraries/SmartStore.Services/Messages/Importer/NewsLetterSubscriptionImporter.cs @@ -104,9 +104,7 @@ public void Execute(IImportExecuteContext context) toAdd.Clear(); // update modified subscribers - _subscriptionRepository.AutoCommitEnabled = null; - toUpdate.Each(x => _subscriptionRepository.Update(x)); - _subscriptionRepository.Context.SaveChanges(); + _subscriptionRepository.UpdateRange(toUpdate); toUpdate.Clear(); } catch (Exception exception) diff --git a/src/Plugins/SmartStore.GoogleAnalytics/Localization/resources.de-de.xml b/src/Plugins/SmartStore.GoogleAnalytics/Localization/resources.de-de.xml index 627698df96..d7f6055f92 100644 --- a/src/Plugins/SmartStore.GoogleAnalytics/Localization/resources.de-de.xml +++ b/src/Plugins/SmartStore.GoogleAnalytics/Localization/resources.de-de.xml @@ -5,13 +5,14 @@ Google Analytics ist ein kostenloser Statistikdienst von Google. Der Dienst erfasst Statistiken über Besucher und Ecommerce-Konversion auf Ihrer Webseite

    +

    Google Analytics ist ein kostenloser Statistikdienst von Google. Der Dienst erfasst Statistiken über Besucher und Ecommerce-Konversion auf Ihrer Webseite.

    Führen Sie die folgenden Schritte aus um Google Analytics auf Ihrer Webseite einzubinden:

      -
    • erstellen Sie hier einen "Google Analytics"-Account und folgen Sie dem Wizard um Ihre Webseite zuzufügen
    • -
    • Kopieren Sie die "Google Analytics"-ID in das entspechende Feld in folgendem Formular
    • -
    • Kopieren Sie den Tracking-Code in die "Tracking-Code"-Box in folgendem Formular
    • -
    • KLicken Sie den "Speichern"-Button und Google Analytics wird in Ihre Webseite integriert
    • +
    • Erstellen Sie hier einen Google-Analytics-Account und folgen Sie dem Wizard um Ihre Webseite zuzufügen.
    • +
    • Kopieren Sie die Google-Analytics-ID in das entspechende Feld in folgendem Formular.
    • +
    • Kopieren Sie den Tracking-Code in die Tracking-Code-Box in folgendem Formular.
    • +
    • Klicken Sie den Speichern-Button.
    • +
    • Aktivieren Sie das Google Analytics Widget unter CMS > Widgets und Google Analytics wird in Ihre Webseite integriert.
    ]]>
    diff --git a/src/Plugins/SmartStore.GoogleAnalytics/Localization/resources.en-us.xml b/src/Plugins/SmartStore.GoogleAnalytics/Localization/resources.en-us.xml index 2ac97f8895..d54877d501 100644 --- a/src/Plugins/SmartStore.GoogleAnalytics/Localization/resources.en-us.xml +++ b/src/Plugins/SmartStore.GoogleAnalytics/Localization/resources.en-us.xml @@ -5,14 +5,14 @@ Google Analytics is a free website stats tool from Google. It keeps track of statistics - about the visitors and ecommerce conversion on your website.

    +

    Google Analytics is a free website statistics tool from Google. It keeps track of statistics about the visitors and ecommerce conversion on your website.

    Follow the next steps to enable Google Analytics integration:

      -
    • Create a Google Analytics account and follow the wizard to add your website
    • -
    • Copy the Google Analytics ID into the 'ID' box below
    • -
    • Copy the tracking code from Google Analytics into the 'Tracking Code' box below
    • -
    • Click the 'Save' button below and Google Analytics will be integrated into your store
    • +
    • Create a Google Analytics account and follow the wizard to add your website.
    • +
    • Copy the Google Analytics ID into the ID field below.
    • +
    • Copy the tracking code from Google Analytics into the Tracking Code field below.
    • +
    • Click the Save button below.
    • +
    • Activate the Google Analytics widget under CMS > Widgets to integrate Google Analytics into your store.
    ]]>
    From df31f4f375026c4129096ca0cc0cecdfbb7a1863 Mon Sep 17 00:00:00 2001 From: Murat Cakir Date: Thu, 7 Jan 2016 20:22:45 +0100 Subject: [PATCH 220/707] TaskScheduler: logging the sweep call for debugging puposes (temp only) --- .../SmartStore.Core/Extensions/ConversionExtensions.cs | 6 +++++- src/Libraries/SmartStore.Services/Tasks/TaskScheduler.cs | 9 ++++++++- .../Controllers/TaskSchedulerController.cs | 2 +- 3 files changed, 14 insertions(+), 3 deletions(-) diff --git a/src/Libraries/SmartStore.Core/Extensions/ConversionExtensions.cs b/src/Libraries/SmartStore.Core/Extensions/ConversionExtensions.cs index 64297abe9d..387bc9a614 100644 --- a/src/Libraries/SmartStore.Core/Extensions/ConversionExtensions.cs +++ b/src/Libraries/SmartStore.Core/Extensions/ConversionExtensions.cs @@ -239,7 +239,11 @@ public static string AsString(this Stream stream, Encoding encoding) // convert stream to string string result; - stream.Position = 0; + + if (stream.CanSeek) + { + stream.Position = 0; + } using (StreamReader sr = new StreamReader(stream, encoding)) { diff --git a/src/Libraries/SmartStore.Services/Tasks/TaskScheduler.cs b/src/Libraries/SmartStore.Services/Tasks/TaskScheduler.cs index 22cecb7046..50b4df021b 100644 --- a/src/Libraries/SmartStore.Services/Tasks/TaskScheduler.cs +++ b/src/Libraries/SmartStore.Services/Tasks/TaskScheduler.cs @@ -173,8 +173,15 @@ protected internal virtual void CallEndpoint(string url) } else { + var response = t.Result; + + using (var logger = new TraceLogger()) + { + logger.Debug("TaskScheduler Sweep called successfully: {0}".FormatCurrent(response.GetResponseStream().AsString())); + } + _errCount = 0; - t.Result.Dispose(); + response.Dispose(); } }); } diff --git a/src/Presentation/SmartStore.Web/Controllers/TaskSchedulerController.cs b/src/Presentation/SmartStore.Web/Controllers/TaskSchedulerController.cs index 9b7b6763c2..860da5fa85 100644 --- a/src/Presentation/SmartStore.Web/Controllers/TaskSchedulerController.cs +++ b/src/Presentation/SmartStore.Web/Controllers/TaskSchedulerController.cs @@ -65,7 +65,7 @@ public ActionResult Sweep() } } - return Content("{0} tasks executed".FormatInvariant(count)); + return Content("{0} of {1} pending tasks executed".FormatInvariant(count, pendingTasks.Count)); } [HttpPost] From d401828451b56e35817f1b01770bf533cf9d0e1c Mon Sep 17 00:00:00 2001 From: Michael Herzog Date: Fri, 8 Jan 2016 14:30:31 +0100 Subject: [PATCH 221/707] Performance: eliminated sending of the whole product model to data grid via json response in several locations --- .../Controllers/CategoryController.cs | 9 ++- .../Controllers/ManufacturerController.cs | 9 ++- .../Controllers/ProductController.cs | 64 +++++++++++++++++-- 3 files changed, 73 insertions(+), 9 deletions(-) diff --git a/src/Presentation/SmartStore.Web/Administration/Controllers/CategoryController.cs b/src/Presentation/SmartStore.Web/Administration/Controllers/CategoryController.cs index a1b8d695d6..245cce40b5 100644 --- a/src/Presentation/SmartStore.Web/Administration/Controllers/CategoryController.cs +++ b/src/Presentation/SmartStore.Web/Administration/Controllers/CategoryController.cs @@ -911,7 +911,14 @@ public ActionResult ProductAddPopupList(GridCommand command, CategoryModel.AddCa gridModel.Data = products.Select(x => { - var productModel = x.ToModel(); + var productModel = new ProductModel + { + Sku = x.Sku, + Published = x.Published, + ProductTypeLabelHint = x.ProductTypeLabelHint, + Name = x.Name, + Id = x.Id + }; productModel.ProductTypeName = x.GetProductTypeLabel(_localizationService); return productModel; diff --git a/src/Presentation/SmartStore.Web/Administration/Controllers/ManufacturerController.cs b/src/Presentation/SmartStore.Web/Administration/Controllers/ManufacturerController.cs index 2e7460bff4..51f74261f5 100644 --- a/src/Presentation/SmartStore.Web/Administration/Controllers/ManufacturerController.cs +++ b/src/Presentation/SmartStore.Web/Administration/Controllers/ManufacturerController.cs @@ -596,7 +596,14 @@ public ActionResult ProductAddPopupList(GridCommand command, ManufacturerModel.A gridModel.Data = products.Select(x => { - var productModel = x.ToModel(); + var productModel = new ProductModel + { + Sku = x.Sku, + Published = x.Published, + ProductTypeLabelHint = x.ProductTypeLabelHint, + Name = x.Name, + Id = x.Id + }; productModel.ProductTypeName = x.GetProductTypeLabel(_localizationService); return productModel; diff --git a/src/Presentation/SmartStore.Web/Administration/Controllers/ProductController.cs b/src/Presentation/SmartStore.Web/Administration/Controllers/ProductController.cs index 09139d349c..bb8c302ba9 100644 --- a/src/Presentation/SmartStore.Web/Administration/Controllers/ProductController.cs +++ b/src/Presentation/SmartStore.Web/Administration/Controllers/ProductController.cs @@ -943,8 +943,18 @@ public ActionResult ProductList(GridCommand command, ProductListModel model) gridModel.Data = products.Select(x => { - var productModel = x.ToModel(); - productModel.FullDescription = ""; // Perf + var productModel = new ProductModel + { + Sku = x.Sku, + Published = x.Published, + ProductTypeLabelHint = x.ProductTypeLabelHint, + Name = x.Name, + Id = x.Id, + StockQuantity = x.StockQuantity, + Price = x.Price, + LimitedToStores = x.LimitedToStores + }; + PrepareProductPictureThumbnailModel(productModel, x); productModel.ProductTypeName = x.GetProductTypeLabel(_localizationService); @@ -1654,7 +1664,15 @@ public ActionResult RelatedProductAddPopupList(GridCommand command, ProductModel gridModel.Data = products.Select(x => { - var productModel = x.ToModel(); + var productModel = new ProductModel + { + Sku = x.Sku, + Published = x.Published, + ProductTypeLabelHint = x.ProductTypeLabelHint, + Name = x.Name, + Id = x.Id + }; + productModel.ProductTypeName = x.GetProductTypeLabel(_localizationService); return productModel; @@ -1876,7 +1894,15 @@ public ActionResult CrossSellProductAddPopupList(GridCommand command, ProductMod gridModel.Data = products.Select(x => { - var productModel = x.ToModel(); + var productModel = new ProductModel + { + Sku = x.Sku, + Published = x.Published, + ProductTypeLabelHint = x.ProductTypeLabelHint, + Name = x.Name, + Id = x.Id + }; + productModel.ProductTypeName = x.GetProductTypeLabel(_localizationService); return productModel; @@ -2095,7 +2121,15 @@ public ActionResult AssociatedProductAddPopupList(GridCommand command, ProductMo gridModel.Data = products.Select(x => { - var productModel = x.ToModel(); + var productModel = new ProductModel + { + Sku = x.Sku, + Published = x.Published, + ProductTypeLabelHint = x.ProductTypeLabelHint, + Name = x.Name, + Id = x.Id + }; + productModel.ProductTypeName = x.GetProductTypeLabel(_localizationService); return productModel; @@ -2411,7 +2445,15 @@ public ActionResult BundleItemAddPopupList(GridCommand command, ProductModel.Add gridModel.Data = products.Select(x => { - var productModel = x.ToModel(); + var productModel = new ProductModel + { + Sku = x.Sku, + Published = x.Published, + ProductTypeLabelHint = x.ProductTypeLabelHint, + Name = x.Name, + Id = x.Id + }; + productModel.ProductTypeName = x.GetProductTypeLabel(_localizationService); productModel.ProductSelectCheckboxClass = (!x.CanBeBundleItem() ? " hide" : ""); @@ -3611,7 +3653,15 @@ public ActionResult ProductAttributeValueLinkagePopupList(GridCommand command, P gridModel.Data = products.Select(x => { - var productModel = x.ToModel(); + var productModel = new ProductModel + { + Sku = x.Sku, + Published = x.Published, + ProductTypeLabelHint = x.ProductTypeLabelHint, + Name = x.Name, + Id = x.Id + }; + productModel.ProductTypeName = x.GetProductTypeLabel(_localizationService); return productModel; From 6530f97a5ab382a831c056d9f02ed8176bfd9429 Mon Sep 17 00:00:00 2001 From: Murat Cakir Date: Fri, 8 Jan 2016 19:38:35 +0100 Subject: [PATCH 222/707] Removed TaskScheduler sweep logging --- .../SmartStore.Services/Tasks/TaskScheduler.cs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/Libraries/SmartStore.Services/Tasks/TaskScheduler.cs b/src/Libraries/SmartStore.Services/Tasks/TaskScheduler.cs index 50b4df021b..8cb0fbc0d7 100644 --- a/src/Libraries/SmartStore.Services/Tasks/TaskScheduler.cs +++ b/src/Libraries/SmartStore.Services/Tasks/TaskScheduler.cs @@ -173,14 +173,14 @@ protected internal virtual void CallEndpoint(string url) } else { + _errCount = 0; var response = t.Result; - using (var logger = new TraceLogger()) - { - logger.Debug("TaskScheduler Sweep called successfully: {0}".FormatCurrent(response.GetResponseStream().AsString())); - } + //using (var logger = new TraceLogger()) + //{ + // logger.Debug("TaskScheduler Sweep called successfully: {0}".FormatCurrent(response.GetResponseStream().AsString())); + //} - _errCount = 0; response.Dispose(); } }); From 94cc64cd43133ea5f0a0d36b25d2d53181369d7b Mon Sep 17 00:00:00 2001 From: Marcus Gesing Date: Sat, 9 Jan 2016 12:55:50 +0100 Subject: [PATCH 223/707] Resolves #760 Setting to set a customer role for new registered users --- changelog.md | 1 + .../Domain/Customers/CustomerSettings.cs | 9 +- .../201512151526290_ImportFramework.cs | 22 +++ .../Customers/CustomerRegistrationService.cs | 148 +++++++++--------- .../Controllers/SettingController.cs | 26 +-- .../Settings/CustomerUserSettingsModel.cs | 10 +- .../Views/Setting/CustomerUser.cshtml | 11 +- .../CustomerRegistrationServiceTests.cs | 6 +- 8 files changed, 141 insertions(+), 92 deletions(-) diff --git a/changelog.md b/changelog.md index f6fa16e556..6a82d8e636 100644 --- a/changelog.md +++ b/changelog.md @@ -33,6 +33,7 @@ * #841 Activity log for deleting an order * More settings to control creation of SEO names * GMC feed: Supporting fields multipack, bundle, adult, energy efficiency class and custom label (0 to 4) +* #760 Setting to set a customer role for new registered users ### Improvements * (Perf) Implemented static caches for URL aliases and localized properties. Increases app startup and request speed by up to 30%. diff --git a/src/Libraries/SmartStore.Core/Domain/Customers/CustomerSettings.cs b/src/Libraries/SmartStore.Core/Domain/Customers/CustomerSettings.cs index 83380a63a3..d0dbf678e5 100644 --- a/src/Libraries/SmartStore.Core/Domain/Customers/CustomerSettings.cs +++ b/src/Libraries/SmartStore.Core/Domain/Customers/CustomerSettings.cs @@ -151,7 +151,6 @@ public CustomerSettings() /// public bool StoreLastVisitedPage { get; set; } - #region Form fields /// @@ -246,8 +245,12 @@ public CustomerSettings() #endregion - // codehint: sm-add (no ui, only db edit) public string PrefillLoginUsername { get; set; } public string PrefillLoginPwd { get; set; } - } + + /// + /// Identifier of a customer role that new registered customers will be assigned to + /// + public int RegisterCustomerRoleId { get; set; } + } } \ No newline at end of file diff --git a/src/Libraries/SmartStore.Data/Migrations/201512151526290_ImportFramework.cs b/src/Libraries/SmartStore.Data/Migrations/201512151526290_ImportFramework.cs index 7f2dec3086..2699566e17 100644 --- a/src/Libraries/SmartStore.Data/Migrations/201512151526290_ImportFramework.cs +++ b/src/Libraries/SmartStore.Data/Migrations/201512151526290_ImportFramework.cs @@ -316,6 +316,28 @@ public void MigrateLocaleResources(LocaleResourcesBuilder builder) builder.AddOrUpdate("Admin.System.Warnings.DigitsOnly", "Please enter digits only.", "Bitte nur Ziffern eingeben."); + + builder.AddOrUpdate("Account.Register.Errors.CannotRegisterSearchEngine", + "A search engine can't be registered.", + "Eine Suchmaschine kann nicht registriert werden."); + + builder.AddOrUpdate("Account.Register.Errors.CannotRegisterTaskAccount", + "A background task account can't be registered.", + "Das Konto einer geplanten Aufgabe kann nicht registriert werden."); + + builder.AddOrUpdate("Account.Register.Errors.AlreadyRegistered", + "The customer is already registered.", + "Der Kunde ist bereits registriert."); + + builder.AddOrUpdate("Admin.Customers.CustomerRoles.CannotFoundRole", + "The customer role \"{0}\" cannot be found.", + "Die Kundengruppe \"{0}\" wurde nicht gefunden."); + + builder.AddOrUpdate("Admin.Configuration.Settings.CustomerUser.RegisterCustomerRole", + "Customer role at registrations", + "Kundengruppe bei Registrierungen", + "Specifies a customer role that will be assigned to newly registered customers.", + "Legt eine Kundengruppe fest, die neu registrierten Kunden zugeordnet wird."); } } } diff --git a/src/Libraries/SmartStore.Services/Customers/CustomerRegistrationService.cs b/src/Libraries/SmartStore.Services/Customers/CustomerRegistrationService.cs index 1615a2ce96..49fb4587aa 100644 --- a/src/Libraries/SmartStore.Services/Customers/CustomerRegistrationService.cs +++ b/src/Libraries/SmartStore.Services/Customers/CustomerRegistrationService.cs @@ -3,23 +3,22 @@ using SmartStore.Core; using SmartStore.Core.Domain.Customers; using SmartStore.Core.Events; -using SmartStore.Services.Localization; +using SmartStore.Core.Localization; using SmartStore.Services.Messages; using SmartStore.Services.Security; namespace SmartStore.Services.Customers { - /// - /// Customer registration service - /// - public partial class CustomerRegistrationService : ICustomerRegistrationService + /// + /// Customer registration service + /// + public partial class CustomerRegistrationService : ICustomerRegistrationService { #region Fields private readonly ICustomerService _customerService; private readonly IEncryptionService _encryptionService; private readonly INewsLetterSubscriptionService _newsLetterSubscriptionService; - private readonly ILocalizationService _localizationService; private readonly RewardPointsSettings _rewardPointsSettings; private readonly CustomerSettings _customerSettings; private readonly IStoreContext _storeContext; @@ -35,31 +34,33 @@ public partial class CustomerRegistrationService : ICustomerRegistrationService public CustomerRegistrationService(ICustomerService customerService, IEncryptionService encryptionService, INewsLetterSubscriptionService newsLetterSubscriptionService, - ILocalizationService localizationService, RewardPointsSettings rewardPointsSettings, CustomerSettings customerSettings, IStoreContext storeContext, IEventPublisher eventPublisher) { this._customerService = customerService; this._encryptionService = encryptionService; this._newsLetterSubscriptionService = newsLetterSubscriptionService; - this._localizationService = localizationService; this._rewardPointsSettings = rewardPointsSettings; this._customerSettings = customerSettings; this._storeContext = storeContext; this._eventPublisher = eventPublisher; - } - #endregion + T = NullLocalizer.Instance; + } - #region Methods + #endregion - /// - /// Validate customer - /// - /// Username or email - /// Password - /// Result - public virtual bool ValidateCustomer(string usernameOrEmail, string password) + public Localizer T { get; set; } + + #region Methods + + /// + /// Validate customer + /// + /// Username or email + /// Password + /// Result + public virtual bool ValidateCustomer(string usernameOrEmail, string password) { Customer customer = null; if (_customerSettings.UsernamesEnabled) @@ -112,48 +113,46 @@ public virtual bool ValidateCustomer(string usernameOrEmail, string password) /// Result public virtual CustomerRegistrationResult RegisterCustomer(CustomerRegistrationRequest request) { - if (request == null) - throw new ArgumentNullException("request"); - - if (request.Customer == null) - throw new ArgumentException("Can't load current customer"); + Guard.ArgumentNotNull(() => request); + Guard.ArgumentNotNull(() => request.Customer); var result = new CustomerRegistrationResult(); + if (request.Customer.IsSearchEngineAccount()) { - result.AddError("Search engine can't be registered"); + result.AddError(T("Account.Register.Errors.CannotRegisterSearchEngine")); return result; } if (request.Customer.IsBackgroundTaskAccount()) { - result.AddError("Background task account can't be registered"); + result.AddError(T("Account.Register.Errors.CannotRegisterTaskAccount")); return result; } if (request.Customer.IsRegistered()) { - result.AddError("Current customer is already registered"); + result.AddError(T("Account.Register.Errors.AlreadyRegistered")); return result; } if (String.IsNullOrEmpty(request.Email)) { - result.AddError(_localizationService.GetResource("Account.Register.Errors.EmailIsNotProvided")); + result.AddError(T("Account.Register.Errors.EmailIsNotProvided")); return result; } if (!request.Email.IsEmail()) { - result.AddError(_localizationService.GetResource("Common.WrongEmail")); + result.AddError(T("Common.WrongEmail")); return result; } if (String.IsNullOrWhiteSpace(request.Password)) { - result.AddError(_localizationService.GetResource("Account.Register.Errors.PasswordIsNotProvided")); + result.AddError(T("Account.Register.Errors.PasswordIsNotProvided")); return result; } if (_customerSettings.UsernamesEnabled) { if (String.IsNullOrEmpty(request.Username)) { - result.AddError(_localizationService.GetResource("Account.Register.Errors.UsernameIsNotProvided")); + result.AddError(T("Account.Register.Errors.UsernameIsNotProvided")); return result; } } @@ -161,14 +160,14 @@ public virtual CustomerRegistrationResult RegisterCustomer(CustomerRegistrationR //validate unique user if (_customerService.GetCustomerByEmail(request.Email) != null) { - result.AddError(_localizationService.GetResource("Account.Register.Errors.EmailAlreadyExists")); + result.AddError(T("Account.Register.Errors.EmailAlreadyExists")); return result; } if (_customerSettings.UsernamesEnabled) { if (_customerService.GetCustomerByUsername(request.Username) != null) { - result.AddError(_localizationService.GetResource("Account.Register.Errors.UsernameAlreadyExists")); + result.AddError(T("Account.Register.Errors.UsernameAlreadyExists")); return result; } } @@ -180,45 +179,52 @@ public virtual CustomerRegistrationResult RegisterCustomer(CustomerRegistrationR switch (request.PasswordFormat) { - case PasswordFormat.Clear: - { - request.Customer.Password = request.Password; - } - break; - case PasswordFormat.Encrypted: - { - request.Customer.Password = _encryptionService.EncryptText(request.Password); - } - break; - case PasswordFormat.Hashed: - { - string saltKey = _encryptionService.CreateSaltKey(5); - request.Customer.PasswordSalt = saltKey; - request.Customer.Password = _encryptionService.CreatePasswordHash(request.Password, saltKey, _customerSettings.HashedPasswordFormat); - } - break; - default: - break; + case PasswordFormat.Clear: + request.Customer.Password = request.Password; + break; + case PasswordFormat.Encrypted: + request.Customer.Password = _encryptionService.EncryptText(request.Password); + break; + case PasswordFormat.Hashed: + string saltKey = _encryptionService.CreateSaltKey(5); + request.Customer.PasswordSalt = saltKey; + request.Customer.Password = _encryptionService.CreatePasswordHash(request.Password, saltKey, _customerSettings.HashedPasswordFormat); + break; } request.Customer.Active = request.IsApproved; - - //add to 'Registered' role - var registeredRole = _customerService.GetCustomerRoleBySystemName(SystemCustomerRoleNames.Registered); - if (registeredRole == null) - throw new SmartException("'Registered' role could not be loaded"); + + if (_customerSettings.RegisterCustomerRoleId != 0) + { + var customerRole = _customerService.GetCustomerRoleById(_customerSettings.RegisterCustomerRoleId); + request.Customer.CustomerRoles.Add(customerRole); + } + + //add to 'Registered' role + var registeredRole = _customerService.GetCustomerRoleBySystemName(SystemCustomerRoleNames.Registered); + if (registeredRole == null) + { + throw new SmartException(T("Admin.Customers.CustomerRoles.CannotFoundRole", "Registered")); + } + request.Customer.CustomerRoles.Add(registeredRole); + //remove from 'Guests' role var guestRole = request.Customer.CustomerRoles.FirstOrDefault(cr => cr.SystemName == SystemCustomerRoleNames.Guests); - if (guestRole != null) - request.Customer.CustomerRoles.Remove(guestRole); + if (guestRole != null) + { + request.Customer.CustomerRoles.Remove(guestRole); + } - //Add reward points for customer registration (if enabled) - if (_rewardPointsSettings.Enabled && _rewardPointsSettings.PointsForRegistration > 0) - request.Customer.AddRewardPointsHistoryEntry(_rewardPointsSettings.PointsForRegistration, _localizationService.GetResource("RewardPoints.Message.RegisteredAsCustomer")); + //Add reward points for customer registration (if enabled) + if (_rewardPointsSettings.Enabled && _rewardPointsSettings.PointsForRegistration > 0) + { + request.Customer.AddRewardPointsHistoryEntry(_rewardPointsSettings.PointsForRegistration, T("RewardPoints.Message.RegisteredAsCustomer")); + } _customerService.UpdateCustomer(request.Customer); - _eventPublisher.Publish(new CustomerRegisteredEvent{ Customer = request.Customer }); + _eventPublisher.Publish(new CustomerRegisteredEvent { Customer = request.Customer }); + return result; } @@ -235,19 +241,19 @@ public virtual PasswordChangeResult ChangePassword(ChangePasswordRequest request var result = new PasswordChangeResult(); if (String.IsNullOrWhiteSpace(request.Email)) { - result.AddError(_localizationService.GetResource("Account.ChangePassword.Errors.EmailIsNotProvided")); + result.AddError(T("Account.ChangePassword.Errors.EmailIsNotProvided")); return result; } if (String.IsNullOrWhiteSpace(request.NewPassword)) { - result.AddError(_localizationService.GetResource("Account.ChangePassword.Errors.PasswordIsNotProvided")); + result.AddError(T("Account.ChangePassword.Errors.PasswordIsNotProvided")); return result; } var customer = _customerService.GetCustomerByEmail(request.Email); if (customer == null) { - result.AddError(_localizationService.GetResource("Account.ChangePassword.Errors.EmailNotFound")); + result.AddError(T("Account.ChangePassword.Errors.EmailNotFound")); return result; } @@ -272,7 +278,7 @@ public virtual PasswordChangeResult ChangePassword(ChangePasswordRequest request bool oldPasswordIsValid = oldPwd == customer.Password; if (!oldPasswordIsValid) - result.AddError(_localizationService.GetResource("Account.ChangePassword.Errors.OldPasswordDoesntMatch")); + result.AddError(T("Account.ChangePassword.Errors.OldPasswordDoesntMatch")); if (oldPasswordIsValid) requestIsValid = true; @@ -327,14 +333,14 @@ public virtual void SetEmail(Customer customer, string newEmail) string oldEmail = customer.Email; if (!newEmail.IsEmail()) - throw new SmartException(_localizationService.GetResource("Account.EmailUsernameErrors.NewEmailIsNotValid")); + throw new SmartException(T("Account.EmailUsernameErrors.NewEmailIsNotValid")); if (newEmail.Length > 100) - throw new SmartException(_localizationService.GetResource("Account.EmailUsernameErrors.EmailTooLong")); + throw new SmartException(T("Account.EmailUsernameErrors.EmailTooLong")); var customer2 = _customerService.GetCustomerByEmail(newEmail); if (customer2 != null && customer.Id != customer2.Id) - throw new SmartException(_localizationService.GetResource("Account.EmailUsernameErrors.EmailAlreadyExists")); + throw new SmartException(T("Account.EmailUsernameErrors.EmailAlreadyExists")); customer.Email = newEmail; _customerService.UpdateCustomer(customer); @@ -370,11 +376,11 @@ public virtual void SetUsername(Customer customer, string newUsername) newUsername = newUsername.Trim(); if (newUsername.Length > 100) - throw new SmartException(_localizationService.GetResource("Account.EmailUsernameErrors.UsernameTooLong")); + throw new SmartException(T("Account.EmailUsernameErrors.UsernameTooLong")); var user2 = _customerService.GetCustomerByUsername(newUsername); if (user2 != null && customer.Id != user2.Id) - throw new SmartException(_localizationService.GetResource("Account.EmailUsernameErrors.UsernameAlreadyExists")); + throw new SmartException(T("Account.EmailUsernameErrors.UsernameAlreadyExists")); customer.Username = newUsername; _customerService.UpdateCustomer(customer); diff --git a/src/Presentation/SmartStore.Web/Administration/Controllers/SettingController.cs b/src/Presentation/SmartStore.Web/Administration/Controllers/SettingController.cs index 85ea07067b..47df2024dc 100644 --- a/src/Presentation/SmartStore.Web/Administration/Controllers/SettingController.cs +++ b/src/Presentation/SmartStore.Web/Administration/Controllers/SettingController.cs @@ -902,13 +902,15 @@ public ActionResult CustomerUser() var storeScope = this.GetActiveStoreScopeConfiguration(_services.StoreService, _services.WorkContext); StoreDependingSettings.CreateViewDataObject(storeScope); + var allCustomerRoles = _customerService.GetAllCustomerRoles(true); + var customerSettings = _services.Settings.LoadSetting(storeScope); var addressSettings = _services.Settings.LoadSetting(storeScope); var dateTimeSettings = _services.Settings.LoadSetting(storeScope); var externalAuthenticationSettings = _services.Settings.LoadSetting(storeScope); - //merge settings - var model = new CustomerUserSettingsModel(); + //merge settings + var model = new CustomerUserSettingsModel(); model.CustomerSettings = customerSettings.ToModel(); StoreDependingSettings.GetOverrideKeys(customerSettings, model.CustomerSettings, storeScope, _services.Settings, false); @@ -919,14 +921,15 @@ public ActionResult CustomerUser() model.DateTimeSettings.AllowCustomersToSetTimeZone = dateTimeSettings.AllowCustomersToSetTimeZone; model.DateTimeSettings.DefaultStoreTimeZoneId = _dateTimeHelper.DefaultStoreTimeZone.Id; + foreach (TimeZoneInfo timeZone in _dateTimeHelper.GetSystemTimeZones()) { - model.DateTimeSettings.AvailableTimeZones.Add(new SelectListItem() - { - Text = timeZone.DisplayName, - Value = timeZone.Id, - Selected = timeZone.Id.Equals(_dateTimeHelper.DefaultStoreTimeZone.Id, StringComparison.InvariantCultureIgnoreCase) - }); + model.DateTimeSettings.AvailableTimeZones.Add(new SelectListItem + { + Text = timeZone.DisplayName, + Value = timeZone.Id, + Selected = timeZone.Id.Equals(_dateTimeHelper.DefaultStoreTimeZone.Id, StringComparison.InvariantCultureIgnoreCase) + }); } StoreDependingSettings.GetOverrideKeys(dateTimeSettings, model.DateTimeSettings, storeScope, _services.Settings, false); @@ -938,7 +941,12 @@ public ActionResult CustomerUser() model.CustomerSettings.AvailableCustomerNumberMethods = customerSettings.CustomerNumberMethod.ToSelectList(); model.CustomerSettings.AvailableCustomerNumberVisibilities = customerSettings.CustomerNumberVisibility.ToSelectList(); - return View(model); + model.CustomerSettings.AvailableRegisterCustomerRoles = allCustomerRoles + .Where(x => x.SystemName != SystemCustomerRoleNames.Registered && x.SystemName != SystemCustomerRoleNames.Guests) + .Select(x => new SelectListItem { Text = x.Name, Value = x.Id.ToString() }) + .ToList(); + + return View(model); } [HttpPost] diff --git a/src/Presentation/SmartStore.Web/Administration/Models/Settings/CustomerUserSettingsModel.cs b/src/Presentation/SmartStore.Web/Administration/Models/Settings/CustomerUserSettingsModel.cs index 1ad5872150..2e076d6471 100644 --- a/src/Presentation/SmartStore.Web/Administration/Models/Settings/CustomerUserSettingsModel.cs +++ b/src/Presentation/SmartStore.Web/Administration/Models/Settings/CustomerUserSettingsModel.cs @@ -29,8 +29,9 @@ public partial class CustomerSettingsModel [SmartResourceDisplayName("Admin.Configuration.Settings.Catalog.DefaultSortOrderMode")] public CustomerNumberMethod CustomerNumberMethod { get; set; } public SelectList AvailableCustomerNumberMethods { get; set; } + public IList AvailableRegisterCustomerRoles { get; set; } - [SmartResourceDisplayName("Admin.Configuration.Settings.Catalog.DefaultSortOrderMode")] + [SmartResourceDisplayName("Admin.Configuration.Settings.Catalog.DefaultSortOrderMode")] public CustomerNumberVisibility CustomerNumberVisibility { get; set; } public SelectList AvailableCustomerNumberVisibilities { get; set; } @@ -43,7 +44,10 @@ public partial class CustomerSettingsModel [SmartResourceDisplayName("Admin.Configuration.Settings.CustomerUser.UserRegistrationType")] public int UserRegistrationType { get; set; } - [SmartResourceDisplayName("Admin.Configuration.Settings.CustomerUser.AllowCustomersToUploadAvatars")] + [SmartResourceDisplayName("Admin.Configuration.Settings.CustomerUser.RegisterCustomerRole")] + public int RegisterCustomerRoleId { get; set; } + + [SmartResourceDisplayName("Admin.Configuration.Settings.CustomerUser.AllowCustomersToUploadAvatars")] public bool AllowCustomersToUploadAvatars { get; set; } [SmartResourceDisplayName("Admin.Configuration.Settings.CustomerUser.DefaultAvatarEnabled")] @@ -131,7 +135,7 @@ public partial class CustomerSettingsModel public bool FaxEnabled { get; set; } [SmartResourceDisplayName("Admin.Configuration.Settings.CustomerUser.FaxRequired")] public bool FaxRequired { get; set; } - } + } public partial class AddressSettingsModel { diff --git a/src/Presentation/SmartStore.Web/Administration/Views/Setting/CustomerUser.cshtml b/src/Presentation/SmartStore.Web/Administration/Views/Setting/CustomerUser.cshtml index b22985819c..d3c493aad1 100644 --- a/src/Presentation/SmartStore.Web/Administration/Views/Setting/CustomerUser.cshtml +++ b/src/Presentation/SmartStore.Web/Administration/Views/Setting/CustomerUser.cshtml @@ -3,7 +3,6 @@ @using SmartStore.Core.Domain.Customers; @using SmartStore.Core.Domain.Security; @{ - //page title ViewBag.Title = T("Admin.Configuration.Settings.CustomerUser").Text; } @using (Html.BeginForm()) @@ -128,6 +127,16 @@ @Html.ValidationMessageFor(model => model.CustomerSettings.UserRegistrationType)
    + @Html.SmartLabelFor(model => model.CustomerSettings.RegisterCustomerRoleId) + + @Html.SettingOverrideCheckbox(model => Model.CustomerSettings.RegisterCustomerRoleId) + @Html.DropDownListFor(model => model.CustomerSettings.RegisterCustomerRoleId, Model.CustomerSettings.AvailableRegisterCustomerRoles, T("Common.Unspecified")) + @Html.ValidationMessageFor(model => model.CustomerSettings.RegisterCustomerRoleId) +
    @Html.SmartLabelFor(model => model.CustomerSettings.AllowCustomersToUploadAvatars) diff --git a/src/Tests/SmartStore.Services.Tests/Customers/CustomerRegistrationServiceTests.cs b/src/Tests/SmartStore.Services.Tests/Customers/CustomerRegistrationServiceTests.cs index b356946e7c..990c27b02f 100644 --- a/src/Tests/SmartStore.Services.Tests/Customers/CustomerRegistrationServiceTests.cs +++ b/src/Tests/SmartStore.Services.Tests/Customers/CustomerRegistrationServiceTests.cs @@ -11,7 +11,6 @@ using SmartStore.Core.Events; using SmartStore.Services.Common; using SmartStore.Services.Customers; -using SmartStore.Services.Localization; using SmartStore.Services.Messages; using SmartStore.Services.Security; using SmartStore.Tests; @@ -29,7 +28,6 @@ public class CustomerRegistrationServiceTests : ServiceTest IEncryptionService _encryptionService; ICustomerService _customerService; ICustomerRegistrationService _customerRegistrationService; - ILocalizationService _localizationService; CustomerSettings _customerSettings; INewsLetterSubscriptionService _newsLetterSubscriptionService; IEventPublisher _eventPublisher; @@ -117,15 +115,13 @@ public class CustomerRegistrationServiceTests : ServiceTest _genericAttributeService = MockRepository.GenerateMock(); _newsLetterSubscriptionService = MockRepository.GenerateMock(); - _localizationService = MockRepository.GenerateMock(); _storeContext = MockRepository.GenerateMock(); _customerService = new CustomerService(new NullCache(), _customerRepo, _customerRoleRepo, _genericAttributeRepo, _rewardPointsHistoryRepo, _genericAttributeService, _eventPublisher, _rewardPointsSettings); _customerRegistrationService = new CustomerRegistrationService(_customerService, - _encryptionService, _newsLetterSubscriptionService, _localizationService, - _rewardPointsSettings, _customerSettings, _storeContext, _eventPublisher); + _encryptionService, _newsLetterSubscriptionService, _rewardPointsSettings, _customerSettings, _storeContext, _eventPublisher); } //[Test] From 019a4d24f9f72f7f45cfb798b19b102e30017efe Mon Sep 17 00:00:00 2001 From: Marcus Gesing Date: Sun, 10 Jan 2016 11:49:19 +0100 Subject: [PATCH 224/707] Resolves #800 Multi-store: Option to display all orders of all stores for customer in frontend --- changelog.md | 1 + .../Domain/Orders/OrderSettings.cs | 6 +++- .../201512151526290_ImportFramework.cs | 9 ++++++ .../Controllers/SettingController.cs | 5 ++- .../Infrastructure/AutoMapperStartupTask.cs | 1 + .../Models/Settings/OrderSettingsModel.cs | 4 +++ .../Administration/Views/Setting/Order.cshtml | 12 +++++++ .../Controllers/CustomerController.cs | 31 ++++++++++++------- 8 files changed, 55 insertions(+), 14 deletions(-) diff --git a/changelog.md b/changelog.md index 6a82d8e636..519c0f8906 100644 --- a/changelog.md +++ b/changelog.md @@ -34,6 +34,7 @@ * More settings to control creation of SEO names * GMC feed: Supporting fields multipack, bundle, adult, energy efficiency class and custom label (0 to 4) * #760 Setting to set a customer role for new registered users +* #800 Multi-store: Option to display all orders of all stores for customer in frontend ### Improvements * (Perf) Implemented static caches for URL aliases and localized properties. Increases app startup and request speed by up to 30%. diff --git a/src/Libraries/SmartStore.Core/Domain/Orders/OrderSettings.cs b/src/Libraries/SmartStore.Core/Domain/Orders/OrderSettings.cs index 7a55c36f70..996271de79 100644 --- a/src/Libraries/SmartStore.Core/Domain/Orders/OrderSettings.cs +++ b/src/Libraries/SmartStore.Core/Domain/Orders/OrderSettings.cs @@ -83,5 +83,9 @@ public OrderSettings() /// public int MinimumOrderPlacementInterval { get; set; } - } + /// + /// Gets or sets a value indicating whether to display all orders of all stores to a customer + /// + public bool DisplayOrdersOfAllStores { get; set; } + } } \ No newline at end of file diff --git a/src/Libraries/SmartStore.Data/Migrations/201512151526290_ImportFramework.cs b/src/Libraries/SmartStore.Data/Migrations/201512151526290_ImportFramework.cs index 2699566e17..767af5b90c 100644 --- a/src/Libraries/SmartStore.Data/Migrations/201512151526290_ImportFramework.cs +++ b/src/Libraries/SmartStore.Data/Migrations/201512151526290_ImportFramework.cs @@ -338,6 +338,15 @@ public void MigrateLocaleResources(LocaleResourcesBuilder builder) "Kundengruppe bei Registrierungen", "Specifies a customer role that will be assigned to newly registered customers.", "Legt eine Kundengruppe fest, die neu registrierten Kunden zugeordnet wird."); + + builder.AddOrUpdate("Admin.Configuration.Settings.Order.DisplayOrdersOfAllStores", + "Display orders of all stores", + "Auftrge aller Shops anzeigen", + "Specifies whether to display the orders of all stores to the customer. If this option is disabled, only the orders of the current store are displayed.", + "Legt fest, ob dem Kunden die Auftrge aller Shops angezeigt werden sollen. Ist diese Option deaktiviert, so werden nur die Auftrge des aktuellen Shops angezeigt."); + + builder.AddOrUpdate("Admin.Configuration.Settings.Order.GiftCards_Deactivated") + .Value("de", "Geschenkgutschein wird deaktiviert, wenn Auftragsstatus..."); } } } diff --git a/src/Presentation/SmartStore.Web/Administration/Controllers/SettingController.cs b/src/Presentation/SmartStore.Web/Administration/Controllers/SettingController.cs index 47df2024dc..1d9becf2f3 100644 --- a/src/Presentation/SmartStore.Web/Administration/Controllers/SettingController.cs +++ b/src/Presentation/SmartStore.Web/Administration/Controllers/SettingController.cs @@ -685,13 +685,16 @@ public ActionResult Order() //load settings for a chosen store scope var storeScope = this.GetActiveStoreScopeConfiguration(_services.StoreService, _services.WorkContext); var orderSettings = _services.Settings.LoadSetting(storeScope); - var store = (storeScope == 0 ? _services.StoreContext.CurrentStore : _services.StoreService.GetStoreById(storeScope)); + + var allStores = _services.StoreService.GetAllStores(); + var store = (storeScope == 0 ? _services.StoreContext.CurrentStore : allStores.FirstOrDefault(x => x.Id == storeScope)); var model = orderSettings.ToModel(); StoreDependingSettings.GetOverrideKeys(orderSettings, model, storeScope, _services.Settings); model.PrimaryStoreCurrencyCode = store.PrimaryStoreCurrency.CurrencyCode; + model.StoreCount = allStores.Count; //gift card activation/deactivation model.GiftCards_Activated_OrderStatuses = OrderStatus.Pending.ToSelectList(false).ToList(); diff --git a/src/Presentation/SmartStore.Web/Administration/Infrastructure/AutoMapperStartupTask.cs b/src/Presentation/SmartStore.Web/Administration/Infrastructure/AutoMapperStartupTask.cs index 9c6a24d877..3cbb5afe21 100644 --- a/src/Presentation/SmartStore.Web/Administration/Infrastructure/AutoMapperStartupTask.cs +++ b/src/Presentation/SmartStore.Web/Administration/Infrastructure/AutoMapperStartupTask.cs @@ -640,6 +640,7 @@ public void Execute() .ForMember(dest => dest.GiftCards_Activated_OrderStatuses, mo => mo.Ignore()) .ForMember(dest => dest.GiftCards_Deactivated_OrderStatuses, mo => mo.Ignore()) .ForMember(dest => dest.PrimaryStoreCurrencyCode, mo => mo.Ignore()) + .ForMember(dest => dest.StoreCount, mo => mo.Ignore()) .ForMember(dest => dest.OrderIdent, mo => mo.Ignore()) .ForMember(dest => dest.Locales, mo => mo.Ignore()); Mapper.CreateMap() diff --git a/src/Presentation/SmartStore.Web/Administration/Models/Settings/OrderSettingsModel.cs b/src/Presentation/SmartStore.Web/Administration/Models/Settings/OrderSettingsModel.cs index ea2bc65410..c54a264eb5 100644 --- a/src/Presentation/SmartStore.Web/Administration/Models/Settings/OrderSettingsModel.cs +++ b/src/Presentation/SmartStore.Web/Administration/Models/Settings/OrderSettingsModel.cs @@ -58,10 +58,14 @@ public OrderSettingsModel() public IList GiftCards_Deactivated_OrderStatuses { get; set; } public string PrimaryStoreCurrencyCode { get; set; } + public int StoreCount { get; set; } [SmartResourceDisplayName("Admin.Configuration.Settings.Order.OrderIdent")] public int? OrderIdent { get; set; } + [SmartResourceDisplayName("Admin.Configuration.Settings.Order.DisplayOrdersOfAllStores")] + public bool DisplayOrdersOfAllStores { get; set; } + public IList Locales { get; set; } } diff --git a/src/Presentation/SmartStore.Web/Administration/Views/Setting/Order.cshtml b/src/Presentation/SmartStore.Web/Administration/Views/Setting/Order.cshtml index 3c29b263a1..df566da1ed 100644 --- a/src/Presentation/SmartStore.Web/Administration/Views/Setting/Order.cshtml +++ b/src/Presentation/SmartStore.Web/Administration/Views/Setting/Order.cshtml @@ -116,6 +116,18 @@
    + @Html.SmartLabelFor(model => model.DisplayOrdersOfAllStores) + + @Html.SettingEditorFor(model => model.DisplayOrdersOfAllStores) + @Html.ValidationMessageFor(model => model.DisplayOrdersOfAllStores) +
    } diff --git a/src/Presentation/SmartStore.Web/Controllers/CustomerController.cs b/src/Presentation/SmartStore.Web/Controllers/CustomerController.cs index 1c9fa88791..e6b81ab62f 100644 --- a/src/Presentation/SmartStore.Web/Controllers/CustomerController.cs +++ b/src/Presentation/SmartStore.Web/Controllers/CustomerController.cs @@ -360,11 +360,14 @@ protected CustomerOrderListModel PrepareCustomerOrderListModel(Customer customer var model = new CustomerOrderListModel(); model.NavigationModel = GetCustomerNavigationModel(customer); model.NavigationModel.SelectedTab = CustomerNavigationEnum.Orders; - var orders = _orderService.SearchOrders(_storeContext.CurrentStore.Id, customer.Id, - null, null, null, null, null, null, null, null, 0, int.MaxValue); + + var storeScope = (_orderSettings.DisplayOrdersOfAllStores ? 0 : _storeContext.CurrentStore.Id); + + var orders = _orderService.SearchOrders(storeScope, customer.Id, null, null, null, null, null, null, null, null, 0, int.MaxValue); + foreach (var order in orders) { - var orderModel = new CustomerOrderListModel.OrderDetailsModel() + var orderModel = new CustomerOrderListModel.OrderDetailsModel { Id = order.Id, OrderNumber = order.GetOrderNumber(), @@ -372,6 +375,7 @@ protected CustomerOrderListModel PrepareCustomerOrderListModel(Customer customer OrderStatus = order.OrderStatus.GetLocalizedEnum(_localizationService, _workContext), IsReturnRequestAllowed = _orderProcessingService.IsReturnRequestAllowed(order) }; + var orderTotalInCustomerCurrency = _currencyService.ConvertCurrency(order.OrderTotal, order.CurrencyRate); orderModel.OrderTotal = _priceFormatter.FormatPrice(orderTotalInCustomerCurrency, true, order.CustomerCurrencyCode, false, _workContext.WorkingLanguage); @@ -382,7 +386,7 @@ protected CustomerOrderListModel PrepareCustomerOrderListModel(Customer customer foreach (var recurringPayment in recurringPayments) { - var recurringPaymentModel = new CustomerOrderListModel.RecurringOrderModel() + var recurringPaymentModel = new CustomerOrderListModel.RecurringOrderModel { Id = recurringPayment.Id, StartDate = _dateTimeHelper.ConvertToUserTime(recurringPayment.StartDateUtc, DateTimeKind.Utc).ToString(), @@ -1291,6 +1295,7 @@ public ActionResult Orders() var customer = _workContext.CurrentCustomer; var model = PrepareCustomerOrderListModel(customer); + return View(model); } @@ -1303,9 +1308,13 @@ public ActionResult CancelRecurringPayment(FormCollection form) //get recurring payment identifier int recurringPaymentId = 0; - foreach (var formValue in form.AllKeys) - if (formValue.StartsWith("cancelRecurringPayment", StringComparison.InvariantCultureIgnoreCase)) - recurringPaymentId = Convert.ToInt32(formValue.Substring("cancelRecurringPayment".Length)); + foreach (var formValue in form.AllKeys) + { + if (formValue.StartsWith("cancelRecurringPayment", StringComparison.InvariantCultureIgnoreCase)) + { + recurringPaymentId = Convert.ToInt32(formValue.Substring("cancelRecurringPayment".Length)); + } + } var recurringPayment = _orderService.GetRecurringPaymentById(recurringPaymentId); if (recurringPayment == null) @@ -1323,11 +1332,9 @@ public ActionResult CancelRecurringPayment(FormCollection form) return View(model); } - else - { - return RedirectToAction("Orders"); - } - } + + return RedirectToAction("Orders"); + } #endregion From 480cb8f4d23dd7e6379bf01eed349d47aadebabc Mon Sep 17 00:00:00 2001 From: Marcus Gesing Date: Mon, 11 Jan 2016 13:29:59 +0100 Subject: [PATCH 225/707] Resolves #790 Improve language editing --- changelog.md | 1 + .../201512151526290_ImportFramework.cs | 10 + .../Administration/Content/admin.less | 15 ++ .../Controllers/LanguageController.cs | 195 +++++++++--------- .../Infrastructure/AutoMapperStartupTask.cs | 4 +- .../Models/Localization/LanguageModel.cs | 13 +- .../Localization/LanguageValidator.cs | 29 +-- .../Administration/Views/Language/List.cshtml | 7 +- .../Views/Language/_CreateOrUpdate.cshtml | 86 ++++---- 9 files changed, 205 insertions(+), 155 deletions(-) diff --git a/changelog.md b/changelog.md index 519c0f8906..f8dec5cd62 100644 --- a/changelog.md +++ b/changelog.md @@ -70,6 +70,7 @@ * Product grid sortable by name, price and created on * #26 Display company or name in order list * Added inline editing of country grid +* #790 Improved language editing ### Bugfixes * #523 Redirecting to payment provider performed by core instead of plugin diff --git a/src/Libraries/SmartStore.Data/Migrations/201512151526290_ImportFramework.cs b/src/Libraries/SmartStore.Data/Migrations/201512151526290_ImportFramework.cs index 767af5b90c..f281df8a32 100644 --- a/src/Libraries/SmartStore.Data/Migrations/201512151526290_ImportFramework.cs +++ b/src/Libraries/SmartStore.Data/Migrations/201512151526290_ImportFramework.cs @@ -347,6 +347,16 @@ public void MigrateLocaleResources(LocaleResourcesBuilder builder) builder.AddOrUpdate("Admin.Configuration.Settings.Order.GiftCards_Deactivated") .Value("de", "Geschenkgutschein wird deaktiviert, wenn Auftragsstatus..."); + + builder.AddOrUpdate("Admin.Configuration.Languages.Fields.UniqueSeoCode.Required", + "Please select a SEO language code.", + "Bitte legen Sie einen SEO Sprach-Code fest."); + + builder.AddOrUpdate("Admin.Configuration.Languages.Fields.FlagImageFileName", + "Flag image", + "Flaggenbild", + "Specifies the flag image. The files for the flag images must be stored in /Content/Images/flags/.", + "Legt das Flaggenbild fest. Die Dateien der Flaggenbilder mssen in /Content/Images/flags/ liegen."); } } } diff --git a/src/Presentation/SmartStore.Web/Administration/Content/admin.less b/src/Presentation/SmartStore.Web/Administration/Content/admin.less index eff6584861..26c3604e2a 100644 --- a/src/Presentation/SmartStore.Web/Administration/Content/admin.less +++ b/src/Presentation/SmartStore.Web/Administration/Content/admin.less @@ -432,6 +432,21 @@ td.adminData > input[type="checkbox"] { min-width: 314px; /* ensures more clean look & feel */ } +.select2-image-item { + img { + margin-bottom: 3px; + } + span:not(.select2-icon) { + padding-left: 5px; + } + .icon-container { + float: left; + display: inline-block; + width: 16px; + min-width: 16px; + max-width: 16px; + } +} /* select2 with large, templated items -------------------------------------------------------------- */ diff --git a/src/Presentation/SmartStore.Web/Administration/Controllers/LanguageController.cs b/src/Presentation/SmartStore.Web/Administration/Controllers/LanguageController.cs index 02587df34f..20824005a4 100644 --- a/src/Presentation/SmartStore.Web/Administration/Controllers/LanguageController.cs +++ b/src/Presentation/SmartStore.Web/Administration/Controllers/LanguageController.cs @@ -1,15 +1,17 @@ using System; using System.Collections.Generic; +using System.Globalization; using System.IO; using System.Linq; using System.Web.Mvc; using SmartStore.Admin.Models.Localization; -using SmartStore.Core; using SmartStore.Core.Data; using SmartStore.Core.Domain.Common; using SmartStore.Core.Domain.DataExchange; using SmartStore.Core.Domain.Localization; using SmartStore.Core.Plugins; +using SmartStore.Services; +using SmartStore.Services.Directory; using SmartStore.Services.Localization; using SmartStore.Services.Security; using SmartStore.Services.Stores; @@ -28,74 +30,95 @@ public partial class LanguageController : AdminControllerBase #region Fields private readonly ILanguageService _languageService; - private readonly ILocalizationService _localizationService; - private readonly IStoreService _storeService; private readonly IStoreMappingService _storeMappingService; - private readonly IPermissionService _permissionService; - private readonly IWebHelper _webHelper; private readonly AdminAreaSettings _adminAreaSettings; private readonly IPluginFinder _pluginFinder; + private readonly ICountryService _countryService; + private readonly ICommonServices _services; #endregion #region Constructors public LanguageController(ILanguageService languageService, - ILocalizationService localizationService, - IStoreService storeService, IStoreMappingService storeMappingService, - IPermissionService permissionService, - IWebHelper webHelper, AdminAreaSettings adminAreaSettings, - IPluginFinder pluginFinder) + IPluginFinder pluginFinder, + ICountryService countryService, + ICommonServices services) { - this._localizationService = localizationService; this._languageService = languageService; - this._storeService = storeService; this._storeMappingService = storeMappingService; - this._permissionService = permissionService; - this._webHelper = webHelper; this._adminAreaSettings = adminAreaSettings; this._pluginFinder = pluginFinder; + this._countryService = countryService; + this._services = services; } - #endregion - + #endregion + #region Utilities - [NonAction] - private void PrepareFlagsModel(LanguageModel model) - { - if (model == null) - throw new ArgumentNullException("model"); + private void PrepareLanguageModel(LanguageModel model, Language language, bool excludeProperties) + { + var languageId = _services.WorkContext.WorkingLanguage.Id; - model.FlagFileNames = System.IO.Directory - .EnumerateFiles(_webHelper.MapPath("~/Content/Images/flags/"), "*.png", SearchOption.TopDirectoryOnly) - .Select(System.IO.Path.GetFileName) - .ToList(); - } + var allCultures = CultureInfo.GetCultures(CultureTypes.SpecificCultures) + .OrderBy(x => x.DisplayName) + .ToList(); - [NonAction] - private void PrepareStoresMappingModel(LanguageModel model, Language language, bool excludeProperties) - { - if (model == null) - throw new ArgumentNullException("model"); + var allCountryNames = _countryService.GetAllCountries(true) + .ToDictionary(x => x.TwoLetterIsoCode.EmptyNull().ToLower(), x => x.GetLocalized(y => y.Name, languageId, true, false)); - model.AvailableStores = _storeService - .GetAllStores() - .Select(s => s.ToModel()) + model.AvailableCultures = allCultures + .Select(x => new SelectListItem { Text = "{0} [{1}]".FormatInvariant(x.DisplayName, x.IetfLanguageTag), Value = x.IetfLanguageTag }) .ToList(); - if (!excludeProperties) + + model.AvailableTwoLetterLanguageCodes = new List(); + model.AvailableFlags = new List(); + + foreach (var item in allCultures) { - if (language != null) - { - model.SelectedStoreIds = _storeMappingService.GetStoresIdsWithAccess(language); - } - else + if (!model.AvailableTwoLetterLanguageCodes.Any(x => x.Value.IsCaseInsensitiveEqual(item.TwoLetterISOLanguageName))) { - model.SelectedStoreIds = new int[0]; + // display language name is not provided by net framework + var index = item.DisplayName.EmptyNull().IndexOf(" ("); + + if (index == -1) + index = item.DisplayName.EmptyNull().IndexOf(" ["); + + var displayName = "{0} [{1}]".FormatInvariant( + index == -1 ? item.DisplayName : item.DisplayName.Substring(0, index), + item.TwoLetterISOLanguageName); + + model.AvailableTwoLetterLanguageCodes.Add(new SelectListItem { Text = displayName, Value = item.TwoLetterISOLanguageName }); } } + + foreach (var path in Directory.EnumerateFiles(_services.WebHelper.MapPath("~/Content/Images/flags/"), "*.png", SearchOption.TopDirectoryOnly)) + { + var name = Path.GetFileNameWithoutExtension(path).EmptyNull().ToLower(); + string countryDescription = null; + + if (allCountryNames.ContainsKey(name)) + countryDescription = "{0} [{1}]".FormatInvariant(allCountryNames[name], name); + + if (countryDescription.IsEmpty()) + countryDescription = name; + + model.AvailableFlags.Add(new SelectListItem { Text = countryDescription, Value = Path.GetFileName(path) }); + } + + model.AvailableFlags = model.AvailableFlags.OrderBy(x => x.Text).ToList(); + + model.AvailableStores = _services.StoreService.GetAllStores() + .Select(s => s.ToModel()) + .ToList(); + + if (!excludeProperties) + { + model.SelectedStoreIds = _storeMappingService.GetStoresIdsWithAccess(language); + } } #endregion @@ -109,15 +132,17 @@ public ActionResult Index() public ActionResult List() { - if (!_permissionService.Authorize(StandardPermissionProvider.ManageLanguages)) + if (!_services.Permissions.Authorize(StandardPermissionProvider.ManageLanguages)) return AccessDeniedView(); var languages = _languageService.GetAllLanguages(true); + var gridModel = new GridModel { Data = languages.Select(x => x.ToModel()), Total = languages.Count() }; + return View(gridModel); } @@ -126,7 +151,7 @@ public ActionResult List(GridCommand command) { var model = new GridModel(); - if (_permissionService.Authorize(StandardPermissionProvider.ManageLanguages)) + if (_services.Permissions.Authorize(StandardPermissionProvider.ManageLanguages)) { var languages = _languageService.GetAllLanguages(true); @@ -148,26 +173,20 @@ public ActionResult List(GridCommand command) public ActionResult Create() { - if (!_permissionService.Authorize(StandardPermissionProvider.ManageLanguages)) + if (!_services.Permissions.Authorize(StandardPermissionProvider.ManageLanguages)) return AccessDeniedView(); var model = new LanguageModel(); - //flags - PrepareFlagsModel(model); - - //Stores - PrepareStoresMappingModel(model, null, false); + PrepareLanguageModel(model, null, false); - //default values - //model.Published = true; return View(model); } [HttpPost, ParameterBasedOnFormName("save-continue", "continueEditing")] public ActionResult Create(LanguageModel model, bool continueEditing) { - if (!_permissionService.Authorize(StandardPermissionProvider.ManageLanguages)) + if (!_services.Permissions.Authorize(StandardPermissionProvider.ManageLanguages)) return AccessDeniedView(); if (ModelState.IsValid) @@ -183,18 +202,14 @@ public ActionResult Create(LanguageModel model, bool continueEditing) foreach (var plugin in plugins) { - _localizationService.ImportPluginResourcesFromXml(plugin, null, false, filterLanguages); + _services.Localization.ImportPluginResourcesFromXml(plugin, null, false, filterLanguages); } - NotifySuccess(_localizationService.GetResource("Admin.Configuration.Languages.Added")); + NotifySuccess(T("Admin.Configuration.Languages.Added")); return continueEditing ? RedirectToAction("Edit", new { id = language.Id }) : RedirectToAction("List"); } - //flags - PrepareFlagsModel(model); - - //Stores - PrepareStoresMappingModel(model, null, true); + PrepareLanguageModel(model, null, true); //If we got this far, something failed, redisplay form return View(model); @@ -202,7 +217,7 @@ public ActionResult Create(LanguageModel model, bool continueEditing) public ActionResult Edit(int id) { - if (!_permissionService.Authorize(StandardPermissionProvider.ManageLanguages)) + if (!_services.Permissions.Authorize(StandardPermissionProvider.ManageLanguages)) return AccessDeniedView(); var language = _languageService.GetLanguageById(id); @@ -214,11 +229,7 @@ public ActionResult Edit(int id) var model = language.ToModel(); - //flags - PrepareFlagsModel(model); - - //Stores - PrepareStoresMappingModel(model, language, false); + PrepareLanguageModel(model, language, false); return View(model); } @@ -226,7 +237,7 @@ public ActionResult Edit(int id) [HttpPost, ParameterBasedOnFormName("save-continue", "continueEditing")] public ActionResult Edit(LanguageModel model, bool continueEditing) { - if (!_permissionService.Authorize(StandardPermissionProvider.ManageLanguages)) + if (!_services.Permissions.Authorize(StandardPermissionProvider.ManageLanguages)) return AccessDeniedView(); var language = _languageService.GetLanguageById(model.Id); @@ -252,15 +263,11 @@ public ActionResult Edit(LanguageModel model, bool continueEditing) _storeMappingService.SaveStoreMappings(language, model.SelectedStoreIds); //notification - NotifySuccess(_localizationService.GetResource("Admin.Configuration.Languages.Updated")); + NotifySuccess(T("Admin.Configuration.Languages.Updated")); return continueEditing ? RedirectToAction("Edit", new { id = language.Id }) : RedirectToAction("List"); } - //flags - PrepareFlagsModel(model); - - //Stores - PrepareStoresMappingModel(model, language, true); + PrepareLanguageModel(model, language, true); //If we got this far, something failed, redisplay form return View(model); @@ -269,7 +276,7 @@ public ActionResult Edit(LanguageModel model, bool continueEditing) [HttpPost] public ActionResult Delete(int id) { - if (!_permissionService.Authorize(StandardPermissionProvider.ManageLanguages)) + if (!_services.Permissions.Authorize(StandardPermissionProvider.ManageLanguages)) return AccessDeniedView(); var language = _languageService.GetLanguageById(id); @@ -288,7 +295,7 @@ public ActionResult Delete(int id) _languageService.DeleteLanguage(language); //notification - NotifySuccess(_localizationService.GetResource("Admin.Configuration.Languages.Deleted")); + NotifySuccess(T("Admin.Configuration.Languages.Deleted")); return RedirectToAction("List"); } @@ -298,7 +305,7 @@ public ActionResult Delete(int id) public ActionResult Resources(int languageId) { - if (!_permissionService.Authorize(StandardPermissionProvider.ManageLanguages)) + if (!_services.Permissions.Authorize(StandardPermissionProvider.ManageLanguages)) return AccessDeniedView(); ViewBag.AllLanguages = _languageService.GetAllLanguages(true) @@ -312,7 +319,7 @@ public ActionResult Resources(int languageId) ViewBag.LanguageId = languageId; ViewBag.LanguageName = language.Name; - var resources = _localizationService + var resources = _services.Localization .GetResourceValues(languageId, true) .Where(x => x.Key != "!!___EOF___!!" && x.Value != null) .OrderBy(x => x.Key) @@ -339,11 +346,11 @@ public ActionResult Resources(int languageId, GridCommand command) { var model = new GridModel(); - if (_permissionService.Authorize(StandardPermissionProvider.ManageLanguages)) + if (_services.Permissions.Authorize(StandardPermissionProvider.ManageLanguages)) { var language = _languageService.GetLanguageById(languageId); - var resources = _localizationService + var resources = _services.Localization .GetResourceValues(languageId, true) .OrderBy(x => x.Key) .Where(x => x.Key != "!!___EOF___!!" && x.Value != null) @@ -377,7 +384,7 @@ public ActionResult Resources(int languageId, GridCommand command) [GridAction(EnableCustomBinding = true)] public ActionResult ResourceUpdate(LanguageResourceModel model, GridCommand command) { - if (_permissionService.Authorize(StandardPermissionProvider.ManageLanguages)) + if (_services.Permissions.Authorize(StandardPermissionProvider.ManageLanguages)) { if (model.Name != null) model.Name = model.Name.Trim(); @@ -390,11 +397,11 @@ public ActionResult ResourceUpdate(LanguageResourceModel model, GridCommand comm return Content(modelStateErrors.FirstOrDefault()); } - var resource = _localizationService.GetLocaleStringResourceById(model.Id); + var resource = _services.Localization.GetLocaleStringResourceById(model.Id); // if the resourceName changed, ensure it isn't being used by another resource if (!resource.ResourceName.Equals(model.Name, StringComparison.InvariantCultureIgnoreCase)) { - var res = _localizationService.GetLocaleStringResourceByName(model.Name, model.LanguageId, false); + var res = _services.Localization.GetLocaleStringResourceByName(model.Name, model.LanguageId, false); if (res != null && res.Id != resource.Id) { return Content(T("Admin.Configuration.Languages.Resources.NameAlreadyExists", res.ResourceName)); @@ -405,7 +412,7 @@ public ActionResult ResourceUpdate(LanguageResourceModel model, GridCommand comm resource.ResourceValue = model.Value; resource.IsTouched = true; - _localizationService.UpdateLocaleStringResource(resource); + _services.Localization.UpdateLocaleStringResource(resource); } return Resources(model.LanguageId, command); @@ -414,7 +421,7 @@ public ActionResult ResourceUpdate(LanguageResourceModel model, GridCommand comm [GridAction(EnableCustomBinding = true)] public ActionResult ResourceAdd(int id, LanguageResourceModel model, GridCommand command) { - if (_permissionService.Authorize(StandardPermissionProvider.ManageLanguages)) + if (_services.Permissions.Authorize(StandardPermissionProvider.ManageLanguages)) { if (model.Name != null) model.Name = model.Name.Trim(); @@ -427,7 +434,7 @@ public ActionResult ResourceAdd(int id, LanguageResourceModel model, GridCommand return Content(modelStateErrors.FirstOrDefault()); } - var res = _localizationService.GetLocaleStringResourceByName(model.Name, model.LanguageId, false); + var res = _services.Localization.GetLocaleStringResourceByName(model.Name, model.LanguageId, false); if (res == null) { var resource = new LocaleStringResource { LanguageId = id }; @@ -435,7 +442,7 @@ public ActionResult ResourceAdd(int id, LanguageResourceModel model, GridCommand resource.ResourceValue = model.Value; resource.IsTouched = true; - _localizationService.InsertLocaleStringResource(resource); + _services.Localization.InsertLocaleStringResource(resource); } else { @@ -449,11 +456,11 @@ public ActionResult ResourceAdd(int id, LanguageResourceModel model, GridCommand [GridAction(EnableCustomBinding = true)] public ActionResult ResourceDelete(int id, int languageId, GridCommand command) { - if (_permissionService.Authorize(StandardPermissionProvider.ManageLanguages)) + if (_services.Permissions.Authorize(StandardPermissionProvider.ManageLanguages)) { - var resource = _localizationService.GetLocaleStringResourceById(id); + var resource = _services.Localization.GetLocaleStringResourceById(id); - _localizationService.DeleteLocaleStringResource(resource); + _services.Localization.DeleteLocaleStringResource(resource); } return Resources(languageId, command); @@ -465,7 +472,7 @@ public ActionResult ResourceDelete(int id, int languageId, GridCommand command) public ActionResult ExportXml(int id) { - if (!_permissionService.Authorize(StandardPermissionProvider.ManageLanguages)) + if (!_services.Permissions.Authorize(StandardPermissionProvider.ManageLanguages)) return AccessDeniedView(); var language = _languageService.GetLanguageById(id); @@ -474,7 +481,7 @@ public ActionResult ExportXml(int id) try { - var xml = _localizationService.ExportResourcesToXml(language); + var xml = _services.Localization.ExportResourcesToXml(language); return new XmlDownloadResult(xml, "language-pack-{0}.xml".FormatInvariant(language.UniqueSeoCode)); } catch (Exception exc) @@ -487,7 +494,7 @@ public ActionResult ExportXml(int id) [HttpPost] public ActionResult ImportXml(int id, FormCollection form, ImportModeFlags mode, bool updateTouched) { - if (!_permissionService.Authorize(StandardPermissionProvider.ManageLanguages)) + if (!_services.Permissions.Authorize(StandardPermissionProvider.ManageLanguages)) return AccessDeniedView(); var language = _languageService.GetLanguageById(id); @@ -502,15 +509,15 @@ public ActionResult ImportXml(int id, FormCollection form, ImportModeFlags mode, var file = Request.Files["importxmlfile"]; if (file != null && file.ContentLength > 0) { - _localizationService.ImportResourcesFromXml(language, file.InputStream.AsString(), mode: mode, updateTouchedResources: updateTouched); + _services.Localization.ImportResourcesFromXml(language, file.InputStream.AsString(), mode: mode, updateTouchedResources: updateTouched); } else { - NotifyError(_localizationService.GetResource("Admin.Common.UploadFile")); + NotifyError(T("Admin.Common.UploadFile")); return RedirectToAction("Edit", new { id = language.Id }); } - NotifySuccess(_localizationService.GetResource("Admin.Configuration.Languages.Imported")); + NotifySuccess(T("Admin.Configuration.Languages.Imported")); return RedirectToAction("Edit", new { id = language.Id }); } catch (Exception exc) diff --git a/src/Presentation/SmartStore.Web/Administration/Infrastructure/AutoMapperStartupTask.cs b/src/Presentation/SmartStore.Web/Administration/Infrastructure/AutoMapperStartupTask.cs index 3cbb5afe21..cf6652c228 100644 --- a/src/Presentation/SmartStore.Web/Administration/Infrastructure/AutoMapperStartupTask.cs +++ b/src/Presentation/SmartStore.Web/Administration/Infrastructure/AutoMapperStartupTask.cs @@ -129,7 +129,9 @@ public void Execute() .ForMember(dest => dest.Country, mo => mo.Ignore()); //language Mapper.CreateMap() - .ForMember(dest => dest.FlagFileNames, mo => mo.Ignore()) + .ForMember(dest => dest.AvailableFlags, mo => mo.Ignore()) + .ForMember(dest => dest.AvailableCultures, mo => mo.Ignore()) + .ForMember(dest => dest.AvailableTwoLetterLanguageCodes, mo => mo.Ignore()) .ForMember(dest => dest.AvailableStores, mo => mo.Ignore()) .ForMember(dest => dest.SelectedStoreIds, mo => mo.Ignore()); Mapper.CreateMap() diff --git a/src/Presentation/SmartStore.Web/Administration/Models/Localization/LanguageModel.cs b/src/Presentation/SmartStore.Web/Administration/Models/Localization/LanguageModel.cs index b720c69d5f..28d3dfaf30 100644 --- a/src/Presentation/SmartStore.Web/Administration/Models/Localization/LanguageModel.cs +++ b/src/Presentation/SmartStore.Web/Administration/Models/Localization/LanguageModel.cs @@ -8,7 +8,7 @@ namespace SmartStore.Admin.Models.Localization { - [Validator(typeof(LanguageValidator))] + [Validator(typeof(LanguageValidator))] public class LanguageModel : EntityModelBase { public LanguageModel() @@ -23,18 +23,21 @@ public LanguageModel() [SmartResourceDisplayName("Admin.Configuration.Languages.Fields.LanguageCulture")] [AllowHtml] public string LanguageCulture { get; set; } + public List AvailableCultures { get; set; } - [SmartResourceDisplayName("Admin.Configuration.Languages.Fields.UniqueSeoCode")] + [SmartResourceDisplayName("Admin.Configuration.Languages.Fields.UniqueSeoCode")] [AllowHtml] public string UniqueSeoCode { get; set; } + public List AvailableTwoLetterLanguageCodes { get; set; } - //flags - [SmartResourceDisplayName("Admin.Configuration.Languages.Fields.FlagImageFileName")] + //flags + [SmartResourceDisplayName("Admin.Configuration.Languages.Fields.FlagImageFileName")] [AllowHtml] public string FlagImageFileName { get; set; } public IList FlagFileNames { get; set; } + public List AvailableFlags { get; set; } - [SmartResourceDisplayName("Admin.Configuration.Languages.Fields.Rtl")] + [SmartResourceDisplayName("Admin.Configuration.Languages.Fields.Rtl")] public bool Rtl { get; set; } [SmartResourceDisplayName("Admin.Configuration.Languages.Fields.Published")] diff --git a/src/Presentation/SmartStore.Web/Administration/Validators/Localization/LanguageValidator.cs b/src/Presentation/SmartStore.Web/Administration/Validators/Localization/LanguageValidator.cs index ea6ba1314e..891c093efc 100644 --- a/src/Presentation/SmartStore.Web/Administration/Validators/Localization/LanguageValidator.cs +++ b/src/Presentation/SmartStore.Web/Administration/Validators/Localization/LanguageValidator.cs @@ -9,29 +9,32 @@ public partial class LanguageValidator : AbstractValidator { public LanguageValidator(ILocalizationService localizationService) { - RuleFor(x => x.Name).NotEmpty().WithMessage(localizationService.GetResource("Admin.Configuration.Languages.Fields.Name.Required")); + RuleFor(x => x.Name) + .NotEmpty() + .WithMessage(localizationService.GetResource("Admin.Configuration.Languages.Fields.Name.Required")); + RuleFor(x => x.LanguageCulture) .Must(x => - { - try - { - var culture = new CultureInfo(x); - return culture != null; - } - catch - { - return false; - } - }) + { + try + { + var culture = new CultureInfo(x); + return culture != null; + } + catch + { + return false; + } + }) .WithMessage(localizationService.GetResource("Admin.Configuration.Languages.Fields.LanguageCulture.Validation")); RuleFor(x => x.UniqueSeoCode) .NotNull() .WithMessage(localizationService.GetResource("Admin.Configuration.Languages.Fields.UniqueSeoCode.Required")); + RuleFor(x => x.UniqueSeoCode) .Length(2) .WithMessage(localizationService.GetResource("Admin.Configuration.Languages.Fields.UniqueSeoCode.Length")); - } } } \ No newline at end of file diff --git a/src/Presentation/SmartStore.Web/Administration/Views/Language/List.cshtml b/src/Presentation/SmartStore.Web/Administration/Views/Language/List.cshtml index 362dd5f5a6..91c1fe8140 100644 --- a/src/Presentation/SmartStore.Web/Administration/Views/Language/List.cshtml +++ b/src/Presentation/SmartStore.Web/Administration/Views/Language/List.cshtml @@ -1,7 +1,6 @@ @model Telerik.Web.Mvc.GridModel @using Telerik.Web.Mvc.UI @{ - //page title ViewBag.Title = T("Admin.Configuration.Languages").Text; }
    @@ -24,7 +23,7 @@ columns.Bound(x => x.Name) .Template(x => Html.ActionLink(x.Name, "Edit", new { id = x.Id })); columns.Bound(x => x.LanguageCulture) - .Width(150) + .Width(200) .Centered(); columns.Template( @
    @@ -34,10 +33,10 @@ .Centered() .Title(T("Admin.Configuration.Languages.Resources.View").Text); columns.Bound(x => x.DisplayOrder) - .Width(100) + .Width(200) .Centered(); columns.Bound(x => x.Published) - .Width(100) + .Width(200) .Template(item => @Html.SymbolForBool(item.Published)) .ClientTemplate(@Html.SymbolForBool("Published")) .Centered(); diff --git a/src/Presentation/SmartStore.Web/Administration/Views/Language/_CreateOrUpdate.cshtml b/src/Presentation/SmartStore.Web/Administration/Views/Language/_CreateOrUpdate.cshtml index 621e963481..7f393dd8c5 100644 --- a/src/Presentation/SmartStore.Web/Administration/Views/Language/_CreateOrUpdate.cshtml +++ b/src/Presentation/SmartStore.Web/Administration/Views/Language/_CreateOrUpdate.cshtml @@ -1,9 +1,7 @@ -@model LanguageModel +@using SmartStore.Web.Framework.UI; +@model LanguageModel -@using Telerik.Web.Mvc.UI; -@using SmartStore.Web.Framework.UI; - -@Html.ValidationSummary(true) +@Html.ValidationSummary(false) @Html.HiddenFor(model => model.Id) @Html.SmartStore().TabStrip().Name("language-edit").Style(TabsStyle.Tabs).Position(TabsPosition.Top).Items(x => { @@ -16,20 +14,7 @@ @helper TabInfo() { - var cultures = System.Globalization.CultureInfo.GetCultures(System.Globalization.CultureTypes.SpecificCultures).ToList(); - - - +
    @@ -54,7 +38,7 @@ @Html.SmartLabelFor(model => model.UniqueSeoCode) @@ -63,20 +47,15 @@ @Html.SmartLabelFor(model => model.FlagImageFileName) @@ -118,9 +97,40 @@ toggleStoreMapping(); - $("#pnlAllFlags a.flag").click(function () { - $("#FlagImageFileName").val($(this).data("filename")); + // init flags select + $('#LanguageEditTable').find('select[name=FlagImageFileName]').select2({ + allowClear: true, + minimumResultsForSearch: 16, + formatResult: flagSelectItemFormatting, + formatSelection: flagSelectItemFormatting }); + + function flagSelectItemFormatting(item) { + var flagUrl = '@Url.Content("~/Content/Images/flags/")'; + + try { + if (item.text.length > 0) { + var option = $(item.element), + html = '
    '; + + // item.element is undefined for selection formatting + if (option.length === 0) { + option = $('select[name="FlagImageFileName"]').find('option[value="' + item.id + '"]'); + } + + if (option.length !== 0) { + html += '
    '; + } + + html += '' + item.text + '
    '; + + return html; + } + } + catch (e) { } + + return item.text; + } }); @@ -132,8 +142,8 @@ $('#pnl-available-stores').hide(); } } - +
    @Html.SmartLabelFor(model => model.Name) @@ -44,8 +29,7 @@ @Html.SmartLabelFor(model => model.LanguageCulture) - @Html.DropDownListFor(x => x.LanguageCulture, cultures.Select(x => - new SelectListItem { Value = x.IetfLanguageTag, Text = string.Format("{0} [{1}]", x.DisplayName, x.IetfLanguageTag) })) + @Html.DropDownListFor(x => x.LanguageCulture, Model.AvailableCultures) @Html.ValidationMessageFor(model => model.LanguageCulture)
    - @Html.EditorFor(model => model.UniqueSeoCode) + @Html.DropDownListFor(x => x.UniqueSeoCode, Model.AvailableTwoLetterLanguageCodes) @Html.ValidationMessageFor(model => model.UniqueSeoCode)
    - @Html.EditorFor(model => model.FlagImageFileName) + @Html.ValidationMessageFor(model => model.FlagImageFileName) -
    - @T("Admin.Common.Show") -
    From c1a189e89bb48c296704eaecd1b2380f2a472385 Mon Sep 17 00:00:00 2001 From: Michael Herzog Date: Mon, 11 Jan 2016 14:54:42 +0100 Subject: [PATCH 226/707] Suppresses opening of a non existing link in a new window according to forum post 47526 --- .../SmartStore.Web/Views/Checkout/Confirm.cshtml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Presentation/SmartStore.Web/Views/Checkout/Confirm.cshtml b/src/Presentation/SmartStore.Web/Views/Checkout/Confirm.cshtml index fed6c42b8a..30d4231846 100644 --- a/src/Presentation/SmartStore.Web/Views/Checkout/Confirm.cshtml +++ b/src/Presentation/SmartStore.Web/Views/Checkout/Confirm.cshtml @@ -8,8 +8,8 @@ //title Html.AddTitleParts(T("PageTitle.Checkout").Text); - string termsLink = ""; - string disclaimerLink = ""; + string termsLink = ""; + string disclaimerLink = ""; string terms = string.Format(T("Checkout.TermsOfService.IAccept"), termsLink, "", disclaimerLink); } @section orderProgress{ @@ -38,7 +38,7 @@ $("#terms-of-service-modal .modal-body").html('