/// <summary>
		/// Searches HTML for the HEAD META tags that describe OpenID provider services.
		/// </summary>
		/// <param name="claimedIdentifier">The final URL that provided this HTML document.
		/// This may not be the same as (this) userSuppliedIdentifier if the
		/// userSuppliedIdentifier pointed to a 301 Redirect.</param>
		/// <param name="userSuppliedIdentifier">The user supplied identifier.</param>
		/// <param name="html">The HTML that was downloaded and should be searched.</param>
		/// <returns>
		/// A sequence of any discovered ServiceEndpoints.
		/// </returns>
		private static IEnumerable<IdentifierDiscoveryResult> DiscoverFromHtml(Uri claimedIdentifier, UriIdentifier userSuppliedIdentifier, string html) {
			var linkTags = new List<HtmlLink>(HtmlParser.HeadTags<HtmlLink>(html));
			foreach (var protocol in Protocol.AllPracticalVersions) {
				// rel attributes are supposed to be interpreted with case INsensitivity, 
				// and is a space-delimited list of values. (http://www.htmlhelp.com/reference/html40/values.html#linktypes)
				var serverLinkTag = linkTags.WithAttribute("rel").FirstOrDefault(tag => Regex.IsMatch(tag.Attributes["rel"], @"\b" + Regex.Escape(protocol.HtmlDiscoveryProviderKey) + @"\b", RegexOptions.IgnoreCase));
				if (serverLinkTag == null) {
					continue;
				}

				Uri providerEndpoint = null;
				if (Uri.TryCreate(serverLinkTag.Href, UriKind.Absolute, out providerEndpoint)) {
					// See if a LocalId tag of the discovered version exists
					Identifier providerLocalIdentifier = null;
					var delegateLinkTag = linkTags.WithAttribute("rel").FirstOrDefault(tag => Regex.IsMatch(tag.Attributes["rel"], @"\b" + Regex.Escape(protocol.HtmlDiscoveryLocalIdKey) + @"\b", RegexOptions.IgnoreCase));
					if (delegateLinkTag != null) {
						if (Identifier.IsValid(delegateLinkTag.Href)) {
							providerLocalIdentifier = delegateLinkTag.Href;
						} else {
							Logger.Yadis.WarnFormat("Skipping endpoint data because local id is badly formed ({0}).", delegateLinkTag.Href);
							continue; // skip to next version
						}
					}

					// Choose the TypeURI to match the OpenID version detected.
					string[] typeURIs = { protocol.ClaimedIdentifierServiceTypeURI };
					yield return IdentifierDiscoveryResult.CreateForClaimedIdentifier(
						claimedIdentifier,
						userSuppliedIdentifier,
						providerLocalIdentifier,
						new ProviderEndpointDescription(providerEndpoint, typeURIs),
						(int?)null,
						(int?)null);
				}
			}
		}
 protected internal virtual bool IsValidPageType(Type type)
 {
     IEnumerable<Type> types = new List<Type> { type };
     return types.WithAttribute<PageTypeAttribute>().Count() > 0 && !type.IsAbstract;
 }