Browse Source

3.0.5582.2

Luke Pulverenti 10 years ago
parent
commit
c7b95a2513

+ 0 - 1
MediaBrowser.Api/StartupWizardService.cs

@@ -66,7 +66,6 @@ namespace MediaBrowser.Api
             _config.Configuration.EnableStandaloneMetadata = true;
             _config.Configuration.EnableStandaloneMetadata = true;
             _config.Configuration.EnableLibraryMetadataSubFolder = true;
             _config.Configuration.EnableLibraryMetadataSubFolder = true;
             _config.Configuration.EnableUserSpecificUserViews = true;
             _config.Configuration.EnableUserSpecificUserViews = true;
-            _config.Configuration.EnableUserSpecificUserViews2 = true;
             _config.SaveConfiguration();
             _config.SaveConfiguration();
         }
         }
 
 

+ 8 - 1
MediaBrowser.Controller/Persistence/IItemRepository.cs

@@ -107,7 +107,7 @@ namespace MediaBrowser.Controller.Persistence
         /// </summary>
         /// </summary>
         /// <param name="type">The type.</param>
         /// <param name="type">The type.</param>
         /// <returns>IEnumerable{Guid}.</returns>
         /// <returns>IEnumerable{Guid}.</returns>
-        IEnumerable<Guid> GetItemsOfType(Type type);
+        IEnumerable<Guid> GetItemIdsOfType(Type type);
 
 
         /// <summary>
         /// <summary>
         /// Saves the children.
         /// Saves the children.
@@ -133,6 +133,13 @@ namespace MediaBrowser.Controller.Persistence
         /// <param name="cancellationToken">The cancellation token.</param>
         /// <param name="cancellationToken">The cancellation token.</param>
         /// <returns>Task.</returns>
         /// <returns>Task.</returns>
         Task SaveMediaStreams(Guid id, IEnumerable<MediaStream> streams, CancellationToken cancellationToken);
         Task SaveMediaStreams(Guid id, IEnumerable<MediaStream> streams, CancellationToken cancellationToken);
+
+        /// <summary>
+        /// Gets the type of the items of.
+        /// </summary>
+        /// <param name="type">The type.</param>
+        /// <returns>IEnumerable&lt;BaseItem&gt;.</returns>
+        IEnumerable<BaseItem> GetItemsOfType(Type type);
     }
     }
 }
 }
 
 

+ 19 - 12
MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs

@@ -489,28 +489,35 @@ namespace MediaBrowser.MediaEncoding.Encoder
             await resourcePool.WaitAsync(cancellationToken).ConfigureAwait(false);
             await resourcePool.WaitAsync(cancellationToken).ConfigureAwait(false);
 
 
             var processWrapper = new ProcessWrapper(process, this);
             var processWrapper = new ProcessWrapper(process, this);
-
-            StartProcess(processWrapper);
+            bool ranToCompletion;
 
 
             var memoryStream = new MemoryStream();
             var memoryStream = new MemoryStream();
 
 
+            try
+            {
+                StartProcess(processWrapper);
+
 #pragma warning disable 4014
 #pragma warning disable 4014
-            // Important - don't await the log task or we won't be able to kill ffmpeg when the user stops playback
-            process.StandardOutput.BaseStream.CopyToAsync(memoryStream);
+                // Important - don't await the log task or we won't be able to kill ffmpeg when the user stops playback
+                process.StandardOutput.BaseStream.CopyToAsync(memoryStream);
 #pragma warning restore 4014
 #pragma warning restore 4014
 
 
-            // MUST read both stdout and stderr asynchronously or a deadlock may occurr
-            process.BeginErrorReadLine();
+                // MUST read both stdout and stderr asynchronously or a deadlock may occurr
+                process.BeginErrorReadLine();
 
 
-            var ranToCompletion = process.WaitForExit(10000);
+                ranToCompletion = process.WaitForExit(10000);
 
 
-            if (!ranToCompletion)
+                if (!ranToCompletion)
+                {
+                    StopProcess(processWrapper, 1000, false);
+                }
+
+            }
+            finally
             {
             {
-                StopProcess(processWrapper, 1000, false);
+                resourcePool.Release();
             }
             }
 
 
-            resourcePool.Release();
-
             var exitCode = ranToCompletion ? processWrapper.ExitCode ?? 0 : -1;
             var exitCode = ranToCompletion ? processWrapper.ExitCode ?? 0 : -1;
 
 
             if (exitCode == -1 || memoryStream.Length == 0)
             if (exitCode == -1 || memoryStream.Length == 0)
@@ -614,7 +621,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
                         ranToCompletion = true;
                         ranToCompletion = true;
                         break;
                         break;
                     }
                     }
-                    
+
                     cancellationToken.ThrowIfCancellationRequested();
                     cancellationToken.ThrowIfCancellationRequested();
 
 
                     var jpegCount = Directory.GetFiles(targetDirectory)
                     var jpegCount = Directory.GetFiles(targetDirectory)

+ 0 - 5
MediaBrowser.Model/Configuration/ServerConfiguration.cs

@@ -49,11 +49,6 @@ namespace MediaBrowser.Model.Configuration
         /// </summary>
         /// </summary>
         /// <value><c>true</c> if [enable user specific user views]; otherwise, <c>false</c>.</value>
         /// <value><c>true</c> if [enable user specific user views]; otherwise, <c>false</c>.</value>
         public bool EnableUserSpecificUserViews { get; set; }
         public bool EnableUserSpecificUserViews { get; set; }
-        /// <summary>
-        /// Gets or sets a value indicating whether [enable user specific user views2].
-        /// </summary>
-        /// <value><c>true</c> if [enable user specific user views2]; otherwise, <c>false</c>.</value>
-        public bool EnableUserSpecificUserViews2 { get; set; }
 
 
         /// <summary>
         /// <summary>
         /// Gets or sets the value pointing to the file system where the ssl certiifcate is located..
         /// Gets or sets the value pointing to the file system where the ssl certiifcate is located..

+ 5 - 1
MediaBrowser.Providers/MediaInfo/VideoImageProvider.cs

@@ -6,6 +6,7 @@ using MediaBrowser.Controller.Providers;
 using MediaBrowser.Model.Drawing;
 using MediaBrowser.Model.Drawing;
 using MediaBrowser.Model.Entities;
 using MediaBrowser.Model.Entities;
 using MediaBrowser.Model.IO;
 using MediaBrowser.Model.IO;
+using MediaBrowser.Model.Logging;
 using MediaBrowser.Model.MediaInfo;
 using MediaBrowser.Model.MediaInfo;
 using System;
 using System;
 using System.Collections.Generic;
 using System.Collections.Generic;
@@ -20,13 +21,15 @@ namespace MediaBrowser.Providers.MediaInfo
         private readonly IMediaEncoder _mediaEncoder;
         private readonly IMediaEncoder _mediaEncoder;
         private readonly IServerConfigurationManager _config;
         private readonly IServerConfigurationManager _config;
         private readonly ILibraryManager _libraryManager;
         private readonly ILibraryManager _libraryManager;
+        private readonly ILogger _logger;
 
 
-        public VideoImageProvider(IIsoManager isoManager, IMediaEncoder mediaEncoder, IServerConfigurationManager config, ILibraryManager libraryManager)
+        public VideoImageProvider(IIsoManager isoManager, IMediaEncoder mediaEncoder, IServerConfigurationManager config, ILibraryManager libraryManager, ILogger logger)
         {
         {
             _isoManager = isoManager;
             _isoManager = isoManager;
             _mediaEncoder = mediaEncoder;
             _mediaEncoder = mediaEncoder;
             _config = config;
             _config = config;
             _libraryManager = libraryManager;
             _libraryManager = libraryManager;
+            _logger = logger;
         }
         }
 
 
         /// <summary>
         /// <summary>
@@ -74,6 +77,7 @@ namespace MediaBrowser.Providers.MediaInfo
             // Can't extract if we didn't find a video stream in the file
             // Can't extract if we didn't find a video stream in the file
             if (!video.DefaultVideoStreamIndex.HasValue)
             if (!video.DefaultVideoStreamIndex.HasValue)
             {
             {
+                _logger.Debug("Skipping image extraction due to missing DefaultVideoStreamIndex for {0}.", video.Path ?? string.Empty);
                 return Task.FromResult(new DynamicImageResponse { HasImage = false });
                 return Task.FromResult(new DynamicImageResponse { HasImage = false });
             }
             }
 
 

+ 1 - 5
MediaBrowser.Server.Implementations/Library/UserViewManager.cs

@@ -209,11 +209,6 @@ namespace MediaBrowser.Server.Implementations.Library
 
 
                 var enableRichView = !user.Configuration.PlainFolderViews.Contains(parentId.ToString("N"), StringComparer.OrdinalIgnoreCase);
                 var enableRichView = !user.Configuration.PlainFolderViews.Contains(parentId.ToString("N"), StringComparer.OrdinalIgnoreCase);
 
 
-                if (_config.Configuration.EnableUserSpecificUserViews2)
-                {
-                    return await GetUserView(parentId, name, viewType, enableRichView, string.Empty, user, cancellationToken).ConfigureAwait(false);
-                }
-
                 if (_config.Configuration.EnableUserSpecificUserViews)
                 if (_config.Configuration.EnableUserSpecificUserViews)
                 {
                 {
                     viewType = enableRichView ? viewType : null;
                     viewType = enableRichView ? viewType : null;
@@ -227,6 +222,7 @@ namespace MediaBrowser.Server.Implementations.Library
                     return view;
                     return view;
                 }
                 }
 
 
+                viewType = enableRichView ? viewType : CollectionType.Folders;
                 return await _libraryManager.GetNamedView(user, name, viewType, sortName, cancellationToken).ConfigureAwait(false);
                 return await _libraryManager.GetNamedView(user, name, viewType, sortName, cancellationToken).ConfigureAwait(false);
             }
             }
             else
             else

+ 59 - 47
MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs

@@ -54,11 +54,9 @@ namespace MediaBrowser.Server.Implementations.LiveTv
             new ConcurrentDictionary<string, LiveStreamData>();
             new ConcurrentDictionary<string, LiveStreamData>();
 
 
         private List<Guid> _channelIdList = new List<Guid>();
         private List<Guid> _channelIdList = new List<Guid>();
-        private Dictionary<Guid, LiveTvProgram> _programs = new Dictionary<Guid, LiveTvProgram>();
+        private Dictionary<Guid, LiveTvProgram> _programs;
         private readonly ConcurrentDictionary<Guid, bool> _refreshedPrograms = new ConcurrentDictionary<Guid, bool>();
         private readonly ConcurrentDictionary<Guid, bool> _refreshedPrograms = new ConcurrentDictionary<Guid, bool>();
 
 
-        private readonly SemaphoreSlim _refreshSemaphore = new SemaphoreSlim(1, 1);
-
         public LiveTvManager(IApplicationHost appHost, IServerConfigurationManager config, ILogger logger, IItemRepository itemRepo, IImageProcessor imageProcessor, IUserDataManager userDataManager, IDtoService dtoService, IUserManager userManager, ILibraryManager libraryManager, ITaskManager taskManager, ILocalizationManager localization, IJsonSerializer jsonSerializer, IProviderManager providerManager)
         public LiveTvManager(IApplicationHost appHost, IServerConfigurationManager config, ILogger logger, IItemRepository itemRepo, IImageProcessor imageProcessor, IUserDataManager userDataManager, IDtoService dtoService, IUserManager userManager, ILibraryManager libraryManager, ITaskManager taskManager, ILocalizationManager localization, IJsonSerializer jsonSerializer, IProviderManager providerManager)
         {
         {
             _config = config;
             _config = config;
@@ -109,6 +107,37 @@ namespace MediaBrowser.Server.Implementations.LiveTv
             _taskManager.CancelIfRunningAndQueue<RefreshChannelsScheduledTask>();
             _taskManager.CancelIfRunningAndQueue<RefreshChannelsScheduledTask>();
         }
         }
 
 
+        private readonly object _programsDataLock = new object();
+        private Dictionary<Guid, LiveTvProgram> GetProgramsDictionary()
+        {
+            if (_programs == null)
+            {
+                lock (_programsDataLock)
+                {
+                    if (_programs == null)
+                    {
+                        var dict = new Dictionary<Guid, LiveTvProgram>();
+
+                        foreach (var item in _itemRepo.GetItemsOfType(typeof (LiveTvProgram))
+                            .Cast<LiveTvProgram>()
+                            .ToList())
+                        {
+                            dict[item.Id] = item;    
+                        }
+
+                        _programs = dict;
+                    }
+                }
+            }
+
+            return _programs;
+        }
+
+        private IEnumerable<LiveTvProgram> GetPrograms()
+        {
+            return GetProgramsDictionary().Values;
+        }
+
         public async Task<QueryResult<LiveTvChannel>> GetInternalChannels(LiveTvChannelQuery query, CancellationToken cancellationToken)
         public async Task<QueryResult<LiveTvChannel>> GetInternalChannels(LiveTvChannelQuery query, CancellationToken cancellationToken)
         {
         {
             var user = string.IsNullOrEmpty(query.UserId) ? null : _userManager.GetUserById(query.UserId);
             var user = string.IsNullOrEmpty(query.UserId) ? null : _userManager.GetUserById(query.UserId);
@@ -260,7 +289,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv
 
 
             LiveTvProgram obj = null;
             LiveTvProgram obj = null;
 
 
-            _programs.TryGetValue(guid, out obj);
+            GetProgramsDictionary().TryGetValue(guid, out obj);
 
 
             if (obj != null)
             if (obj != null)
             {
             {
@@ -597,7 +626,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv
 
 
             item.ProductionYear = info.ProductionYear;
             item.ProductionYear = info.ProductionYear;
             item.PremiereDate = item.PremiereDate ?? info.OriginalAirDate;
             item.PremiereDate = item.PremiereDate ?? info.OriginalAirDate;
-            
+
             await item.UpdateToRepository(ItemUpdateType.MetadataImport, cancellationToken).ConfigureAwait(false);
             await item.UpdateToRepository(ItemUpdateType.MetadataImport, cancellationToken).ConfigureAwait(false);
 
 
             return item;
             return item;
@@ -691,7 +720,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv
 
 
         public async Task<QueryResult<ProgramInfoDto>> GetPrograms(ProgramQuery query, CancellationToken cancellationToken)
         public async Task<QueryResult<ProgramInfoDto>> GetPrograms(ProgramQuery query, CancellationToken cancellationToken)
         {
         {
-            IEnumerable<LiveTvProgram> programs = _programs.Values;
+            IEnumerable<LiveTvProgram> programs = GetPrograms();
 
 
             if (query.MinEndDate.HasValue)
             if (query.MinEndDate.HasValue)
             {
             {
@@ -806,7 +835,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv
 
 
         public async Task<QueryResult<LiveTvProgram>> GetRecommendedProgramsInternal(RecommendedProgramQuery query, CancellationToken cancellationToken)
         public async Task<QueryResult<LiveTvProgram>> GetRecommendedProgramsInternal(RecommendedProgramQuery query, CancellationToken cancellationToken)
         {
         {
-            IEnumerable<LiveTvProgram> programs = _programs.Values;
+            IEnumerable<LiveTvProgram> programs = GetPrograms();
 
 
             var user = _userManager.GetUserById(query.UserId);
             var user = _userManager.GetUserById(query.UserId);
 
 
@@ -995,24 +1024,15 @@ namespace MediaBrowser.Server.Implementations.LiveTv
 
 
         internal async Task RefreshChannels(IProgress<double> progress, CancellationToken cancellationToken)
         internal async Task RefreshChannels(IProgress<double> progress, CancellationToken cancellationToken)
         {
         {
-            await _refreshSemaphore.WaitAsync(cancellationToken).ConfigureAwait(false);
-
-            try
-            {
-                var innerProgress = new ActionableProgress<double>();
-                innerProgress.RegisterAction(p => progress.Report(p * .9));
-                await RefreshChannelsInternal(innerProgress, cancellationToken).ConfigureAwait(false);
+            var innerProgress = new ActionableProgress<double>();
+            innerProgress.RegisterAction(p => progress.Report(p * .9));
+            await RefreshChannelsInternal(innerProgress, cancellationToken).ConfigureAwait(false);
 
 
-                innerProgress = new ActionableProgress<double>();
-                innerProgress.RegisterAction(p => progress.Report(90 + (p * .1)));
-                await CleanDatabaseInternal(progress, cancellationToken).ConfigureAwait(false);
+            innerProgress = new ActionableProgress<double>();
+            innerProgress.RegisterAction(p => progress.Report(90 + (p * .1)));
+            await CleanDatabaseInternal(progress, cancellationToken).ConfigureAwait(false);
 
 
-                RefreshIfNeeded(_programs.Values.Where(i => (i.StartDate - DateTime.UtcNow).TotalDays <= 1).ToList());
-            }
-            finally
-            {
-                _refreshSemaphore.Release();
-            }
+            RefreshIfNeeded(GetPrograms().Where(i => (i.StartDate - DateTime.UtcNow).TotalDays <= 1).ToList());
         }
         }
 
 
         private async Task RefreshChannelsInternal(IProgress<double> progress, CancellationToken cancellationToken)
         private async Task RefreshChannelsInternal(IProgress<double> progress, CancellationToken cancellationToken)
@@ -1136,7 +1156,11 @@ namespace MediaBrowser.Server.Implementations.LiveTv
                 progress.Report(80 * percent + 10);
                 progress.Report(80 * percent + 10);
             }
             }
 
 
-            _programs = programs.ToDictionary(i => i.Id);
+            lock (_programsDataLock)
+            {
+                _programs = programs.ToDictionary(i => i.Id);
+            }
+
             _refreshedPrograms.Clear();
             _refreshedPrograms.Clear();
             progress.Report(90);
             progress.Report(90);
 
 
@@ -1147,28 +1171,14 @@ namespace MediaBrowser.Server.Implementations.LiveTv
             progress.Report(100);
             progress.Report(100);
         }
         }
 
 
-        public async Task CleanDatabase(IProgress<double> progress, CancellationToken cancellationToken)
-        {
-            await _refreshSemaphore.WaitAsync(cancellationToken).ConfigureAwait(false);
-
-            try
-            {
-                await DeleteOldPrograms(_programs.Keys.ToList(), progress, cancellationToken).ConfigureAwait(false);
-            }
-            finally
-            {
-                _refreshSemaphore.Release();
-            }
-        }
-
         private Task CleanDatabaseInternal(IProgress<double> progress, CancellationToken cancellationToken)
         private Task CleanDatabaseInternal(IProgress<double> progress, CancellationToken cancellationToken)
         {
         {
-            return DeleteOldPrograms(_programs.Keys.ToList(), progress, cancellationToken);
+            return DeleteOldPrograms(GetProgramsDictionary().Keys.ToList(), progress, cancellationToken);
         }
         }
 
 
         private async Task DeleteOldPrograms(List<Guid> currentIdList, IProgress<double> progress, CancellationToken cancellationToken)
         private async Task DeleteOldPrograms(List<Guid> currentIdList, IProgress<double> progress, CancellationToken cancellationToken)
         {
         {
-            var list = _itemRepo.GetItemsOfType(typeof(LiveTvProgram)).ToList();
+            var list = _itemRepo.GetItemIdsOfType(typeof(LiveTvProgram)).ToList();
 
 
             var numComplete = 0;
             var numComplete = 0;
 
 
@@ -1549,7 +1559,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv
         {
         {
             var now = DateTime.UtcNow;
             var now = DateTime.UtcNow;
 
 
-            var program = _programs.Values
+            var program = GetPrograms()
                 .Where(i => string.Equals(externalChannelId, i.ExternalChannelId, StringComparison.OrdinalIgnoreCase))
                 .Where(i => string.Equals(externalChannelId, i.ExternalChannelId, StringComparison.OrdinalIgnoreCase))
                 .OrderBy(i => i.StartDate)
                 .OrderBy(i => i.StartDate)
                 .SkipWhile(i => now >= (i.EndDate ?? DateTime.MinValue))
                 .SkipWhile(i => now >= (i.EndDate ?? DateTime.MinValue))
@@ -1742,7 +1752,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv
         {
         {
             var dtoOptions = new DtoOptions();
             var dtoOptions = new DtoOptions();
             dtoOptions.Fields.Remove(ItemFields.SyncInfo);
             dtoOptions.Fields.Remove(ItemFields.SyncInfo);
-            
+
             var recordingResult = await GetRecordings(new RecordingQuery
             var recordingResult = await GetRecordings(new RecordingQuery
             {
             {
                 UserId = query.UserId
                 UserId = query.UserId
@@ -1855,13 +1865,15 @@ namespace MediaBrowser.Server.Implementations.LiveTv
 
 
         public GuideInfo GetGuideInfo()
         public GuideInfo GetGuideInfo()
         {
         {
-            var programs = _programs.ToList();
+            var programs = GetPrograms().OrderBy(i => i.StartDate).ToList();
 
 
-            var startDate = _programs.Count == 0 ? DateTime.MinValue :
-                programs.Select(i => i.Value.StartDate).Min();
+            var startDate = programs.Count == 0 ?
+                DateTime.MinValue :
+                programs[0].StartDate;
 
 
-            var endDate = programs.Count == 0 ? DateTime.MinValue :
-                programs.Select(i => i.Value.StartDate).Max();
+            var endDate = programs.Count == 0 ?
+                DateTime.MinValue :
+                programs[programs.Count - 1].StartDate;
 
 
             return new GuideInfo
             return new GuideInfo
             {
             {

+ 1 - 1
MediaBrowser.Server.Implementations/Localization/Server/server.json

@@ -1433,5 +1433,5 @@
     "ToAccessPreferencesHelp": "To access your preferences later, click your user icon in the top right header and select My Preferences.",
     "ToAccessPreferencesHelp": "To access your preferences later, click your user icon in the top right header and select My Preferences.",
     "HeaderViewStyles": "View Styles",
     "HeaderViewStyles": "View Styles",
     "LabelSelectViewStyles": "Enable rich presentations for:",
     "LabelSelectViewStyles": "Enable rich presentations for:",
-    "LabelSelectViewStylesHelp": "If enabled, views will be built with metadata to offer categories such as Suggestions, Latest, Genres, and more. If disabled, they'll be displayed with plain folders."
+    "LabelSelectViewStylesHelp": "If enabled, views will be built with metadata to offer categories such as Suggestions, Latest, Genres, and more. If disabled, they'll be displayed with simple folders."
 }
 }

+ 32 - 2
MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs

@@ -522,7 +522,7 @@ namespace MediaBrowser.Server.Implementations.Persistence
             }
             }
         }
         }
 
 
-        public IEnumerable<Guid> GetItemsOfType(Type type)
+        public IEnumerable<BaseItem> GetItemsOfType(Type type)
         {
         {
             if (type == null)
             if (type == null)
             {
             {
@@ -530,7 +530,37 @@ namespace MediaBrowser.Server.Implementations.Persistence
             }
             }
 
 
             CheckDisposed();
             CheckDisposed();
-            
+
+            using (var cmd = _connection.CreateCommand())
+            {
+                cmd.CommandText = "select type,data from TypedBaseItems where type = @type";
+
+                cmd.Parameters.Add(cmd, "@type", DbType.String).Value = type.FullName;
+
+                using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess | CommandBehavior.SingleResult))
+                {
+                    while (reader.Read())
+                    {
+                        var item = GetItem(reader);
+
+                        if (item != null)
+                        {
+                            yield return item;
+                        }
+                    }
+                }
+            }
+        }
+
+        public IEnumerable<Guid> GetItemIdsOfType(Type type)
+        {
+            if (type == null)
+            {
+                throw new ArgumentNullException("type");
+            }
+
+            CheckDisposed();
+
             using (var cmd = _connection.CreateCommand())
             using (var cmd = _connection.CreateCommand())
             {
             {
                 cmd.CommandText = "select guid from TypedBaseItems where type = @type";
                 cmd.CommandText = "select guid from TypedBaseItems where type = @type";

+ 2 - 2
SharedVersion.cs

@@ -1,4 +1,4 @@
 using System.Reflection;
 using System.Reflection;
 
 
-[assembly: AssemblyVersion("3.0.*")]
-//[assembly: AssemblyVersion("3.0.5582.1")]
+//[assembly: AssemblyVersion("3.0.*")]
+[assembly: AssemblyVersion("3.0.5582.2")]