public void BuildStats(List<FileRevision> list)
		{
			// dump info about versions count per file
			using (var versionsCountLog = File.CreateText(VersionsCountFileName))
			{
				var listG = list
					.GroupBy(f => f.FileSpec)
					.Select(g => new { Count = g.Count(), Spec = g.Key })
					.OrderByDescending(x => x.Count)
					.ToList()
				;

				listG.ForEach(g => versionsCountLog.WriteLine("{0,6} {1}", g.Count, g.Spec));
			}

			// reduce pinned files to single revision
			list = list
				.GroupBy(f => f.FileSpec)
				.Select(g => {
					if (IsShouldBePinned(g.Key))
						return g.Take(1).ToArray();
					return g.ToArray();
				})
				.SelectMany(x => x)
				.ToList()
			;

			using (var cache = new VssFileCache(_options.CacheDir, _options.SourceSafeIni))
			using (var errLog = File.CreateText(ErrorsFileName))
			using (var onlyLastVersionsLog = File.CreateText(OnlyLastVersionFileName))
			{
				errLog.AutoFlush = true;
				onlyLastVersionsLog.AutoFlush = true;

				// undone list
				using (var log = File.CreateText(UndoneVersionsCountFileName))
				{
					var listG = list
						.Where(v => cache.GetFileInfo(v.FileSpec, v.VssVersion) == null)
						.GroupBy(f => f.FileSpec)
						.Select(g => new { Count = g.Count(), Spec = g.Key })
						.OrderByDescending(x => x.Count)
						.ToList()
					;

					listG.ForEach(g => log.WriteLine("{0,6} {1}", g.Count, g.Spec));
				}

				var cached = 0;
				var errors = 0;
				var onlyLastVersions = 0;
				var notCached = 0;

				var onlyLastVersionSpecs = new HashSet<string>();

				foreach (var file in list)
				{
					if (cache.GetFilePath(file.FileSpec, file.VssVersion) != null)
					{
						cached++;
					}
					else
					{
						var err = cache.GetFileError(file.FileSpec, file.VssVersion);
						if (!string.IsNullOrWhiteSpace(err))
						{
							if (err == "not-retained")
							{
								if (!onlyLastVersionSpecs.Contains(file.FileSpec))
								{
									onlyLastVersions++;
									onlyLastVersionsLog.WriteLine("{0}", file.FileSpec);
									onlyLastVersionSpecs.Add(file.FileSpec);
								}
							}
							else
							{
								errors++;
								errLog.WriteLine("{0}@{1}\n\t{2}", file.FileSpec, file.VssVersion, err);
							}
							cached++;
						}
						else
						{
							notCached++;
						}
					}
				}

				Console.WriteLine("Cached: {0} (Errors: {1})  Not Cached: {2}", cached, errors, notCached);
				Console.WriteLine("Only Last Version: {0}", onlyLastVersions);
				Console.WriteLine("Not Cached: {0:0.00}%", 100.0 * notCached / list.Count);
				Console.WriteLine();
			}
		}
		public void Build(List<FileRevision> versions, Action<float> progress = null)
		{
			var sw = Stopwatch.StartNew();

			_tempDir = Path.Combine(Environment.CurrentDirectory, "vss-temp");
			Directory.CreateDirectory(_tempDir);

			_db = _options.DB.Value;
			var originalVersions = versions.ToList();

			using(_cache = new VssFileCache(_options.CacheDir, _db.SrcSafeIni))
			{
				// filterout cached versions
				if (!_options.Force)
				{
					Console.WriteLine("Skip already cached versions...");

					var cached = 0;
					var notRetained = 0;
					var errors = 0;

					versions.Clear();
					foreach (var file in originalVersions)
					{
						if (_cache.GetFilePath(file.FileSpec, file.VssVersion) != null)
						{
							cached++;
							continue;
						}

						if (!string.IsNullOrWhiteSpace(_cache.GetFileError(file.FileSpec, file.VssVersion)))
						{
							var err = _cache.GetFileError(file.FileSpec, file.VssVersion);

							if (err == "not-retained")
								notRetained++;
							else
								errors++;

							continue;
						}

						versions.Add(file);
					}

					Console.WriteLine("Cached(good): {0}", cached);
					Console.WriteLine("Cached(errors): {0}", errors);
					Console.WriteLine("Cached(not retained version): {0}", notRetained);
					Console.WriteLine("Not Cached: {0}", versions.Count);
				}
				Console.WriteLine();

				// sort versions
				versions = versions
					.GroupBy(f => f.FileSpec)
					// order by versions count. posible you do not want to convert all versions for some autogenerated files
					.OrderBy(g => g.Count())
					// start retrieveing from recent (high versions) to ancient (version 1)
					.SelectMany(g => g.OrderByDescending(v => v.VssVersion))
					.ToList()
				;

				using(_log = File.CreateText(LogFileName))
				{
					_log.AutoFlush = true;

					// cache
					var fileGroups = versions.GroupBy(v => v.FileSpec).ToList();

					for (var j = 0; j < fileGroups.Count; j++)
					{
						var fileGroup = fileGroups[j];

						Console.Write("[{0}/{1}] Get: {3,5} x {2}", j, fileGroups.Count, fileGroup.Key, fileGroup.Count());
						if (progress != null)
							progress((float)j / fileGroups.Count);

						foreach (var fg in fileGroup)
						{
							Process(fg);
						}

						Console.WriteLine();
					}
				}

				// build cached versions list
				BuildCachedVersionsList(originalVersions);
			}

			sw.Stop();

			Console.WriteLine();
			Console.WriteLine("Building cache complete. Take {0}", sw.Elapsed);
		}