|  | @@ -307,7 +307,17 @@ namespace MediaBrowser.Controller.Entities
 | 
	
		
			
				|  |  |          /// <param name="recursive">if set to <c>true</c> [recursive].</param>
 | 
	
		
			
				|  |  |          /// <param name="forceRefreshMetadata">if set to <c>true</c> [force refresh metadata].</param>
 | 
	
		
			
				|  |  |          /// <returns>Task.</returns>
 | 
	
		
			
				|  |  | -        public async Task ValidateChildren(IProgress<double> progress, CancellationToken cancellationToken, bool? recursive = null, bool forceRefreshMetadata = false)
 | 
	
		
			
				|  |  | +        public Task ValidateChildren(IProgress<double> progress, CancellationToken cancellationToken, bool? recursive = null, bool forceRefreshMetadata = false)
 | 
	
		
			
				|  |  | +        {
 | 
	
		
			
				|  |  | +            return ValidateChildrenWithCancellationSupport(progress, cancellationToken, recursive ?? true, true,
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +                new MetadataRefreshOptions
 | 
	
		
			
				|  |  | +                {
 | 
	
		
			
				|  |  | +                    ReplaceAllMetadata = forceRefreshMetadata
 | 
	
		
			
				|  |  | +                });
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        private async Task ValidateChildrenWithCancellationSupport(IProgress<double> progress, CancellationToken cancellationToken, bool recursive, bool refreshChildMetadata, MetadataRefreshOptions refreshOptions)
 | 
	
		
			
				|  |  |          {
 | 
	
		
			
				|  |  |              cancellationToken.ThrowIfCancellationRequested();
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -327,7 +337,7 @@ namespace MediaBrowser.Controller.Entities
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |                  var linkedCancellationTokenSource = CancellationTokenSource.CreateLinkedTokenSource(innerCancellationTokenSource.Token, cancellationToken);
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -                await ValidateChildrenInternal(progress, linkedCancellationTokenSource.Token, recursive, forceRefreshMetadata).ConfigureAwait(false);
 | 
	
		
			
				|  |  | +                await ValidateChildrenInternal(progress, linkedCancellationTokenSource.Token, recursive, refreshChildMetadata, refreshOptions).ConfigureAwait(false);
 | 
	
		
			
				|  |  |              }
 | 
	
		
			
				|  |  |              catch (OperationCanceledException ex)
 | 
	
		
			
				|  |  |              {
 | 
	
	
		
			
				|  | @@ -352,15 +362,15 @@ namespace MediaBrowser.Controller.Entities
 | 
	
		
			
				|  |  |          }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |          /// <summary>
 | 
	
		
			
				|  |  | -        /// Compare our current children (presumably just read from the repo) with the current state of the file system and adjust for any changes
 | 
	
		
			
				|  |  | -        /// ***Currently does not contain logic to maintain items that are unavailable in the file system***
 | 
	
		
			
				|  |  | +        /// Validates the children internal.
 | 
	
		
			
				|  |  |          /// </summary>
 | 
	
		
			
				|  |  |          /// <param name="progress">The progress.</param>
 | 
	
		
			
				|  |  |          /// <param name="cancellationToken">The cancellation token.</param>
 | 
	
		
			
				|  |  |          /// <param name="recursive">if set to <c>true</c> [recursive].</param>
 | 
	
		
			
				|  |  | -        /// <param name="forceRefreshMetadata">if set to <c>true</c> [force refresh metadata].</param>
 | 
	
		
			
				|  |  | +        /// <param name="refreshChildMetadata">if set to <c>true</c> [refresh child metadata].</param>
 | 
	
		
			
				|  |  | +        /// <param name="refreshOptions">The refresh options.</param>
 | 
	
		
			
				|  |  |          /// <returns>Task.</returns>
 | 
	
		
			
				|  |  | -        protected async virtual Task ValidateChildrenInternal(IProgress<double> progress, CancellationToken cancellationToken, bool? recursive = null, bool forceRefreshMetadata = false)
 | 
	
		
			
				|  |  | +        protected async virtual Task ValidateChildrenInternal(IProgress<double> progress, CancellationToken cancellationToken, bool recursive, bool refreshChildMetadata, MetadataRefreshOptions refreshOptions)
 | 
	
		
			
				|  |  |          {
 | 
	
		
			
				|  |  |              var locationType = LocationType;
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -401,33 +411,23 @@ namespace MediaBrowser.Controller.Entities
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |                      if (currentChildren.TryGetValue(child.Id, out currentChild))
 | 
	
		
			
				|  |  |                      {
 | 
	
		
			
				|  |  | -                        //existing item - check if it has changed
 | 
	
		
			
				|  |  | -                        if (currentChild.HasChanged(child))
 | 
	
		
			
				|  |  | +                        var currentChildLocationType = currentChild.LocationType;
 | 
	
		
			
				|  |  | +                        if (currentChildLocationType != LocationType.Remote &&
 | 
	
		
			
				|  |  | +                            currentChildLocationType != LocationType.Virtual)
 | 
	
		
			
				|  |  |                          {
 | 
	
		
			
				|  |  | -                            var currentChildLocationType = currentChild.LocationType;
 | 
	
		
			
				|  |  | -                            if (currentChildLocationType != LocationType.Remote &&
 | 
	
		
			
				|  |  | -                                currentChildLocationType != LocationType.Virtual)
 | 
	
		
			
				|  |  | -                            {
 | 
	
		
			
				|  |  | -                                currentChild.DateModified = child.DateModified;
 | 
	
		
			
				|  |  | -                            }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -                            currentChild.IsInMixedFolder = child.IsInMixedFolder;
 | 
	
		
			
				|  |  | -                            validChildren.Add(currentChild);
 | 
	
		
			
				|  |  | -                        }
 | 
	
		
			
				|  |  | -                        else
 | 
	
		
			
				|  |  | -                        {
 | 
	
		
			
				|  |  | -                            validChildren.Add(currentChild);
 | 
	
		
			
				|  |  | +                            currentChild.DateModified = child.DateModified;
 | 
	
		
			
				|  |  |                          }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +                        currentChild.IsInMixedFolder = child.IsInMixedFolder;
 | 
	
		
			
				|  |  |                          currentChild.IsOffline = false;
 | 
	
		
			
				|  |  |                      }
 | 
	
		
			
				|  |  |                      else
 | 
	
		
			
				|  |  |                      {
 | 
	
		
			
				|  |  |                          //brand new item - needs to be added
 | 
	
		
			
				|  |  |                          newItems.Add(child);
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -                        validChildren.Add(child);
 | 
	
		
			
				|  |  |                      }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +                    validChildren.Add(currentChild);
 | 
	
		
			
				|  |  |                  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |                  // If any items were added or removed....
 | 
	
	
		
			
				|  | @@ -435,7 +435,6 @@ namespace MediaBrowser.Controller.Entities
 | 
	
		
			
				|  |  |                  {
 | 
	
		
			
				|  |  |                      // That's all the new and changed ones - now see if there are any that are missing
 | 
	
		
			
				|  |  |                      var itemsRemoved = currentChildren.Values.Except(validChildren).ToList();
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  |                      var actualRemovals = new List<BaseItem>();
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |                      foreach (var item in itemsRemoved)
 | 
	
	
		
			
				|  | @@ -450,7 +449,6 @@ namespace MediaBrowser.Controller.Entities
 | 
	
		
			
				|  |  |                          else if (!string.IsNullOrEmpty(item.Path) && IsPathOffline(item.Path))
 | 
	
		
			
				|  |  |                          {
 | 
	
		
			
				|  |  |                              item.IsOffline = true;
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  |                              validChildren.Add(item);
 | 
	
		
			
				|  |  |                          }
 | 
	
		
			
				|  |  |                          else
 | 
	
	
		
			
				|  | @@ -486,78 +484,135 @@ namespace MediaBrowser.Controller.Entities
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |              cancellationToken.ThrowIfCancellationRequested();
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -            await RefreshChildren(validChildren, progress, cancellationToken, recursive, forceRefreshMetadata).ConfigureAwait(false);
 | 
	
		
			
				|  |  | +            if (recursive)
 | 
	
		
			
				|  |  | +            {
 | 
	
		
			
				|  |  | +                await ValidateSubFolders(validChildren.OfType<Folder>().ToList(), progress, cancellationToken).ConfigureAwait(false);
 | 
	
		
			
				|  |  | +            }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +            progress.Report(20);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +            if (refreshChildMetadata)
 | 
	
		
			
				|  |  | +            {
 | 
	
		
			
				|  |  | +                var container = this as IMetadataContainer;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +                var innerProgress = new ActionableProgress<double>();
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +                innerProgress.RegisterAction(p => progress.Report((.80 * p) + 20));
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +                if (container != null)
 | 
	
		
			
				|  |  | +                {
 | 
	
		
			
				|  |  | +                    await container.RefreshAllMetadata(refreshOptions, innerProgress, cancellationToken).ConfigureAwait(false);
 | 
	
		
			
				|  |  | +                }
 | 
	
		
			
				|  |  | +                else
 | 
	
		
			
				|  |  | +                {
 | 
	
		
			
				|  |  | +                    await RefreshMetadataRecursive(refreshOptions, recursive, innerProgress, cancellationToken);
 | 
	
		
			
				|  |  | +                }
 | 
	
		
			
				|  |  | +            }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |              progress.Report(100);
 | 
	
		
			
				|  |  |          }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -        /// <summary>
 | 
	
		
			
				|  |  | -        /// Refreshes the children.
 | 
	
		
			
				|  |  | -        /// </summary>
 | 
	
		
			
				|  |  | -        /// <param name="children">The children.</param>
 | 
	
		
			
				|  |  | -        /// <param name="progress">The progress.</param>
 | 
	
		
			
				|  |  | -        /// <param name="cancellationToken">The cancellation token.</param>
 | 
	
		
			
				|  |  | -        /// <param name="recursive">if set to <c>true</c> [recursive].</param>
 | 
	
		
			
				|  |  | -        /// <param name="forceRefreshMetadata">if set to <c>true</c> [force refresh metadata].</param>
 | 
	
		
			
				|  |  | -        /// <returns>Task.</returns>
 | 
	
		
			
				|  |  | -        private async Task RefreshChildren(IList<BaseItem> children, IProgress<double> progress, CancellationToken cancellationToken, bool? recursive, bool forceRefreshMetadata = false)
 | 
	
		
			
				|  |  | +        private async Task RefreshMetadataRecursive(MetadataRefreshOptions refreshOptions, bool recursive, IProgress<double> progress, CancellationToken cancellationToken)
 | 
	
		
			
				|  |  |          {
 | 
	
		
			
				|  |  | -            var list = children;
 | 
	
		
			
				|  |  | +            var children = ActualChildren.ToList();
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -            var percentages = new Dictionary<Guid, double>(list.Count);
 | 
	
		
			
				|  |  | +            var percentages = new Dictionary<Guid, double>(children.Count);
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |              var tasks = new List<Task>();
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -            foreach (var tuple in list)
 | 
	
		
			
				|  |  | +            foreach (var child in children)
 | 
	
		
			
				|  |  |              {
 | 
	
		
			
				|  |  | -                if (tasks.Count > 10)
 | 
	
		
			
				|  |  | +                if (tasks.Count > 3)
 | 
	
		
			
				|  |  |                  {
 | 
	
		
			
				|  |  |                      await Task.WhenAll(tasks).ConfigureAwait(false);
 | 
	
		
			
				|  |  | +                    tasks.Clear();
 | 
	
		
			
				|  |  |                  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -                tasks.Add(RefreshChild(tuple, progress, percentages, list.Count, cancellationToken, recursive, forceRefreshMetadata));
 | 
	
		
			
				|  |  | -            }
 | 
	
		
			
				|  |  | +                cancellationToken.ThrowIfCancellationRequested();
 | 
	
		
			
				|  |  | +                var innerProgress = new ActionableProgress<double>();
 | 
	
		
			
				|  |  | +                
 | 
	
		
			
				|  |  | +                // Avoid implicitly captured closure
 | 
	
		
			
				|  |  | +                var currentChild = child;
 | 
	
		
			
				|  |  | +                innerProgress.RegisterAction(p =>
 | 
	
		
			
				|  |  | +                {
 | 
	
		
			
				|  |  | +                    lock (percentages)
 | 
	
		
			
				|  |  | +                    {
 | 
	
		
			
				|  |  | +                        percentages[currentChild.Id] = p / 100;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -            cancellationToken.ThrowIfCancellationRequested();
 | 
	
		
			
				|  |  | +                        var percent = percentages.Values.Sum();
 | 
	
		
			
				|  |  | +                        percent /= children.Count;
 | 
	
		
			
				|  |  | +                        percent *= 100;
 | 
	
		
			
				|  |  | +                        progress.Report(percent);
 | 
	
		
			
				|  |  | +                    }
 | 
	
		
			
				|  |  | +                });
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +                if (child.IsFolder)
 | 
	
		
			
				|  |  | +                {
 | 
	
		
			
				|  |  | +                    await RefreshChildMetadata(child, refreshOptions, recursive, innerProgress, cancellationToken)
 | 
	
		
			
				|  |  | +                      .ConfigureAwait(false);
 | 
	
		
			
				|  |  | +                }
 | 
	
		
			
				|  |  | +                else
 | 
	
		
			
				|  |  | +                {
 | 
	
		
			
				|  |  | +                    tasks.Add(RefreshChildMetadata(child, refreshOptions, recursive, innerProgress, cancellationToken));
 | 
	
		
			
				|  |  | +                }
 | 
	
		
			
				|  |  | +            }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |              await Task.WhenAll(tasks).ConfigureAwait(false);
 | 
	
		
			
				|  |  | +            progress.Report(100);
 | 
	
		
			
				|  |  |          }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -        private async Task RefreshChild(BaseItem item, IProgress<double> progress, Dictionary<Guid, double> percentages, int childCount, CancellationToken cancellationToken, bool? recursive, bool forceRefreshMetadata = false)
 | 
	
		
			
				|  |  | +        private async Task RefreshChildMetadata(BaseItem child, MetadataRefreshOptions refreshOptions, bool recursive, IProgress<double> progress, CancellationToken cancellationToken)
 | 
	
		
			
				|  |  |          {
 | 
	
		
			
				|  |  | -            cancellationToken.ThrowIfCancellationRequested();
 | 
	
		
			
				|  |  | +            var container = child as IMetadataContainer;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -            var child = item;
 | 
	
		
			
				|  |  | -            try
 | 
	
		
			
				|  |  | +            if (container != null)
 | 
	
		
			
				|  |  |              {
 | 
	
		
			
				|  |  | -                //refresh it
 | 
	
		
			
				|  |  | -                await child.RefreshMetadata(new MetadataRefreshOptions
 | 
	
		
			
				|  |  | -                {
 | 
	
		
			
				|  |  | -                    ReplaceAllMetadata = forceRefreshMetadata
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -                }, cancellationToken).ConfigureAwait(false);
 | 
	
		
			
				|  |  | +                await container.RefreshAllMetadata(refreshOptions, progress, cancellationToken).ConfigureAwait(false);
 | 
	
		
			
				|  |  |              }
 | 
	
		
			
				|  |  | -            catch (IOException ex)
 | 
	
		
			
				|  |  | +            else
 | 
	
		
			
				|  |  |              {
 | 
	
		
			
				|  |  | -                Logger.ErrorException("Error refreshing {0}", ex, child.Path ?? child.Name);
 | 
	
		
			
				|  |  | +                await child.RefreshMetadata(refreshOptions, cancellationToken).ConfigureAwait(false);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +                if (recursive)
 | 
	
		
			
				|  |  | +                {
 | 
	
		
			
				|  |  | +                    var folder = child as Folder;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +                    if (folder != null)
 | 
	
		
			
				|  |  | +                    {
 | 
	
		
			
				|  |  | +                        await folder.RefreshMetadataRecursive(refreshOptions, true, progress, cancellationToken);
 | 
	
		
			
				|  |  | +                    }
 | 
	
		
			
				|  |  | +                }
 | 
	
		
			
				|  |  |              }
 | 
	
		
			
				|  |  | +            progress.Report(100);
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        /// <summary>
 | 
	
		
			
				|  |  | +        /// Refreshes the children.
 | 
	
		
			
				|  |  | +        /// </summary>
 | 
	
		
			
				|  |  | +        /// <param name="children">The children.</param>
 | 
	
		
			
				|  |  | +        /// <param name="progress">The progress.</param>
 | 
	
		
			
				|  |  | +        /// <param name="cancellationToken">The cancellation token.</param>
 | 
	
		
			
				|  |  | +        /// <returns>Task.</returns>
 | 
	
		
			
				|  |  | +        private async Task ValidateSubFolders(IList<Folder> children, IProgress<double> progress, CancellationToken cancellationToken)
 | 
	
		
			
				|  |  | +        {
 | 
	
		
			
				|  |  | +            var list = children;
 | 
	
		
			
				|  |  | +            var childCount = list.Count;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -            // Refresh children if a folder and the item changed or recursive is set to true
 | 
	
		
			
				|  |  | -            var refreshChildren = child.IsFolder;
 | 
	
		
			
				|  |  | +            var percentages = new Dictionary<Guid, double>(list.Count);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +            var tasks = new List<Task>();
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -            if (refreshChildren)
 | 
	
		
			
				|  |  | +            foreach (var item in list)
 | 
	
		
			
				|  |  |              {
 | 
	
		
			
				|  |  | -                // Don't refresh children if explicitly set to false
 | 
	
		
			
				|  |  | -                if (recursive.HasValue && recursive.Value == false)
 | 
	
		
			
				|  |  | +                if (tasks.Count > 10)
 | 
	
		
			
				|  |  |                  {
 | 
	
		
			
				|  |  | -                    refreshChildren = false;
 | 
	
		
			
				|  |  | +                    await Task.WhenAll(tasks).ConfigureAwait(false);
 | 
	
		
			
				|  |  |                  }
 | 
	
		
			
				|  |  | -            }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -            if (refreshChildren)
 | 
	
		
			
				|  |  | -            {
 | 
	
		
			
				|  |  |                  cancellationToken.ThrowIfCancellationRequested();
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +                var child = item;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |                  var innerProgress = new ActionableProgress<double>();
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |                  innerProgress.RegisterAction(p =>
 | 
	
	
		
			
				|  | @@ -569,24 +624,16 @@ namespace MediaBrowser.Controller.Entities
 | 
	
		
			
				|  |  |                          var percent = percentages.Values.Sum();
 | 
	
		
			
				|  |  |                          percent /= childCount;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -                        progress.Report((90 * percent) + 10);
 | 
	
		
			
				|  |  | +                        progress.Report((10 * percent) + 10);
 | 
	
		
			
				|  |  |                      }
 | 
	
		
			
				|  |  |                  });
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -                await ((Folder)child).ValidateChildren(innerProgress, cancellationToken, recursive, forceRefreshMetadata).ConfigureAwait(false);
 | 
	
		
			
				|  |  | +                tasks.Add(child.ValidateChildrenWithCancellationSupport(innerProgress, cancellationToken, true, false, null));
 | 
	
		
			
				|  |  |              }
 | 
	
		
			
				|  |  | -            else
 | 
	
		
			
				|  |  | -            {
 | 
	
		
			
				|  |  | -                lock (percentages)
 | 
	
		
			
				|  |  | -                {
 | 
	
		
			
				|  |  | -                    percentages[child.Id] = 1;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -                    var percent = percentages.Values.Sum();
 | 
	
		
			
				|  |  | -                    percent /= childCount;
 | 
	
		
			
				|  |  | +            cancellationToken.ThrowIfCancellationRequested();
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -                    progress.Report((90 * percent) + 10);
 | 
	
		
			
				|  |  | -                }
 | 
	
		
			
				|  |  | -            }
 | 
	
		
			
				|  |  | +            await Task.WhenAll(tasks).ConfigureAwait(false);
 | 
	
		
			
				|  |  |          }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |          /// <summary>
 | 
	
	
		
			
				|  | @@ -962,11 +1009,11 @@ namespace MediaBrowser.Controller.Entities
 | 
	
		
			
				|  |  |          /// <returns>Task.</returns>
 | 
	
		
			
				|  |  |          public override async Task ChangedExternally()
 | 
	
		
			
				|  |  |          {
 | 
	
		
			
				|  |  | -            await base.ChangedExternally().ConfigureAwait(false);
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  |              var progress = new Progress<double>();
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |              await ValidateChildren(progress, CancellationToken.None).ConfigureAwait(false);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +            await base.ChangedExternally().ConfigureAwait(false);
 | 
	
		
			
				|  |  |          }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |          /// <summary>
 |