protected void DoTrackerItemsLoaded(TrackerItem[] retrievedItems)
		{
			lock (this)
			{
				_isProcessing = false;
				_trackerItems = retrievedItems;
				_processingError = null;
			}
			if (TrackerItemsLoaded != null)
			{
				TrackerItemsLoaded(this, new TrackerItemsAffectedEventArgs(retrievedItems));
			}
		}
		protected virtual TrackerItem[] ProcessTrackerItemList(string html)
		{
			ArrayList items = new ArrayList();
			Uri[] urls = ParseTrackerItemListUrls(html);
			for (int i = 0; i < urls.Length; i++)
			{
				Uri url = urls[i];
				DoTrackerLoadStatusChanged(i+1
					, urls.Length
					, "Retrieving bug tracker items...");
				TrackerItem item = new TrackerItem(url);
				items.Add(item);
			}
			return (TrackerItem[]) items.ToArray(typeof (TrackerItem));
		}
		private TrackerItem[] FilterExceptionItems(TrackerItem[] items, Exception ex)
		{
			ArrayList filteredItems = new ArrayList();
			for (int i = 0; i < items.Length; i++)
			{
				TrackerItem item = items[i];
				if (item.Description.Replace("\r\n", "")
					.IndexOf(ex.StackTrace.Replace("\r\n", "")) >= 0)
				{
					filteredItems.Add(item);
				}
			}
			return (TrackerItem[]) filteredItems.ToArray(typeof (TrackerItem));
		}
		public TrackerItemsAffectedEventArgs(TrackerItem[] affectedItems)
		{
			AffectedTrackerItems = affectedItems;
		}
		private void BindTrackerItemsGrid(TrackerItem[] items)
		{
			DataGridHelper.SetGridDataSource(gridItemList, items);

			DataGridHelper.AddDataGridColumn(gridItemList, "ID", "ID")
				.Width = 55;
			DataGridColumnStyle date = 
				DataGridHelper.AddDataGridColumn(gridItemList, "DateOpened", "Date Submitted", "yyyy-MM-dd");
			date.Width = 85;
			DataGridHelper.AddDataGridColumn(gridItemList, "Status", "Status")
				.Width = 55;
			DataGridHelper.AddDataGridColumn(gridItemList, "Summary", "Summary")
				.Width = 395;
			
			gridItemList.TableStyles[0].RowHeadersVisible = false;
			gridItemList.TableStyles[0].BackColor = Color.White;
			gridItemList.TableStyles[0].AlternatingBackColor = Color.WhiteSmoke;
		}
		private void ValidateKnownTrackerItem_1306821(TrackerItem item)
		{
			Assert.AreEqual("1306821", item.ID, "Incorrect ID");
			Assert.AreEqual(DateTime.Parse("2005-09-28 04:45"), item.DateOpened, "Incorrect opened date");
			Assert.AreEqual(DateTime.Parse("2005-09-28 04:46"), item.DateClosed, "Incorrect closed date");
			Assert.AreEqual("CLOSED", item.Status.Name.ToUpper(), "Incorrect status");
			Assert.AreEqual("XML Text editor fails to correctly identify file encoding", item.Summary, "Incorrect summary");
			string desc = "If the file has no byte-order mark, the text editor\r\ndoes not identify a file as being Unicode";
			Assert.AreEqual(desc, item.Description.Substring(0, desc.Length), "Incorrect description");
		}
		public void TestDescriptionMatchesSummary_WithBackSlash()
		{
			// Make sure we get the correct description when
			// the beginning of the description is the same as
			// the summary.
			// Also tests that description parsing works when the 
			// summary has a backslash character in it.
			TrackerItem item =
				new TrackerItem(HTML_ENCODED_SUMMARY_AND_MATCHING_DESCRIPTION);
			Assert.Greater(item.Description.Length
				, item.Summary.Length
				, "Item description should be longer than the summary.");
			Assert.AreEqual(item.Summary
				, item.Description.Substring(0, item.Summary.Length)
				, "Item description does not start with summary text.");
		}
		public void TestHtmlEncodedSummary()
		{
			TrackerItem item =
				new TrackerItem(HTML_ENCODED_SUMMARY_AND_MATCHING_DESCRIPTION);
			Assert.AreEqual(@"\""Packages\"" node... doesn't work"
				, item.Summary
				, "Incorrect summary");
		}
		private void ValidateKnownTrackerItem_OpenItem(TrackerItem item)
		{
			Assert.AreEqual("OPEN", item.Status.Name.ToUpper(), "Incorrect status");
		}