Browse Source

Merge pull request #2726 from MediaBrowser/dev

Dev
Luke 8 years ago
parent
commit
287178cbf5
34 changed files with 485 additions and 930 deletions
  1. 4 4
      Emby.Drawing.Skia/SkiaEncoder.cs
  2. 5 0
      Emby.Drawing/ImageProcessor.cs
  3. 2 5
      Emby.Server.Implementations/Data/SqliteItemRepository.cs
  4. 9 4
      Emby.Server.Implementations/LiveTv/Listings/XmlTvListingsProvider.cs
  5. 1 1
      Emby.Server.Implementations/LiveTv/TunerHosts/M3UTunerHost.cs
  6. 2 1
      MediaBrowser.Api/ApiEntryPoint.cs
  7. 1 1
      MediaBrowser.Api/Images/ImageService.cs
  8. 4 0
      MediaBrowser.Api/Playback/BaseStreamingService.cs
  9. 5 0
      MediaBrowser.Api/Playback/Hls/DynamicHlsService.cs
  10. 2 0
      MediaBrowser.Api/Playback/MediaInfoService.cs
  11. 5 2
      MediaBrowser.Api/Playback/UniversalAudioService.cs
  12. 2 0
      MediaBrowser.Controller/Drawing/IImageProcessor.cs
  13. 4 4
      MediaBrowser.Controller/Entities/Folder.cs
  14. 21 1
      MediaBrowser.Controller/MediaEncoding/EncodingJobInfo.cs
  15. 2 0
      MediaBrowser.Controller/MediaEncoding/EncodingJobOptions.cs
  16. 0 1
      MediaBrowser.Model/Configuration/UserConfiguration.cs
  17. 0 1
      MediaBrowser.Model/Dlna/ProfileCondition.cs
  18. 248 23
      MediaBrowser.Model/Dlna/StreamBuilder.cs
  19. 8 12
      MediaBrowser.Model/Dlna/StreamInfo.cs
  20. 4 0
      MediaBrowser.Model/Dto/MediaSourceInfo.cs
  21. 0 10
      MediaBrowser.Model/Dto/UserDto.cs
  22. 2 0
      MediaBrowser.Model/LiveTv/LiveTvOptions.cs
  23. 1 0
      MediaBrowser.Model/Net/MimeTypes.cs
  24. 33 0
      MediaBrowser.Model/Session/TranscodingInfo.cs
  25. 2 2
      MediaBrowser.Server.Mono/ImageEncoderHelper.cs
  26. 5 5
      MediaBrowser.ServerApplication/ImageEncoderHelper.cs
  27. 0 136
      MediaBrowser.ServerApplication/MainForm.Designer.cs
  28. 0 12
      MediaBrowser.ServerApplication/MainForm.cs
  29. 0 576
      MediaBrowser.ServerApplication/MainForm.resx
  30. 3 34
      MediaBrowser.ServerApplication/MainStartup.cs
  31. 1 10
      MediaBrowser.ServerApplication/MediaBrowser.ServerApplication.csproj
  32. 1 2
      MediaBrowser.ServerApplication/ServerNotifyIcon.cs
  33. 107 82
      Mono.Nat/NatUtility.cs
  34. 1 1
      SharedVersion.cs

+ 4 - 4
Emby.Drawing.Skia/SkiaEncoder.cs

@@ -63,15 +63,15 @@ namespace Emby.Drawing.Skia
 
         private void LogVersion()
         {
+            // test an operation that requires the native library
+            SKPMColor.PreMultiply(SKColors.Black);
+
             _logger.Info("SkiaSharp version: " + GetVersion());
         }
 
         public static string GetVersion()
         {
-            using (var bitmap = new SKBitmap())
-            {
-                return typeof(SKBitmap).GetTypeInfo().Assembly.GetName().Version.ToString();
-            }
+            return typeof(SKBitmap).GetTypeInfo().Assembly.GetName().Version.ToString();
         }
 
         private static bool IsWhiteSpace(SKColor color)

+ 5 - 0
Emby.Drawing/ImageProcessor.cs

@@ -410,6 +410,11 @@ namespace Emby.Drawing
             return GetCachePath(ResizedImageCachePath, filename, "." + format.ToString().ToLower());
         }
 
+        public ImageSize GetImageSize(ItemImageInfo info, bool allowSlowMethods)
+        {
+            return GetImageSize(info.Path, info.DateModified, allowSlowMethods);
+        }
+
         public ImageSize GetImageSize(ItemImageInfo info)
         {
             return GetImageSize(info.Path, info.DateModified, false);

+ 2 - 5
Emby.Server.Implementations/Data/SqliteItemRepository.cs

@@ -4297,12 +4297,9 @@ namespace Emby.Server.Implementations.Data
                 }
             }
 
-            if (query.HasDeadParentId.HasValue)
+            if (query.HasDeadParentId.HasValue && query.HasDeadParentId.Value)
             {
-                if (query.HasDeadParentId.Value)
-                {
-                    whereClauses.Add("ParentId NOT NULL AND ParentId NOT IN (select guid from TypedBaseItems)");
-                }
+                whereClauses.Add("ParentId NOT NULL AND ParentId NOT IN (select guid from TypedBaseItems)");
             }
 
             if (query.Years.Length == 1)

+ 9 - 4
Emby.Server.Implementations/LiveTv/Listings/XmlTvListingsProvider.cs

@@ -49,8 +49,13 @@ namespace Emby.Server.Implementations.LiveTv.Listings
             get { return "xmltv"; }
         }
 
-        private string GetLanguage()
+        private string GetLanguage(ListingsProviderInfo info)
         {
+            if (!string.IsNullOrWhiteSpace(info.PreferredLanguage))
+            {
+                return info.PreferredLanguage;
+            }
+
             return _config.Configuration.PreferredMetadataLanguage;
         }
 
@@ -152,7 +157,7 @@ namespace Emby.Server.Implementations.LiveTv.Listings
             _logger.Debug("Getting xmltv programs for channel {0}", channelId);
 
             var path = await GetXml(info.Path, cancellationToken).ConfigureAwait(false);
-            var reader = new XmlTvReader(path, GetLanguage());
+            var reader = new XmlTvReader(path, GetLanguage(info));
 
             var results = reader.GetProgrammes(channelId, startDateUtc, endDateUtc, cancellationToken);
             return results.Select(p => GetProgramInfo(p, info));
@@ -254,7 +259,7 @@ namespace Emby.Server.Implementations.LiveTv.Listings
         {
             // In theory this should never be called because there is always only one lineup
             var path = await GetXml(info.Path, CancellationToken.None).ConfigureAwait(false);
-            var reader = new XmlTvReader(path, GetLanguage());
+            var reader = new XmlTvReader(path, GetLanguage(info));
             var results = reader.GetChannels();
 
             // Should this method be async?
@@ -265,7 +270,7 @@ namespace Emby.Server.Implementations.LiveTv.Listings
         {
             // In theory this should never be called because there is always only one lineup
             var path = await GetXml(info.Path, cancellationToken).ConfigureAwait(false);
-            var reader = new XmlTvReader(path, GetLanguage());
+            var reader = new XmlTvReader(path, GetLanguage(info));
             var results = reader.GetChannels();
 
             // Should this method be async?

+ 1 - 1
Emby.Server.Implementations/LiveTv/TunerHosts/M3UTunerHost.cs

@@ -148,7 +148,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts
                     },
                     RequiresOpening = true,
                     RequiresClosing = true,
-                    RequiresLooping = true,
+                    RequiresLooping = info.EnableStreamLooping,
 
                     ReadAtNativeFramerate = false,
 

+ 2 - 1
MediaBrowser.Api/ApiEntryPoint.cs

@@ -265,7 +265,8 @@ namespace MediaBrowser.Api
                     Height = state.OutputHeight,
                     AudioChannels = state.OutputAudioChannels,
                     IsAudioDirect = string.Equals(state.OutputAudioCodec, "copy", StringComparison.OrdinalIgnoreCase),
-                    IsVideoDirect = string.Equals(state.OutputVideoCodec, "copy", StringComparison.OrdinalIgnoreCase)
+                    IsVideoDirect = string.Equals(state.OutputVideoCodec, "copy", StringComparison.OrdinalIgnoreCase),
+                    TranscodeReasons = state.TranscodeReasons
                 });
             }
         }

+ 1 - 1
MediaBrowser.Api/Images/ImageService.cs

@@ -326,7 +326,7 @@ namespace MediaBrowser.Api.Images
                         var fileInfo = _fileSystem.GetFileInfo(info.Path);
                         length = fileInfo.Length;
 
-                        var size = _imageProcessor.GetImageSize(info);
+                        var size = _imageProcessor.GetImageSize(info, true);
 
                         width = Convert.ToInt32(size.Width);
                         height = Convert.ToInt32(size.Height);

+ 4 - 0
MediaBrowser.Api/Playback/BaseStreamingService.cs

@@ -583,6 +583,10 @@ namespace MediaBrowser.Api.Playback
                         videoRequest.DeInterlace = string.Equals("true", val, StringComparison.OrdinalIgnoreCase);
                     }
                 }
+                else if (i == 33)
+                {
+                    request.TranscodeReasons = val;
+                }
             }
         }
 

+ 5 - 0
MediaBrowser.Api/Playback/Hls/DynamicHlsService.cs

@@ -541,6 +541,11 @@ namespace MediaBrowser.Api.Playback.Hls
             {
                 queryString += "&SegmentContainer=" + state.Request.SegmentContainer;
             }
+            // from universal audio service
+            if (!string.IsNullOrWhiteSpace(state.Request.TranscodeReasons) && queryString.IndexOf("TranscodeReasons=", StringComparison.OrdinalIgnoreCase) == -1)
+            {
+                queryString += "&TranscodeReasons=" + state.Request.TranscodeReasons;
+            }
 
             // Main stream
             var playlistUrl = isLiveStream ? "live.m3u8" : "main.m3u8";

+ 2 - 0
MediaBrowser.Api/Playback/MediaInfoService.cs

@@ -513,6 +513,8 @@ namespace MediaBrowser.Api.Playback
             var profiles = info.GetSubtitleProfiles(false, "-", accessToken);
             mediaSource.DefaultSubtitleStreamIndex = info.SubtitleStreamIndex;
 
+            mediaSource.TranscodeReasons = info.TranscodeReasons;
+
             foreach (var profile in profiles)
             {
                 foreach (var stream in mediaSource.MediaStreams)

+ 5 - 2
MediaBrowser.Api/Playback/UniversalAudioService.cs

@@ -1,6 +1,7 @@
 using System;
 using System.Collections.Generic;
 using System.Globalization;
+using System.Linq;
 using System.Threading.Tasks;
 using MediaBrowser.Api.Playback.Hls;
 using MediaBrowser.Api.Playback.Progressive;
@@ -265,7 +266,8 @@ namespace MediaBrowser.Api.Playback
                     Static = isStatic,
                     SegmentContainer = request.TranscodingContainer,
                     AudioSampleRate = request.MaxAudioSampleRate,
-                    BreakOnNonKeyFrames = transcodingProfile.BreakOnNonKeyFrames
+                    BreakOnNonKeyFrames = transcodingProfile.BreakOnNonKeyFrames,
+                    TranscodeReasons = mediaSource.TranscodeReasons == null ? null : string.Join(",", mediaSource.TranscodeReasons.Select(i => i.ToString()).ToArray())
                 };
 
                 if (isHeadRequest)
@@ -307,7 +309,8 @@ namespace MediaBrowser.Api.Playback
                     PlaySessionId = playbackInfoResult.PlaySessionId,
                     StartTimeTicks = request.StartTimeTicks,
                     Static = isStatic,
-                    AudioSampleRate = request.MaxAudioSampleRate
+                    AudioSampleRate = request.MaxAudioSampleRate,
+                    TranscodeReasons = mediaSource.TranscodeReasons == null ? null : string.Join(",", mediaSource.TranscodeReasons.Select(i => i.ToString()).ToArray())
                 };
 
                 if (isHeadRequest)

+ 2 - 0
MediaBrowser.Controller/Drawing/IImageProcessor.cs

@@ -33,6 +33,8 @@ namespace MediaBrowser.Controller.Drawing
         /// <returns>ImageSize.</returns>
         ImageSize GetImageSize(ItemImageInfo info);
 
+        ImageSize GetImageSize(ItemImageInfo info, bool allowSlowMethods);
+
         /// <summary>
         /// Gets the size of the image.
         /// </summary>

+ 4 - 4
MediaBrowser.Controller/Entities/Folder.cs

@@ -487,7 +487,7 @@ namespace MediaBrowser.Controller.Entities
                     var folder = this;
                     innerProgress.RegisterAction(p =>
                     {
-                        double newPct = .70 * p + 10;
+                        double newPct = .80 * p + 10;
                         progress.Report(newPct);
                         ProviderManager.OnRefreshProgress(folder, newPct);
                     });
@@ -498,11 +498,11 @@ namespace MediaBrowser.Controller.Entities
 
             if (refreshChildMetadata)
             {
-                progress.Report(80);
+                progress.Report(90);
 
                 if (recursive)
                 {
-                    ProviderManager.OnRefreshProgress(this, 80);
+                    ProviderManager.OnRefreshProgress(this, 90);
                 }
 
                 var container = this as IMetadataContainer;
@@ -512,7 +512,7 @@ namespace MediaBrowser.Controller.Entities
                     var folder = this;
                     innerProgress.RegisterAction(p =>
                     {
-                        double newPct = .20 * p + 80;
+                        double newPct = .10 * p + 90;
                         progress.Report(newPct);
                         if (recursive)
                         {

+ 21 - 1
MediaBrowser.Controller/MediaEncoding/EncodingJobInfo.cs

@@ -1,6 +1,7 @@
 using System;
 using System.Collections.Generic;
 using System.Globalization;
+using System.Linq;
 using MediaBrowser.Controller.Entities;
 using MediaBrowser.Model.Dlna;
 using MediaBrowser.Model.Dto;
@@ -9,6 +10,7 @@ using MediaBrowser.Model.IO;
 using MediaBrowser.Model.Logging;
 using MediaBrowser.Model.MediaInfo;
 using MediaBrowser.Model.Drawing;
+using MediaBrowser.Model.Session;
 
 namespace MediaBrowser.Controller.MediaEncoding
 {
@@ -40,6 +42,24 @@ namespace MediaBrowser.Controller.MediaEncoding
 
         public bool ReadInputAtNativeFramerate { get; set; }
 
+        private List<TranscodeReason> _transcodeReasons = null;
+        public List<TranscodeReason> TranscodeReasons
+        {
+            get
+            {
+                if (_transcodeReasons == null)
+                {
+                    _transcodeReasons = (BaseRequest.TranscodeReasons ?? string.Empty)
+                        .Split(',')
+                        .Where(i => !string.IsNullOrWhiteSpace(i))
+                        .Select(v => (TranscodeReason)Enum.Parse(typeof(TranscodeReason), v, true))
+                        .ToList();
+                }
+
+                return _transcodeReasons;
+            }
+        }
+
         public bool IgnoreInputDts
         {
             get
@@ -251,7 +271,7 @@ namespace MediaBrowser.Controller.MediaEncoding
                     {
                         return AudioStream.SampleRate;
                     }
-                } 
+                }
 
                 else if (BaseRequest.AudioSampleRate.HasValue)
                 {

+ 2 - 0
MediaBrowser.Controller/MediaEncoding/EncodingJobOptions.cs

@@ -204,6 +204,8 @@ namespace MediaBrowser.Controller.MediaEncoding
 
         public string SubtitleCodec { get; set; }
 
+        public string TranscodeReasons { get; set; }
+
         /// <summary>
         /// Gets or sets the index of the audio stream.
         /// </summary>

+ 0 - 1
MediaBrowser.Model/Configuration/UserConfiguration.cs

@@ -55,7 +55,6 @@ namespace MediaBrowser.Model.Configuration
 
             HidePlayedInLatest = true;
             PlayDefaultAudioTrack = true;
-            DisplayMissingEpisodes = true;
 
             LatestItemsExcludes = new string[] { };
             OrderedViews = new string[] { };

+ 0 - 1
MediaBrowser.Model/Dlna/ProfileCondition.cs

@@ -1,5 +1,4 @@
 using System.Xml.Serialization;
-using MediaBrowser.Model.Dlna;
 
 namespace MediaBrowser.Model.Dlna
 {

+ 248 - 23
MediaBrowser.Model/Dlna/StreamBuilder.cs

@@ -105,8 +105,99 @@ namespace MediaBrowser.Model.Dlna
             return null;
         }
 
+        private TranscodeReason? GetTranscodeReasonForFailedCondition(ProfileCondition condition)
+        {
+            switch (condition.Property)
+            {
+                case ProfileConditionValue.AudioBitrate:
+                    if (condition.Condition == ProfileConditionType.LessThanEqual)
+                    {
+                        return TranscodeReason.AudioBitrateNotSupported;
+                    }
+                    return TranscodeReason.AudioBitrateNotSupported;
+
+                case ProfileConditionValue.AudioChannels:
+                    if (condition.Condition == ProfileConditionType.LessThanEqual)
+                    {
+                        return TranscodeReason.AudioChannelsNotSupported;
+                    }
+                    return TranscodeReason.AudioChannelsNotSupported;
+
+                case ProfileConditionValue.AudioProfile:
+                    return TranscodeReason.AudioProfileNotSupported;
+
+                case ProfileConditionValue.AudioSampleRate:
+                    return TranscodeReason.AudioSampleRateNotSupported;
+
+                case ProfileConditionValue.Has64BitOffsets:
+                    // TODO
+                    return null;
+
+                case ProfileConditionValue.Height:
+                    return TranscodeReason.VideoResolutionNotSupported;
+
+                case ProfileConditionValue.IsAnamorphic:
+                    return TranscodeReason.AnamorphicVideoNotSupported;
+
+                case ProfileConditionValue.IsAvc:
+                    // TODO
+                    return null;
+
+                case ProfileConditionValue.IsInterlaced:
+                    return TranscodeReason.InterlacedVideoNotSupported;
+
+                case ProfileConditionValue.IsSecondaryAudio:
+                    return TranscodeReason.SecondaryAudioNotSupported;
+
+                case ProfileConditionValue.NumAudioStreams:
+                    // TODO
+                    return null;
+
+                case ProfileConditionValue.NumVideoStreams:
+                    // TODO
+                    return null;
+
+                case ProfileConditionValue.PacketLength:
+                    // TODO
+                    return null;
+
+                case ProfileConditionValue.RefFrames:
+                    return TranscodeReason.RefFramesNotSupported;
+
+                case ProfileConditionValue.VideoBitDepth:
+                    return TranscodeReason.VideoBitDepthNotSupported;
+
+                case ProfileConditionValue.VideoBitrate:
+                    return TranscodeReason.VideoBitrateNotSupported;
+
+                case ProfileConditionValue.VideoCodecTag:
+                    return TranscodeReason.VideoCodecNotSupported;
+
+                case ProfileConditionValue.VideoFramerate:
+                    return TranscodeReason.VideoFramerateNotSupported;
+
+                case ProfileConditionValue.VideoLevel:
+                    return TranscodeReason.VideoLevelNotSupported;
+
+                case ProfileConditionValue.VideoProfile:
+                    return TranscodeReason.VideoProfileNotSupported;
+
+                case ProfileConditionValue.VideoTimestamp:
+                    // TODO
+                    return null;
+
+                case ProfileConditionValue.Width:
+                    return TranscodeReason.VideoResolutionNotSupported;
+
+                default:
+                    return null;
+            }
+        }
+
         private StreamInfo BuildAudioItem(MediaSourceInfo item, AudioOptions options)
         {
+            List<TranscodeReason> transcodeReasons = new List<TranscodeReason>();
+
             StreamInfo playlistItem = new StreamInfo
             {
                 ItemId = options.ItemId,
@@ -133,7 +224,10 @@ namespace MediaBrowser.Model.Dlna
 
             MediaStream audioStream = item.GetDefaultAudioStream(null);
 
-            List<PlayMethod> directPlayMethods = GetAudioDirectPlayMethods(item, audioStream, options);
+            var directPlayInfo = GetAudioDirectPlayMethods(item, audioStream, options);
+
+            List<PlayMethod> directPlayMethods = directPlayInfo.Item1;
+            transcodeReasons.AddRange(directPlayInfo.Item2);
 
             ConditionProcessor conditionProcessor = new ConditionProcessor();
 
@@ -180,6 +274,11 @@ namespace MediaBrowser.Model.Dlna
                         if (!conditionProcessor.IsAudioConditionSatisfied(c, inputAudioChannels, inputAudioBitrate, inputAudioSampleRate))
                         {
                             LogConditionFailure(options.Profile, "AudioCodecProfile", c, item);
+                            var transcodeReason = GetTranscodeReasonForFailedCondition(c);
+                            if (transcodeReason.HasValue)
+                            {
+                                transcodeReasons.Add(transcodeReason.Value);
+                            }
                             all = false;
                             break;
                         }
@@ -292,9 +391,9 @@ namespace MediaBrowser.Model.Dlna
 
                 var longBitrate = Math.Min(transcodingBitrate, playlistItem.AudioBitrate ?? transcodingBitrate);
                 playlistItem.AudioBitrate = longBitrate > int.MaxValue ? int.MaxValue : Convert.ToInt32(longBitrate);
-
             }
 
+            playlistItem.TranscodeReasons = transcodeReasons;
             return playlistItem;
         }
 
@@ -308,8 +407,10 @@ namespace MediaBrowser.Model.Dlna
             return options.GetMaxBitrate(isAudio);
         }
 
-        private List<PlayMethod> GetAudioDirectPlayMethods(MediaSourceInfo item, MediaStream audioStream, AudioOptions options)
+        private Tuple<List<PlayMethod>, List<TranscodeReason>> GetAudioDirectPlayMethods(MediaSourceInfo item, MediaStream audioStream, AudioOptions options)
         {
+            List<TranscodeReason> transcodeReasons = new List<TranscodeReason>();
+
             DirectPlayProfile directPlayProfile = null;
             foreach (DirectPlayProfile i in options.Profile.DirectPlayProfiles)
             {
@@ -325,27 +426,134 @@ namespace MediaBrowser.Model.Dlna
             if (directPlayProfile != null)
             {
                 // While options takes the network and other factors into account. Only applies to direct stream
-                if (item.SupportsDirectStream && IsAudioEligibleForDirectPlay(item, options.GetMaxBitrate(true), PlayMethod.DirectStream) && options.EnableDirectStream)
+                if (item.SupportsDirectStream)
                 {
-                    playMethods.Add(PlayMethod.DirectStream);
+                    if (IsAudioEligibleForDirectPlay(item, options.GetMaxBitrate(true), PlayMethod.DirectStream))
+                    {
+                        if (options.EnableDirectStream)
+                        {
+                            playMethods.Add(PlayMethod.DirectStream);
+                        }
+                    }
+                    else
+                    {
+                        transcodeReasons.Add(TranscodeReason.ContainerBitrateExceedsLimit);
+                    }
                 }
 
                 // The profile describes what the device supports
                 // If device requirements are satisfied then allow both direct stream and direct play
-                if (item.SupportsDirectPlay &&
-                    IsAudioEligibleForDirectPlay(item, GetBitrateForDirectPlayCheck(item, options, true), PlayMethod.DirectPlay) && options.EnableDirectPlay)
+                if (item.SupportsDirectPlay)
                 {
-                    playMethods.Add(PlayMethod.DirectPlay);
+                    if (IsAudioEligibleForDirectPlay(item, GetBitrateForDirectPlayCheck(item, options, true), PlayMethod.DirectPlay))
+                    {
+                        if (options.EnableDirectPlay)
+                        {
+                            playMethods.Add(PlayMethod.DirectPlay);
+                        }
+                    }
+                    else
+                    {
+                        transcodeReasons.Add(TranscodeReason.ContainerBitrateExceedsLimit);
+                    }
                 }
             }
             else
             {
+                transcodeReasons.InsertRange(0, GetTranscodeReasonsFromDirectPlayProfile(item, null, audioStream, options.Profile.DirectPlayProfiles));
+
                 _logger.Info("Profile: {0}, No direct play profiles found for Path: {1}",
                     options.Profile.Name ?? "Unknown Profile",
                     item.Path ?? "Unknown path");
             }
 
-            return playMethods;
+            if (playMethods.Count > 0)
+            {
+                transcodeReasons.Clear();
+            }
+            else
+            {
+                transcodeReasons = transcodeReasons.Distinct().ToList();
+            }
+
+            return new Tuple<List<PlayMethod>, List<TranscodeReason>>(playMethods, transcodeReasons);
+        }
+
+        private List<TranscodeReason> GetTranscodeReasonsFromDirectPlayProfile(MediaSourceInfo item, MediaStream videoStream, MediaStream audioStream, IEnumerable<DirectPlayProfile> directPlayProfiles)
+        {
+            var list = new List<TranscodeReason>();
+            var containerSupported = false;
+            var audioSupported = false;
+            var videoSupported = false;
+
+            foreach (var profile in directPlayProfiles)
+            {
+                if (profile.Container.Length > 0)
+                {
+                    // Check container type
+                    string mediaContainer = item.Container ?? string.Empty;
+                    foreach (string i in profile.GetContainers())
+                    {
+                        if (StringHelper.EqualsIgnoreCase(i, mediaContainer))
+                        {
+                            containerSupported = true;
+
+                            if (videoStream != null)
+                            {
+                                // Check video codec
+                                List<string> videoCodecs = profile.GetVideoCodecs();
+                                if (videoCodecs.Count > 0)
+                                {
+                                    string videoCodec = videoStream.Codec;
+                                    if (!string.IsNullOrEmpty(videoCodec) && ListHelper.ContainsIgnoreCase(videoCodecs, videoCodec))
+                                    {
+                                        videoSupported = true;
+                                    }
+                                }
+                                else
+                                {
+                                    videoSupported = true;
+                                }
+                            }
+
+                            if (audioStream != null)
+                            {
+                                // Check audio codec
+                                List<string> audioCodecs = profile.GetAudioCodecs();
+                                if (audioCodecs.Count > 0)
+                                {
+                                    string audioCodec = audioStream.Codec;
+                                    if (!string.IsNullOrEmpty(audioCodec) && ListHelper.ContainsIgnoreCase(audioCodecs, audioCodec))
+                                    {
+                                        audioSupported = true;
+                                    }
+                                }
+                                else
+                                {
+                                    audioSupported = true;
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+
+            if (!containerSupported)
+            {
+                list.Add(TranscodeReason.ContainerNotSupported);
+            }
+
+            if (videoStream != null && !videoSupported)
+            {
+                list.Add(TranscodeReason.VideoCodecNotSupported);
+            }
+
+            if (audioStream != null && !audioSupported)
+            {
+                list.Add(TranscodeReason.VideoCodecNotSupported);
+            }
+
+            return list;
         }
 
         private int? GetDefaultSubtitleStreamIndex(MediaSourceInfo item, SubtitleProfile[] subtitleProfiles)
@@ -393,6 +601,8 @@ namespace MediaBrowser.Model.Dlna
 
         private StreamInfo BuildVideoItem(MediaSourceInfo item, VideoOptions options)
         {
+            List<TranscodeReason> transcodeReasons = new List<TranscodeReason>();
+
             StreamInfo playlistItem = new StreamInfo
             {
                 ItemId = options.ItemId,
@@ -428,7 +638,8 @@ namespace MediaBrowser.Model.Dlna
             if (isEligibleForDirectPlay || isEligibleForDirectStream)
             {
                 // See if it can be direct played
-                PlayMethod? directPlay = GetVideoDirectPlayProfile(options, item, videoStream, audioStream, isEligibleForDirectPlay, isEligibleForDirectStream);
+                var directPlayInfo = GetVideoDirectPlayProfile(options, item, videoStream, audioStream, isEligibleForDirectPlay, isEligibleForDirectStream);
+                var directPlay = directPlayInfo.Item1;
 
                 if (directPlay != null)
                 {
@@ -445,6 +656,8 @@ namespace MediaBrowser.Model.Dlna
 
                     return playlistItem;
                 }
+
+                transcodeReasons.AddRange(directPlayInfo.Item2);
             }
 
             // Can't direct play, find the transcoding profile
@@ -618,6 +831,8 @@ namespace MediaBrowser.Model.Dlna
                 }
             }
 
+            playlistItem.TranscodeReasons = transcodeReasons;
+
             return playlistItem;
         }
 
@@ -677,7 +892,7 @@ namespace MediaBrowser.Model.Dlna
             return Math.Min(defaultBitrate, encoderAudioBitrateLimit);
         }
 
-        private PlayMethod? GetVideoDirectPlayProfile(VideoOptions options,
+        private Tuple<PlayMethod?, List<TranscodeReason>> GetVideoDirectPlayProfile(VideoOptions options,
             MediaSourceInfo mediaSource,
             MediaStream videoStream,
             MediaStream audioStream,
@@ -688,11 +903,11 @@ namespace MediaBrowser.Model.Dlna
 
             if (options.ForceDirectPlay)
             {
-                return PlayMethod.DirectPlay;
+                return new Tuple<PlayMethod?, List<TranscodeReason>>(PlayMethod.DirectPlay, new List<TranscodeReason>());
             }
             if (options.ForceDirectStream)
             {
-                return PlayMethod.DirectStream;
+                return new Tuple<PlayMethod?, List<TranscodeReason>>(PlayMethod.DirectStream, new List<TranscodeReason>());
             }
 
             if (videoStream == null)
@@ -701,7 +916,7 @@ namespace MediaBrowser.Model.Dlna
                     profile.Name ?? "Unknown Profile",
                     mediaSource.Path ?? "Unknown path");
 
-                return null;
+                return new Tuple<PlayMethod?, List<TranscodeReason>>(null, new List<TranscodeReason> { TranscodeReason.UnknownVideoStreamInfo });
             }
 
             // See if it can be direct played
@@ -721,7 +936,7 @@ namespace MediaBrowser.Model.Dlna
                     profile.Name ?? "Unknown Profile",
                     mediaSource.Path ?? "Unknown path");
 
-                return null;
+                return new Tuple<PlayMethod?, List<TranscodeReason>>(null, GetTranscodeReasonsFromDirectPlayProfile(mediaSource, videoStream, audioStream, profile.DirectPlayProfiles));
             }
 
             string container = mediaSource.Container;
@@ -784,7 +999,7 @@ namespace MediaBrowser.Model.Dlna
                     profile.Name ?? "Unknown Profile",
                     mediaSource.Path ?? "Unknown path");
 
-                return null;
+                return new Tuple<PlayMethod?, List<TranscodeReason>>(null, new List<TranscodeReason> { TranscodeReason.UnknownVideoStreamInfo });
             }
 
             conditions = new List<ProfileCondition>();
@@ -819,7 +1034,12 @@ namespace MediaBrowser.Model.Dlna
                 {
                     LogConditionFailure(profile, "VideoCodecProfile", i, mediaSource);
 
-                    return null;
+                    var transcodeReason = GetTranscodeReasonForFailedCondition(i);
+                    var transcodeReasons = transcodeReason.HasValue
+                        ? new List<TranscodeReason> { transcodeReason.Value }
+                        : new List<TranscodeReason> { };
+
+                    return new Tuple<PlayMethod?, List<TranscodeReason>>(null, transcodeReasons);
                 }
             }
 
@@ -833,7 +1053,7 @@ namespace MediaBrowser.Model.Dlna
                         profile.Name ?? "Unknown Profile",
                         mediaSource.Path ?? "Unknown path");
 
-                    return null;
+                    return new Tuple<PlayMethod?, List<TranscodeReason>>(null, new List<TranscodeReason> { TranscodeReason.UnknownAudioStreamInfo });
                 }
 
                 conditions = new List<ProfileCondition>();
@@ -870,17 +1090,22 @@ namespace MediaBrowser.Model.Dlna
                     {
                         LogConditionFailure(profile, "VideoAudioCodecProfile", i, mediaSource);
 
-                        return null;
+                        var transcodeReason = GetTranscodeReasonForFailedCondition(i);
+                        var transcodeReasons = transcodeReason.HasValue
+                            ? new List<TranscodeReason> { transcodeReason.Value }
+                            : new List<TranscodeReason> { };
+
+                        return new Tuple<PlayMethod?, List<TranscodeReason>>(null, transcodeReasons);
                     }
                 }
             }
 
             if (isEligibleForDirectStream && mediaSource.SupportsDirectStream)
             {
-                return PlayMethod.DirectStream;
+                return new Tuple<PlayMethod?, List<TranscodeReason>>(PlayMethod.DirectStream, new List<TranscodeReason>());
             }
 
-            return null;
+            return new Tuple<PlayMethod?, List<TranscodeReason>>(null, new List<TranscodeReason> { TranscodeReason.ContainerBitrateExceedsLimit });
         }
 
         private void LogConditionFailure(DeviceProfile profile, string type, ProfileCondition condition, MediaSourceInfo mediaSource)
@@ -1047,12 +1272,12 @@ namespace MediaBrowser.Model.Dlna
             // Don't restrict by bitrate if coming from an external domain
             if (item.IsRemote)
             {
-                return true;    
+                return true;
             }
 
             if (!maxBitrate.HasValue)
             {
-                _logger.Info("Cannot "+ playMethod + " due to unknown supported bitrate");
+                _logger.Info("Cannot " + playMethod + " due to unknown supported bitrate");
                 return false;
             }
 

+ 8 - 12
MediaBrowser.Model/Dlna/StreamInfo.cs

@@ -21,6 +21,7 @@ namespace MediaBrowser.Model.Dlna
             AudioCodecs = new string[] { };
             VideoCodecs = new string[] { };
             SubtitleCodecs = new string[] { };
+            TranscodeReasons = new List<TranscodeReason>();
         }
 
         public string ItemId { get; set; }
@@ -89,6 +90,7 @@ namespace MediaBrowser.Model.Dlna
 
         public string PlaySessionId { get; set; }
         public List<MediaSourceInfo> AllMediaSources { get; set; }
+        public List<TranscodeReason> TranscodeReasons { get; set; }
 
         public string MediaSourceId
         {
@@ -231,22 +233,11 @@ namespace MediaBrowser.Model.Dlna
             list.Add(new NameValuePair("MaxWidth", item.MaxWidth.HasValue ? StringHelper.ToStringCultureInvariant(item.MaxWidth.Value) : string.Empty));
             list.Add(new NameValuePair("MaxHeight", item.MaxHeight.HasValue ? StringHelper.ToStringCultureInvariant(item.MaxHeight.Value) : string.Empty));
 
-            var forceStartPosition = false;
             long startPositionTicks = item.StartPositionTicks;
-            //if (item.MediaSource.DateLiveStreamOpened.HasValue && startPositionTicks == 0)
-            //{
-            //    var elapsed = DateTime.UtcNow - item.MediaSource.DateLiveStreamOpened.Value;
-            //    elapsed -= TimeSpan.FromSeconds(20);
-            //    if (elapsed.TotalSeconds >= 0)
-            //    {
-            //        startPositionTicks = elapsed.Ticks + startPositionTicks;
-            //        forceStartPosition = true;
-            //    }
-            //}
 
             var isHls = StringHelper.EqualsIgnoreCase(item.SubProtocol, "hls");
 
-            if (isHls && !forceStartPosition)
+            if (isHls)
             {
                 list.Add(new NameValuePair("StartTimeTicks", string.Empty));
             }
@@ -310,6 +301,11 @@ namespace MediaBrowser.Model.Dlna
                 list.Add(new NameValuePair("BreakOnNonKeyFrames", item.BreakOnNonKeyFrames.ToString()));
             }
 
+            if (isDlna || !item.IsDirectStream)
+            {
+                list.Add(new NameValuePair("TranscodeReasons", string.Join(",", item.TranscodeReasons.Distinct().Select(i => i.ToString()).ToArray())));
+            }
+
             return list;
         }
 

+ 4 - 0
MediaBrowser.Model/Dto/MediaSourceInfo.cs

@@ -4,6 +4,7 @@ using MediaBrowser.Model.MediaInfo;
 using System.Collections.Generic;
 using System.Linq;
 using MediaBrowser.Model.Serialization;
+using MediaBrowser.Model.Session;
 
 namespace MediaBrowser.Model.Dto
 {
@@ -110,6 +111,9 @@ namespace MediaBrowser.Model.Dto
             }
         }
 
+        [IgnoreDataMember]
+        public List<TranscodeReason> TranscodeReasons { get; set; }
+
         public int? DefaultAudioStreamIndex { get; set; }
         public int? DefaultSubtitleStreamIndex { get; set; }
 

+ 0 - 10
MediaBrowser.Model/Dto/UserDto.cs

@@ -122,16 +122,6 @@ namespace MediaBrowser.Model.Dto
         /// <value>The primary image aspect ratio.</value>
         public double? PrimaryImageAspectRatio { get; set; }
 
-        /// <summary>
-        /// Gets a value indicating whether this instance has primary image.
-        /// </summary>
-        /// <value><c>true</c> if this instance has primary image; otherwise, <c>false</c>.</value>
-        [IgnoreDataMember]
-        public bool HasPrimaryImage
-        {
-            get { return PrimaryImageTag != null; }
-        }
-
         /// <summary>
         /// Initializes a new instance of the <see cref="UserDto"/> class.
         /// </summary>

+ 2 - 0
MediaBrowser.Model/LiveTv/LiveTvOptions.cs

@@ -47,6 +47,7 @@ namespace MediaBrowser.Model.LiveTv
         public bool ImportFavoritesOnly { get; set; }
         public bool AllowHWTranscoding { get; set; }
         public bool EnableTvgId { get; set; }
+        public bool EnableStreamLooping { get; set; }
 
         public TunerHostInfo()
         {
@@ -74,6 +75,7 @@ namespace MediaBrowser.Model.LiveTv
         public NameValuePair[] ChannelMappings { get; set; }
         public string MoviePrefix { get; set; }
         public bool EnableNewProgramIds { get; set; }
+        public string PreferredLanguage { get; set; }
 
         public ListingsProviderInfo()
         {

+ 1 - 0
MediaBrowser.Model/Net/MimeTypes.cs

@@ -72,6 +72,7 @@ namespace MediaBrowser.Model.Net
             dict.Add(".tbn", "image/jpeg");
             dict.Add(".png", "image/png");
             dict.Add(".gif", "image/gif");
+            dict.Add(".tiff", "image/tiff");
             dict.Add(".webp", "image/webp");
             dict.Add(".ico", "image/vnd.microsoft.icon");
             dict.Add(".mpg", "video/mpeg");

+ 33 - 0
MediaBrowser.Model/Session/TranscodingInfo.cs

@@ -1,3 +1,5 @@
+using System.Collections.Generic;
+
 namespace MediaBrowser.Model.Session
 {
     public class TranscodingInfo
@@ -15,5 +17,36 @@ namespace MediaBrowser.Model.Session
         public int? Width { get; set; }
         public int? Height { get; set; }
         public int? AudioChannels { get; set; }
+
+        public List<TranscodeReason> TranscodeReasons { get; set; }
+
+        public TranscodingInfo()
+        {
+            TranscodeReasons = new List<TranscodeReason>();
+        }
+    }
+
+    public enum TranscodeReason
+    {
+        ContainerNotSupported = 0,
+        VideoCodecNotSupported = 1,
+        AudioCodecNotSupported = 2,
+        ContainerBitrateExceedsLimit = 3,
+        AudioBitrateNotSupported = 4,
+        AudioChannelsNotSupported = 5,
+        VideoResolutionNotSupported = 6,
+        UnknownVideoStreamInfo = 7,
+        UnknownAudioStreamInfo = 8,
+        AudioProfileNotSupported = 9,
+        AudioSampleRateNotSupported = 10,
+        AnamorphicVideoNotSupported = 11,
+        InterlacedVideoNotSupported = 12,
+        SecondaryAudioNotSupported = 13,
+        RefFramesNotSupported = 14,
+        VideoBitDepthNotSupported = 15,
+        VideoBitrateNotSupported = 16,
+        VideoFramerateNotSupported = 17,
+        VideoLevelNotSupported = 18,
+        VideoProfileNotSupported = 19
     }
 }

+ 2 - 2
MediaBrowser.Server.Mono/ImageEncoderHelper.cs

@@ -31,7 +31,7 @@ namespace MediaBrowser.Server.Startup.Common
                 }
                 catch (Exception ex)
                 {
-                    logger.Info("Error loading Skia: {0}. Will revert to ImageMagick.", ex.Message);
+                    logger.Error("Skia not available. Will try next image processor. {0}", ex.Message);
                 }
 
                 try
@@ -40,7 +40,7 @@ namespace MediaBrowser.Server.Startup.Common
                 }
                 catch
                 {
-                    logger.Error("Error loading ImageMagick. Will revert to GDI.");
+                    logger.Error("ImageMagick not available. Will try next image processor.");
                 }
             }
 

+ 5 - 5
MediaBrowser.ServerApplication/ImageEncoderHelper.cs

@@ -14,10 +14,10 @@ namespace MediaBrowser.Server.Startup.Common
 {
     public class ImageEncoderHelper
     {
-        public static IImageEncoder GetImageEncoder(ILogger logger, 
-            ILogManager logManager, 
-            IFileSystem fileSystem, 
-            StartupOptions startupOptions, 
+        public static IImageEncoder GetImageEncoder(ILogger logger,
+            ILogManager logManager,
+            IFileSystem fileSystem,
+            StartupOptions startupOptions,
             Func<IHttpClient> httpClient,
             IApplicationPaths appPaths)
         {
@@ -27,7 +27,7 @@ namespace MediaBrowser.Server.Startup.Common
             }
             catch
             {
-                logger.Error("Error loading Skia. Will revert to ImageMagick.");
+                logger.Error("Skia not available. Will try next image processor.");
             }
 
             return new NullImageEncoder();

+ 0 - 136
MediaBrowser.ServerApplication/MainForm.Designer.cs

@@ -1,136 +0,0 @@
-namespace MediaBrowser.ServerApplication
-{
-    partial class MainForm
-    {
-        /// <summary>
-        /// Required designer variable.
-        /// </summary>
-        private System.ComponentModel.IContainer components = null;
-
-        /// <summary>
-        /// Clean up any resources being used.
-        /// </summary>
-        /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
-        protected override void Dispose(bool disposing)
-        {
-            if (disposing && (components != null))
-            {
-                components.Dispose();
-            }
-            base.Dispose(disposing);
-        }
-
-        #region Windows Form Designer generated code
-
-        /// <summary>
-        /// Required method for Designer support - do not modify
-        /// the contents of this method with the code editor.
-        /// </summary>
-        private void InitializeComponent()
-        {
-            this.components = new System.ComponentModel.Container();
-            System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(MainForm));
-            this.notifyIcon1 = new System.Windows.Forms.NotifyIcon(this.components);
-            this.contextMenuStrip1 = new System.Windows.Forms.ContextMenuStrip(this.components);
-            this.cmdBrowse = new System.Windows.Forms.ToolStripMenuItem();
-            this.cmdConfigure = new System.Windows.Forms.ToolStripMenuItem();
-            this.toolStripSeparator2 = new System.Windows.Forms.ToolStripSeparator();
-            this.cmdRestart = new System.Windows.Forms.ToolStripMenuItem();
-            this.toolStripSeparator1 = new System.Windows.Forms.ToolStripSeparator();
-            this.cmdCommunity = new System.Windows.Forms.ToolStripMenuItem();
-            this.cmdExit = new System.Windows.Forms.ToolStripMenuItem();
-            this.contextMenuStrip1.SuspendLayout();
-            this.SuspendLayout();
-            // 
-            // notifyIcon1
-            // 
-            this.notifyIcon1.ContextMenuStrip = this.contextMenuStrip1;
-            this.notifyIcon1.Icon = ((System.Drawing.Icon)(resources.GetObject("notifyIcon1.Icon")));
-            this.notifyIcon1.Text = "Emby";
-            this.notifyIcon1.Visible = true;
-            // 
-            // contextMenuStrip1
-            // 
-            this.contextMenuStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
-            this.cmdBrowse,
-            this.cmdConfigure,
-            this.toolStripSeparator2,
-            this.cmdRestart,
-            this.toolStripSeparator1,
-            this.cmdCommunity,
-            this.cmdExit});
-            this.contextMenuStrip1.Name = "contextMenuStrip1";
-            this.contextMenuStrip1.ShowCheckMargin = true;
-            this.contextMenuStrip1.ShowImageMargin = false;
-            this.contextMenuStrip1.Size = new System.Drawing.Size(209, 192);
-            // 
-            // cmdBrowse
-            // 
-            this.cmdBrowse.Name = "cmdBrowse";
-            this.cmdBrowse.Size = new System.Drawing.Size(208, 22);
-            this.cmdBrowse.Text = "Browse Library";
-            // 
-            // cmdConfigure
-            // 
-            this.cmdConfigure.Name = "cmdConfigure";
-            this.cmdConfigure.Size = new System.Drawing.Size(208, 22);
-            this.cmdConfigure.Text = "Configure Media Browser";
-            // 
-            // toolStripSeparator2
-            // 
-            this.toolStripSeparator2.Name = "toolStripSeparator2";
-            this.toolStripSeparator2.Size = new System.Drawing.Size(205, 6);
-            // 
-            // cmdRestart
-            // 
-            this.cmdRestart.Name = "cmdRestart";
-            this.cmdRestart.Size = new System.Drawing.Size(208, 22);
-            this.cmdRestart.Text = "Restart Server";
-            // 
-            // toolStripSeparator1
-            // 
-            this.toolStripSeparator1.Name = "toolStripSeparator1";
-            this.toolStripSeparator1.Size = new System.Drawing.Size(205, 6);
-            // 
-            // cmdCommunity
-            // 
-            this.cmdCommunity.Name = "cmdCommunity";
-            this.cmdCommunity.Size = new System.Drawing.Size(208, 22);
-            this.cmdCommunity.Text = "Visit Community";
-            // 
-            // cmdExit
-            // 
-            this.cmdExit.Name = "cmdExit";
-            this.cmdExit.Size = new System.Drawing.Size(208, 22);
-            this.cmdExit.Text = "Exit";
-            // 
-            // MainForm
-            // 
-            this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
-            this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
-            this.ClientSize = new System.Drawing.Size(284, 261);
-            this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.None;
-            this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon")));
-            this.Name = "MainForm";
-            this.ShowInTaskbar = false;
-            this.SizeGripStyle = System.Windows.Forms.SizeGripStyle.Hide;
-            this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent;
-            this.Text = "MainForm";
-            this.contextMenuStrip1.ResumeLayout(false);
-            this.ResumeLayout(false);
-
-        }
-
-        #endregion
-
-        private System.Windows.Forms.NotifyIcon notifyIcon1;
-        private System.Windows.Forms.ContextMenuStrip contextMenuStrip1;
-        private System.Windows.Forms.ToolStripMenuItem cmdExit;
-        private System.Windows.Forms.ToolStripMenuItem cmdBrowse;
-        private System.Windows.Forms.ToolStripMenuItem cmdConfigure;
-        private System.Windows.Forms.ToolStripSeparator toolStripSeparator2;
-        private System.Windows.Forms.ToolStripMenuItem cmdRestart;
-        private System.Windows.Forms.ToolStripSeparator toolStripSeparator1;
-        private System.Windows.Forms.ToolStripMenuItem cmdCommunity;
-    }
-}

+ 0 - 12
MediaBrowser.ServerApplication/MainForm.cs

@@ -1,12 +0,0 @@
-using System.Windows.Forms;
-
-namespace MediaBrowser.ServerApplication
-{
-    public partial class MainForm : Form
-    {
-        public MainForm()
-        {
-            InitializeComponent();
-        }
-    }
-}

+ 0 - 576
MediaBrowser.ServerApplication/MainForm.resx

@@ -1,576 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<root>
-  <!-- 
-    Microsoft ResX Schema 
-    
-    Version 2.0
-    
-    The primary goals of this format is to allow a simple XML format 
-    that is mostly human readable. The generation and parsing of the 
-    various data types are done through the TypeConverter classes 
-    associated with the data types.
-    
-    Example:
-    
-    ... ado.net/XML headers & schema ...
-    <resheader name="resmimetype">text/microsoft-resx</resheader>
-    <resheader name="version">2.0</resheader>
-    <resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
-    <resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
-    <data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
-    <data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
-    <data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
-        <value>[base64 mime encoded serialized .NET Framework object]</value>
-    </data>
-    <data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
-        <value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
-        <comment>This is a comment</comment>
-    </data>
-                
-    There are any number of "resheader" rows that contain simple 
-    name/value pairs.
-    
-    Each data row contains a name, and value. The row also contains a 
-    type or mimetype. Type corresponds to a .NET class that support 
-    text/value conversion through the TypeConverter architecture. 
-    Classes that don't support this are serialized and stored with the 
-    mimetype set.
-    
-    The mimetype is used for serialized objects, and tells the 
-    ResXResourceReader how to depersist the object. This is currently not 
-    extensible. For a given mimetype the value must be set accordingly:
-    
-    Note - application/x-microsoft.net.object.binary.base64 is the format 
-    that the ResXResourceWriter will generate, however the reader can 
-    read any of the formats listed below.
-    
-    mimetype: application/x-microsoft.net.object.binary.base64
-    value   : The object must be serialized with 
-            : System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
-            : and then encoded with base64 encoding.
-    
-    mimetype: application/x-microsoft.net.object.soap.base64
-    value   : The object must be serialized with 
-            : System.Runtime.Serialization.Formatters.Soap.SoapFormatter
-            : and then encoded with base64 encoding.
-
-    mimetype: application/x-microsoft.net.object.bytearray.base64
-    value   : The object must be serialized into a byte array 
-            : using a System.ComponentModel.TypeConverter
-            : and then encoded with base64 encoding.
-    -->
-  <xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
-    <xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
-    <xsd:element name="root" msdata:IsDataSet="true">
-      <xsd:complexType>
-        <xsd:choice maxOccurs="unbounded">
-          <xsd:element name="metadata">
-            <xsd:complexType>
-              <xsd:sequence>
-                <xsd:element name="value" type="xsd:string" minOccurs="0" />
-              </xsd:sequence>
-              <xsd:attribute name="name" use="required" type="xsd:string" />
-              <xsd:attribute name="type" type="xsd:string" />
-              <xsd:attribute name="mimetype" type="xsd:string" />
-              <xsd:attribute ref="xml:space" />
-            </xsd:complexType>
-          </xsd:element>
-          <xsd:element name="assembly">
-            <xsd:complexType>
-              <xsd:attribute name="alias" type="xsd:string" />
-              <xsd:attribute name="name" type="xsd:string" />
-            </xsd:complexType>
-          </xsd:element>
-          <xsd:element name="data">
-            <xsd:complexType>
-              <xsd:sequence>
-                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
-                <xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
-              </xsd:sequence>
-              <xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
-              <xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
-              <xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
-              <xsd:attribute ref="xml:space" />
-            </xsd:complexType>
-          </xsd:element>
-          <xsd:element name="resheader">
-            <xsd:complexType>
-              <xsd:sequence>
-                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
-              </xsd:sequence>
-              <xsd:attribute name="name" type="xsd:string" use="required" />
-            </xsd:complexType>
-          </xsd:element>
-        </xsd:choice>
-      </xsd:complexType>
-    </xsd:element>
-  </xsd:schema>
-  <resheader name="resmimetype">
-    <value>text/microsoft-resx</value>
-  </resheader>
-  <resheader name="version">
-    <value>2.0</value>
-  </resheader>
-  <resheader name="reader">
-    <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
-  </resheader>
-  <resheader name="writer">
-    <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
-  </resheader>
-  <assembly alias="System.Drawing" name="System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
-  <data name="notifyIcon1.TrayLocation" type="System.Drawing.Point, System.Drawing">
-    <value>17, 17</value>
-  </data>
-  <data name="contextMenuStrip1.TrayLocation" type="System.Drawing.Point, System.Drawing">
-    <value>130, 17</value>
-  </data>
-  <data name="$this.Icon" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
-    <value>
-        AAABAAgAMDAAAAEAIACoJQAAhgAAADAwAAABAAgAqA4AAC4mAAAgIAAAAQAgAKgQAADWNAAAICAAAAEA
-        CACoCAAAfkUAABgYAAABACAAiAkAACZOAAAYGAAAAQAIAMgGAACuVwAAEBAAAAEAIABoBAAAdl4AABAQ
-        AAABAAgAaAUAAN5iAAAoAAAAMAAAAGAAAAABACAAAAAAAABIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
-        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
-        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEu2UkpItlMxAAAAAAAAAAAAAAAAAAAAAAAA
-        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
-        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
-        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAS7RQM0u1Uv9LtVL/S7NSJQAA
-        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
-        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
-        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABKtFIfS7VS/0u1
-        Uv9LtVL/S7VS/0i2SAcAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
-        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
-        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEuz
-        Uz1LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9ItkgHAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
-        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
-        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
-        AAAAAAAAS7NRTku1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7NSJQAAAAAAAAAAAAAAAAAA
-        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
-        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
-        AAAAAAAAAAAAAAAAAABLs1FOS7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0i2
-        UzEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
-        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
-        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAEuzUz1LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1
-        Uv9LtVL/S7VS/0u1Uv/OtgAVAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
-        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
-        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAASrRSH0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1
-        Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/xsYACQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
-        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
-        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABLtFAzS7VS/0u1Uv9LtVL/S7VS/0u1
-        Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/wAAAAAAAAAAAAAAAAAA
-        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
-        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKqqAAMAAAAAAAAAAEu2UkpLtVL/S7VS/0u1
-        Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1
-        Uv/atgAOAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
-        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAS7VS/0u1Uv/MuwAPTLVSUEu1
-        Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1
-        Uv9LtVL/S7VS/0u1Uv9LtVL/0rwAFwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
-        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABLtVL/S7VS/0u1
-        Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1
-        Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/9K8ABcAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
-        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEu1
-        Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1
-        Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv/atgAOAAAAAAAA
-        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
-        AAAAAAAAS7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1
-        Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1
-        Uv8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
-        AAAAAAAAAAAAAAAAAABLtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1
-        Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1
-        Uv9LtVL/S7VS/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
-        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAEu1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1
-        Uv9LtVL/S7VS/8Dkwf9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1
-        Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
-        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAS7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1
-        Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS////////////bsBk/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1
-        Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/AAAAAAAAAAAAAAAAAAAAAAAA
-        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABLtVL/S7VS/0u1Uv9LtVL/S7VS/0u1
-        Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS//////////////////////9LtVL/S7VS/0u1
-        Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/wAA
-        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEu1Uv9LtVL/S7VS/0u1
-        Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS////////////////////
-        /////////////0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1
-        Uv9LtVL/S7VS/0u1Uv8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAS7VS/0u1
-        Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS////
-        ///////////////////////////////////d6sP/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1
-        Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
-        AABLtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1
-        Uv9LtVL/S7VS/////////////////////////////////////////////////0u1Uv9LtVL/S7VS/0u1
-        Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/wAAAAAAAAAAAAAAAAAA
-        AAAAAAAAAAAAAEu1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1
-        Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS////////////////////////////////////////////////////
-        ////////S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1
-        Uv8AAAAAAAAAAAAAAAAAAAAAAAAAAEu1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1
-        Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS////////////////////////////////////
-        //////////////////////////////////9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1
-        Uv9LtVL/S7VS/0u1Uv9LtVL/AAAAAAAAAAAAAAAAAAAAAAAAAABLtVL/S7VS/0u1Uv9LtVL/S7VS/0u1
-        Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS////////////////////
-        ////////////////////////////////////////////////////////0uOr/0u1Uv9LtVL/S7VS/0u1
-        Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/wAAAAAAAAAAAAAAAAAAAAAA/wABS7VS/0u1
-        Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS////
-        ////////////////////////////////////////////////////////////////////////V7lZ/0u1
-        Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv8AAAAAAAAAAAAA
-        AAAAAAAAAAAAAEu1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1
-        Uv9LtVL/S7VS/////////////////////////////////////////////////////////////////7Dd
-        rP9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1
-        Uv9LtVL/AAAAAAAAAAAAAAAAAAAAAAAAAABLtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1
-        Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS////////////////////////////////////////////////////
-        ////////S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1
-        Uv9LtVL/S7VS/0u1Uv9ItlMxAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAS7VS/0u1Uv9LtVL/S7VS/0u1
-        Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS////////////////////////////////////
-        /////////////0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1
-        Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0uzUiUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEu1
-        Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS////////////////////
-        //////////////////9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1
-        Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/SLZIBwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
-        AAAAAAAAAAAAAAD/AAFLtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS////
-        ////////////////////////+fff/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1
-        Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9ItkgHAAAAAAAAAAAAAAAAAAAAAAAA
-        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAS7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1
-        Uv9LtVL/S7VS//////////////////////9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1
-        Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/9S4ABIAAAAAAAAAAAAA
-        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEu1Uv9LtVL/S7VS/0u1
-        Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS////////////S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1
-        Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/1L8AGAAA
-        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
-        AABLtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/1q6Xf9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1
-        Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1
-        Uv/OtgAVAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
-        AAAAAAAAAAAAAAAAAABLtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1
-        Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1
-        Uv9LtVL/S7VS/8bGAAkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
-        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAEu1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1
-        Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1
-        Uv9LtVL/S7VS/0u1Uv9LtVL/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
-        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEu1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1
-        Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1
-        Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv/atgAOAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
-        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABLtVL/S7VS/0u1
-        Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1
-        Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/9K8ABcAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
-        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
-        AAAAAAAAS7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1
-        Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtFHOAAAAAEu1Uv9LtVL/0rwAFwAAAAAAAAAAAAAAAAAA
-        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
-        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAEu1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1
-        Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0q0UdQAAAAAAAAAAAAAAADatgAOAAAAAAAA
-        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
-        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABLtVL/S7VS/0u1Uv9LtVL/S7VS/0u1
-        Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/SrVS7AAAAAAAAAAAAAAAAAAA
-        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
-        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAS7VS/0u1
-        Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/AAAAAAAA
-        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
-        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
-        AAAAAAAAAAAAAEu1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0q0
-        UuIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
-        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
-        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABLtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1
-        Uv9LtVL/SrVS0AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
-        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
-        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAS7VS/0u1Uv9LtVL/S7VS/0u1
-        Uv9LtVL/S7VS/0u1Uv9KtVLQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
-        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
-        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEu1
-        Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0q0UuIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
-        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
-        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
-        AAAAAAAAAAAAAAAAAABLtVL/S7VS/0u1Uv9LtVL/S7VS/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
-        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
-        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
-        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAS7VS/0u1Uv9KtVLsAAAAAAAAAAAAAAAAAAAAAAAA
-        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
-        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
-        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEq0UdQAAAAAAAAAAAAA
-        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
-        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA////////AAD///+f//8AAP///w///wAA///+B///
-        AAD///wD//8AAP//+AH//wAA///wAP//AAD//+AAf/8AAP//wAA//wAA//+AAB//AAD/8wAAD/8AAP/g
-        AAAH/wAA/8AAAAP/AAD/gAAAA/8AAP8AAAAH/wAA/gAAAAP/AAD8AAAAAf8AAPgAAAAA/wAA8AAAAAB/
-        AADgAAAAAD8AAMAAAAAAHwAAgAAAAAAPAACAAAAAAAcAAMAAAAAAAwAA4AAAAAABAADwAAAAAAAAAPgA
-        AAAAAQAA/AAAAAADAAD+AAAAAAcAAP8AAAAADwAA/4AAAAAfAAD/wAAAAD8AAP/gAAAAfwAA/+AAAAD/
-        AAD/wAAAAf8AAP/AAAAD/wAA/+AAAAf/AAD/8AAAT/8AAP/4AAD//wAA//wAAf//AAD//gAD//8AAP//
-        AAf//wAA//+AD///AAD//8Af//8AAP//4D///wAA///wf///AAD///j///8AAP///f///wAAKAAAADAA
-        AABgAAAAAQAIAAAAAAAAEgAAAAAAAAAAAAAAAAAAAAAAAAAAAP9vtzz/cLc8/1+2Rv9RtU//S7VS/0y1
-        Uf9NtVH/TrVQ/0+1UP9NtlP/TbZU/062VP9Rt1f/VLla/1W5W/9WuVz/Y7ZD/2C2Rf9htkX/YrZE/2O2
-        RP9otkD/Yb5m/2S/aP9mv2j/aMBq/3jHef95x3z/e8h8/3zIfP9+yX//f8qD/4PMiP+R0ZL/ktGS/5TS
-        lP+V0pX/mdSY/6jaqP+s3Kv/r92t/7Ddrv/G5sL/xufF/8jnxv/L6cj/3fDb/9/x3f/g8d3/4/Pg/+/4
-        7f/x+e//8vnv//r8+P/7/fn//v/+/////v8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
-        AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
-        AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
-        AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
-        AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
-        AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
-        AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
-        AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
-        AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
-        AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
-        AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
-        AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
-        AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
-        AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAAAAAAAAAAAAAAAAAAAAAAAAAAA
-        AAAABQUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFBQUFAAAAAAAA
-        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAUFBQUFBQAAAAAAAAAAAAAAAAAAAAAA
-        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABQUFBQUFBQUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
-        AAAAAAAAAAAAAAUFBQUFBQUFBQUFAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAUF
-        BQUFBQUFBQUFBQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABQUFBQUFBQUFBQUFBQMA
-        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFBQUFBQUFBQUFBQUFBQYDAAAAAAAAAAAAAAAA
-        AAAAAAAAAAAAAAAAAAAAAAAAAAUFBQUFBQUFBQUFBQUFBQUGAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
-        AAAUEgAABQUFBQUFBQUFBQUFBQUFBQUFBgMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABUHBhIFBQUFBQUF
-        BQUFBQUFBQUFBQUFBQYDAAAAAAAAAAAAAAAAAAAAAAAAAAAAFQcFBQYFBQUFBQUFBQUFBQUFBQUFBQUF
-        BQUGAwAAAAAAAAAAAAAAAAAAAAAAAAAVBwUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBhIAAAAAAAAA
-        AAAAAAAAAAAAABUHBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFCBUAAAAAAAAAAAAAAAAAAAAAFQcF
-        BQUFBQUFBQUGBQUFBQUFBQUFBQUFBQUFBQUFEwAAAAAAAAAAAAAAAAAAAAAVBwUFBQUFBQUFBQUgKg8F
-        BQUFBQUFBQUFBQUFBQUFBQUAAAAAAAAAAAAAAAAAABUHBQUFBQUFBQUFBQUhOTUkDAUFBQUFBQUFBQUF
-        BQUFBQUFAAAAAAAAAAAAAAAAFQcFBQUFBQUFBQUFBQUhOTk5MR4FBQUFBQUFBQUFBQUFBQUFBQAAAAAA
-        AAAAAAASBwUFBQUFBQUFBQUFBQUhOTk5OTgsGAUFBQUFBQUFBQUFBQUFBQUAAAAAAAAAAAUFBQUFBQUF
-        BQUFBQUFBQUhOTk5OTk5NygOBQUFBQUFBQUFBQUFBQUFAAAAAAAABQUFBQUFBQUFBQUFBQUFBQUhOTk5
-        OTk5OTkzIwsFBQUFBQUFBQUFBQUFBQAAAAAFBQUFBQUFBQUFBQUFBQUFBQUhOTk5OTk5OTk5OS8bBQUF
-        BQUFBQUFBQUFBQUAAAAFBQUFBQUFBQUFBQUFBQUFBQUhOTk5OTk5OTk5OTk4KxcFBQUFBQUFBQUFBQUF
-        AAAABQUFBQUFBQUFBQUFBQUFBQUhOTk5OTk5OTk5OTk5OTYnDQUFBQUFBQUFBQUFBQAAAAUFBQUFBQUF
-        BQUFBQUFBQUhOTk5OTk5OTk5OTk5OTMiCwUFBQUFBQUFBQUFBQUAAAAFBQUFBQUFBQUFBQUFBQUhOTk5
-        OTk5OTk5OTk2KQ4FBQUFBQUFBQUFBQUFBQUAAAAABQUFBQUFBQUFBQUFBQUhOTk5OTk5OTk5OS0ZBQUF
-        BQUFBQUFBQUFBQUFBQUAAAAAAAUFBQUFBQUFBQUFBQUhOTk5OTk5OTkwHQUFBQUFBQUFBQUFBQUFBQUF
-        BQAAAAAAAAAFBQUFBQUFBQUFBQUhOTk5OTk5NCUKBQUFBQUFBQUFBQUFBQUFBQUFAAAAAAAAAAAABQUF
-        BQUFBQUFBQUhOTk5OTcpEAUFBQUFBQUFBQUFBQUFBQUFBQUAAAAAAAAAAAAAAAUFBQUFBQUFBQUhOTk5
-        LhoFBQUFBQUFBQUFBQUFBQUFBQUGAwAAAAAAAAAAAAAAAAAFBQUFBQUFBQUhOTIfBQUFBQUFBQUFBQUF
-        BQUFBQUFBQYDAAAAAAAAAAAAAAAAAAAABQUFBQUFBQUcJgsFBQUFBQUFBQUFBQUFBQUFBQUFBgMAAAAA
-        AAAAAAAAAAAAAAAAFgcFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUGAwAAAAAAAAAAAAAAAAAAAAAW
-        CQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQYDAAAAAAAAAAAAAAAAAAAAAAARBwUFBQUFBQUFBQUF
-        BQUFBQUFBQUFBQUFBQUFBgMAAAAAAAAAAAAAAAAAAAAAAAAAFQcFBQUFBQUFBQUFBQUFBQUFBQUFBQUH
-        BQUGAwAAAAAAAAAAAAAAAAAAAAAAAAAAABUHBQUFBQUFBQUFBQUFBQUFBQUFBQUBBAYDAAAAAAAAAAAA
-        AAAAAAAAAAAAAAAAAAAUBwUFBQUFBQUFBQUFBQUFBQUFBQUAAhQAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
-        AAAAFAcFBQUFBQUFBQUFBQUFBQUFBQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABQHBQUFBQUF
-        BQUFBQUFBQUFAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAVBwUFBQUFBQUFBQUFBQUAAAAA
-        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFQcFBQUFBQUFBQUFBQAAAAAAAAAAAAAAAAAAAAAA
-        AAAAAAAAAAAAAAAAAAAAAAAAABQHBQUFBQUFBQUFAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
-        AAAAAAAAAAAVBwUFBQUFBQUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFQcF
-        BQUFBQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABUHBQUFAAAAAAAAAAAA
-        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAVBwUAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
-        AAD///////8AAP///5///wAA////D///AAD///4H//8AAP///AP//wAA///4Af//AAD///AA//8AAP//
-        4AB//wAA///AAD//AAD//4AAH/8AAP/zAAAP/wAA/+AAAAf/AAD/wAAAA/8AAP+AAAAD/wAA/wAAAAf/
-        AAD+AAAAA/8AAPwAAAAB/wAA+AAAAAD/AADwAAAAAH8AAOAAAAAAPwAAwAAAAAAfAACAAAAAAA8AAIAA
-        AAAABwAAwAAAAAADAADgAAAAAAEAAPAAAAAAAAAA+AAAAAABAAD8AAAAAAMAAP4AAAAABwAA/wAAAAAP
-        AAD/gAAAAB8AAP/AAAAAPwAA/+AAAAB/AAD/4AAAAP8AAP/AAAAB/wAA/8AAAAP/AAD/4AAAB/8AAP/w
-        AABP/wAA//gAAP//AAD//AAB//8AAP/+AAP//wAA//8AB///AAD//4AP//8AAP//wB///wAA///gP///
-        AAD///B///8AAP//+P///wAA///9////AAAoAAAAIAAAAEAAAAABACAAAAAAAAAgAAAAAAAAAAAAAAAA
-        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
-        AAAAAAAAAAAAAAAAAABLtVL/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
-        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
-        AAAAAAAAAAAAAAAAAAAAAAAAS7VS/0u1Uv9LtVL/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
-        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
-        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAEu1Uv9LtVL/S7VS/0u1Uv9LtVL/AAAAAAAAAAAAAAAAAAAAAAAA
-        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
-        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABLtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/AAAAAAAA
-        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
-        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAS7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1
-        Uv9LtVL/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
-        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEu1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1
-        Uv9LtVL/S7VS/0u1Uv9LtVL/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
-        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABLtVL/AAAAAAAAAABLtVL/S7VS/0u1Uv9LtVL/S7VS/0u1
-        Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
-        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAS7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1
-        Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/AAAAAAAAAAAAAAAAAAAAAAAA
-        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEu1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1
-        Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/AAAAAAAA
-        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABLtFH+S7VS/0u1Uv9LtVL/S7VS/0u1
-        Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/wAA
-        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAS7VS/0u1Uv9LtVL/S7VS/0u1
-        Uv9LtVL/S7VS/0u1Uv/8/fz/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1
-        Uv9LtVL/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEu1Uv9LtVL/S7VS/0u1
-        Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS//z9/P///////////0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1
-        Uv9LtVL/S7VS/0u1Uv9LtVL/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABLtVH/S7VS/0u1
-        Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL//P38//////////////////////9LtVL/S7VS/0u1
-        Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAS7VS/0u1
-        Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv/8/fz/////////////////////////
-        ///q8dP/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/AAAAAAAAAAAAAAAAAAAAAEu1
-        Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS//z9/P//////////////
-        ////////////////////////S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/AAAAAAAA
-        AAAAAAAAAAAAAEu1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL//P38////
-        /////////////////////////////////////////////0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1
-        Uv9LtVL/AAAAAAAAAAAAAAAAAAAAAEu1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1
-        Uv/8/fz/////////////////////////////////////////////////S7VS/0u1Uv9LtVL/S7VS/0u1
-        Uv9LtVL/S7VS/0u1Uv9LtVL/AAAAAAAAAAAAAAAAAAAAAEu1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1
-        Uv9LtVL/S7VS//z9/P//////////////////////////////////////S7VS/0u1Uv9LtVL/S7VS/0u1
-        Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/AAAAAAAAAAAAAAAAAAAAAEu1Uv9LtVL/S7VS/0u1
-        Uv9LtVL/S7VS/0u1Uv9LtVL//P38////////////////////////////mspu/0u1Uv9LtVL/S7VS/0u1
-        Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEu1
-        Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv/8/fz//////////////////v7+/0u1Uv9LtVL/S7VS/0u1
-        Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv8AAAAAAAAAAAAAAAAAAAAAAAAAAAAA
-        AAAAAAAAAAAAAEu1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS//z9/P///////////0u1Uv9LtVL/S7VS/0u1
-        Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/AAAAAAAAAAAAAAAAAAAAAAAA
-        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAEu1Uv9LtVL/S7VS/0u1Uv9LtVL//P38/0u1Uv9LtVL/S7VS/0u1
-        Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/wAAAAAAAAAAAAAAAAAA
-        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAS7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1
-        Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv8AAAAAAAAAAAAA
-        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEu1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1
-        Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/AAAAAAAA
-        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEu1Uv9LtVL/S7VS/0u1
-        Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/wAA
-        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEu1
-        Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv8AAAAAAAAAAEu1
-        Uv8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
-        AAAAAAAAAAAAAEu0Uf5LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/AAAAAAAA
-        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
-        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAEu1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/wAA
-        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
-        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEu1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1
-        Uv8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
-        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEu1Uf9LtVL/S7VS/0u1
-        Uv9LtVL/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
-        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEu1
-        Uv9LtVL/S7VS/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
-        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
-        AAAAAAAAAAAAAEu1Uv8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
-        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAP//v////x////4P///8B///+AP///AB//9gAP/+AAB//AAAP/gA
-        AH/wAAB/4AAAP8AAAB+AAAAPAAAAB4AAAAPAAAAB4AAAAPAAAAH4AAAD/AAAB/4AAA/+AAAf/AAAP/4A
-        AH//AAb//4AP///AH///4D////B////4/////f//KAAAACAAAABAAAAAAQAIAAAAAAAACAAAAAAAAAAA
-        AAAAAAAAAAAAAAAAAP95tzb/erc2/3u3Nf9wtzz/VrZL/1C1T/9RtU7/UrVO/1O1Tf9VtUz/VbZM/0u1
-        Uv9NtVH/TrVQ/0+1UP9NtlT/ULdW/1a5W/9gtkb/Y7ZE/2i2QP9bu2D/Zb9p/2vCb/9vw3L/d8d6/33J
-        fv+NuCr/jrgq/4+4Kf+SuSf/k7kn/5C5Kf+SuSj/hcyG/4fNif+U0pX/l9OY/5bUmf+e15//n9eh/63d
-        rv+s3bD/uOG5/8jox//Q68//0+zS/97x3f/h8t//5vTl//D47//1+/T/+/36//3+/f//////AAAA/wAA
-        AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
-        AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
-        AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
-        AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
-        AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
-        AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
-        AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
-        AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
-        AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
-        AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
-        AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
-        AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
-        AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
-        AP8AAAD/AAAA/wAAAP8AAAAAAAAAAAAAAAAAAAAADAwMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
-        AAwMDAwMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMDAwMDAwMAAAAAAAAAAAAAAAAAAAAAAAAAAAA
-        AAAADAwMDAwMDAwMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwMDAwMDAwMDAYCAAAAAAAAAAAAAAAAAAAA
-        AAAAAAAMDAwMDAwMDAwMDAcBAAAAAAAAAAAAAAAAAAAAIAsTDAwMDAwMDAwMDAwMDAcDAAAAAAAAAAAA
-        AAAAACAJDA4MDAwMDAwMDAwMDAwMDAcDAAAAAAAAAAAAAAAdCQwMDAwMDAwMDAwMDAwMDAwMDAoAAAAA
-        AAAAAAAAHgkMDAwMDAwMDAwMDAwMDAwMDAwNFAAAAAAAAAAAACAJDAwMDAwMDCkmEAwMDAwMDAwMDAwM
-        AAAAAAAAAAAhCQwMDAwMDAwMKzcxGwwMDAwMDAwMDAwMAAAAAAAADAcMDAwMDAwMDAwrNzc3LRcMDAwM
-        DAwMDAwMAAAAAAwMDAwMDAwMDAwMDCs3Nzc3NSoSDAwMDAwMDAwMAAAADAwMDAwMDAwMDAwMKzc3Nzc3
-        NzMlEAwMDAwMDAwMAAAMDAwMDAwMDAwMDAwrNzc3Nzc3NzcwGgwMDAwMDAwMAAAMDAwMDAwMDAwMDCs3
-        Nzc3Nzc3Ny4YDAwMDAwMDAwMAAAMDAwMDAwMDAwMKzc3Nzc3NzIjDAwMDAwMDAwMDAwAAAAMDAwMDAwM
-        DAwrNzc3NzQoEQwMDAwMDAwMDAwMDAAAAAAMDAwMDAwMDCs3NzYsFgwMDAwMDAwMDAwMDAwAAAAAAAAM
-        DAwMDAwMKzcvGQwMDAwMDAwMDAwMDAcCAAAAAAAAAAAMDAwMDAwnJAwMDAwMDAwMDAwMDAwHAwAAAAAA
-        AAAAABUPDAwMDAwMDAwMDAwMDAwMDAwMBwIAAAAAAAAAAAAABQwMDAwMDAwMDAwMDAwMDAwMDAcBAAAA
-        AAAAAAAAAAAfCQwMDAwMDAwMDAwMDAwMDwwHAgAAAAAAAAAAAAAAAAAfCQwMDAwMDAwMDAwMDAwEBQIA
-        AAAAAAAAAAAAAAAAAAAcCQwMDAwMDAwMDAwMAAAAAAAAAAAAAAAAAAAAAAAAAAAeCQwMDAwMDAwMDAAA
-        AAAAAAAAAAAAAAAAAAAAAAAAAAAgCQwMDAwMDAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeCQwMDAwM
-        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAdCQwMDAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAi
-        CAwAAAAAAAAAAAAAAAAAAAAA//+/////H////g////wH///4A///8AH//2AA//4AAH/8AAA/+AAAf/AA
-        AH/gAAA/wAAAH4AAAA8AAAAHgAAAA8AAAAHgAAAA8AAAAfgAAAP8AAAH/gAAD/4AAB/8AAA//gAAf/8A
-        Bv//gA///8Af///gP///8H////j////9//8oAAAAGAAAADAAAAABACAAAAAAAAASAAAAAAAAAAAAAAAA
-        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAASrRSQUm1
-        Ty0AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
-        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABJtU8tS7VS/0u1Uv8AAAAAAAAAAAAAAAAAAAAAAAAAAAAA
-        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEuz
-        UVFLtVL/S7VS/0u1Uv9LtVL/SbVPLQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
-        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAASbVPLUu1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/8+/
-        ABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
-        AABKtFJBS7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv/UqgAGAAAAAAAAAAAAAAAAAAAAAAAA
-        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAS7VS/2S1QV5LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1
-        Uv9LtVL/S7VS/0u1Uv9LtVL/1L8AGAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
-        AABLtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/wAA
-        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEu1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1
-        Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
-        AAAAAAAAS7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL///////////9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1
-        Uv9LtVL/S7VS/0u1Uv8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABLtVL/S7VS/0u1Uv9LtVL/S7VS/0u1
-        Uv9LtVL//////////////////////0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/AAAAAAAA
-        AAAAAAAAAAAAAEu1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/////////////////////////
-        ///29+b/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/wAAAAAAAAAAAAAAAEu1Uv9LtVL/S7VS/0u1
-        Uv9LtVL/S7VS/0u1Uv9LtVL//////////////////////////////////////0u1Uv9LtVL/S7VS/0u1
-        Uv9LtVL/S7VS/0u1Uv8AAAAAAAAAAAAAAABLtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/////////
-        /////////////////////////////0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/AAAAAAAA
-        AAAAAAAAS7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL///////////////////////////+l1ZP/S7VS/0u1
-        Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9JtU8tAAAAAAAAAAAAAAAAAAAAAEu1Uv9LtVL/S7VS/0u1
-        Uv9LtVL//////////////////////0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/wAA
-        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABLtVL/S7VS/0u1Uv9LtVL///////////9LtVL/S7VS/0u1
-        Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/0LkAFgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
-        AAAAAAAAS7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1
-        Uv/PvwAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABLtVL/S7VS/0u1Uv9LtVL/S7VS/0u1
-        Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/9SqAAYAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
-        AAAAAAAAAAAAAAAAAAAAAAAAS7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u0
-        UtJLtVL/1L8AGAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEu1
-        Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/SrVR3gAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
-        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABLtVL/S7VS/0u1Uv9LtVL/S7VS/0u1
-        Uv9KtVLyAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
-        AAAAAAAAAAAAAAAAAAAAAAAAS7VS/0u1Uv9LtVL/S7VS/0u0Uc4AAAAAAAAAAAAAAAAAAAAAAAAAAAAA
-        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEu1
-        Uv9LtVL/SrVS8gAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
-        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABKtVHeAAAAAAAAAAAAAAAAAAAAAAAA
-        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA////AP/z/wD/4f8A/8D/AP+AfwD9AD8A+AAfAPAA
-        HwDgAA8AwAAHAIAAAwCAAAEAwAAAAOAAAQDwAAMA+AAHAPwADwD4AB8A/AA/AP4A/wD/Af8A/4P/AP/H
-        /wD/7/8AKAAAABgAAAAwAAAAAQAIAAAAAACABAAAAAAAAAAAAAAAAAAAAAAAAAAAAP9UtUz/VbZM/0u1
-        Uv9MtVH/TbVR/061UP9PtVD/TLZT/062VP9SuFj/Vrlc/2W2Qv9htkX/Xr1j/2XAav9qwW7/ccR1/3LF
-        dv99yYD/iM6L/5PSlv+j2aX/r92w/73kvv/B5sP/yejJ/9ju1//h8uD/6vbp//H58P/3/Pb/+/36//7+
-        /v//////AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
-        AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
-        AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
-        AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
-        AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
-        AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
-        AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
-        AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
-        AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
-        AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
-        AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
-        AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
-        AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
-        AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
-        AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAAAAAAAAAAA
-        AAADAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAMDAwMAAAAAAAAAAAAAAAAAAAAAAAAAAwMDAwMDAAAAAAAA
-        AAAAAAAAAAAAAAADAwMDAwMDAQAAAAAAAAAAAAAAAAANAAMDAwMDAwMDAwEAAAAAAAAAAAAAAAIEBgMD
-        AwMDAwMDAwMBAAAAAAAAAAAAAgQDAwMDAwMDAwMDAwMEDQAAAAAAAAACBAMDAwMRCQMDAwMDAwMFAwAA
-        AAAAAAIEAwMDAwMZHBMDAwMDAwMDAwMAAAAABwQDAwMDAwMZIiIaDwMDAwMDAwMDAAADAwMDAwMDAwMZ
-        IiIiIBcLAwMDAwMDAwADAwMDAwMDAwMZIiIiIiIeFQgDAwMDAwMAAwMDAwMDAwMZIiIiIiIdFAMDAwMD
-        AwMAAAMDAwMDAwMZIiIiHxYKAwMDAwMDAwMAAAADAwMDAwMZIiEYDgMDAwMDAwMDAwAAAAAAAwMDAwMZ
-        GxIDAwMDAwMDAwMBAAAAAAAAAAYDAwMQBAMDAwMDAwMDAwEAAAAAAAAADAUDAwMDAwMDAwMDAwMDAQAA
-        AAAAAAAAAAIEAwMDAwMDAwMDBQUBAAAAAAAAAAAAAAACBAMDAwMDAwMDAwwAAAAAAAAAAAAAAAAAAgQD
-        AwMDAwMDAAAAAAAAAAAAAAAAAAAAAAIEAwMDAwMAAAAAAAAAAAAAAAAAAAAAAAACBAMDAwAAAAAAAAAA
-        AAAAAAAAAAAAAAAAAgQDAAAAAAAAAAAAAAD///8A//P/AP/h/wD/wP8A/4B/AP0APwD4AB8A8AAfAOAA
-        DwDAAAcAgAADAIAAAQDAAAAA4AABAPAAAwD4AAcA/AAPAPgAHwD8AD8A/gD/AP8B/wD/g/8A/8f/AP/v
-        /wAoAAAAEAAAACAAAAABACAAAAAAAAAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
-        AAAAAAAAAAAAAAAAAABLtVL/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
-        AAAAAAAAAAAAAAAAAABLtVL/S7VS/0u1Uv8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
-        AAAAAAAAAAAAAAAAAABLtVL/S7VS/0u1Uv9LtVL/S7VS/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
-        AAAAAAAAAAAAAEu1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/AAAAAAAAAAAAAAAAAAAAAAAA
-        AAAAAAAAAAAAAEu1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv8AAAAAAAAAAAAA
-        AAAAAAAAAAAAAEu1Uv9LtVL/S7VS/0u1Uv//////S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/AAAAAAAA
-        AAAAAAAAAAAAAEu1Uv9LtVL/S7VS/0u1Uv9LtVL/////////////////S7VS/0u1Uv9LtVL/S7VS/0u1
-        Uv8AAAAAAAAAAEu1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS////////////////////////////S7VS/0u1
-        Uv9LtVL/S7VS/wAAAAAAAAAAS7VS/0u1Uv9LtVL/S7VS/0u1Uv//////////////////////sN2s/0u1
-        Uv9LtVL/S7VS/0u1Uv9LtVL/AAAAAAAAAABLtVL/S7VS/0u1Uv9LtVL/////////////////S7VS/0u1
-        Uv9LtVL/S7VS/0u1Uv9LtVL/AAAAAAAAAAAAAAAAAAAAAEu1Uv9LtVL/S7VS//////9LtVL/S7VS/0u1
-        Uv9LtVL/S7VS/0u1Uv9LtVL/AAAAAAAAAAAAAAAAAAAAAAAAAABLtVL/S7VS/0u1Uv9LtVL/S7VS/0u1
-        Uv9LtVL/S7VS/0u1Uv9LtVL/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEu1Uv9LtVL/S7VS/0u1
-        Uv9LtVL/S7VS/0u1Uv9LtVL/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAS7VS/0u1
-        Uv9LtVL/S7VS/0u1Uv8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
-        AABLtVL/S7VS/0u1Uv8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
-        AAAAAAAAAAAAAEu1Uv8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP9/AAD+PwAA/B8AAPAP
-        AADgBwAAwAcAAIADAAAAAQAAgAAAAMABAADgAwAA4AcAAPAPAAD4PwAA/H8AAP7/AAAoAAAAEAAAACAA
-        AAABAAgAAAAAAAACAAAAAAAAAAAAAAAAAAAAAAAAAAAA/0+1T/9QtU//VLVM/1W2TP9LtVL/TLVR/021
-        Uf9PtVD/U7hZ/1a5XP9hvmb/ZsBr/3bGev99yYH/qNuq/6/esf+y37T/uOK6/8Lmw//K6cr/1u7X//n8
-        +f/7/fv////+/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
-        AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
-        AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
-        AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
-        AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
-        AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
-        AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
-        AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
-        AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
-        AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
-        AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
-        AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
-        AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
-        AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
-        AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
-        AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAAAAAAAFBQUAAAAAAAAAAAAAAAAFBQUF
-        BQAAAAAAAAAAAAAFBQUFBQYDAAAAAAAAAAQBBQUFBQUFBgMAAAAAAAQGBQUFBQUFBQUIAAAAAAQGBQUF
-        Eg4FBQUFBQUAAAUGBQUFBRUYFAwFBQUFBQAFBQUFBQUVGBgXEAoFBQUFBQUFBQUFFRgYFg8JBQUFBQAF
-        BQUFBRUYEwsFBQUFBQUAAAUFBQURDQUFBQUFBgMAAAAAAgUFBQUFBQUFBgMAAAAAAAQGBQUFBQUFAQMA
-        AAAAAAAABAYFBQUFBQAAAAAAAAAAAAAEBgUFBQAAAAAAAAAAAAAAAAQHBQAAAAAAAAD/fwAA/j8AAPwf
-        AADwDwAA4AcAAMAHAACAAwAAAAEAAIAAAADAAQAA4AMAAOAHAADwDwAA+D8AAPx/AAD+/wAA
-</value>
-  </data>
-</root>

+ 3 - 34
MediaBrowser.ServerApplication/MainStartup.cs

@@ -53,31 +53,10 @@ namespace MediaBrowser.ServerApplication
 
         private static IFileSystem FileSystem;
 
-        public static bool TryGetLocalFromUncDirectory(string local, out string unc)
-        {
-            if ((local == null) || (local == ""))
-            {
-                unc = "";
-                throw new ArgumentNullException("local");
-            }
-
-            ManagementObjectSearcher searcher = new ManagementObjectSearcher("SELECT Name FROM Win32_share WHERE path ='" + local.Replace("\\", "\\\\") + "'");
-            ManagementObjectCollection coll = searcher.Get();
-            if (coll.Count == 1)
-            {
-                foreach (ManagementObject share in searcher.Get())
-                {
-                    unc = share["Name"] as String;
-                    unc = "\\\\" + SystemInformation.ComputerName + "\\" + unc;
-                    return true;
-                }
-            }
-            unc = "";
-            return false;
-        }
         /// <summary>
         /// Defines the entry point of the application.
         /// </summary>
+        [STAThread]
         public static void Main()
         {
             var options = new StartupOptions(Environment.GetCommandLineArgs());
@@ -321,8 +300,6 @@ namespace MediaBrowser.ServerApplication
             }
         }
 
-        private static readonly TaskCompletionSource<bool> ApplicationTaskCompletionSource = new TaskCompletionSource<bool>();
-
         /// <summary>
         /// Runs the application.
         /// </summary>
@@ -394,9 +371,6 @@ namespace MediaBrowser.ServerApplication
                 HideSplashScreen();
 
                 ShowTrayIcon();
-
-                task = ApplicationTaskCompletionSource.Task;
-                Task.WaitAll(task);
             }
         }
 
@@ -487,7 +461,6 @@ namespace MediaBrowser.ServerApplication
         /// <param name="e">The <see cref="EventArgs"/> instance containing the event data.</param>
         static void service_Disposed(object sender, EventArgs e)
         {
-            ApplicationTaskCompletionSource.SetResult(true);
             OnServiceShutdown();
         }
 
@@ -706,14 +679,10 @@ namespace MediaBrowser.ServerApplication
                 _serverNotifyIcon = null;
             }
 
-            //_logger.Info("Calling Application.Exit");
+            _logger.Info("Calling Application.Exit");
             //Application.Exit();
-
-            _logger.Info("Calling Environment.Exit");
+            
             Environment.Exit(0);
-
-            _logger.Info("Calling ApplicationTaskCompletionSource.SetResult");
-            ApplicationTaskCompletionSource.SetResult(true);
         }
 
         private static void ShutdownWindowsService()

+ 1 - 10
MediaBrowser.ServerApplication/MediaBrowser.ServerApplication.csproj

@@ -130,12 +130,6 @@
       <SubType>Component</SubType>
     </Compile>
     <Compile Include="ImageEncoderHelper.cs" />
-    <Compile Include="MainForm.cs">
-      <SubType>Form</SubType>
-    </Compile>
-    <Compile Include="MainForm.Designer.cs">
-      <DependentUpon>MainForm.cs</DependentUpon>
-    </Compile>
     <Compile Include="MainStartup.cs" />
     <Compile Include="Native\LoopUtil.cs" />
     <Compile Include="Native\PowerManagement.cs" />
@@ -167,9 +161,6 @@
     <None Include="packages.config" />
   </ItemGroup>
   <ItemGroup>
-    <EmbeddedResource Include="MainForm.resx">
-      <DependentUpon>MainForm.cs</DependentUpon>
-    </EmbeddedResource>
     <EmbeddedResource Include="Properties\Resources.resx">
       <Generator>ResXFileCodeGenerator</Generator>
       <LastGenOutput>Resources.Designer.cs</LastGenOutput>
@@ -197,7 +188,7 @@
     <Content Include="x64\sqlite3.dll">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
-    <Content Include="Icon.ico" />
+    <EmbeddedResource Include="Icon.ico" />
     <Content Include="Resources\Images\mb3logo800.png" />
     <Content Include="x86\libSkiaSharp.dll">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>

+ 1 - 2
MediaBrowser.ServerApplication/ServerNotifyIcon.cs

@@ -45,7 +45,6 @@ namespace MediaBrowser.ServerApplication
 
             components = new System.ComponentModel.Container();
 
-            var resources = new System.ComponentModel.ComponentResourceManager(typeof(MainForm));
             contextMenuStrip1 = new ContextMenuStrip(components);
             notifyIcon1 = new NotifyIcon(components);
 
@@ -62,7 +61,7 @@ namespace MediaBrowser.ServerApplication
             // notifyIcon1
             // 
             notifyIcon1.ContextMenuStrip = contextMenuStrip1;
-            notifyIcon1.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon")));
+            notifyIcon1.Icon = new System.Drawing.Icon(GetType().Assembly.GetManifestResourceStream(GetType().Namespace + ".Icon.ico"));
             notifyIcon1.Text = "Emby";
             notifyIcon1.Visible = true;
             // 

+ 107 - 82
Mono.Nat/NatUtility.cs

@@ -41,26 +41,25 @@ using MediaBrowser.Model.Logging;
 
 namespace Mono.Nat
 {
-	public static class NatUtility
-	{
-        private static ManualResetEvent searching;
-		public static event EventHandler<DeviceEventArgs> DeviceFound;
-		public static event EventHandler<DeviceEventArgs> DeviceLost;
-        
-		private static List<ISearcher> controllers;
-		private static bool verbose;
+    public static class NatUtility
+    {
+        public static event EventHandler<DeviceEventArgs> DeviceFound;
+        public static event EventHandler<DeviceEventArgs> DeviceLost;
+
+        private static List<ISearcher> controllers;
+        private static bool verbose;
 
         public static List<NatProtocol> EnabledProtocols { get; set; }
 
-	    public static ILogger Logger { get; set; }
+        public static ILogger Logger { get; set; }
         public static IHttpClient HttpClient { get; set; }
 
         public static bool Verbose
-		{
-			get { return verbose; }
-			set { verbose = value; }
-		}
-		
+        {
+            get { return verbose; }
+            set { verbose = value; }
+        }
+
         static NatUtility()
         {
             EnabledProtocols = new List<NatProtocol>
@@ -68,8 +67,6 @@ namespace Mono.Nat
                 NatProtocol.Pmp
             };
 
-            searching = new ManualResetEvent(false);
-
             controllers = new List<ISearcher>();
             controllers.Add(PmpSearcher.Instance);
 
@@ -86,23 +83,19 @@ namespace Mono.Nat
                             DeviceLost(sender, args);
                     };
                 });
-
-            Task.Factory.StartNew(SearchAndListen, TaskCreationOptions.LongRunning);
         }
 
-		internal static void Log(string format, params object[] args)
-		{
-			var logger = Logger;
-		    if (logger != null)
-		        logger.Debug(format, args);
-		}
+        internal static void Log(string format, params object[] args)
+        {
+            var logger = Logger;
+            if (logger != null)
+                logger.Debug(format, args);
+        }
 
-        private static async Task SearchAndListen()
+        private static async Task SearchAndListen(CancellationToken cancellationToken)
         {
-            while (true)
+            while (!cancellationToken.IsCancellationRequested)
             {
-                searching.WaitOne();
-
                 try
                 {
                     var enabledProtocols = EnabledProtocols.ToList();
@@ -123,67 +116,99 @@ namespace Mono.Nat
                 }
                 catch (Exception e)
                 {
-                    
+
                 }
                 await Task.Delay(100).ConfigureAwait(false);
             }
-		}
-
-		static async Task Receive (ISearcher searcher, List<UdpClient> clients)
-		{
-			foreach (UdpClient client in clients)
-			{
-				if (client.Available > 0)
-				{
-				    IPAddress localAddress = ((IPEndPoint)client.Client.LocalEndPoint).Address;
-				    var result = await client.ReceiveAsync().ConfigureAwait(false);
-				    var data = result.Buffer;
-				    var received = result.RemoteEndPoint;
-					searcher.Handle(localAddress, data, received);
-				}
+        }
+
+        static async Task Receive(ISearcher searcher, List<UdpClient> clients)
+        {
+            foreach (UdpClient client in clients)
+            {
+                if (client.Available > 0)
+                {
+                    IPAddress localAddress = ((IPEndPoint)client.Client.LocalEndPoint).Address;
+                    var result = await client.ReceiveAsync().ConfigureAwait(false);
+                    var data = result.Buffer;
+                    var received = result.RemoteEndPoint;
+                    searcher.Handle(localAddress, data, received);
+                }
+            }
+        }
+
+        private static CancellationTokenSource _currentCancellationTokenSource;
+        private static object _runSyncLock = new object();
+        public static void StartDiscovery()
+        {
+            lock (_runSyncLock)
+            {
+                if (_currentCancellationTokenSource == null)
+                {
+                    return;
+                }
+
+                var tokenSource = new CancellationTokenSource();
+
+                _currentCancellationTokenSource = tokenSource;
+                //Task.Factory.StartNew(() => SearchAndListen(tokenSource.Token), tokenSource.Token, TaskCreationOptions.LongRunning, TaskScheduler.Default);
             }
         }
-		
-		public static void StartDiscovery ()
-		{
-            searching.Set();
-		}
-
-		public static void StopDiscovery ()
-		{
-            searching.Reset();
-		}
-		
-		//checks if an IP address is a private address space as defined by RFC 1918
-		public static bool IsPrivateAddressSpace (IPAddress address)
-		{
-			byte[] ba = address.GetAddressBytes ();
-
-			switch ((int)ba[0]) {
-			case 10:
-				return true; //10.x.x.x
-			case 172:
-				return ((int)ba[1] & 16) != 0; //172.16-31.x.x
-			case 192:
-				return (int)ba[1] == 168; //192.168.x.x
-			default:
-				return false;
-			}
-		}
-
-	    public static void Handle(IPAddress localAddress, byte[] response, IPEndPoint endpoint, NatProtocol protocol)
-	    {
-	        switch (protocol)
-	        {
+
+        public static void StopDiscovery()
+        {
+            lock (_runSyncLock)
+            {
+                var tokenSource = _currentCancellationTokenSource;
+
+                if (tokenSource != null)
+                {
+                    try
+                    {
+                        tokenSource.Cancel();
+                        tokenSource.Dispose();
+                    }
+                    catch
+                    {
+
+                    }
+
+                    _currentCancellationTokenSource = null;
+                }
+            }
+        }
+
+        //checks if an IP address is a private address space as defined by RFC 1918
+        public static bool IsPrivateAddressSpace(IPAddress address)
+        {
+            byte[] ba = address.GetAddressBytes();
+
+            switch ((int)ba[0])
+            {
+                case 10:
+                    return true; //10.x.x.x
+                case 172:
+                    return ((int)ba[1] & 16) != 0; //172.16-31.x.x
+                case 192:
+                    return (int)ba[1] == 168; //192.168.x.x
+                default:
+                    return false;
+            }
+        }
+
+        public static void Handle(IPAddress localAddress, byte[] response, IPEndPoint endpoint, NatProtocol protocol)
+        {
+            switch (protocol)
+            {
                 case NatProtocol.Upnp:
-	                //UpnpSearcher.Instance.Handle(localAddress, response, endpoint);
-	                break;
+                    //UpnpSearcher.Instance.Handle(localAddress, response, endpoint);
+                    break;
                 case NatProtocol.Pmp:
-	                PmpSearcher.Instance.Handle(localAddress, response, endpoint);
-	                break;
-	            default:
-	                throw new ArgumentException("Unexpected protocol: " + protocol);
-	        }
+                    PmpSearcher.Instance.Handle(localAddress, response, endpoint);
+                    break;
+                default:
+                    throw new ArgumentException("Unexpected protocol: " + protocol);
+            }
         }
 
         public static void Handle(IPAddress localAddress, UpnpDeviceInfo deviceInfo, IPEndPoint endpoint, NatProtocol protocol)

+ 1 - 1
SharedVersion.cs

@@ -1,3 +1,3 @@
 using System.Reflection;
 
-[assembly: AssemblyVersion("3.2.20.11")]
+[assembly: AssemblyVersion("3.2.20.12")]