/// <summary>
		/// Prepares to render the control.
		/// </summary>
		/// <param name="e">An <see cref="T:System.EventArgs"/> object that contains the event data.</param>
		protected override void OnPreRender(EventArgs e) {
			base.OnPreRender(e);

			if (!this.Visible) {
				return;
			}

			if (this.DownloadYahooUILibrary) {
				// Although we'll add the <script> tag to download the YAHOO component,
				// a download failure may have occurred, so protect ourselves from a 
				// script error using an if (YAHOO) block.  But apparently at least in IE
				// that's not even enough, so we use a try/catch.
				string yuiLoadScript = @"try { if (YAHOO) {
	var loader = new YAHOO.util.YUILoader({
		require: ['button', 'menu'],
		loadOptional: false,
		combine: true
	});

	loader.insert();
} } catch (e) { }";
				this.Page.ClientScript.RegisterClientScriptInclude("yuiloader", this.Page.Request.Url.IsTransportSecure() ? YuiLoaderHttps : YuiLoaderHttp);
				this.Page.ClientScript.RegisterClientScriptBlock(this.GetType(), "requiredYuiComponents", yuiLoadScript, true);
			}

			var css = new HtmlLink();
			try {
				css.Href = this.Page.ClientScript.GetWebResourceUrl(typeof(OpenIdAjaxTextBox), EmbeddedStylesheetResourceName);
				css.Attributes["rel"] = "stylesheet";
				css.Attributes["type"] = "text/css";
				ErrorUtilities.VerifyHost(this.Page.Header != null, OpenIdStrings.HeadTagMustIncludeRunatServer);
				this.Page.Header.Controls.AddAt(0, css); // insert at top so host page can override
			} catch {
				css.Dispose();
				throw;
			}

			this.PrepareClientJavascript();

			// If an Identifier is preset on this control, preload discovery on that identifier,
			// but only if we're not already persisting an authentication result since that would
			// be redundant.
			if (this.Identifier != null && this.AuthenticationResponse == null) {
				this.PreloadDiscovery(this.Identifier);
			}
		}
		/// <summary>
		/// Raises the <see cref="E:System.Web.UI.Control.PreRender"/> event.
		/// </summary>
		/// <param name="e">An <see cref="T:System.EventArgs"/> object that contains the event data.</param>
		protected override void OnPreRender(EventArgs e) {
			base.OnPreRender(e);

			this.EnsureValidButtons();

			var css = new HtmlLink();
			try {
				css.Href = this.Page.ClientScript.GetWebResourceUrl(typeof(OpenIdSelector), EmbeddedStylesheetResourceName);
				css.Attributes["rel"] = "stylesheet";
				css.Attributes["type"] = "text/css";
				ErrorUtilities.VerifyHost(this.Page.Header != null, OpenIdStrings.HeadTagMustIncludeRunatServer);
				this.Page.Header.Controls.AddAt(0, css); // insert at top so host page can override
			} catch {
				css.Dispose();
				throw;
			}

			// Import the .js file where most of the code is.
			this.Page.ClientScript.RegisterClientScriptResource(typeof(OpenIdSelector), EmbeddedScriptResourceName);

			// Provide javascript with a way to post the login assertion.
			const string PostLoginAssertionMethodName = "postLoginAssertion";
			const string PositiveAssertionParameterName = "positiveAssertion";
			const string ScriptFormat = @"window.{2} = function({0}) {{
	$('#{3}')[0].setAttribute('value', {0});
	{1};
}};";
			string script = string.Format(
				CultureInfo.InvariantCulture,
				ScriptFormat,
				PositiveAssertionParameterName,
				this.Page.ClientScript.GetPostBackEventReference(this, null, false),
				PostLoginAssertionMethodName,
				this.positiveAssertionField.ClientID);
			this.Page.ClientScript.RegisterClientScriptBlock(this.GetType(), "Postback", script, true);

			this.Page.RegisterAsyncTask(new PageAsyncTask(async ct => {
				await this.PreloadDiscoveryAsync(
					this.Buttons.OfType<SelectorProviderButton>().Select(op => op.OPIdentifier).Where(id => id != null),
					ct);
			}));
			this.textBox.Visible = this.OpenIdTextBoxVisible;
		}