public IAcceptInputTransition <string> ActivateRegexNFATransitionFromRegexCondition(RegexCondition <string> regex)
            {
                if (regex == null)
                {
                    throw new ArgumentNullException(nameof(regex));
                }

                RangeSet <string> set = new RangeSet <string>(this.rangeInfo);

                if (regex is RegexConst <string> regexConst)
                {
                    set.Add(regexConst.ConstValue);
                }
                else if (regex is RegexRange <string> regexRange)
                {
                    set.AddRange(regexRange.Minimum, regexRange.Maximum, regexRange.CanTakeMinimum, regexRange.CanTakeMaximum);
                }
                else if (regex is IRange <string> range)
                {
                    set.AddRange(range.Minimum, range.Maximum, range.CanTakeMinimum, range.CanTakeMaximum);
                }
                else
                {
                    throw new NotSupportedException();
                }

                return(new RangeSetRegexFATransition <string, BasicRegexNFAState <string> >(set));
            }
		/// <summary>
		/// Starts the file download.
		/// </summary>
		public void StartDownload()
		{
			Trace.TraceInformation(String.Format("[{0}] Downloading.", m_uriURL.ToString()));
			if (!FileExists)
				throw new FileNotFoundException("The file to download does not exist.", m_uriURL.ToString());

			Int32 intConnectionsToUse = m_fmdInfo.SupportsResume ? m_intMaxConnections : 1;
			if (ServicePointManager.DefaultConnectionLimit < 1)
				throw new Exception(String.Format("Only {0} connections can be created to the same file; {1} are wanted.", ServicePointManager.DefaultConnectionLimit, 1));
			else if (ServicePointManager.DefaultConnectionLimit < intConnectionsToUse)
				intConnectionsToUse = ServicePointManager.DefaultConnectionLimit;

			//get the list of ranges we have not already downloaded
			RangeSet rgsMissingRanges = new RangeSet();
			rgsMissingRanges.AddRange(new Range(0, m_fmdInfo.Length - 1));
			if (File.Exists(m_strFileMetadataPath))
			{
				string[] strRanges = File.ReadAllLines(m_strFileMetadataPath);
				foreach (string strRange in strRanges)
				{
					string strCleanRange = strRange.Trim().Trim('\0');
					if (String.IsNullOrEmpty(strCleanRange))
						continue;
					rgsMissingRanges.RemoveRange(Range.Parse(strCleanRange));
				}
			}
			else if (File.Exists(m_strSavePath))
				File.Delete(m_strSavePath);

			Int32 intMinBlockSize = (Int32)Math.Min((UInt64)m_intMinBlockSize, rgsMissingRanges.TotalSize);
			Int32 intBaseBlockSize = (Int32)Math.Max(rgsMissingRanges.TotalSize / (UInt64)intConnectionsToUse, (UInt64)intMinBlockSize);
			if (intConnectionsToUse > 1)
				intBaseBlockSize = Math.Min(intBaseBlockSize, m_intMaxBlockSize);

			//break the ranges into blocks to be downloaded
			foreach (Range rngNeeded in rgsMissingRanges)
			{
				//find out how many blocks will fit into the range
				Int32 intBlockCount = (Int32)(rngNeeded.Size / (UInt64)intBaseBlockSize);
				if (intBlockCount == 0)
					intBlockCount = 1;
				//there is likely to be some remainder (there are likely a fractional number of blocks
				// in the range), so lets distrubute the remainder amongst all of the blocks
				// we do this by elarging our blocksize
				UInt64 intBlockSize = (UInt64)Math.Ceiling(rngNeeded.Size / (double)intBlockCount);
				UInt64 intBlockStart = rngNeeded.StartByte;
				for (; intBlockStart + intBlockSize < rngNeeded.EndByte; intBlockStart += intBlockSize)
					m_queRequiredBlocks.Enqueue(new Range(intBlockStart, intBlockStart + intBlockSize - 1));
				m_queRequiredBlocks.Enqueue(new Range(intBlockStart, rngNeeded.EndByte));
			}

			m_fwrWriter = new FileWriter(m_strSavePath, m_strFileMetadataPath);

			m_dteStartTime = DateTime.Now;
			//spawn the downloading threads
			Int32 intRequiredBlocks = m_queRequiredBlocks.Count;
			lock (m_lstDownloaders)
			{
				for (Int32 i = 0; i < (intRequiredBlocks < intConnectionsToUse ? intRequiredBlocks : intConnectionsToUse); i++)
				{
					BlockDownloader bdrDownloader = new BlockDownloader(this, m_fmdInfo, m_fwrWriter, m_intWriteBufferSize, m_strUserAgent);
					bdrDownloader.FinishedDownloading += new EventHandler(Downloader_FinishedDownloading);
					bdrDownloader.Start();
					m_lstDownloaders.Add(bdrDownloader);
				}
			}
		}
		/// <summary>
		/// Sets up the initial values of the downloader.
		/// </summary>
		/// <param name="p_strSavePath">The path to which to save the file.
		/// If <paramref name="p_booUseDefaultFileName"/> is <c>false</c>, this value should be a complete
		/// path, including filename. If <paramref name="p_booUseDefaultFileName"/> is <c>true</c>,
		/// this value should be the directory in which to save the file.</param>
		/// <param name="p_booUseDefaultFileName">Whether to use the file name suggested by the server.</param>
		private void Initialize(string p_strSavePath, bool p_booUseDefaultFileName)
		{
			m_fmdInfo = GetMetadata();

			string strFilename = p_booUseDefaultFileName ? m_fmdInfo.SuggestedFileName : Path.GetFileName(p_strSavePath);

			strFilename = Uri.UnescapeDataString(strFilename);

			foreach (char chrInvalid in Path.GetInvalidFileNameChars())
				strFilename = strFilename.Replace(chrInvalid, '_');
			p_strSavePath = Path.Combine(p_strSavePath, strFilename);

			m_strSavePath = p_strSavePath + ".partial";
			m_strFileMetadataPath = p_strSavePath + ".parts";

			if (!m_fmdInfo.SupportsResume)
			{
				File.Delete(m_strFileMetadataPath);
				File.Delete(m_strSavePath);
			}

			//get the list of ranges we have already downloaded
			RangeSet rgsRanges = new RangeSet();
			if (File.Exists(m_strFileMetadataPath))
			{
				string[] strRanges = File.ReadAllLines(m_strFileMetadataPath);
				foreach (string strRange in strRanges)
				{
					string strCleanRange = strRange.Trim().Trim('\0');
					if (String.IsNullOrEmpty(strCleanRange))
						continue;
					rgsRanges.AddRange(Range.Parse(strCleanRange));
				}
			}
			m_intInitialByteCount = rgsRanges.TotalSize;
			m_intInitialDownloadedByteCount = rgsRanges.TotalSize / 1024;
		}