/// <summary>
        /// Build a callstack pattern for a crash to ease bucketing of crashes into Buggs.
        /// </summary>
        /// <param name="CrashInstance">A crash that was recently added to the database.</param>
        public void BuildPattern(Crash CrashInstance)
        {
            List <string> Pattern = new List <string>();

            // Get an array of callstack items
            CallStackContainer CallStack = new CallStackContainer(CrashInstance);

            CallStack.bDisplayFunctionNames = true;

            if (CrashInstance.Pattern == null)
            {
                // Set the module based on the modules in the callstack
                CrashInstance.Module = CallStack.GetModuleName();
                try
                {
                    foreach (CallStackEntry Entry in CallStack.CallStackEntries)
                    {
                        FunctionCall CurrentFunctionCall = new FunctionCall();

                        if (FunctionCalls.Where(f => f.Call == Entry.FunctionName).Count() > 0)
                        {
                            CurrentFunctionCall = FunctionCalls.Where(f => f.Call == Entry.FunctionName).First();
                        }
                        else
                        {
                            CurrentFunctionCall      = new FunctionCall();
                            CurrentFunctionCall.Call = Entry.FunctionName;
                            FunctionCalls.InsertOnSubmit(CurrentFunctionCall);
                        }

                        int Count = Crash_FunctionCalls.Where(c => c.CrashId == CrashInstance.Id && c.FunctionCallId == CurrentFunctionCall.Id).Count();
                        if (Count < 1)
                        {
                            Crash_FunctionCall JoinTable = new Crash_FunctionCall();
                            JoinTable.Crash        = CrashInstance;
                            JoinTable.FunctionCall = CurrentFunctionCall;
                            Crash_FunctionCalls.InsertOnSubmit(JoinTable);
                        }

                        SubmitChanges();

                        Pattern.Add(CurrentFunctionCall.Id.ToString());
                    }

                    CrashInstance.Pattern = string.Join("+", Pattern);
                    SubmitChanges();
                }
                catch (Exception Ex)
                {
                    Debug.WriteLine("Exception in BuildPattern: " + Ex.ToString());
                }
            }
        }
        /// <summary>
        /// Build a callstack pattern for a crash to ease bucketing of crashes into Buggs.
        /// </summary>
        /// <param name="CrashInstance">A crash that was recently added to the database.</param>
        public void BuildPattern(Crash CrashInstance)
        {
            using (FAutoScopedLogTimer LogTimer = new FAutoScopedLogTimer(this.GetType().ToString() + "(Crash=" + CrashInstance.Id + ")"))
            {
                List <string> Pattern = new List <string>();

                // Get an array of callstack items
                CallStackContainer CallStack = new CallStackContainer(CrashInstance);
                CallStack.bDisplayFunctionNames = true;

                if (CrashInstance.Pattern == null)
                {
                    // Set the module based on the modules in the callstack
                    CrashInstance.Module = CallStack.GetModuleName();
                    try
                    {
                        foreach (CallStackEntry Entry in CallStack.CallStackEntries)
                        {
                            FunctionCall CurrentFunctionCall = new FunctionCall();

                            if (FunctionCalls.Where(f => f.Call == Entry.FunctionName).Count() > 0)
                            {
                                CurrentFunctionCall = FunctionCalls.Where(f => f.Call == Entry.FunctionName).First();
                            }
                            else
                            {
                                CurrentFunctionCall      = new FunctionCall();
                                CurrentFunctionCall.Call = Entry.FunctionName;
                                FunctionCalls.InsertOnSubmit(CurrentFunctionCall);
                            }

                            SubmitChanges();

                            Pattern.Add(CurrentFunctionCall.Id.ToString());
                        }

                        //CrashInstance.Pattern = "+";
                        CrashInstance.Pattern = string.Join("+", Pattern);
                        // We need something like this +1+2+3+5+ for searching for exact pattern like +5+
                        //CrashInstance.Pattern += "+";

                        SubmitChanges();
                    }
                    catch (Exception Ex)
                    {
                        FLogger.WriteException("BuildPattern: " + Ex.ToString());
                    }
                }
            }
        }
Exemple #3
0
        /// <summary>
        /// Build a callstack pattern for a crash to ease bucketing of crashes into Buggs.
        /// </summary>
        public void BuildPattern(CrashReportDataContext Context)
        {
            using (FAutoScopedLogTimer LogTimer = new FAutoScopedLogTimer(this.GetType().ToString() + "(Crash=" + Id + ")"))
            {
                List <string> PatternList   = new List <string>();
                var           FunctionCalls = Context.FunctionCalls;

                // Get an array of callstack items
                CallStackContainer CallStack = GetCallStack();

                if (Pattern == null)
                {
                    // Set the module based on the modules in the callstack
                    Module = CallStack.GetModuleName();
                    try
                    {
                        foreach (CallStackEntry Entry in CallStack.CallStackEntries.Take(64))
                        {
                            FunctionCall CurrentFunctionCall = new FunctionCall();

                            if (FunctionCalls.Where(f => f.Call == Entry.FunctionName).Count() > 0)
                            {
                                CurrentFunctionCall = FunctionCalls.Where(f => f.Call == Entry.FunctionName).First();
                            }
                            else
                            {
                                CurrentFunctionCall      = new FunctionCall();
                                CurrentFunctionCall.Call = Entry.FunctionName;
                                FunctionCalls.InsertOnSubmit(CurrentFunctionCall);
                            }

                            Context.SubmitChanges();

                            PatternList.Add(CurrentFunctionCall.Id.ToString());
                        }

                        //CrashInstance.Pattern = "+";
                        Pattern = string.Join("+", PatternList);
                        // We need something like this +1+2+3+5+ for searching for exact pattern like +5+
                        //CrashInstance.Pattern += "+";

                        Context.SubmitChanges();
                    }
                    catch (Exception Ex)
                    {
                        FLogger.Global.WriteException("BuildPattern: " + Ex.ToString());
                    }
                }
            }
        }
		/// <summary>
		/// Retrieve a cached (and pre-parsed) callstack container from the cache, or parse the raw callstack, and add to the cache.
		/// </summary>
		/// <param name="CurrentCrash">The crash to retrieve the parsed callstack for.</param>
		/// <returns>A parsed callstack.</returns>
		public DataModels.CallStackContainer GetCallStackFast( DataModels.Crash CurrentCrash )
		{
			using( var logTimer = new FAutoScopedLogTimer( this.GetType().ToString() + "(CrashId=" + CurrentCrash.Id + ")" ) )
			{
				var key = CacheKeyPrefix + CallstackKeyPrefix + CurrentCrash.Id;
				var callStack = (CallStackContainer)CacheInstance[key];
			    if (callStack != null) return callStack;
			    callStack = new CallStackContainer( CurrentCrash );
			    callStack.bDisplayFunctionNames = true;
			    CacheInstance.Insert( key, callStack );

			    return callStack;
			}
		}
        /// <summary>
        /// Retrieve a cached (and pre-parsed) callstack container from the cache, or parse the raw callstack, and add to the cache.
        /// </summary>
        /// <param name="CurrentCrash">The crash to retrieve the parsed callstack for.</param>
        /// <returns>A parsed callstack.</returns>
        public CallStackContainer GetCallStack(Crash CurrentCrash)
        {
            string             Key       = CacheKeyPrefix + CallstackKeyPrefix + CurrentCrash.Id;
            CallStackContainer CallStack = ( CallStackContainer )CacheInstance[Key];

            if (CallStack == null)
            {
                CallStack = new CallStackContainer(CurrentCrash);
                CallStack.bDisplayFunctionNames = true;
                CacheInstance.Insert(Key, CallStack);
            }

            return(CallStack);
        }
        /// <summary>
        /// Retrieve a cached (and pre-parsed) callstack container from the cache, or parse the raw callstack, and add to the cache.
        /// </summary>
        /// <param name="CurrentCrash">The crash to retrieve the parsed callstack for.</param>
        /// <returns>A parsed callstack.</returns>
        public CallStackContainer GetCallStack(Crash CurrentCrash)
        {
            using (FAutoScopedLogTimer LogTimer = new FAutoScopedLogTimer(this.GetType().ToString() + "(CrashId=" + CurrentCrash.Id + ")"))
            {
                string             Key       = CacheKeyPrefix + CallstackKeyPrefix + CurrentCrash.Id;
                CallStackContainer CallStack = (CallStackContainer)CacheInstance[Key];
                if (CallStack == null)
                {
                    CallStack = new CallStackContainer(CurrentCrash);
                    CallStack.bDisplayFunctionNames = true;
                    CacheInstance.Insert(Key, CallStack);
                }

                return(CallStack);
            }
        }
        /// <summary>
        /// Retrieve a cached (and pre-parsed) callstack container from the cache, or parse the raw callstack, and add to the cache.
        /// </summary>
        /// <param name="CurrentCrash">The crash to retrieve the parsed callstack for.</param>
        /// <returns>A parsed callstack.</returns>
        public CallStackContainer GetCallStackFast( Crash CurrentCrash )
        {
            using( FAutoScopedLogTimer LogTimer = new FAutoScopedLogTimer( this.GetType().ToString() + "(CrashId=" + CurrentCrash.Id + ")" ) )
            {
                string Key = CacheKeyPrefix + CallstackKeyPrefix + CurrentCrash.Id;
                CallStackContainer CallStack = (CallStackContainer)CacheInstance[Key];
                if( CallStack == null )
                {
                    CallStack = new CallStackContainer( CurrentCrash );
                    CallStack.bDisplayFunctionNames = true;
                    CacheInstance.Insert( Key, CallStack );
                }

                return CallStack;
            }
        }
        /// <summary>
        /// Retrieve a cached (and pre-parsed) callstack container from the cache, or parse the raw callstack, and add to the cache.
        /// </summary>
        /// <param name="currentCrash">The Crash to retrieve the parsed callstack for.</param>
        /// <returns>A parsed callstack.</returns>
        public DataModels.CallStackContainer GetCallStackFast(Crash currentCrash)
        {
            using (var logTimer = new FAutoScopedLogTimer(this.GetType().ToString() + "(CrashId=" + currentCrash.Id + ")"))
            {
                var key       = CacheKeyPrefix + CallstackKeyPrefix + currentCrash.Id;
                var callStack = (CallStackContainer)CacheInstance[key];
                if (callStack != null)
                {
                    return(callStack);
                }
                callStack = new CallStackContainer(currentCrash);
                callStack.bDisplayFunctionNames = true;
                CacheInstance.Insert(key, callStack);

                return(callStack);
            }
        }
        /// <summary>
        /// Build a callstack pattern for a crash to ease bucketing of crashes into Buggs.
        /// </summary>
        public void BuildPattern(CrashReportDataContext Context)
        {
            using (FAutoScopedLogTimer LogTimer = new FAutoScopedLogTimer(this.GetType().ToString() + "(Crash=" + Id + ")"))
            {
                List <string> PatternList   = new List <string>();
                var           FunctionCalls = Context.FunctionCalls;

                // Get an array of call stack items
                CallStackContainer CallStack = GetCallStack();

                if (Pattern == null)
                {
                    // Set the module based on the modules in the call stack
                    Module = CallStack.GetModuleName();
                    try
                    {
                        foreach (CallStackEntry Entry in CallStack.CallStackEntries.Take(CallStackContainer.MaxLinesToParse))
                        {
                            FunctionCall currentFunctionCall;

                            if (FunctionCalls.Any(f => f.Call == Entry.FunctionName))
                            {
                                currentFunctionCall = FunctionCalls.First(f => f.Call == Entry.FunctionName);
                            }
                            else
                            {
                                currentFunctionCall      = new FunctionCall();
                                currentFunctionCall.Call = Entry.FunctionName;
                                FunctionCalls.InsertOnSubmit(currentFunctionCall);
                            }

                            Context.SubmitChanges();
                            PatternList.Add(currentFunctionCall.Id.ToString());
                        }

                        Pattern = string.Join("+", PatternList);

                        Context.SubmitChanges();
                    }
                    catch (Exception Ex)
                    {
                        FLogger.Global.WriteException("BuildPattern exception: " + Ex.Message.ToString());
                    }
                }
            }
        }
        /// <summary>
        /// The Show action.
        /// </summary>
        /// <param name="BuggsForm">The form of user data passed up from the client.</param>
        /// <param name="id">The unique id of the Bugg.</param>
        /// <returns>The view to display a Bugg on the client.</returns>
        public ActionResult Show( FormCollection BuggsForm, int id )
        {
            using( FAutoScopedLogTimer LogTimer = new FAutoScopedLogTimer( this.GetType().ToString() + "(BuggId=" + id + ")", bCreateNewLog: true ) )
            {
                // Handle 'CopyToJira' button
                int BuggIDToBeAddedToJira = 0;
                foreach( var Entry in BuggsForm )
                {
                    if( Entry.ToString().Contains( Bugg.JiraSubmitName ) )
                    {
                        int.TryParse( Entry.ToString().Substring( Bugg.JiraSubmitName.Length ), out BuggIDToBeAddedToJira );
                        break;
                    }
                }

                BuggRepository Buggs = new BuggRepository();

                // Set the display properties based on the radio buttons
                bool DisplayModuleNames = false;
                if( BuggsForm["DisplayModuleNames"] == "true" )
                {
                    DisplayModuleNames = true;
                }

                bool DisplayFunctionNames = false;
                if( BuggsForm["DisplayFunctionNames"] == "true" )
                {
                    DisplayFunctionNames = true;
                }

                bool DisplayFileNames = false;
                if( BuggsForm["DisplayFileNames"] == "true" )
                {
                    DisplayFileNames = true;
                }

                bool DisplayFilePathNames = false;
                if( BuggsForm["DisplayFilePathNames"] == "true" )
                {
                    DisplayFilePathNames = true;
                    DisplayFileNames = false;
                }

                bool DisplayUnformattedCallStack = false;
                if( BuggsForm["DisplayUnformattedCallStack"] == "true" )
                {
                    DisplayUnformattedCallStack = true;
                }

                // Create a new view and populate with crashes
                List<Crash> Crashes = null;

                BuggViewModel Model = new BuggViewModel();
                Bugg NewBugg = Buggs.GetBugg( id );
                if( NewBugg == null )
                {
                    return RedirectToAction( "" );
                }

                Crashes = NewBugg.GetCrashes();

                using (FAutoScopedLogTimer GetCrashesTimer = new FAutoScopedLogTimer( "Bugg.PrepareBuggForJira" ))
                {
                    if (Crashes.Count > 0)
                    {
                        NewBugg.PrepareBuggForJira( Crashes );

                        if (BuggIDToBeAddedToJira != 0)
                        {
                            NewBugg.CopyToJira();
                        }
                    }

                }

                using( FAutoScopedLogTimer JiraResultsTimer = new FAutoScopedLogTimer( "Bugg.GrabJira" ) )
                {
                    var JC = JiraConnection.Get();
                    bool bValidJira = false;

                    // Verify valid JiraID, this may be still a TTP
                    if( !string.IsNullOrEmpty( NewBugg.Jira ) )
                    {
                        int TTPID = 0;
                        int.TryParse( NewBugg.Jira, out TTPID );

                        if( TTPID == 0 )
                        {
                            //AddBuggJiraMapping( NewBugg, ref FoundJiras, ref JiraIDtoBugg );
                            bValidJira = true;
                        }
                    }

                    if( JC.CanBeUsed() && bValidJira )
                    {
                        // Grab the data form JIRA.
                        string JiraSearchQuery = "key = " + NewBugg.Jira;

                        var JiraResults = JC.SearchJiraTickets(
                            JiraSearchQuery,
                            new string[]
                            {
                                "key",				// string
                                "summary",			// string
                                "components",		// System.Collections.ArrayList, Dictionary<string,object>, name
                                "resolution",		// System.Collections.Generic.Dictionary`2[System.String,System.Object], name
                                "fixVersions",		// System.Collections.ArrayList, Dictionary<string,object>, name
                                "customfield_11200" // string
                            } );

                        // Jira Key, Summary, Components, Resolution, Fix version, Fix changelist
                        foreach( var Jira in JiraResults )
                        {
                            string JiraID = Jira.Key;

                            string Summary = (string)Jira.Value["summary"];

                            string ComponentsText = "";
                            System.Collections.ArrayList Components = (System.Collections.ArrayList)Jira.Value["components"];
                            foreach( Dictionary<string, object> Component in Components )
                            {
                                ComponentsText += (string)Component["name"];
                                ComponentsText += " ";
                            }

                            Dictionary<string, object> ResolutionFields = (Dictionary<string, object>)Jira.Value["resolution"];
                            string Resolution = ResolutionFields != null ? (string)ResolutionFields["name"] : "";

                            string FixVersionsText = "";
                            System.Collections.ArrayList FixVersions = (System.Collections.ArrayList)Jira.Value["fixVersions"];
                            foreach( Dictionary<string, object> FixVersion in FixVersions )
                            {
                                FixVersionsText += (string)FixVersion["name"];
                                FixVersionsText += " ";
                            }

                            int FixCL = Jira.Value["customfield_11200"] != null ? (int)(decimal)Jira.Value["customfield_11200"] : 0;

                            NewBugg.JiraSummary = Summary;
                            NewBugg.JiraComponentsText = ComponentsText;
                            NewBugg.JiraResolution = Resolution;
                            NewBugg.JiraFixVersionsText = FixVersionsText;
                            if( FixCL != 0 )
                            {
                                NewBugg.JiraFixCL = FixCL.ToString();
                            }

                            break;
                        }
                    }
                }

                // Apply any user settings
                if( BuggsForm.Count > 0 )
                {
                    if( !string.IsNullOrEmpty( BuggsForm["SetStatus"] ) )
                    {
                        NewBugg.Status = BuggsForm["SetStatus"];
                        Buggs.SetBuggStatus( NewBugg.Status, id );
                    }

                    if( !string.IsNullOrEmpty( BuggsForm["SetFixedIn"] ) )
                    {
                        NewBugg.FixedChangeList = BuggsForm["SetFixedIn"];
                        Buggs.SetBuggFixedChangeList( NewBugg.FixedChangeList, id );
                    }

                    if( !string.IsNullOrEmpty( BuggsForm["SetTTP"] ) )
                    {
                        NewBugg.Jira = BuggsForm["SetTTP"];
                        Buggs.SetJIRAForBuggAndCrashes( NewBugg.Jira, id );
                    }

                    // <STATUS>
                }

                // Set up the view model with the crash data
                Model.Bugg = NewBugg;
                Model.Crashes = Crashes;

                Crash NewCrash = Model.Crashes.FirstOrDefault();
                if( NewCrash != null )
                {
                    using( FScopedLogTimer LogTimer2 = new FScopedLogTimer( "CallstackTrimming" ) )
                    {
                        CallStackContainer CallStack = new CallStackContainer( NewCrash );

                        // Set callstack properties
                        CallStack.bDisplayModuleNames = DisplayModuleNames;
                        CallStack.bDisplayFunctionNames = DisplayFunctionNames;
                        CallStack.bDisplayFileNames = DisplayFileNames;
                        CallStack.bDisplayFilePathNames = DisplayFilePathNames;
                        CallStack.bDisplayUnformattedCallStack = DisplayUnformattedCallStack;

                        Model.CallStack = CallStack;

                        // Shorten very long function names.
                        foreach( CallStackEntry Entry in Model.CallStack.CallStackEntries )
                        {
                            Entry.FunctionName = Entry.GetTrimmedFunctionName( 128 );
                        }

                        Model.SourceContext = NewCrash.SourceContext;
                    }

                    Model.Bugg.LatestCrashSummary = NewCrash.Summary;
                }

                Model.GenerationTime = LogTimer.GetElapsedSeconds().ToString( "F2" );
                return View( "Show", Model );
            }
        }
Exemple #11
0
		/// <summary>
		/// The Show action.
		/// </summary>
		/// <param name="BuggsForm">The form of user data passed up from the client.</param>
		/// <param name="id">The unique id of the Bugg.</param>
		/// <returns>The view to display a Bugg on the client.</returns>
		public ActionResult Show( FormCollection BuggsForm, int id )
		{
			using( FAutoScopedLogTimer LogTimer = new FAutoScopedLogTimer( this.GetType().ToString() + "(BuggId=" + id + ")" ) )
			{
				// Set the display properties based on the radio buttons
				bool DisplayModuleNames = false;
				if( BuggsForm["DisplayModuleNames"] == "true" )
				{
					DisplayModuleNames = true;
				}

				bool DisplayFunctionNames = false;
				if( BuggsForm["DisplayFunctionNames"] == "true" )
				{
					DisplayFunctionNames = true;
				}

				bool DisplayFileNames = false;
				if( BuggsForm["DisplayFileNames"] == "true" )
				{
					DisplayFileNames = true;
				}

				bool DisplayFilePathNames = false;
				if( BuggsForm["DisplayFilePathNames"] == "true" )
				{
					DisplayFilePathNames = true;
					DisplayFileNames = false;
				}

				bool DisplayUnformattedCallStack = false;
				if( BuggsForm["DisplayUnformattedCallStack"] == "true" )
				{
					DisplayUnformattedCallStack = true;
				}

				// Create a new view and populate with crashes
				List<Crash> Crashes = null;
				Bugg Bugg = new Bugg();

				BuggViewModel Model = new BuggViewModel();
				Bugg = LocalBuggRepository.GetBugg( id );
				if( Bugg == null )
				{
					return RedirectToAction( "" );
				}

				// @TODO yrx 2015-02-17 JIRA
				using( FAutoScopedLogTimer GetCrashesTimer = new FAutoScopedLogTimer( "Bugg.GetCrashes().ToList" ) )
				{
					Crashes = Bugg.GetCrashes();
					Bugg.AffectedVersions = new SortedSet<string>();

					HashSet<string> MachineIds = new HashSet<string>();
					foreach( Crash Crash in Crashes )
					{
						MachineIds.Add( Crash.ComputerName );
						// Ignore bad build versions.
						if( Crash.BuildVersion.StartsWith( "4." ) )
						{
							Bugg.AffectedVersions.Add( Crash.BuildVersion );
						}

						if( Crash.User == null )
						{
							//??
						}
					}
					Bugg.NumberOfUniqueMachines = MachineIds.Count;
				}

				// Apply any user settings
				if( BuggsForm.Count > 0 )
				{
					if( !string.IsNullOrEmpty( BuggsForm["SetStatus"] ) )
					{
						Bugg.Status = BuggsForm["SetStatus"];
						LocalCrashRepository.SetBuggStatus( Bugg.Status, id );
					}

					if( !string.IsNullOrEmpty( BuggsForm["SetFixedIn"] ) )
					{
						Bugg.FixedChangeList = BuggsForm["SetFixedIn"];
						LocalCrashRepository.SetBuggFixedChangeList( Bugg.FixedChangeList, id );
					}

					if( !string.IsNullOrEmpty( BuggsForm["SetTTP"] ) )
					{
						Bugg.TTPID = BuggsForm["SetTTP"];
						BuggRepository.SetJIRAForBuggAndCrashes( Bugg.TTPID, id );
					}

					if( !string.IsNullOrEmpty( BuggsForm["Description"] ) )
					{
						Bugg.Description = BuggsForm["Description"];
					}

					// <STATUS>
				}

				// Set up the view model with the crash data
				Model.Bugg = Bugg;
				Model.Crashes = Crashes;

				Crash NewCrash = Model.Crashes.FirstOrDefault();
				if( NewCrash != null )
				{
					using( FScopedLogTimer LogTimer2 = new FScopedLogTimer( "CallstackTrimming" ) )
					{
						CallStackContainer CallStack = new CallStackContainer( NewCrash );

						// Set callstack properties
						CallStack.bDisplayModuleNames = DisplayModuleNames;
						CallStack.bDisplayFunctionNames = DisplayFunctionNames;
						CallStack.bDisplayFileNames = DisplayFileNames;
						CallStack.bDisplayFilePathNames = DisplayFilePathNames;
						CallStack.bDisplayUnformattedCallStack = DisplayUnformattedCallStack;

						Model.CallStack = CallStack;

						// Shorten very long function names.
						foreach( CallStackEntry Entry in Model.CallStack.CallStackEntries )
						{
							Entry.FunctionName = Entry.GetTrimmedFunctionName( 128 );
						}

						Model.SourceContext = NewCrash.SourceContext;
					}
				}

				/*using( FScopedLogTimer LogTimer2 = new FScopedLogTimer( "BuggsController.Show.PopulateUserInfo" + "(id=" + id + ")" ) )
				{
					// Add in the users for each crash in the Bugg
					foreach( Crash CrashInstance in Model.Crashes )
					{
						LocalCrashRepository.PopulateUserInfo( CrashInstance );
					}
				}*/
				return View( "Show", Model );
			}
		}
        /// <summary>
        /// Show detailed information about a crash.
        /// </summary>
        /// <param name="CrashesForm">A form of user data passed up from the client.</param>
        /// <param name="Id">The unique id of the crash we wish to show the details of.</param>
        /// <returns>A view to show crash details.</returns>
        public ActionResult Show( FormCollection CrashesForm, int? Id )
        {
            if (!Id.HasValue)
            {
                return RedirectToAction("");
            }

            CallStackContainer CurrentCallStack = null;

            // Update the selected crash based on the form contents
            Crash CurrentCrash = LocalCrashRepository.GetCrash( Id.Value );

            if (CurrentCrash == null)
            {
                return RedirectToAction( "" );
            }

            if( !string.IsNullOrEmpty( CrashesForm["SetStatus"] ) )
            {
                CurrentCrash.Status = CrashesForm["SetStatus"];
                LocalCrashRepository.SetCrashStatus(CurrentCrash.Status, Id.Value);
            }

            if( !string.IsNullOrEmpty( CrashesForm["SetFixedIn"] ) )
            {
                CurrentCrash.FixedChangeList = CrashesForm["SetFixedIn"];
                LocalCrashRepository.SetCrashFixedChangeList(CurrentCrash.FixedChangeList, Id.Value);
            }

            if( !string.IsNullOrEmpty( CrashesForm["SetTTP"] ) )
            {
                CurrentCrash.TTPID = CrashesForm["SetTTP"];
                LocalCrashRepository.SetCrashTTPID(CurrentCrash.TTPID, Id.Value);
            }

            if( !string.IsNullOrEmpty( CrashesForm["Description"] ) )
            {
                CurrentCrash.Description = CrashesForm["Description"];
                LocalCrashRepository.SetCrashDescription(CurrentCrash.Description, Id.Value);
            }
            else
            {
                if( !string.IsNullOrEmpty( CurrentCrash.Description ) && string.IsNullOrEmpty( CrashesForm["Description"] ) )
                {
                    CurrentCrash.Description = "";
                    LocalCrashRepository.SetCrashDescription(CurrentCrash.Description, Id.Value);
                }
            }

            CurrentCallStack = new CallStackContainer( CurrentCrash );

            // Set callstack properties
            CurrentCallStack.bDisplayModuleNames = true;
            CurrentCallStack.bDisplayFunctionNames = true;
            CurrentCallStack.bDisplayFileNames = true;
            CurrentCallStack.bDisplayFilePathNames = true;
            CurrentCallStack.bDisplayUnformattedCallStack = false;

            CurrentCrash.CallStackContainer = CurrentCrash.GetCallStack();

            // Populate the crash with the correct user data
            LocalCrashRepository.PopulateUserInfo( CurrentCrash );

            return View( "Show", new CrashViewModel { Crash = CurrentCrash, CallStack = CurrentCallStack } );
        }
        /// <summary>
        /// The Show action.
        /// </summary>
        /// <param name="BuggsForm">The form of user data passed up from the client.</param>
        /// <param name="id">The unique id of the Bugg.</param>
        /// <returns>The view to display a Bugg on the client.</returns>
        public ActionResult Show( FormCollection BuggsForm, int id )
        {
            // Set the display properties based on the radio buttons
            bool DisplayModuleNames = false;
            if( BuggsForm["DisplayModuleNames"] == "true" )
            {
                DisplayModuleNames = true;
            }

            bool DisplayFunctionNames = false;
            if( BuggsForm["DisplayFunctionNames"] == "true" )
            {
                DisplayFunctionNames = true;
            }

            bool DisplayFileNames = false;
            if( BuggsForm["DisplayFileNames"] == "true" )
            {
                DisplayFileNames = true;
            }

            bool DisplayFilePathNames = false;
            if( BuggsForm["DisplayFilePathNames"] == "true" )
            {
                DisplayFilePathNames = true;
                DisplayFileNames = false;
            }

            bool DisplayUnformattedCallStack = false;
            if( BuggsForm["DisplayUnformattedCallStack"] == "true" )
            {
                DisplayUnformattedCallStack = true;
            }

            // Create a new view and populate with crashes
            List<Crash> Crashes = null;
            Bugg Bugg = new Bugg();

            BuggViewModel Model = new BuggViewModel();
            Bugg = LocalBuggRepository.GetBugg( id );
            if( Bugg == null )
            {
                return RedirectToAction( "" );
            }

            Crashes = Bugg.GetCrashes().ToList();

            // Apply any user settings
            if( BuggsForm.Count > 0 )
            {
                if( !string.IsNullOrEmpty( BuggsForm["SetStatus"] ) )
                {
                    Bugg.Status = BuggsForm["SetStatus"];
                    LocalCrashRepository.SetBuggStatus( Bugg.Status, id );
                }

                if( !string.IsNullOrEmpty( BuggsForm["SetFixedIn"] ) )
                {
                    Bugg.FixedChangeList = BuggsForm["SetFixedIn"];
                    LocalCrashRepository.SetBuggFixedChangeList( Bugg.FixedChangeList, id );
                }

                if( !string.IsNullOrEmpty( BuggsForm["SetTTP"] ) )
                {
                    Bugg.TTPID = BuggsForm["SetTTP"];
                    LocalCrashRepository.SetBuggTTPID( Bugg.TTPID, id );
                }

                if( !string.IsNullOrEmpty( BuggsForm["Description"] ) )
                {
                    Bugg.Description = BuggsForm["Description"];
                }
            }

            // Set up the view model with the crash data
            Model.Bugg = Bugg;
            Model.Crashes = Crashes;

            Crash NewCrash = Model.Crashes.FirstOrDefault();
            if( NewCrash != null )
            {
                CallStackContainer CallStack = new CallStackContainer( NewCrash );

                // Set callstack properties
                CallStack.bDisplayModuleNames = DisplayModuleNames;
                CallStack.bDisplayFunctionNames = DisplayFunctionNames;
                CallStack.bDisplayFileNames = DisplayFileNames;
                CallStack.bDisplayFilePathNames = DisplayFilePathNames;
                CallStack.bDisplayUnformattedCallStack = DisplayUnformattedCallStack;

                Model.CallStack = CallStack;

                NewCrash.CallStackContainer = NewCrash.GetCallStack();
            }

            // Add in the users for each crash in the Bugg
            foreach( Crash CrashInstance in Model.Crashes )
            {
                LocalCrashRepository.PopulateUserInfo( CrashInstance );
            }

            return View( "Show", Model );
        }
        /// <summary>
        /// Prepares Bugg for JIRA
        /// </summary>
        /// <param name="CrashesForBugg"></param>
        public void PrepareBuggForJira(List <Crash> CrashesForBugg)
        {
            var JC = JiraConnection.Get();

            this.AffectedVersions        = new SortedSet <string>();
            this.AffectedMajorVersions   = new SortedSet <string>();          // 4.4, 4.5 and so
            this.BranchesFoundIn         = new SortedSet <string>();
            this.AffectedPlatforms       = new SortedSet <string>();
            this.CrashesInTimeFrameAll   = CrashesForBugg.Count;
            this.CrashesInTimeFrameGroup = CrashesForBugg.Count;
            var HashSetDescriptions = new HashSet <string>();

            HashSet <string> MachineIds = new HashSet <string>();
            int FirstCLAffected         = int.MaxValue;

            foreach (var Crash in CrashesForBugg)
            {
                // Only add machine if the number has 32 characters
                if (Crash.MachineId != null && Crash.MachineId.Length == 32)
                {
                    MachineIds.Add(Crash.MachineId);
                    if (Crash.Description.Length > 4)
                    {
                        HashSetDescriptions.Add(Crash.Description);
                    }
                }

                // @TODO Ignore bad build versions.
                {
                    if (!string.IsNullOrEmpty(Crash.BuildVersion))
                    {
                        this.AffectedVersions.Add(Crash.BuildVersion);
                    }
                    // Depot || Stream
                    if (!string.IsNullOrEmpty(Crash.Branch))
                    {
                        this.BranchesFoundIn.Add(Crash.Branch);
                    }

                    int CrashBuiltFromCL = 0;
                    int.TryParse(Crash.BuiltFromCL, out CrashBuiltFromCL);
                    if (CrashBuiltFromCL > 0)
                    {
                        FirstCLAffected = Math.Min(FirstCLAffected, CrashBuiltFromCL);
                    }

                    if (!string.IsNullOrEmpty(Crash.Platform))
                    {
                        // Platform = "Platform [Desc]";
                        var PlatSubs = Crash.Platform.Split(" ".ToCharArray(), StringSplitOptions.RemoveEmptyEntries);
                        if (PlatSubs.Length >= 1)
                        {
                            this.AffectedPlatforms.Add(PlatSubs[0]);
                        }
                    }
                }
            }

            // CopyToJira
            foreach (var Line in HashSetDescriptions)
            {
                string ListItem = "- " + HttpUtility.HtmlEncode(Line);
                ToJiraDescriptions.Add(ListItem);
            }

            this.ToJiraFirstCLAffected = FirstCLAffected;

            if (this.AffectedVersions.Count > 0)
            {
                this.BuildVersion = this.AffectedVersions.Last();                       // Latest Version Affected
            }

            foreach (var AffectedBuild in this.AffectedVersions)
            {
                var Subs = AffectedBuild.Split(".".ToCharArray(), StringSplitOptions.RemoveEmptyEntries);
                if (Subs.Length >= 2)
                {
                    string MajorVersion = Subs[0] + "." + Subs[1];
                    this.AffectedMajorVersions.Add(MajorVersion);
                }
            }

            string BV = this.BuildVersion;

            this.NumberOfUniqueMachines = MachineIds.Count;                     // # Affected Users
            string LatestCLAffected = CrashesForBugg.                           // CL of the latest build
                                      Where(Crash => Crash.BuildVersion == BV).
                                      Max(Crash => Crash.BuiltFromCL);

            int ILatestCLAffected = -1;

            int.TryParse(LatestCLAffected, out ILatestCLAffected);
            this.LatestCLAffected = ILatestCLAffected;                                  // Latest CL Affected

            string LatestOSAffected = CrashesForBugg.OrderByDescending(Crash => Crash.TimeOfCrash).First().Platform;

            this.LatestOSAffected = LatestOSAffected;                                   // Latest Environment Affected

            // ToJiraSummary
            var FunctionCalls = new CallStackContainer(CrashesForBugg.First()).GetFunctionCallsForJira();

            if (FunctionCalls.Count > 0)
            {
                this.ToJiraSummary       = FunctionCalls[0];
                this.ToJiraFunctionCalls = FunctionCalls;
            }
            else
            {
                this.ToJiraSummary       = "No valid callstack found";
                this.ToJiraFunctionCalls = new List <string>();
            }

            // ToJiraVersions
            this.ToJiraVersions = new List <object>();
            foreach (var Version in this.AffectedMajorVersions)
            {
                bool bValid = JC.GetNameToVersions().ContainsKey(Version);
                if (bValid)
                {
                    this.ToJiraVersions.Add(JC.GetNameToVersions()[Version]);
                }
            }

            // ToJiraBranches
            this.ToJiraBranches = new HashSet <string>();
            foreach (var BranchName in this.BranchesFoundIn)
            {
                if (!string.IsNullOrEmpty(BranchName))
                {
                    // Stream
                    if (BranchName.StartsWith("//"))
                    {
                        this.ToJiraBranches.Add(BranchName);
                    }
                    // Depot
                    else
                    {
                        this.ToJiraBranches.Add(CrashReporterConstants.P4_DEPOT_PREFIX + BranchName);
                    }
                }
            }

            // ToJiraPlatforms
            this.ToJiraPlatforms = new List <object>();
            foreach (var platform in this.AffectedPlatforms)
            {
                bool bValid = JC.GetNameToPlatform().ContainsKey(platform);
                if (bValid)
                {
                    this.ToJiraPlatforms.Add(JC.GetNameToPlatform()[platform]);
                }
            }

            // ToJiraPlatforms
            this.ToBranchName = new List <object>();
            foreach (var BranchName in this.BranchesFoundIn)
            {
                bool bValid = JC.GetNameToBranch().ContainsKey(BranchName);
                if (bValid)
                {
                    this.ToBranchName.Add(JC.GetNameToBranch()[BranchName]);
                }
            }
        }
		void BuildPattern( Crash CrashInstance )
		{

			List<string> Pattern = new List<string>();

			// Get an array of callstack items
			CallStackContainer CallStack = new CallStackContainer( CrashInstance );
			CallStack.bDisplayFunctionNames = true;

			if( CrashInstance.Pattern == null )
			{
				// Set the module based on the modules in the callstack
				CrashInstance.Module = CallStack.GetModuleName();
				try
				{
					using( FAutoScopedLogTimer LogTimer = new FAutoScopedLogTimer( this.GetType().ToString() + "(Id=" + CrashInstance.Id + ")" ) )
					{
						foreach( CallStackEntry Entry in CallStack.CallStackEntries.Take( 64 ) )
						{
							FunctionCall CurrentFunctionCall = new FunctionCall();

							if( FunctionCalls.Where( f => f.Call == Entry.FunctionName ).Count() > 0 )
							{
								CurrentFunctionCall = FunctionCalls.Where( f => f.Call == Entry.FunctionName ).First();
							}
							else
							{
								CurrentFunctionCall = new FunctionCall();
								CurrentFunctionCall.Call = Entry.FunctionName;
								FunctionCalls.InsertOnSubmit( CurrentFunctionCall );
							}

							//CrashRepository.Context.SubmitChanges();

							Pattern.Add( CurrentFunctionCall.Id.ToString() );
						}

						//CrashInstance.Pattern = "+";
						CrashInstance.Pattern = string.Join( "+", Pattern );
						// We need something like this +1+2+3+5+ for searching for exact pattern like +5+
						//CrashInstance.Pattern += "+";

						CrashRepository.Context.SubmitChanges();
					}

				}
				catch( Exception Ex )
				{
					FLogger.WriteEvent( "Exception in BuildPattern: " + Ex.ToString() );
				}
			}
		}
		/// <summary>
		/// Prepares Bugg for JIRA
		/// </summary>
		/// <param name="CrashesForBugg"></param>
		public void PrepareBuggForJira( List<Crash> CrashesForBugg )
		{
			var JC = JiraConnection.Get();

			this.AffectedVersions = new SortedSet<string>();
			this.AffectedMajorVersions = new SortedSet<string>(); // 4.4, 4.5 and so
			this.BranchesFoundIn = new SortedSet<string>();
			this.AffectedPlatforms = new SortedSet<string>();
			this.CrashesInTimeFrameAll = CrashesForBugg.Count;
			this.CrashesInTimeFrameGroup = CrashesForBugg.Count;
			var HashSetDescriptions = new HashSet<string>();

			HashSet<string> MachineIds = new HashSet<string>();
			int FirstCLAffected = int.MaxValue;

			foreach( var Crash in CrashesForBugg )
			{
				// Only add machine if the number has 32 characters
				if (Crash.MachineId != null && Crash.MachineId.Length == 32)
				{
					MachineIds.Add( Crash.MachineId );
					if (Crash.Description.Length > 4)
					{
						HashSetDescriptions.Add( Crash.Description );
					}										
				}

				// @TODO Ignore bad build versions.
				{
					if( !string.IsNullOrEmpty( Crash.BuildVersion ) )
					{
						this.AffectedVersions.Add( Crash.BuildVersion );
					}
					// Depot || Stream
					if (!string.IsNullOrEmpty( Crash.Branch ))
					{
						this.BranchesFoundIn.Add( Crash.Branch );
					}

					int CrashBuiltFromCL = 0;
					int.TryParse( Crash.BuiltFromCL, out CrashBuiltFromCL );
					if( CrashBuiltFromCL > 0 )
					{
						FirstCLAffected = Math.Min( FirstCLAffected, CrashBuiltFromCL );
					}

					if( !string.IsNullOrEmpty( Crash.Platform ) )
					{
						// Platform = "Platform [Desc]";
						var PlatSubs = Crash.Platform.Split( " ".ToCharArray(), StringSplitOptions.RemoveEmptyEntries );
						if( PlatSubs.Length >= 1 )
						{
							this.AffectedPlatforms.Add( PlatSubs[0] );
						}
					}
				}
			}

			// CopyToJira 
			foreach( var Line in HashSetDescriptions )
			{
				string ListItem = "- " + HttpUtility.HtmlEncode( Line );
				ToJiraDescriptions.Add( ListItem );
			}
			
			this.ToJiraFirstCLAffected = FirstCLAffected;

			if( this.AffectedVersions.Count > 0 )
			{
				this.BuildVersion = this.AffectedVersions.Last();	// Latest Version Affected
			}
            
			foreach( var AffectedBuild in this.AffectedVersions )
			{
				var Subs = AffectedBuild.Split( ".".ToCharArray(), StringSplitOptions.RemoveEmptyEntries );
				if( Subs.Length >= 2 )
				{
					string MajorVersion = Subs[0] + "." + Subs[1];
					this.AffectedMajorVersions.Add( MajorVersion );
				}
			}

			string BV = this.BuildVersion;
			this.NumberOfUniqueMachines = MachineIds.Count;		// # Affected Users
			string LatestCLAffected = CrashesForBugg.				// CL of the latest build
				Where( Crash => Crash.BuildVersion == BV ).
				Max( Crash => Crash.BuiltFromCL );

			int ILatestCLAffected = -1;
			int.TryParse( LatestCLAffected, out ILatestCLAffected );
			this.LatestCLAffected = ILatestCLAffected;			// Latest CL Affected

			string LatestOSAffected = CrashesForBugg.OrderByDescending( Crash => Crash.TimeOfCrash ).First().Platform;
			this.LatestOSAffected = LatestOSAffected;			// Latest Environment Affected

			// ToJiraSummary
			var FunctionCalls = new CallStackContainer(CrashesForBugg.First()).GetFunctionCallsForJira();
			if( FunctionCalls.Count > 0 )
			{
				this.ToJiraSummary = FunctionCalls[0];
				this.ToJiraFunctionCalls = FunctionCalls;
			}
			else
			{
				this.ToJiraSummary = "No valid callstack found";
				this.ToJiraFunctionCalls = new List<string>();
			}

			// ToJiraVersions
			this.ToJiraVersions = new List<object>();
			foreach( var Version in this.AffectedMajorVersions )
			{
				bool bValid = JC.GetNameToVersions().ContainsKey( Version );
				if( bValid )
				{
					this.ToJiraVersions.Add( JC.GetNameToVersions()[Version] );
				}
			}

			// ToJiraBranches
			this.ToJiraBranches = new HashSet<string>();
			foreach( var BranchName in this.BranchesFoundIn )
			{
				if( !string.IsNullOrEmpty(BranchName) )
				{
					// Stream
					if (BranchName.StartsWith( "//" ))
					{
						this.ToJiraBranches.Add( BranchName );
					}
					// Depot
					else
					{
						this.ToJiraBranches.Add( CrashReporterConstants.P4_DEPOT_PREFIX + BranchName );
					}
				}
			}

			// ToJiraPlatforms
			this.ToJiraPlatforms = new List<object>();
			foreach( var platform in this.AffectedPlatforms )
			{
                bool bValid = JC.GetNameToPlatform().ContainsKey(platform);
				if( bValid )
				{
                    this.ToJiraPlatforms.Add(JC.GetNameToPlatform()[platform]);
				}
			}

            // ToJiraPlatforms
            this.ToBranchName = new List<object>();
            foreach (var BranchName in this.BranchesFoundIn)
            {
                bool bValid = JC.GetNameToBranch().ContainsKey(BranchName);
                if (bValid)
                {
                    this.ToBranchName.Add(JC.GetNameToBranch()[BranchName]);
                }
            }   
		}
        /// <summary>
        /// Show detailed information about a crash.
        /// </summary>
        /// <param name="CrashesForm">A form of user data passed up from the client.</param>
        /// <param name="id">The unique id of the crash we wish to show the details of.</param>
        /// <returns>A view to show crash details.</returns>
        public ActionResult Show( FormCollection CrashesForm, int id )
        {
            using( FAutoScopedLogTimer LogTimer = new FAutoScopedLogTimer( this.GetType().ToString() + "(CrashId=" + id + ")", bCreateNewLog: true ) )
            {
                CrashRepository Crashes = new CrashRepository();

                CallStackContainer CurrentCallStack = null;

                // Update the selected crash based on the form contents
                Crash CurrentCrash = Crashes.GetCrash( id );

                if( CurrentCrash == null )
                {
                    return RedirectToAction( "" );
                }

                string FormValue;

                FormValue = CrashesForm["SetStatus"];
                if( !string.IsNullOrEmpty( FormValue ) )
                {
                    CurrentCrash.Status = FormValue;
                }

                FormValue = CrashesForm["SetFixedIn"];
                if( !string.IsNullOrEmpty( FormValue ) )
                {
                    CurrentCrash.FixedChangeList = FormValue;
                }

                FormValue = CrashesForm["SetTTP"];
                if( !string.IsNullOrEmpty( FormValue ) )
                {
                    CurrentCrash.Jira = FormValue;
                }

                // Valid to set description to an empty string
                FormValue = CrashesForm["Description"];
                if( FormValue != null )
                {
                    CurrentCrash.Description = FormValue;
                }

                CurrentCallStack = new CallStackContainer( CurrentCrash );

                // Set callstack properties
                CurrentCallStack.bDisplayModuleNames = true;
                CurrentCallStack.bDisplayFunctionNames = true;
                CurrentCallStack.bDisplayFileNames = true;
                CurrentCallStack.bDisplayFilePathNames = true;
                CurrentCallStack.bDisplayUnformattedCallStack = false;

                CurrentCrash.CallStackContainer = CurrentCrash.GetCallStack();

                // Populate the crash with the correct user data
                Crashes.PopulateUserInfo( CurrentCrash );
                Crashes.SubmitChanges();

                var Model = new CrashViewModel { Crash = CurrentCrash, CallStack = CurrentCallStack };
                Model.GenerationTime = LogTimer.GetElapsedSeconds().ToString( "F2" );
                return View( "Show", Model );
            }
        }