public static void AnalyzeWordPressUrl(StoryUrlStats urlStats)
        {
            if (endsWithExtensionRegEx.IsMatch(urlStats.Url))
                return; //URL has extension not WordPress blog

            using (var client = new WebClient())
            {
                try
                {
                    var pageContent = client.DownloadString(urlStats.Url);

                    var themeNames = new HashSet<string>();
                    foreach (Match match in wpThemesRegEx.Matches(pageContent))
                        themeNames.Add(match.Groups[1].Value);

                    var pluginNames = new HashSet<string>();
                    foreach (Match match in wpPluginsRegEx.Matches(pageContent))
                        pluginNames.Add(match.Groups[1].Value);

                    urlStats.ThemeNames = themeNames.ToDelimitedString("/");
                    urlStats.PluginNames = pluginNames.ToDelimitedString("/");
                }
                catch (WebException wex)
                {
                    urlStats.FecthErrorStatus = wex.Status.ToString();
                    urlStats.FetchErrorMessage = wex.Message;
                }
            }
        }
        // Cache last user roles and monitor for changes
        private void CacheLastUserRoles(object state)
        {
            try
            {
                // Using an inter-process cache for user roles
                using (UserRoleCache userRoleCache = UserRoleCache.GetCurrentCache())
                {
                    HashSet<string> currentRoles;
                    string[] cachedRoles;

                    // Retrieve current user roles
                    currentRoles = new HashSet<string>(UserData.Roles, StringComparer.OrdinalIgnoreCase);

                    // Attempt to retrieve cached user roles
                    cachedRoles = userRoleCache[UserData.Username];

                    bool rolesChanged = false;
                    string message;
                    EventLogEntryType entryType;

                    if ((object)cachedRoles == null)
                    {
                        if (currentRoles.Count == 0)
                        {
                            // New user access granted
                            message = string.Format("Initial Encounter: user \"{0}\" attempted login with no assigned roles.", UserData.Username);
                            entryType = EventLogEntryType.FailureAudit;
                            rolesChanged = true;
                        }
                        else
                        {
                            // New user access granted
                            message = string.Format("Initial Encounter: user \"{0}\" granted access with role{1} \"{2}\".", UserData.Username, currentRoles.Count == 1 ? "" : "s", currentRoles.ToDelimitedString(", "));
                            entryType = EventLogEntryType.Information;
                            rolesChanged = true;
                        }
                    }
                    else if (!currentRoles.SetEquals(cachedRoles))
                    {
                        if (currentRoles.Count == 0)
                        {
                            // New user access granted
                            message = string.Format("Subsequent Encounter: user \"{0}\" attempted login with no assigned roles - role assignment that existed at last login was \"{1}\".", UserData.Username, cachedRoles.ToDelimitedString(", "));
                            entryType = EventLogEntryType.FailureAudit;
                            rolesChanged = true;
                        }
                        else
                        {
                            // User role access changed
                            message = string.Format("Subsequent Encounter: user \"{0}\" granted access with new role{1} \"{2}\" - role assignment is different from last login, was \"{3}\".", UserData.Username, currentRoles.Count == 1 ? "" : "s", currentRoles.ToDelimitedString(", "), cachedRoles.ToDelimitedString(", "));
                            entryType = EventLogEntryType.Warning;
                            rolesChanged = true;
                        }
                    }
                    else
                    {
                        if (currentRoles.Count == 0)
                        {
                            // New user access granted
                            message = string.Format("Subsequent Encounter: user \"{0}\" attempted login with no assigned roles - same as last login attempt.", UserData.Username);
                            entryType = EventLogEntryType.FailureAudit;
                            rolesChanged = true;
                        }
                        else
                        {
                            message = string.Format("Subsequent Encounter: user \"{0}\" granted access with role{1} \"{2}\" - role assignment is the same as last login.", UserData.Username, currentRoles.Count == 1 ? "" : "s", currentRoles.ToDelimitedString(", "));
                            entryType = EventLogEntryType.SuccessAudit;
                        }
                    }

                    // Log granted role access to event log
                    try
                    {
                        LogEvent(ApplicationName, message, entryType, 0);
                    }
                    catch (Exception ex)
                    {
                        LogError(ex.Source, ex.ToString());
                    }

                    // If role has changed, update cache
                    if (rolesChanged)
                    {
                        userRoleCache[UserData.Username] = currentRoles.ToArray();
                        userRoleCache.WaitForSave();
                    }
                }
            }
            catch (Exception ex)
            {
                LogError(ex.Source, ex.ToString());
            }
        }