问:
IdentityServer3 and external login through OpenIDConnect
In ASP.NET MVC app, I am trying to implement authentication against external OIDC service. For my testing I am using IdentityServer3 (https://identityserver.github.io/Documentation/) and public OIDC demo server: https://mitreid.org/

I cloned this sample from GitHub: https://github.com/IdentityServer/IdentityServer3.Samples/tree/master/source/MVC%20Authentication

Then added the following code to register the public OIDC server as external login provider:

```<code>private void ConfigureIdentityProviders(IAppBuilder app, string signInAsType)
{
    app.UseOpenIdConnectAuthentication(
        new OpenIdConnectAuthenticationOptions
        {
            AuthenticationType = "<AuthTypeName>",
            Authority = "https://mitreid.org/",
            Caption = "MIT Test Server",
            ClientId = "<Client Id>",
            ClientSecret = "<Client Secret>",
            RedirectUri = "https://localhost:44319/", //NOT SURE WHAT TO PUT HERE
            ResponseType = "code",
            Scope = "openid email profile",
            SignInAsAuthenticationType = signInAsType
        });
}
</code>```

The code works, i get the option to login via external OIDC server. The browser redirects to the external server login page and when login and password is entered, the consent page is shown. However, after the browser navigates back to https://localhost:44319/ the user is not authenticated - User.Identity.IsAuthenticated is false.

Question: What should be correct value of RedirectUri property? Does OpenIdConnect middleware have capability to parse the authantication info passed in from external server or it must be coded manually? Is there any sample code how to do this?

答:
I was studying the code and debugging quite a few hours (I am new to this) and I learned that:

This problem is related to OpenIdConnect OWIN Middleware implemented by Microsoft (https://github.com/aspnet/AspNetKatana/tree/dev/src/Microsoft.Owin.Security.OpenIdConnect).

The middleware from Microsoft expect that the OIDC server sends the message using HTTP POST, but the MIT server does HTTP GET

The middleware from Microsoft expect that there is id token along with code in the message  obtained from OIDC server, but the MIT server sends only the code.

Looks like the RedirectUri can be any path under /identity because the middleware method AuthenticateCoreAsync() is hit on every request and it does compare request path to configured Options.CallbackPath (which is set from RedirectURI)

So I just had to implement the standard authorization code flow - exchange the code for id token, get claims, create authentication ticket and redirect to IdentityServer /identity/callback endpoint. When I've done this, everything started working. IdentityServer is awesome!

I inherited new set of classes from OpenIdConnect middleware and did override some methods. The key method is async Task<AuthenticationTicket> AuthenticateCoreAsync() in OpenIdConnectAuthenticationHandler. I pasted the code below in case it would help to someone.

```<code>public class CustomOidcHandler : OpenIdConnectAuthenticationHandler
{
    private const string HandledResponse = "HandledResponse";

    private readonly ILogger _logger;
    private OpenIdConnectConfiguration _configuration;

    public CustomOidcHandler(ILogger logger) : base(logger)
    {
        _logger = logger;
    }

    /// <summary>
    /// Invoked to process incoming authentication messages.
    /// </summary>
    /// <returns>An <see cref="AuthenticationTicket"/> if successful.</returns>
    protected override async Task<AuthenticationTicket> AuthenticateCoreAsync()
    {
        // Allow login to be constrained to a specific path. Need to make this runtime configurable.
        if (Options.CallbackPath.HasValue && Options.CallbackPath != (Request.PathBase + Request.Path))
            return null;

        OpenIdConnectMessage openIdConnectMessage = null;
        if (string.Equals(Request.Method, "GET", StringComparison.OrdinalIgnoreCase))
            openIdConnectMessage = new OpenIdConnectMessage(Request.Query);

        if (openIdConnectMessage == null)
            return null;

        ExceptionDispatchInfo authFailedEx = null;
        try
        {
            return await CreateAuthenticationTicket(openIdConnectMessage).ConfigureAwait(false);
        }
        catch (Exception exception)
        {
            // We can't await inside a catch block, capture and handle outside.
            authFailedEx = ExceptionDispatchInfo.Capture(exception);
        }

        if (authFailedEx != null)
        {
            _logger.WriteError("Exception occurred while processing message: ", authFailedEx.SourceException);

            // Refresh the configuration for exceptions that may be caused by key rollovers. The user can also request a refresh in the notification.
            if (Options.RefreshOnIssuerKeyNotFound && authFailedEx.SourceException.GetType() == typeof(SecurityTokenSignatureKeyNotFoundException))
                Options.ConfigurationManager.RequestRefresh();

            var authenticationFailedNotification = new AuthenticationFailedNotification<OpenIdConnectMessage, OpenIdConnectAuthenticationOptions>(Context, Options)
            {
                ProtocolMessage = openIdConnectMessage,
                Exception = authFailedEx.SourceException
            };
            await Options.Notifications.AuthenticationFailed(authenticationFailedNotification).ConfigureAwait(false);
            if (authenticationFailedNotification.HandledResponse)
                return GetHandledResponseTicket();

            if (authenticationFailedNotification.Skipped)
                return null;

            authFailedEx.Throw();
        }

        return null;
    }

    private async Task<AuthenticationTicket> CreateAuthenticationTicket(OpenIdConnectMessage openIdConnectMessage)
    {
        var messageReceivedNotification =
            new MessageReceivedNotification<OpenIdConnectMessage, OpenIdConnectAuthenticationOptions>(Context, Options)
            {
                ProtocolMessage = openIdConnectMessage
            };
        await Options.Notifications.MessageReceived(messageReceivedNotification).ConfigureAwait(false);
        if (messageReceivedNotification.HandledResponse)
        {
            return GetHandledResponseTicket();
        }
        if (messageReceivedNotification.Skipped)
        {
            return null;
        }

        // runtime always adds state, if we don't find it OR we failed to 'unprotect' it this is not a message we
        // should process.
        AuthenticationProperties properties = GetPropertiesFromState(openIdConnectMessage.State);
        if (properties == null)
        {
            _logger.WriteWarning("The state field is missing or invalid.");
            return null;
        }

        // devs will need to hook AuthenticationFailedNotification to avoid having 'raw' runtime errors displayed to users.
        if (!string.IsNullOrWhiteSpace(openIdConnectMessage.Error))
        {
            throw new OpenIdConnectProtocolException(
                string.Format(CultureInfo.InvariantCulture,
                    openIdConnectMessage.Error,
                    "Exception_OpenIdConnectMessageError", openIdConnectMessage.ErrorDescription ?? string.Empty,
                    openIdConnectMessage.ErrorUri ?? string.Empty));
        }

        // tokens.Item1 contains id token
        // tokens.Item2 contains access token
        Tuple<string, string> tokens = await GetTokens(openIdConnectMessage.Code, Options)
            .ConfigureAwait(false);
        if (string.IsNullOrWhiteSpace(openIdConnectMessage.IdToken))
            openIdConnectMessage.IdToken = tokens.Item1;

        var securityTokenReceivedNotification =
            new SecurityTokenReceivedNotification<OpenIdConnectMessage, OpenIdConnectAuthenticationOptions>(Context,
                Options)
            {
                ProtocolMessage = openIdConnectMessage,
            };
        await Options.Notifications.SecurityTokenReceived(securityTokenReceivedNotification).ConfigureAwait(false);
        if (securityTokenReceivedNotification.HandledResponse)
            return GetHandledResponseTicket();

        if (securityTokenReceivedNotification.Skipped)
            return null;

        if (_configuration == null)
            _configuration = await Options.ConfigurationManager.GetConfigurationAsync(Context.Request.CallCancelled)
                .ConfigureAwait(false);

        // Copy and augment to avoid cross request race conditions for updated configurations.
        TokenValidationParameters tvp = Options.TokenValidationParameters.Clone();
        IEnumerable<string> issuers = new[] {_configuration.Issuer};
        tvp.ValidIssuers = tvp.ValidIssuers?.Concat(issuers) ?? issuers;
        tvp.IssuerSigningTokens = tvp.IssuerSigningTokens?.Concat(_configuration.SigningTokens) ?? _configuration.SigningTokens;

        SecurityToken validatedToken;
        ClaimsPrincipal principal =
            Options.SecurityTokenHandlers.ValidateToken(openIdConnectMessage.IdToken, tvp, out validatedToken);
        ClaimsIdentity claimsIdentity = principal.Identity as ClaimsIdentity;

        var claims = await GetClaims(tokens.Item2).ConfigureAwait(false);

        AddClaim(claims, claimsIdentity, "sub", ClaimTypes.NameIdentifier, Options.AuthenticationType);
        AddClaim(claims, claimsIdentity, "given_name", ClaimTypes.GivenName);
        AddClaim(claims, claimsIdentity, "family_name", ClaimTypes.Surname);
        AddClaim(claims, claimsIdentity, "preferred_username", ClaimTypes.Name);
        AddClaim(claims, claimsIdentity, "email", ClaimTypes.Email);

        // claims principal could have changed claim values, use bits received on wire for validation.
        JwtSecurityToken jwt = validatedToken as JwtSecurityToken;
        AuthenticationTicket ticket = new AuthenticationTicket(claimsIdentity, properties);

        if (Options.ProtocolValidator.RequireNonce)
        {
            if (String.IsNullOrWhiteSpace(openIdConnectMessage.Nonce))
                openIdConnectMessage.Nonce = jwt.Payload.Nonce;

            // deletes the nonce cookie
            RetrieveNonce(openIdConnectMessage);
        }

        // remember 'session_state' and 'check_session_iframe'
        if (!string.IsNullOrWhiteSpace(openIdConnectMessage.SessionState))
            ticket.Properties.Dictionary[OpenIdConnectSessionProperties.SessionState] = openIdConnectMessage.SessionState;

        if (!string.IsNullOrWhiteSpace(_configuration.CheckSessionIframe))
            ticket.Properties.Dictionary[OpenIdConnectSessionProperties.CheckSessionIFrame] =
                _configuration.CheckSessionIframe;

        if (Options.UseTokenLifetime)
        {
            // Override any session persistence to match the token lifetime.
            DateTime issued = jwt.ValidFrom;
            if (issued != DateTime.MinValue)
            {
                ticket.Properties.IssuedUtc = issued.ToUniversalTime();
            }
            DateTime expires = jwt.ValidTo;
            if (expires != DateTime.MinValue)
            {
                ticket.Properties.ExpiresUtc = expires.ToUniversalTime();
            }
            ticket.Properties.AllowRefresh = false;
        }

        var securityTokenValidatedNotification =
            new SecurityTokenValidatedNotification<OpenIdConnectMessage, OpenIdConnectAuthenticationOptions>(Context,
                Options)
            {
                AuthenticationTicket = ticket,
                ProtocolMessage = openIdConnectMessage,
            };

        await Options.Notifications.SecurityTokenValidated(securityTokenValidatedNotification).ConfigureAwait(false);
        if (securityTokenValidatedNotification.HandledResponse)
        {
            return GetHandledResponseTicket();
        }
        if (securityTokenValidatedNotification.Skipped)
        {
            return null;
        }
        // Flow possible changes
        ticket = securityTokenValidatedNotification.AuthenticationTicket;

        // there is no hash of the code (c_hash) in the jwt obtained from the server
        // I don't know how to perform the validation using ProtocolValidator without the hash
        // that is why the code below is commented
        //var protocolValidationContext = new OpenIdConnectProtocolValidationContext
        //{
        //    AuthorizationCode = openIdConnectMessage.Code,
        //    Nonce = nonce
        //};
        //Options.ProtocolValidator.Validate(jwt, protocolValidationContext);

        if (openIdConnectMessage.Code != null)
        {
            var authorizationCodeReceivedNotification = new AuthorizationCodeReceivedNotification(Context, Options)
            {
                AuthenticationTicket = ticket,
                Code = openIdConnectMessage.Code,
                JwtSecurityToken = jwt,
                ProtocolMessage = openIdConnectMessage,
                RedirectUri =
                    ticket.Properties.Dictionary.ContainsKey(OpenIdConnectAuthenticationDefaults.RedirectUriUsedForCodeKey)
                        ? ticket.Properties.Dictionary[OpenIdConnectAuthenticationDefaults.RedirectUriUsedForCodeKey]
                        : string.Empty,
            };
            await Options.Notifications.AuthorizationCodeReceived(authorizationCodeReceivedNotification)
                .ConfigureAwait(false);
            if (authorizationCodeReceivedNotification.HandledResponse)
            {
                return GetHandledResponseTicket();
            }
            if (authorizationCodeReceivedNotification.Skipped)
            {
                return null;
            }
            // Flow possible changes
            ticket = authorizationCodeReceivedNotification.AuthenticationTicket;
        }

        return ticket;
    }

    private static void AddClaim(IEnumerable<Tuple<string, string>> claims, ClaimsIdentity claimsIdentity, string key, string claimType, string issuer = null)
    {
        string subject = claims
            .Where(it => it.Item1 == key)
            .Select(x => x.Item2).SingleOrDefault();
        if (!string.IsNullOrWhiteSpace(subject))
            claimsIdentity.AddClaim(
                new System.Security.Claims.Claim(claimType, subject, ClaimValueTypes.String, issuer));
    }

    private async Task<Tuple<string, string>> GetTokens(string authorizationCode, OpenIdConnectAuthenticationOptions options)
    {
        // exchange authorization code at authorization server for an access and refresh token
        Dictionary<string, string> post = null;
        post = new Dictionary<string, string>
        {
            {"client_id", options.ClientId},
            {"client_secret", options.ClientSecret},
            {"grant_type", "authorization_code"},
            {"code", authorizationCode},
            {"redirect_uri", options.RedirectUri}
        };

        string content;
        using (var client = new HttpClient())
        {
            var postContent = new FormUrlEncodedContent(post);
            var response = await client.PostAsync(options.Authority.TrimEnd('/') + "/token", postContent)
                .ConfigureAwait(false);
            content = await response.Content.ReadAsStringAsync().ConfigureAwait(false);
        }
        // received tokens from authorization server
        var json = JObject.Parse(content);
        var accessToken = json["access_token"].ToString();
        string idToken = null;
        if (json["id_token"] != null)
            idToken = json["id_token"].ToString();

        return new Tuple<string, string>(idToken, accessToken);
    }

    private async Task<IEnumerable<Tuple<string, string>>> GetClaims(string accessToken)
    {
        string userInfoEndpoint = Options.Authority.TrimEnd('/') + "/userinfo";
        var userInfoClient = new UserInfoClient(new Uri(userInfoEndpoint), accessToken);
        var userInfoResponse = await userInfoClient.GetAsync().ConfigureAwait(false);
        var claims = userInfoResponse.Claims;

        return claims;
    }

    private static AuthenticationTicket GetHandledResponseTicket()
    {
        return new AuthenticationTicket(null, new AuthenticationProperties(new Dictionary<string, string>() { { HandledResponse, "true" } }));
    }

    private AuthenticationProperties GetPropertiesFromState(string state)
    {
        // assume a well formed query string: <a=b&>OpenIdConnectAuthenticationDefaults.AuthenticationPropertiesKey=kasjd;fljasldkjflksdj<&c=d>
        int startIndex = 0;
        if (string.IsNullOrWhiteSpace(state) || (startIndex = state.IndexOf("OpenIdConnect.AuthenticationProperties", StringComparison.Ordinal)) == -1)
        {
            return null;
        }

        int authenticationIndex = startIndex + "OpenIdConnect.AuthenticationProperties".Length;
        if (authenticationIndex == -1 || authenticationIndex == state.Length || state[authenticationIndex] != '=')
        {
            return null;
        }

        // scan rest of string looking for '&'
        authenticationIndex++;
        int endIndex = state.Substring(authenticationIndex, state.Length - authenticationIndex).IndexOf("&", StringComparison.Ordinal);

        // -1 => no other parameters are after the AuthenticationPropertiesKey
        if (endIndex == -1)
        {
            return Options.StateDataFormat.Unprotect(Uri.UnescapeDataString(state.Substring(authenticationIndex).Replace('+', ' ')));
        }
        else
        {
            return Options.StateDataFormat.Unprotect(Uri.UnescapeDataString(state.Substring(authenticationIndex, endIndex).Replace('+', ' ')));
        }
    }
}

public static class CustomOidcAuthenticationExtensions
{
    /// <summary>
    /// Adds the <see cref="OpenIdConnectAuthenticationMiddleware"/> into the OWIN runtime.
    /// </summary>
    /// <param name="app">The <see cref="IAppBuilder"/> passed to the configuration method</param>
    /// <param name="openIdConnectOptions">A <see cref="OpenIdConnectAuthenticationOptions"/> contains settings for obtaining identities using the OpenIdConnect protocol.</param>
    /// <returns>The updated <see cref="IAppBuilder"/></returns>
    public static IAppBuilder UseCustomOidcAuthentication(this IAppBuilder app, OpenIdConnectAuthenticationOptions openIdConnectOptions)
    {
        if (app == null)
            throw new ArgumentNullException(nameof(app));

        if (openIdConnectOptions == null)
            throw new ArgumentNullException(nameof(openIdConnectOptions));

        return app.Use(typeof(CustomOidcMiddleware), app, openIdConnectOptions);
    }
}
</code>```

and in Startup.cs

```<code>public class Startup
{
....
public void Configuration(IAppBuilder app)
{
    ....

     private void ConfigureIdentityProviders(IAppBuilder app, string signInAsType)
    {
        app.UseCustomOidcAuthentication(
            new OpenIdConnectAuthenticationOptions
            {
                AuthenticationType = "<name>",
                Authority = "<OIDC server url>",
                Caption = "<caption>",
                ClientId = "<client id>",
                ClientSecret = "<client secret>",
                // might be https://localhost:44319/identity/<anything>
                RedirectUri = "https://localhost:44319/identity/signin-customoidc",
                ResponseType = "code",
                Scope = "openid email profile address phone",
                SignInAsAuthenticationType = signInAsType
            }
        );
    }
    ....
}
....
}
</code>```

Body:
In ASP.NET MVC app, I am trying to implement authentication against external OIDC service. For my testing I am using IdentityServer3 (https://identityserver.github.io/Documentation/) and public OIDC demo server: https://mitreid.org/

I cloned this sample from GitHub: https://github.com/IdentityServer/IdentityServer3.Samples/tree/master/source/MVC%20Authentication

Then added the following code to register the public OIDC server as external login provider:

private void ConfigureIdentityProviders(IAppBuilder app, string signInAsType)
{
    app.UseOpenIdConnectAuthentication(
        new OpenIdConnectAuthenticationOptions
        {
            AuthenticationType = "<AuthTypeName>",
            Authority = "https://mitreid.org/",
            Caption = "MIT Test Server",
            ClientId = "<Client Id>",
            ClientSecret = "<Client Secret>",
            RedirectUri = "https://localhost:44319/", //NOT SURE WHAT TO PUT HERE
            ResponseType = "code",
            Scope = "openid email profile",
            SignInAsAuthenticationType = signInAsType
        });
}

The code works, i get the option to login via external OIDC server. The browser redirects to the external server login page and when login and password is entered, the consent page is shown. However, after the browser navigates back to https://localhost:44319/ the user is not authenticated - User.Identity.IsAuthenticated is false.

Question: What should be correct value of RedirectUri property? Does OpenIdConnect middleware have capability to parse the authantication info passed in from external server or it must be coded manually? Is there any sample code how to do this?

Body:
I was studying the code and debugging quite a few hours (I am new to this) and I learned that:

This problem is related to OpenIdConnect OWIN Middleware implemented by Microsoft (https://github.com/aspnet/AspNetKatana/tree/dev/src/Microsoft.Owin.Security.OpenIdConnect).

The middleware from Microsoft expect that the OIDC server sends the message using HTTP POST, but the MIT server does HTTP GET

The middleware from Microsoft expect that there is id token along with code in the message  obtained from OIDC server, but the MIT server sends only the code.

Looks like the RedirectUri can be any path under /identity because the middleware method AuthenticateCoreAsync() is hit on every request and it does compare request path to configured Options.CallbackPath (which is set from RedirectURI)

So I just had to implement the standard authorization code flow - exchange the code for id token, get claims, create authentication ticket and redirect to IdentityServer /identity/callback endpoint. When I've done this, everything started working. IdentityServer is awesome!

I inherited new set of classes from OpenIdConnect middleware and did override some methods. The key method is async Task<AuthenticationTicket> AuthenticateCoreAsync() in OpenIdConnectAuthenticationHandler. I pasted the code below in case it would help to someone.

public class CustomOidcHandler : OpenIdConnectAuthenticationHandler
{
    private const string HandledResponse = "HandledResponse";

    private readonly ILogger _logger;
    private OpenIdConnectConfiguration _configuration;

    public CustomOidcHandler(ILogger logger) : base(logger)
    {
        _logger = logger;
    }

    /// <summary>
    /// Invoked to process incoming authentication messages.
    /// </summary>
    /// <returns>An <see cref="AuthenticationTicket"/> if successful.</returns>
    protected override async Task<AuthenticationTicket> AuthenticateCoreAsync()
    {
        // Allow login to be constrained to a specific path. Need to make this runtime configurable.
        if (Options.CallbackPath.HasValue && Options.CallbackPath != (Request.PathBase + Request.Path))
            return null;

        OpenIdConnectMessage openIdConnectMessage = null;
        if (string.Equals(Request.Method, "GET", StringComparison.OrdinalIgnoreCase))
            openIdConnectMessage = new OpenIdConnectMessage(Request.Query);

        if (openIdConnectMessage == null)
            return null;

        ExceptionDispatchInfo authFailedEx = null;
        try
        {
            return await CreateAuthenticationTicket(openIdConnectMessage).ConfigureAwait(false);
        }
        catch (Exception exception)
        {
            // We can't await inside a catch block, capture and handle outside.
            authFailedEx = ExceptionDispatchInfo.Capture(exception);
        }

        if (authFailedEx != null)
        {
            _logger.WriteError("Exception occurred while processing message: ", authFailedEx.SourceException);

            // Refresh the configuration for exceptions that may be caused by key rollovers. The user can also request a refresh in the notification.
            if (Options.RefreshOnIssuerKeyNotFound && authFailedEx.SourceException.GetType() == typeof(SecurityTokenSignatureKeyNotFoundException))
                Options.ConfigurationManager.RequestRefresh();

            var authenticationFailedNotification = new AuthenticationFailedNotification<OpenIdConnectMessage, OpenIdConnectAuthenticationOptions>(Context, Options)
            {
                ProtocolMessage = openIdConnectMessage,
                Exception = authFailedEx.SourceException
            };
            await Options.Notifications.AuthenticationFailed(authenticationFailedNotification).ConfigureAwait(false);
            if (authenticationFailedNotification.HandledResponse)
                return GetHandledResponseTicket();

            if (authenticationFailedNotification.Skipped)
                return null;

            authFailedEx.Throw();
        }

        return null;
    }

    private async Task<AuthenticationTicket> CreateAuthenticationTicket(OpenIdConnectMessage openIdConnectMessage)
    {
        var messageReceivedNotification =
            new MessageReceivedNotification<OpenIdConnectMessage, OpenIdConnectAuthenticationOptions>(Context, Options)
            {
                ProtocolMessage = openIdConnectMessage
            };
        await Options.Notifications.MessageReceived(messageReceivedNotification).ConfigureAwait(false);
        if (messageReceivedNotification.HandledResponse)
        {
            return GetHandledResponseTicket();
        }
        if (messageReceivedNotification.Skipped)
        {
            return null;
        }

        // runtime always adds state, if we don't find it OR we failed to 'unprotect' it this is not a message we
        // should process.
        AuthenticationProperties properties = GetPropertiesFromState(openIdConnectMessage.State);
        if (properties == null)
        {
            _logger.WriteWarning("The state field is missing or invalid.");
            return null;
        }

        // devs will need to hook AuthenticationFailedNotification to avoid having 'raw' runtime errors displayed to users.
        if (!string.IsNullOrWhiteSpace(openIdConnectMessage.Error))
        {
            throw new OpenIdConnectProtocolException(
                string.Format(CultureInfo.InvariantCulture,
                    openIdConnectMessage.Error,
                    "Exception_OpenIdConnectMessageError", openIdConnectMessage.ErrorDescription ?? string.Empty,
                    openIdConnectMessage.ErrorUri ?? string.Empty));
        }

        // tokens.Item1 contains id token
        // tokens.Item2 contains access token
        Tuple<string, string> tokens = await GetTokens(openIdConnectMessage.Code, Options)
            .ConfigureAwait(false);
        if (string.IsNullOrWhiteSpace(openIdConnectMessage.IdToken))
            openIdConnectMessage.IdToken = tokens.Item1;

        var securityTokenReceivedNotification =
            new SecurityTokenReceivedNotification<OpenIdConnectMessage, OpenIdConnectAuthenticationOptions>(Context,
                Options)
            {
                ProtocolMessage = openIdConnectMessage,
            };
        await Options.Notifications.SecurityTokenReceived(securityTokenReceivedNotification).ConfigureAwait(false);
        if (securityTokenReceivedNotification.HandledResponse)
            return GetHandledResponseTicket();

        if (securityTokenReceivedNotification.Skipped)
            return null;

        if (_configuration == null)
            _configuration = await Options.ConfigurationManager.GetConfigurationAsync(Context.Request.CallCancelled)
                .ConfigureAwait(false);

        // Copy and augment to avoid cross request race conditions for updated configurations.
        TokenValidationParameters tvp = Options.TokenValidationParameters.Clone();
        IEnumerable<string> issuers = new[] {_configuration.Issuer};
        tvp.ValidIssuers = tvp.ValidIssuers?.Concat(issuers) ?? issuers;
        tvp.IssuerSigningTokens = tvp.IssuerSigningTokens?.Concat(_configuration.SigningTokens) ?? _configuration.SigningTokens;

        SecurityToken validatedToken;
        ClaimsPrincipal principal =
            Options.SecurityTokenHandlers.ValidateToken(openIdConnectMessage.IdToken, tvp, out validatedToken);
        ClaimsIdentity claimsIdentity = principal.Identity as ClaimsIdentity;

        var claims = await GetClaims(tokens.Item2).ConfigureAwait(false);

        AddClaim(claims, claimsIdentity, "sub", ClaimTypes.NameIdentifier, Options.AuthenticationType);
        AddClaim(claims, claimsIdentity, "given_name", ClaimTypes.GivenName);
        AddClaim(claims, claimsIdentity, "family_name", ClaimTypes.Surname);
        AddClaim(claims, claimsIdentity, "preferred_username", ClaimTypes.Name);
        AddClaim(claims, claimsIdentity, "email", ClaimTypes.Email);

        // claims principal could have changed claim values, use bits received on wire for validation.
        JwtSecurityToken jwt = validatedToken as JwtSecurityToken;
        AuthenticationTicket ticket = new AuthenticationTicket(claimsIdentity, properties);

        if (Options.ProtocolValidator.RequireNonce)
        {
            if (String.IsNullOrWhiteSpace(openIdConnectMessage.Nonce))
                openIdConnectMessage.Nonce = jwt.Payload.Nonce;

            // deletes the nonce cookie
            RetrieveNonce(openIdConnectMessage);
        }

        // remember 'session_state' and 'check_session_iframe'
        if (!string.IsNullOrWhiteSpace(openIdConnectMessage.SessionState))
            ticket.Properties.Dictionary[OpenIdConnectSessionProperties.SessionState] = openIdConnectMessage.SessionState;

        if (!string.IsNullOrWhiteSpace(_configuration.CheckSessionIframe))
            ticket.Properties.Dictionary[OpenIdConnectSessionProperties.CheckSessionIFrame] =
                _configuration.CheckSessionIframe;

        if (Options.UseTokenLifetime)
        {
            // Override any session persistence to match the token lifetime.
            DateTime issued = jwt.ValidFrom;
            if (issued != DateTime.MinValue)
            {
                ticket.Properties.IssuedUtc = issued.ToUniversalTime();
            }
            DateTime expires = jwt.ValidTo;
            if (expires != DateTime.MinValue)
            {
                ticket.Properties.ExpiresUtc = expires.ToUniversalTime();
            }
            ticket.Properties.AllowRefresh = false;
        }

        var securityTokenValidatedNotification =
            new SecurityTokenValidatedNotification<OpenIdConnectMessage, OpenIdConnectAuthenticationOptions>(Context,
                Options)
            {
                AuthenticationTicket = ticket,
                ProtocolMessage = openIdConnectMessage,
            };

        await Options.Notifications.SecurityTokenValidated(securityTokenValidatedNotification).ConfigureAwait(false);
        if (securityTokenValidatedNotification.HandledResponse)
        {
            return GetHandledResponseTicket();
        }
        if (securityTokenValidatedNotification.Skipped)
        {
            return null;
        }
        // Flow possible changes
        ticket = securityTokenValidatedNotification.AuthenticationTicket;

        // there is no hash of the code (c_hash) in the jwt obtained from the server
        // I don't know how to perform the validation using ProtocolValidator without the hash
        // that is why the code below is commented
        //var protocolValidationContext = new OpenIdConnectProtocolValidationContext
        //{
        //    AuthorizationCode = openIdConnectMessage.Code,
        //    Nonce = nonce
        //};
        //Options.ProtocolValidator.Validate(jwt, protocolValidationContext);

        if (openIdConnectMessage.Code != null)
        {
            var authorizationCodeReceivedNotification = new AuthorizationCodeReceivedNotification(Context, Options)
            {
                AuthenticationTicket = ticket,
                Code = openIdConnectMessage.Code,
                JwtSecurityToken = jwt,
                ProtocolMessage = openIdConnectMessage,
                RedirectUri =
                    ticket.Properties.Dictionary.ContainsKey(OpenIdConnectAuthenticationDefaults.RedirectUriUsedForCodeKey)
                        ? ticket.Properties.Dictionary[OpenIdConnectAuthenticationDefaults.RedirectUriUsedForCodeKey]
                        : string.Empty,
            };
            await Options.Notifications.AuthorizationCodeReceived(authorizationCodeReceivedNotification)
                .ConfigureAwait(false);
            if (authorizationCodeReceivedNotification.HandledResponse)
            {
                return GetHandledResponseTicket();
            }
            if (authorizationCodeReceivedNotification.Skipped)
            {
                return null;
            }
            // Flow possible changes
            ticket = authorizationCodeReceivedNotification.AuthenticationTicket;
        }

        return ticket;
    }

    private static void AddClaim(IEnumerable<Tuple<string, string>> claims, ClaimsIdentity claimsIdentity, string key, string claimType, string issuer = null)
    {
        string subject = claims
            .Where(it => it.Item1 == key)
            .Select(x => x.Item2).SingleOrDefault();
        if (!string.IsNullOrWhiteSpace(subject))
            claimsIdentity.AddClaim(
                new System.Security.Claims.Claim(claimType, subject, ClaimValueTypes.String, issuer));
    }

    private async Task<Tuple<string, string>> GetTokens(string authorizationCode, OpenIdConnectAuthenticationOptions options)
    {
        // exchange authorization code at authorization server for an access and refresh token
        Dictionary<string, string> post = null;
        post = new Dictionary<string, string>
        {
            {"client_id", options.ClientId},
            {"client_secret", options.ClientSecret},
            {"grant_type", "authorization_code"},
            {"code", authorizationCode},
            {"redirect_uri", options.RedirectUri}
        };

        string content;
        using (var client = new HttpClient())
        {
            var postContent = new FormUrlEncodedContent(post);
            var response = await client.PostAsync(options.Authority.TrimEnd('/') + "/token", postContent)
                .ConfigureAwait(false);
            content = await response.Content.ReadAsStringAsync().ConfigureAwait(false);
        }
        // received tokens from authorization server
        var json = JObject.Parse(content);
        var accessToken = json["access_token"].ToString();
        string idToken = null;
        if (json["id_token"] != null)
            idToken = json["id_token"].ToString();

        return new Tuple<string, string>(idToken, accessToken);
    }

    private async Task<IEnumerable<Tuple<string, string>>> GetClaims(string accessToken)
    {
        string userInfoEndpoint = Options.Authority.TrimEnd('/') + "/userinfo";
        var userInfoClient = new UserInfoClient(new Uri(userInfoEndpoint), accessToken);
        var userInfoResponse = await userInfoClient.GetAsync().ConfigureAwait(false);
        var claims = userInfoResponse.Claims;

        return claims;
    }

    private static AuthenticationTicket GetHandledResponseTicket()
    {
        return new AuthenticationTicket(null, new AuthenticationProperties(new Dictionary<string, string>() { { HandledResponse, "true" } }));
    }

    private AuthenticationProperties GetPropertiesFromState(string state)
    {
        // assume a well formed query string: <a=b&>OpenIdConnectAuthenticationDefaults.AuthenticationPropertiesKey=kasjd;fljasldkjflksdj<&c=d>
        int startIndex = 0;
        if (string.IsNullOrWhiteSpace(state) || (startIndex = state.IndexOf("OpenIdConnect.AuthenticationProperties", StringComparison.Ordinal)) == -1)
        {
            return null;
        }

        int authenticationIndex = startIndex + "OpenIdConnect.AuthenticationProperties".Length;
        if (authenticationIndex == -1 || authenticationIndex == state.Length || state[authenticationIndex] != '=')
        {
            return null;
        }

        // scan rest of string looking for '&'
        authenticationIndex++;
        int endIndex = state.Substring(authenticationIndex, state.Length - authenticationIndex).IndexOf("&", StringComparison.Ordinal);

        // -1 => no other parameters are after the AuthenticationPropertiesKey
        if (endIndex == -1)
        {
            return Options.StateDataFormat.Unprotect(Uri.UnescapeDataString(state.Substring(authenticationIndex).Replace('+', ' ')));
        }
        else
        {
            return Options.StateDataFormat.Unprotect(Uri.UnescapeDataString(state.Substring(authenticationIndex, endIndex).Replace('+', ' ')));
        }
    }
}

public static class CustomOidcAuthenticationExtensions
{
    /// <summary>
    /// Adds the <see cref="OpenIdConnectAuthenticationMiddleware"/> into the OWIN runtime.
    /// </summary>
    /// <param name="app">The <see cref="IAppBuilder"/> passed to the configuration method</param>
    /// <param name="openIdConnectOptions">A <see cref="OpenIdConnectAuthenticationOptions"/> contains settings for obtaining identities using the OpenIdConnect protocol.</param>
    /// <returns>The updated <see cref="IAppBuilder"/></returns>
    public static IAppBuilder UseCustomOidcAuthentication(this IAppBuilder app, OpenIdConnectAuthenticationOptions openIdConnectOptions)
    {
        if (app == null)
            throw new ArgumentNullException(nameof(app));

        if (openIdConnectOptions == null)
            throw new ArgumentNullException(nameof(openIdConnectOptions));

        return app.Use(typeof(CustomOidcMiddleware), app, openIdConnectOptions);
    }
}

and in Startup.cs

public class Startup
{
....
public void Configuration(IAppBuilder app)
{
    ....

     private void ConfigureIdentityProviders(IAppBuilder app, string signInAsType)
    {
        app.UseCustomOidcAuthentication(
            new OpenIdConnectAuthenticationOptions
            {
                AuthenticationType = "<name>",
                Authority = "<OIDC server url>",
                Caption = "<caption>",
                ClientId = "<client id>",
                ClientSecret = "<client secret>",
                // might be https://localhost:44319/identity/<anything>
                RedirectUri = "https://localhost:44319/identity/signin-customoidc",
                ResponseType = "code",
                Scope = "openid email profile address phone",
                SignInAsAuthenticationType = signInAsType
            }
        );
    }
    ....
}
....
}


来源: stackexchange

问:
Determine which JavaFX ListView item was clicked on without selecting it
My JavaFX application has a ListView that contains items that need to be processed. I have two buttons that the user can click to process the next item in the list (i.e. a "forward" button), or to undo the processing of the last item in the list (i.e. a "back" button). I don't want them to arbitrarily select items in the list (they should only be able to move around using those two buttons). However, I would like them to be able to right click on items to get some contextual menu (e.g. like deleting the right-clicked item from the list).

I have the following event filter added to disable selecting an item by clicking on it while still allowing the user to scroll through and look at all the items in the list.

```<code>instrList.addEventFilter(MouseEvent.MOUSE_PRESSED, event -> {
        if (event.getButton() == MouseButton.SECONDARY)
            System.out.println("right clicked... something");
        event.consume();
    });
</code>```

What I am stuck on is determine which item on the list was clicked on so I can do something with it (again, e.g. remove it from the list).

答:
Use a cell factory, so that you can register the listener with the ListCells, instead of with the ListView:

```<code>instrList.setCellFactory(lv -> {
    ListCell<MyDataType> cell = new ListCell<MyDataType>() {
        @Override
        protected void updateItem(MyDataType item, boolean empty) {
            super.updateItem(item, empty);
            if (empty) {
                setText(null);
            } else {
                setText(item.toString());
            }
        }
    };
    cell.addEventFilter(MouseEvent.MOUSE_PRESSED, event -> {
        if (event.getButton()== MouseButton.SECONDARY && (! cell.isEmpty())) {
            MyDataType item = cell.getItem();
            System.out.println("Right clicked "+item);
        }
    });
    return cell ;
});
</code>```

(Replace MyDataType with whatever type you are using for the ListView.)

ContentLicense: CC BY-SA 3.0

Body:
My JavaFX application has a ListView that contains items that need to be processed. I have two buttons that the user can click to process the next item in the list (i.e. a "forward" button), or to undo the processing of the last item in the list (i.e. a "back" button). I don't want them to arbitrarily select items in the list (they should only be able to move around using those two buttons). However, I would like them to be able to right click on items to get some contextual menu (e.g. like deleting the right-clicked item from the list).

I have the following event filter added to disable selecting an item by clicking on it while still allowing the user to scroll through and look at all the items in the list.

instrList.addEventFilter(MouseEvent.MOUSE_PRESSED, event -> {
        if (event.getButton() == MouseButton.SECONDARY)
            System.out.println("right clicked... something");
        event.consume();
    });

What I am stuck on is determine which item on the list was clicked on so I can do something with it (again, e.g. remove it from the list).

Body:
Use a cell factory, so that you can register the listener with the ListCells, instead of with the ListView:

instrList.setCellFactory(lv -> {
    ListCell<MyDataType> cell = new ListCell<MyDataType>() {
        @Override
        protected void updateItem(MyDataType item, boolean empty) {
            super.updateItem(item, empty);
            if (empty) {
                setText(null);
            } else {
                setText(item.toString());
            }
        }
    };
    cell.addEventFilter(MouseEvent.MOUSE_PRESSED, event -> {
        if (event.getButton()== MouseButton.SECONDARY && (! cell.isEmpty())) {
            MyDataType item = cell.getItem();
            System.out.println("Right clicked "+item);
        }
    });
    return cell ;
});

(Replace MyDataType with whatever type you are using for the ListView.)


问:
Modified unrelated files on a specific branch. How to push those files to master branch?
I made a branch for a particular feature. And I had to fix some bugs and forgot I was in that branch. Now I want to push those files with bugs fixed to the master branch and leave the files related to the feature alone in the branch. What should I do?</p>

答:
You can do this by "stashing" your changes. This allows you to store your changes (without a commit), change branches, and then pop them out.

```<code>git stash
git checkout the_other_branch
git stash pop
</code>```

Once this is done, you can continue editing or commit them as normal.

Body:
You can do this by "stashing" your changes. This allows you to store your changes (without a commit), change branches, and then pop them out.

git stash
git checkout the_other_branch
git stash pop

Once this is done, you can continue editing or commit them as normal.


问:
C# Unexpected performance results for different methods of parsing byte[] as hex string
I have created 3 different methods for converting a byte[] into a hex string using the following format: { 0xx2, ... } (Working Demo)

```<code>using System;
using System.Diagnostics;
using System.Text;

public class Program
{
    public delegate string ParseMethod(byte[] Msg);
    public class Parser
    {
        public string Name { get; private set;}
        public ParseMethod Handler { get; private set; }

        public Parser(string name, ParseMethod method)
        {
            Name = name;
            Handler = method;
        }
    }

    public static void Main()
    {
        Parser HexA = new Parser("ToHexA", ToHexA);
        Parser HexB = new Parser("ToHexB", ToHexB);
        Parser HexC = new Parser("ToHexC", ToHexC);

        TestCorrectness(HexA);
        TestCorrectness(HexB);
        TestCorrectness(HexC);

        Console.WriteLine("Small Message Performance:");
        TestPerformance(HexA, MsgSize: 10, Iterations: 1000000);
        TestPerformance(HexB, MsgSize: 10, Iterations: 1000000);
        TestPerformance(HexC, MsgSize: 10, Iterations: 1000000);
        Console.WriteLine();

        Console.WriteLine("Large Message Performance:");
        TestPerformance(HexA, MsgSize: 500, Iterations: 1000000);
        TestPerformance(HexB, MsgSize: 500, Iterations: 1000000);
        TestPerformance(HexC, MsgSize: 500, Iterations: 1000000);
        Console.WriteLine();
    }

    private static void TestCorrectness(Parser parser)
    {
        Console.WriteLine("Testing Correctness of \"{0}(byte[] Msg)\"", parser.Name);
        Console.WriteLine("\"{0}\"", parser.Handler(new byte[]{}));
        Console.WriteLine("\"{0}\"", parser.Handler(new byte[]{ 97 }));
        Console.WriteLine("\"{0}\"", parser.Handler(new byte[]{ 97, 98, 99, 0, 100 }));
        Console.WriteLine();
    }

    private static void TestPerformance(Parser parser, int MsgSize, int Iterations)
    {
        Stopwatch sw = new Stopwatch();
        sw.Reset();

        byte[] Msg = new byte[MsgSize];

        sw.Start();
        for (uint i = 0; i < Iterations; ++i)
        {
            parser.Handler(Msg);
        }
        sw.Stop();

        Console.WriteLine("Performance for \"{0}\", {1}", parser.Name, sw.Elapsed);
    }

    private static string ToHexA(byte[] buffer)
    {
        return
            (
                "{ 0x" +
                    BitConverter.ToString(buffer).ToLower()
                        .Replace("-", ", 0x") +
                " }"
            )
            .Replace(" 0x }", "}");
    }

    private static string ToHexB(byte[] buffer)
    {
        if (buffer.Length == 0) { return "{}"; }

        const string Preamble = "{ 0x";
        const string Delimiter = ", 0x";
        const string Epilogue = " }";

        string Msg = Preamble + buffer[0].ToString("x2");
        for (int i = 1; i < buffer.Length; ++i)
        {
            Msg += Delimiter + buffer[i].ToString("x2");
        }

        return Msg += Epilogue;
    }

    private static string ToHexC(byte[] buffer)
    {
        if (buffer.Length == 0) { return "{}"; }

        const string Preamble = "{ 0x";
        const string Delimiter = ", 0x";
        const string Epilogue = " }";

        StringBuilder HexOut = new StringBuilder(
            Preamble.Length +
            (Delimiter.Length * (buffer.Length - 1)) +
            (2 * buffer.Length) +
            Epilogue.Length
        );

        HexOut.Append(Preamble);
        HexOut.Append(buffer[0].ToString("x2"));
        for (int i = 1; i < buffer.Length; ++i)
        {
            HexOut.Append(Delimiter);
            HexOut.Append(buffer[i].ToString("x2"));
        }
        HexOut.Append(Epilogue);

        return HexOut.ToString();
    }
}
</code>```

Running this code I get the following performance statistics

```<code>Small Message Performance:
Performance for "ToHexA", 00:00:01.3078387
Performance for "ToHexB", 00:00:01.6939201
Performance for "ToHexC", 00:00:01.2997903

Large Message Performance:
Performance for "ToHexA", 00:00:32.5230253
Performance for "ToHexB", 00:04:23.4798762
Performance for "ToHexC", 00:00:56.2404684
</code>```

I find it surprising that ToHexA (relative to ToHexC) executes faster with a longer message but slower with a shorter message. As I understand it, Replace(), +, and ToLower() all have to perform a create/copy operation because strings are immutable.

At the same time, I suspected the overhead for StringBuilder might make it less suitable for shorter messages yet it executes faster than ToHexA in this situation.

The only thing I expected was the performance hit associated with ToHexB which is kind of an in between worst of both worlds scenario...

So, what is going on with these two methods and their performance characteristics?

Edit to make my intentions with this question more clear

I am not particularly interested in exact performance characteristics of two methods that are closely performant. I am aware this will be different on different devices, architectures, background processes, etc etc. and better testing methods exist to control variables and what not

My purpose in asking this question was to better understand why two noticeably dissimilar (in terms of performance) approaches stack up the way they do. The accepted answer explains the mechanics of ToString in a way that satisfies this question.

One constraint of this question the exact formatting of the output was specific and (we can only muse why, I think it's pretty standard) for some reason not one of the standard output formats in C#/.NET; it was this unique format that led to the question: stacking multiple replace and concatenation operations against StringBuilder

答:
Your approach C is going to be the fastest approach to concatenation, however you're still generating garbage with each call to ToString("x2").

In addition to that, the ToString overloads that take a format string are miserably slow for something like this, because they first have to process the format string before they can do actual work, and this format string processing gets repeated many many times.  Too bad there isn't a Converter<byte, string> GetToString(string format) that processes the format string once and returns a stateful conversion object.

In any case, byte.ToString() is very easy to avoid here.

```<code>static readonly char[] digits = "0123456789abcdef".ToCharArray();
private static string ToHexD(byte[] buffer)
{
    if (buffer.Length == 0) { return "{}"; }

    const string Preamble = "{ 0x";
    const string Delimiter = ", 0x";
    const string Epilogue = " }";

    int expectedLength =
        Preamble.Length +
        (Delimiter.Length * (buffer.Length - 1)) +
        (2 * buffer.Length) +
        Epilogue.Length;
    StringBuilder HexOut = new StringBuilder(expectedLength);

    HexOut.Append(Preamble);
    HexOut.Append(digits[buffer[0] >> 4]).Append(digits[buffer[0] & 0x0F]);
    for (int i = 1; i < buffer.Length; ++i)
    {
        HexOut.Append(Delimiter);
        HexOut.Append(digits[buffer[i] >> 4]).Append(digits[buffer[i] & 0x0F]);
    }
    HexOut.Append(Epilogue);

    return HexOut.ToString();
}
</code>```

Two calls to Append(char) should also be faster than one to Append(string), though this is much less important than saving the time on format strings.

As expected, this beats the BitConverter-then-Replace() approach handily at all sizes (by just about a factor of two).

For a tiny bit of further increase in speed, the calculations buffer[i] >> 4 and buffer[i] & 0x0f can both be avoided by preparing lead-digit and tail-digit lookup tables of length 256 each.  But bitwise operations are incredibly fast; on many microcontrollers lacking a large L1 data cache, increasing the size of the lookup tables would cost more performance than the bitwise ops.

Body:
I have created 3 different methods for converting a byte[] into a hex string using the following format: { 0xx2, ... } (Working Demo)

using System;
using System.Diagnostics;
using System.Text;

public class Program
{
    public delegate string ParseMethod(byte[] Msg);
    public class Parser
    {
        public string Name { get; private set;}
        public ParseMethod Handler { get; private set; }

        public Parser(string name, ParseMethod method)
        {
            Name = name;
            Handler = method;
        }
    }

    public static void Main()
    {
        Parser HexA = new Parser("ToHexA", ToHexA);
        Parser HexB = new Parser("ToHexB", ToHexB);
        Parser HexC = new Parser("ToHexC", ToHexC);

        TestCorrectness(HexA);
        TestCorrectness(HexB);
        TestCorrectness(HexC);

        Console.WriteLine("Small Message Performance:");
        TestPerformance(HexA, MsgSize: 10, Iterations: 1000000);
        TestPerformance(HexB, MsgSize: 10, Iterations: 1000000);
        TestPerformance(HexC, MsgSize: 10, Iterations: 1000000);
        Console.WriteLine();

        Console.WriteLine("Large Message Performance:");
        TestPerformance(HexA, MsgSize: 500, Iterations: 1000000);
        TestPerformance(HexB, MsgSize: 500, Iterations: 1000000);
        TestPerformance(HexC, MsgSize: 500, Iterations: 1000000);
        Console.WriteLine();
    }

    private static void TestCorrectness(Parser parser)
    {
        Console.WriteLine("Testing Correctness of \"{0}(byte[] Msg)\"", parser.Name);
        Console.WriteLine("\"{0}\"", parser.Handler(new byte[]{}));
        Console.WriteLine("\"{0}\"", parser.Handler(new byte[]{ 97 }));
        Console.WriteLine("\"{0}\"", parser.Handler(new byte[]{ 97, 98, 99, 0, 100 }));
        Console.WriteLine();
    }

    private static void TestPerformance(Parser parser, int MsgSize, int Iterations)
    {
        Stopwatch sw = new Stopwatch();
        sw.Reset();

        byte[] Msg = new byte[MsgSize];

        sw.Start();
        for (uint i = 0; i < Iterations; ++i)
        {
            parser.Handler(Msg);
        }
        sw.Stop();

        Console.WriteLine("Performance for \"{0}\", {1}", parser.Name, sw.Elapsed);
    }

    private static string ToHexA(byte[] buffer)
    {
        return
            (
                "{ 0x" +
                    BitConverter.ToString(buffer).ToLower()
                        .Replace("-", ", 0x") +
                " }"
            )
            .Replace(" 0x }", "}");
    }

    private static string ToHexB(byte[] buffer)
    {
        if (buffer.Length == 0) { return "{}"; }

        const string Preamble = "{ 0x";
        const string Delimiter = ", 0x";
        const string Epilogue = " }";

        string Msg = Preamble + buffer[0].ToString("x2");
        for (int i = 1; i < buffer.Length; ++i)
        {
            Msg += Delimiter + buffer[i].ToString("x2");
        }

        return Msg += Epilogue;
    }

    private static string ToHexC(byte[] buffer)
    {
        if (buffer.Length == 0) { return "{}"; }

        const string Preamble = "{ 0x";
        const string Delimiter = ", 0x";
        const string Epilogue = " }";

        StringBuilder HexOut = new StringBuilder(
            Preamble.Length +
            (Delimiter.Length * (buffer.Length - 1)) +
            (2 * buffer.Length) +
            Epilogue.Length
        );

        HexOut.Append(Preamble);
        HexOut.Append(buffer[0].ToString("x2"));
        for (int i = 1; i < buffer.Length; ++i)
        {
            HexOut.Append(Delimiter);
            HexOut.Append(buffer[i].ToString("x2"));
        }
        HexOut.Append(Epilogue);

        return HexOut.ToString();
    }
}

Running this code I get the following performance statistics

Small Message Performance:
Performance for "ToHexA", 00:00:01.3078387
Performance for "ToHexB", 00:00:01.6939201
Performance for "ToHexC", 00:00:01.2997903

Large Message Performance:
Performance for "ToHexA", 00:00:32.5230253
Performance for "ToHexB", 00:04:23.4798762
Performance for "ToHexC", 00:00:56.2404684

I find it surprising that ToHexA (relative to ToHexC) executes faster with a longer message but slower with a shorter message. As I understand it, Replace(), +, and ToLower() all have to perform a create/copy operation because strings are immutable.

At the same time, I suspected the overhead for StringBuilder might make it less suitable for shorter messages yet it executes faster than ToHexA in this situation.

The only thing I expected was the performance hit associated with ToHexB which is kind of an in between worst of both worlds scenario...

So, what is going on with these two methods and their performance characteristics?

Edit to make my intentions with this question more clear

I am not particularly interested in exact performance characteristics of two methods that are closely performant. I am aware this will be different on different devices, architectures, background processes, etc etc. and better testing methods exist to control variables and what not

My purpose in asking this question was to better understand why two noticeably dissimilar (in terms of performance) approaches stack up the way they do. The accepted answer explains the mechanics of ToString in a way that satisfies this question.

One constraint of this question the exact formatting of the output was specific and (we can only muse why, I think it's pretty standard) for some reason not one of the standard output formats in C#/.NET; it was this unique format that led to the question: stacking multiple replace and concatenation operations against StringBuilder

Body:
Your approach C is going to be the fastest approach to concatenation, however you're still generating garbage with each call to ToString("x2").

In addition to that, the ToString overloads that take a format string are miserably slow for something like this, because they first have to process the format string before they can do actual work, and this format string processing gets repeated many many times.  Too bad there isn't a Converter<byte, string> GetToString(string format) that processes the format string once and returns a stateful conversion object.

In any case, byte.ToString() is very easy to avoid here.

static readonly char[] digits = "0123456789abcdef".ToCharArray();
private static string ToHexD(byte[] buffer)
{
    if (buffer.Length == 0) { return "{}"; }

    const string Preamble = "{ 0x";
    const string Delimiter = ", 0x";
    const string Epilogue = " }";

    int expectedLength =
        Preamble.Length +
        (Delimiter.Length * (buffer.Length - 1)) +
        (2 * buffer.Length) +
        Epilogue.Length;
    StringBuilder HexOut = new StringBuilder(expectedLength);

    HexOut.Append(Preamble);
    HexOut.Append(digits[buffer[0] >> 4]).Append(digits[buffer[0] & 0x0F]);
    for (int i = 1; i < buffer.Length; ++i)
    {
        HexOut.Append(Delimiter);
        HexOut.Append(digits[buffer[i] >> 4]).Append(digits[buffer[i] & 0x0F]);
    }
    HexOut.Append(Epilogue);

    return HexOut.ToString();
}

Two calls to Append(char) should also be faster than one to Append(string), though this is much less important than saving the time on format strings.

As expected, this beats the BitConverter-then-Replace() approach handily at all sizes (by just about a factor of two).

For a tiny bit of further increase in speed, the calculations buffer[i] >> 4 and buffer[i] & 0x0f can both be avoided by preparing lead-digit and tail-digit lookup tables of length 256 each.  But bitwise operations are incredibly fast; on many microcontrollers lacking a large L1 data cache, increasing the size of the lookup tables would cost more performance than the bitwise ops.


问:
Hibernate: "Field 'id' doesn't have a default value"
I'm facing what I think is a simple problem with Hibernate, but can't solve it (Hibernate forums being unreachable certainly doesn't help).

I have a simple class I'd like to persist, but keep getting:

```<code>SEVERE: Field 'id' doesn't have a default value
Exception in thread "main" org.hibernate.exception.GenericJDBCException: could not insert: [hibtest.model.Mensagem]
    at org.hibernate.exception.SQLStateConverter.handledNonSpecificException(SQLStateConverter.java:103)
    at org.hibernate.exception.SQLStateConverter.convert(SQLStateConverter.java:91)
    [ a bunch more ]
Caused by: java.sql.SQLException: Field 'id' doesn't have a default value
    [ a bunch more ]
</code>```

The relevant code for the persisted class is:

```<code>package hibtest.model;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.Inheritance;
import javax.persistence.InheritanceType;

@Entity
@Inheritance(strategy = InheritanceType.JOINED)
public class Mensagem  {
    protected Long id;

    protected Mensagem() { }

    @Id
    @GeneratedValue
    public Long getId() {
        return id;
}

    public Mensagem setId(Long id) {
        this.id = id;
        return this;
    }
}
</code>```

And the actual running code is just plain:

```<code>SessionFactory factory = new AnnotationConfiguration()
    .configure()
    .buildSessionFactory();

{
    Session session = factory.openSession();
    Transaction tx = session.beginTransaction();

    Mensagem msg = new Mensagem("YARR!");

    session.save(msg);

    tx.commit();
    session.close();
}
</code>```

I tried some "strategies" within the GeneratedValue annotation but it just doesn't seem to work. Initializing id doesn't help either! (eg Long id = 20L).

Could anyone shed some light?

EDIT 2: confirmed: messing with@GeneratedValue(strategy = GenerationType.XXX) doesn't solve it

SOLVED: recreating the database solved the problem

答: Please check whether the Default value for the column id in particular table.if not make it as default</p>

Body:
I'm facing what I think is a simple problem with Hibernate, but can't solve it (Hibernate forums being unreachable certainly doesn't help).

I have a simple class I'd like to persist, but keep getting:

SEVERE: Field 'id' doesn't have a default value
Exception in thread "main" org.hibernate.exception.GenericJDBCException: could not insert: [hibtest.model.Mensagem]
    at org.hibernate.exception.SQLStateConverter.handledNonSpecificException(SQLStateConverter.java:103)
    at org.hibernate.exception.SQLStateConverter.convert(SQLStateConverter.java:91)
    [ a bunch more ]
Caused by: java.sql.SQLException: Field 'id' doesn't have a default value
    [ a bunch more ]

The relevant code for the persisted class is:

package hibtest.model;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.Inheritance;
import javax.persistence.InheritanceType;

@Entity
@Inheritance(strategy = InheritanceType.JOINED)
public class Mensagem  {
    protected Long id;

    protected Mensagem() { }

    @Id
    @GeneratedValue
    public Long getId() {
        return id;
}

    public Mensagem setId(Long id) {
        this.id = id;
        return this;
    }
}

And the actual running code is just plain:

SessionFactory factory = new AnnotationConfiguration()
    .configure()
    .buildSessionFactory();

{
    Session session = factory.openSession();
    Transaction tx = session.beginTransaction();

    Mensagem msg = new Mensagem("YARR!");

    session.save(msg);

    tx.commit();
    session.close();
}

I tried some "strategies" within the GeneratedValue annotation but it just doesn't seem to work. Initializing id doesn't help either! (eg Long id = 20L).

Could anyone shed some light?

EDIT 2: confirmed: messing with@GeneratedValue(strategy = GenerationType.XXX) doesn't solve it

SOLVED: recreating the database solved the problem

ContentLicense: CC BY-SA 2.5


问:
QGIS - Creating a map that uses live data
I am very new to qgis and qgis server, which I have downloaded the plugins of Openlayers, and qgis2web with qgis 2.18.  As an added note, I have a wordpress site which the map will go into.  I have created a map with multiple layers.  Hooked up database's data to it to populate what midwest state counties people had went to, who had went to those counties, and how many times they have been to that county.  Even colored coded it to show case results.  Now I am ready to put the map on the web.  Here is my Question:  How do you put the map on the web so it will show live data from our database we are using?

I have create a map using qgis2web and exporting it and then use place it within my wordpress's wamp server and was able to display it using an iframe. BUT, I assume it only created that one static instance of the map. If the datbase were to update, it will not show the correct mapping results.  In so, I want to keep the map constantly connected to the database so it will show live data.  How would I show live data and having the map constantly update?  I think I have downloaded the qgis server as well, and hopefully set that up correctly. Was thinking of doing that way as well, but no luck.  Any help where to start, or what to do is appreciated.

答: You might want to consider using Rethinkdb. It pushes JSON to your apps in real time.  https://github.com/rethinkdb/rethinkdb</p>


问:
Encoding Javascript in separate file
I have this script in my view:

```<code>@if(ViewBag.UserName != null)
{
    <script type="text/javascript">
        $(function(){
            var msg = 'Welcome, @Encoder.JavaScriptEncode(ViewBag.UserName, false)!';
            $("#welcome-message").html(msg).hide().show('slow');
        })
    </script>
}
</code>```

However, I want to put the Javascript in a separate file, but when I do that the Html Helper "Encoder" won't work obviously, how would I do a work around so that I still have the Encoder but with the Js in the separate file?

答:
Bundle your javascript files, you should get in a habit of doing this anyway. Bundling helps you manage versions of the files (so that the cached files get refreshed when you update them) and also it can minify the files for you, making your data served faster to the clients.

In your App_Start folder, there is a file called BundleConfig.cs It will look something like this:

```<code>public class BundleConfig
{
    // For more information on bundling, visit http://go.microsoft.com/fwlink/?LinkId=301862
    public static void RegisterBundles(BundleCollection bundles)
    {
        /* =====================================  Scripts  ===================================== */

        bundles.Add(
            new ScriptBundle("~/Script/JQuery/JQuery")
                .Include("~/Scripts/JQuery/jquery-{version}.js")
            );
        bundles.Add(
            new StyleBundle("~/bundles/styles/highslide")
                .Include("~/Highslide/Highslide-ie6.css")
                .Include("~/Highslide/Highslide.css")
            );
    }
}
</code>```

In the example above, we are including a javascript file (version here is automatically populated by the framework) and a css library called Highslide. You can see that in this library we can include multiple files. Also, notice how the files are all in different directories. This allows you to structure your project as you see fit.

Now in order to use this in your view all you have to do is this:

```<code>@Scripts.Render("~/Script/JQuery/JQuery")
@Styles.Render("~/bundles/styles/highslide")
</code>```

With that said, you can now in your view do this:

```<code>@if(ViewBag.UserName != null)
{
    @Scripts.Render("~/Script/JQuery/JQuery")
}
</code>```

As for Html encoder issue, why not simply put a javascript variable inside your JS file and then declare and set the variable in the view before you include the file. Like this:

```<code>@if(ViewBag.UserName != null)
{
    <script type="text/javascript">
        var msg = 'Weclome, ' + @Encoder.JavaScriptEncode(ViewBag.UserName, false)!;
    </script>
    @Scripts.Render("~/Script/MyScript")
}
</code>```

Your script file can then look like this:

```<code>$(function(){
    $("#welcome-message").html(msg).hide().show('slow');
})
</code>```

Title: Encoding Javascript in separate file

Body:
I have this script in my view:

@if(ViewBag.UserName != null)
{

}

However, I want to put the Javascript in a separate file, but when I do that the Html Helper "Encoder" won't work obviously, how would I do a work around so that I still have the Encoder but with the Js in the separate file?

Body:
Bundle your javascript files, you should get in a habit of doing this anyway. Bundling helps you manage versions of the files (so that the cached files get refreshed when you update them) and also it can minify the files for you, making your data served faster to the clients.

In your App_Start folder, there is a file called BundleConfig.cs It will look something like this:

public class BundleConfig
{
    // For more information on bundling, visit http://go.microsoft.com/fwlink/?LinkId=301862
    public static void RegisterBundles(BundleCollection bundles)
    {
        /* =====================================  Scripts  ===================================== */

        bundles.Add(
            new ScriptBundle("~/Script/JQuery/JQuery")
                .Include("~/Scripts/JQuery/jquery-{version}.js")
            );
        bundles.Add(
            new StyleBundle("~/bundles/styles/highslide")
                .Include("~/Highslide/Highslide-ie6.css")
                .Include("~/Highslide/Highslide.css")
            );
    }
}

In the example above, we are including a javascript file (version here is automatically populated by the framework) and a css library called Highslide. You can see that in this library we can include multiple files. Also, notice how the files are all in different directories. This allows you to structure your project as you see fit.

Now in order to use this in your view all you have to do is this:

@Scripts.Render("~/Script/JQuery/JQuery")
@Styles.Render("~/bundles/styles/highslide")

With that said, you can now in your view do this:

@if(ViewBag.UserName != null)
{
    @Scripts.Render("~/Script/JQuery/JQuery")
}

As for Html encoder issue, why not simply put a javascript variable inside your JS file and then declare and set the variable in the view before you include the file. Like this:

@if(ViewBag.UserName != null)
{
    <script type="text/javascript">
        var msg = 'Weclome, ' + @Encoder.JavaScriptEncode(ViewBag.UserName, false)!;
    </script>
    @Scripts.Render("~/Script/MyScript")
}

Your script file can then look like this:

$(function(){
    $("#welcome-message").html(msg).hide().show('slow');
})


问:
How to update data in each loop rather that all loop data shown at once in Android
How would I in this code show each loops data separately rather than it working through the loop then displaying the data (I have tried using timers but didn't work).</p>

```<code>int noStart = 20;
int minus = 5;
private void waitUntil(long time) {
    try {
        Thread.sleep(time);
    }
    catch (InterruptedException e) {
        //This is just here to handle an error without crashing
    }
}
public void number(View view){
        for(int loop = 0;noStart<loop;loop+=5){
            noStart -= minus;
            TextView tx  = (TextView) findViewById(R.id.number);
            tx.setText(String.valueOf(noStart));
            waitUntil(500);
        }
    }
</code>```

答:
You can use handler for this task. This way you main UI won't sleep.

```<code>Handler waitHandler = new Handler();
TextView tx = (TextView) findViewById(R.id.number);
waitHandler.post(waitRunnable);

int counter = 0;
static Runnable waitRunnable = new Runnable() {
    @Override
    public void run() {
        for(int i=0; i<5; i++) {
            tx.post(new Runnable() {
                public void run() {
                    tx.setText(String.valueOf(counter));
                }
            });
        }
        counter+=5;
        Thread.sleep(2000);
    }
};
</code>```

This would set the text on tx TextView with 2 second gap with 5,10,15,20 and 25.

Body:
How would I in this code show each loops data separately rather than it working through the loop then displaying the data (I have tried using timers but didn't work).

int noStart = 20;
int minus = 5;
private void waitUntil(long time) {
    try {
        Thread.sleep(time);
    }
    catch (InterruptedException e) {
        //This is just here to handle an error without crashing
    }
}
public void number(View view){
        for(int loop = 0;noStart<loop;loop+=5){
            noStart -= minus;
            TextView tx  = (TextView) findViewById(R.id.number);
            tx.setText(String.valueOf(noStart));
            waitUntil(500);
        }
    }

Body:
You can use handler for this task. This way you main UI won't sleep.

Handler waitHandler = new Handler();
TextView tx = (TextView) findViewById(R.id.number);
waitHandler.post(waitRunnable);

int counter = 0;
static Runnable waitRunnable = new Runnable() {
    @Override
    public void run() {
        for(int i=0; i<5; i++) {
            tx.post(new Runnable() {
                public void run() {
                    tx.setText(String.valueOf(counter));
                }
            });
        }
        counter+=5;
        Thread.sleep(2000);
    }
};

This would set the text on tx TextView with 2 second gap with 5,10,15,20 and 25.


问:
Change action of back bar button item
I want to be able to change the action of the back bar button item on a specific UIViewController in my navigation controller so that it pops to the root view controller. I've tried the following but they don't work:

```<code>let backButton = UIBarButtonItem(title: nil, style: .plain, target: self, action: #selector(back))
self.navigationItem.backBarButtonItem = backButton
</code>```

and

```<code>self.navigationItem.backBarButtonItem?.action = #selector(back)
</code>```

Any suggestions?

答:
First of all backBarButtonItem action not works because you can only change back button title,take a look question about it here.

Solution

In ViewController from which you want to pop to root ViewController you need to set as a delegate of UINavigationControllerDelegate

```<code>override func viewDidLoad() {
    super.viewDidLoad()

     navigationController?.delegate = self
}
</code>```

and implement UINavigationControllerDelegate this method`

```<code>func navigationController(_ navigationController: UINavigationController, didShow viewController: UIViewController, animated: Bool) {
    if viewController.isKind(of:PreviousViewController.self) {
        navigationController.popToRootViewController(animated: animated)
    }
}
</code>```

If my answer not fit your needs you can check similar question here.

Title: Change action of back bar button item

Body:
I want to be able to change the action of the back bar button item on a specific UIViewController in my navigation controller so that it pops to the root view controller. I've tried the following but they don't work:

let backButton = UIBarButtonItem(title: nil, style: .plain, target: self, action: #selector(back))
self.navigationItem.backBarButtonItem = backButton

and

self.navigationItem.backBarButtonItem?.action = #selector(back)

Any suggestions?

Body:
First of all backBarButtonItem action not works because you can only change back button title,take a look question about it here.

Solution

In ViewController from which you want to pop to root ViewController you need to set as a delegate of UINavigationControllerDelegate

override func viewDidLoad() {
    super.viewDidLoad()

     navigationController?.delegate = self
}

and implement UINavigationControllerDelegate this method`

func navigationController(_ navigationController: UINavigationController, didShow viewController: UIViewController, animated: Bool) {
    if viewController.isKind(of:PreviousViewController.self) {
        navigationController.popToRootViewController(animated: animated)
    }
}

If my answer not fit your needs you can check similar question here.


问:
Randomly selecting from Pandas groups with equal probability -- unexpected behavior
I have 12 unique groups that I am trying to randomly sample from, each with a different number of observations. I want to randomly sample from the entire population (dataframe) with each group having the same probability of being selected from. The simplest example of this would be a dataframe with 2 groups.

```<code>    groups  probability
0       a       0.25
1       a       0.25
2       b       0.5
</code>```

using np.random.choice(df['groups'], p=df['probability'], size=100) Each iteration will now have a 50% chance of selecting group a and a 50% chance of selecting group b

To come up with the probabilities I used the formula:

```<code>(1. / num_groups) / size_of_groups
</code>```

or in Python:

```<code>num_groups = len(df['groups'].unique())  # 2
size_of_groups = df.groupby('label').size()  # {a: 2, b: 1}
(1. / num_groups) / size_of_groups
</code>```

Which returns

```<code>    groups
a    0.25
b    0.50
</code>```

This works great until I get past 10 unique groups, after which I start getting weird distributions. Here is a small example:

```<code>np.random.seed(1234)

group_size = 12
groups = np.arange(group_size)

probs = np.random.uniform(size=group_size)
probs = probs / probs.sum()

g = np.random.choice(groups, size=10000, p=probs)
df = pd.DataFrame({'groups': g})

prob_map = ((1. / len(df['groups'].unique())) / df.groupby('groups').size()).to_dict()

df['probability'] = df['groups'].map(prob_map)

plt.hist(np.random.choice(df['groups'], p=df['probability'], size=10000, replace=True))
plt.xticks(np.arange(group_size))
plt.show()
</code>```

I would expect a fairly uniform distribution with a large enough sample size, but I am getting these wings when the number of groups is 11+. If I change the group_size variable to 10 or lower, I do get the desired uniform distribution.

I can't tell if the problem is with my formula for calculating the probabilities, or possibly a floating point precision problem? Anyone know a better way to accomplish this, or a fix for this example?

Thanks in advance!

答:
you are using hist which defaults to 10 bins...

```<code>plt.rcParams['hist.bins']

10
</code>```

pass group_size as the bins parameter.

```<code>plt.hist(
    np.random.choice(df['groups'], p=df['probability'], size=10000, replace=True),
    bins=group_size)
</code>```

Body:
I have 12 unique groups that I am trying to randomly sample from, each with a different number of observations. I want to randomly sample from the entire population (dataframe) with each group having the same probability of being selected from. The simplest example of this would be a dataframe with 2 groups.

    groups  probability
0       a       0.25
1       a       0.25
2       b       0.5

using np.random.choice(df['groups'], p=df['probability'], size=100) Each iteration will now have a 50% chance of selecting group a and a 50% chance of selecting group b

To come up with the probabilities I used the formula:

(1. / num_groups) / size_of_groups

or in Python:

num_groups = len(df['groups'].unique())  # 2
size_of_groups = df.groupby('label').size()  # {a: 2, b: 1}
(1. / num_groups) / size_of_groups

Which returns

    groups
a    0.25
b    0.50

This works great until I get past 10 unique groups, after which I start getting weird distributions. Here is a small example:

np.random.seed(1234)

group_size = 12
groups = np.arange(group_size)

probs = np.random.uniform(size=group_size)
probs = probs / probs.sum()

g = np.random.choice(groups, size=10000, p=probs)
df = pd.DataFrame({'groups': g})

prob_map = ((1. / len(df['groups'].unique())) / df.groupby('groups').size()).to_dict()

df['probability'] = df['groups'].map(prob_map)

plt.hist(np.random.choice(df['groups'], p=df['probability'], size=10000, replace=True))
plt.xticks(np.arange(group_size))
plt.show()

I would expect a fairly uniform distribution with a large enough sample size, but I am getting these wings when the number of groups is 11+. If I change the group_size variable to 10 or lower, I do get the desired uniform distribution.

I can't tell if the problem is with my formula for calculating the probabilities, or possibly a floating point precision problem? Anyone know a better way to accomplish this, or a fix for this example?

Thanks in advance!

Body:
you are using hist which defaults to 10 bins...

plt.rcParams['hist.bins']

10

pass group_size as the bins parameter.

plt.hist(
    np.random.choice(df['groups'], p=df['probability'], size=10000, replace=True),
    bins=group_size)


问:
How to open log with DEBUG level for tensorflow c++ core, not python client
I want to see the debug info for tensorflow c++ core, not python client. TensorFlow config INFO level default. How to modify the level to DEBUG.</p>

答:
There are two types of logging. The INFO/WARNING/etc. logging statements are displayed by default. VLOG(n) statements are only displayed for n=0 by default. For more verbose logging, there is an environmental variable:

```<code>export TF_CPP_MIN_VLOG_LEVEL=2
</code>```

See https://github.com/tensorflow/tensorflow/pull/6375 for details.

This gets you gorgeous messages such as:

```<code>2017-07-07 14:26:43.712063: I tensorflow/core/common_runtime/executor.cc:1557] Process node: 3 step 1 _retval_Const_0_0 = _Retval[T=DT_INT32, index=0, _device="/job:localhost/replica:0/task:0/cpu:0"](Const) is dead: 0
2017-07-07 14:26:43.712074: I tensorflow/core/common_runtime/executor.cc:2345] Delete frame
</code>```

Body:
There are two types of logging. The INFO/WARNING/etc. logging statements are displayed by default. VLOG(n) statements are only displayed for n=0 by default. For more verbose logging, there is an environmental variable:

export TF_CPP_MIN_VLOG_LEVEL=2

See https://github.com/tensorflow/tensorflow/pull/6375 for details.

This gets you gorgeous messages such as:

2017-07-07 14:26:43.712063: I tensorflow/core/common_runtime/executor.cc:1557] Process node: 3 step 1 _retval_Const_0_0 = _Retval[T=DT_INT32, index=0, _device="/job:localhost/replica:0/task:0/cpu:0"](Const) is dead: 0
2017-07-07 14:26:43.712074: I tensorflow/core/common_runtime/executor.cc:2345] Delete frame


问:
How to implement foldl using foldr in Erlang?
This is what I thought, any options for a better thought?</p>

```<code>foldl(Function,Factor,List) -> lists:foldr(fun(X,Acc) -> Acc ++ [X] end,[],lists:foldr(Function,Factor,List)).
</code>```

答: I recommend to read the Code for stdlib of Erlang/OTP.</p>

Body:
This is what I thought, any options for a better thought?

foldl(Function,Factor,List) -> lists:foldr(fun(X,Acc) -> Acc ++ [X] end,[],lists:foldr(Function,Factor,List)).


问:
Serialize multiple models and send all in one json response django rest framework
This question is being asked to expand and fill in the holes from this one: Return results from multiple models with Django REST Framework

my goal is to return a json object that I will use to dynamically populate the options in various select statements in my html code.

so I want  to grab a attribute from model a, another from model b etc

then I want all the values from attribute a and b and c etc

to be in a value as a JSON array to a key so

```<code>json = {
    modelA: {'atter1, atter2, atter3}
    modelB: {'atter1, atter2, atter3}
    model..:{you get the point}
}
</code>```

this part from the post referenced above makes sense:

```<code>class TimelineViewSet(viewsets.ModelViewSet):
    """
    API endpoint that lists all tweet/article objects in rev-chrono.
    """
    queryset = itertools.chain(Tweet.objects.all(), Article.objects.all())
    serializer_class = TimelineSerializer
</code>```

what doesn't is this:

```<code>class TimelineSerializer(serializers.Serializer):
    pk = serializers.Field()
    title = serializers.CharField()
    author = serializers.RelatedField()
    pub_date = serializers.DateTimeField()
</code>```

how do I set the the seperate model attributes to the correct json key?

I assume its something similar to a serializer relation but these values aren't related to eachother via onetoone, onetomany, or many to many. I just want to grab all this info at once instead of creating an api for each value.

I am a lost little girl and I am asking you to help me find my way home.

答:
You'll find things easier in Django REST Framework if you design your response format rationally.

It seems a bit vague at the moment, but I would suggest something like:

```<code>{
    "tweets": [
        {"tweet_attr_A": value_1, ...},  // first tweet
        {"tweet_attr_A": value_2, ...},  // second tweet
        //etc
    ],
    "articles": [
        {"id": 1, ...},  // first article
        {"id": 2, ...},  // second article
        //etc
    ]
}
</code>```

We can express this with three serializers, like:

```<code>class TweetSerializer(serializers.ModelSerializer):
    class Meta:
        model = Tweet

class ArticleSerializer(serializers.ModelSerializer):
    class Meta:
        model = Article

class TimelineSerializer(serializers.Serializer):
    tweets = TweetSerializer(many=True)
    articles = ArticleSerializer(many=True)
</code>```

http://www.django-rest-framework.org/api-guide/serializers/#dealing-with-nested-objects

Then, because we're using more than one model, it's easiest just to define your own custom viewset rather than trying to shoe-horn this into DRF's magic ModelViewSet type.

http://www.django-rest-framework.org/api-guide/viewsets/#example

First we need an object type to pass into our TimelineSerializer. It should have two attributes: tweets and articles

```<code>from collections import namedtuple

Timeline = namedtuple('Timeline', ('tweets', 'articles'))
</code>```

Then we'll define the custom viewset to fetch the tweets and articles, instantiate a Timeline object and return the TimelineSerializer data:

```<code>class TimelineViewSet(viewsets.ViewSet):
    """
    A simple ViewSet for listing the Tweets and Articles in your Timeline.
    """
    def list(self, request):
        timeline = Timeline(
            tweets=Tweet.objects.all(),
            articles=Article.objects.all(),
        )
        serializer = TimelineSerializer(timeline)
        return Response(serializer.data)
</code>```

ContentLicense: CC BY-SA 4.0

Body:
This question is being asked to expand and fill in the holes from this one: Return results from multiple models with Django REST Framework

my goal is to return a json object that I will use to dynamically populate the options in various select statements in my html code.

so I want  to grab a attribute from model a, another from model b etc

then I want all the values from attribute a and b and c etc

to be in a value as a JSON array to a key so

json = {
    modelA: {'atter1, atter2, atter3}
    modelB: {'atter1, atter2, atter3}
    model..:{you get the point}
}

this part from the post referenced above makes sense:

class TimelineViewSet(viewsets.ModelViewSet):
    """
    API endpoint that lists all tweet/article objects in rev-chrono.
    """
    queryset = itertools.chain(Tweet.objects.all(), Article.objects.all())
    serializer_class = TimelineSerializer

what doesn't is this:

class TimelineSerializer(serializers.Serializer):
    pk = serializers.Field()
    title = serializers.CharField()
    author = serializers.RelatedField()
    pub_date = serializers.DateTimeField()

how do I set the the seperate model attributes to the correct json key?

I assume its something similar to a serializer relation but these values aren't related to eachother via onetoone, onetomany, or many to many. I just want to grab all this info at once instead of creating an api for each value.

I am a lost little girl and I am asking you to help me find my way home.

Body:
You'll find things easier in Django REST Framework if you design your response format rationally.

It seems a bit vague at the moment, but I would suggest something like:

{
    "tweets": [
        {"tweet_attr_A": value_1, ...},  // first tweet
        {"tweet_attr_A": value_2, ...},  // second tweet
        //etc
    ],
    "articles": [
        {"id": 1, ...},  // first article
        {"id": 2, ...},  // second article
        //etc
    ]
}

We can express this with three serializers, like:

class TweetSerializer(serializers.ModelSerializer):
    class Meta:
        model = Tweet

class ArticleSerializer(serializers.ModelSerializer):
    class Meta:
        model = Article

class TimelineSerializer(serializers.Serializer):
    tweets = TweetSerializer(many=True)
    articles = ArticleSerializer(many=True)

http://www.django-rest-framework.org/api-guide/serializers/#dealing-with-nested-objects

Then, because we're using more than one model, it's easiest just to define your own custom viewset rather than trying to shoe-horn this into DRF's magic ModelViewSet type.

http://www.django-rest-framework.org/api-guide/viewsets/#example

First we need an object type to pass into our TimelineSerializer. It should have two attributes: tweets and articles

from collections import namedtuple

Timeline = namedtuple('Timeline', ('tweets', 'articles'))

Then we'll define the custom viewset to fetch the tweets and articles, instantiate a Timeline object and return the TimelineSerializer data:

class TimelineViewSet(viewsets.ViewSet):
    """
    A simple ViewSet for listing the Tweets and Articles in your Timeline.
    """
    def list(self, request):
        timeline = Timeline(
            tweets=Tweet.objects.all(),
            articles=Article.objects.all(),
        )
        serializer = TimelineSerializer(timeline)
        return Response(serializer.data)


问:
invalid name @angular/common : npm
I am trying Ionic2, but am getting some error while trying to install default npm packages for Ionic2. I tried to run the following command and getting the error below:

npm install @angular/common like here

Also tried this solution but getting the same error.

package.json file content:

```<code>{
  "dependencies": {
    "@angular/compiler": "^2.0.0-rc.1",
    "@angular/core": "^2.0.0-rc.1",
    "@angular/http": "^2.0.0-rc.1",
    "@angular/platform-browser": "^2.0.0-rc.1",
    "@angular/platform-browser-dynamic": "^2.0.0-rc.1",
    "@angular/router": "^2.0.0-rc.1",
    "es6-shim": "^0.35.0",
    "ionic-angular": "2.0.0-beta.7",
    "ionic-native": "^1.1.0",
    "ionicons": "3.0.0",
    "reflect-metadata": "^0.1.3",
    "rxjs": "5.0.0-beta.6",
    "zone.js": "^0.6.12"
  },
  "devDependencies": {
    "del": "2.2.0",
    "gulp": "3.9.1",
    "gulp-watch": "4.3.5",
    "ionic-gulp-browserify-es2015": "^1.1.0",
    "ionic-gulp-fonts-copy": "^1.0.0",
    "ionic-gulp-html-copy": "^1.0.0",
    "ionic-gulp-sass-build": "^1.0.0",
    "ionic-gulp-scripts-copy": "^2.0.0",
    "run-sequence": "1.1.5"
  }
}
</code>```

答:
try this command </p>

```<code>npm install -g npm
</code>```

Title: invalid name @angular/common : npm

Body:
I am trying Ionic2, but am getting some error while trying to install default npm packages for Ionic2. I tried to run the following command and getting the error below:

npm install @angular/common like here

Also tried this solution but getting the same error.

package.json file content:

{
  "dependencies": {
    "@angular/compiler": "^2.0.0-rc.1",
    "@angular/core": "^2.0.0-rc.1",
    "@angular/http": "^2.0.0-rc.1",
    "@angular/platform-browser": "^2.0.0-rc.1",
    "@angular/platform-browser-dynamic": "^2.0.0-rc.1",
    "@angular/router": "^2.0.0-rc.1",
    "es6-shim": "^0.35.0",
    "ionic-angular": "2.0.0-beta.7",
    "ionic-native": "^1.1.0",
    "ionicons": "3.0.0",
    "reflect-metadata": "^0.1.3",
    "rxjs": "5.0.0-beta.6",
    "zone.js": "^0.6.12"
  },
  "devDependencies": {
    "del": "2.2.0",
    "gulp": "3.9.1",
    "gulp-watch": "4.3.5",
    "ionic-gulp-browserify-es2015": "^1.1.0",
    "ionic-gulp-fonts-copy": "^1.0.0",
    "ionic-gulp-html-copy": "^1.0.0",
    "ionic-gulp-sass-build": "^1.0.0",
    "ionic-gulp-scripts-copy": "^2.0.0",
    "run-sequence": "1.1.5"
  }
}

Body:
try this command

npm install -g npm


问:
Redirect php query with hash using htaccess regex
I'm trying to redirect URLs with a half of MD5 part inside a PHP query and one base64 encoded string after a '#' symbol to a new directory using a .htaccess Rewrite Rule.

URL examples:

A) /?7027fcbbc2a1ccb9#N61/vMSRNqYQBhb+DcaSfv2YGW1HiBbSpMUoSHrtxok=

B) /index.php?f9c4bb60426abaf9#RBmcvFnf5+wFwP54IM8f7pUSvmPn2aOFm1Z6LbIOFK8=

The URL contains two parts:

A half MD5 hash (16 a-f and 0-9 hash)

Followed with one "#" then a base64 encoded string

I'm trying to ask if the URL containts the 16 alphanumeric chars, and if yes, I want to redirect the whole URL (including the #hash followed info) to a new directory.

I'm trying with this Rule:

```<code>RewriteRule ^\\?[a-f0-9]{16}$ /newdirectory/$1 [L]
</code>```

But of course it doesn't work. What is the correct regex for the redirection? Thank you so much!

答:
What you have in your URL is actually a query string not request URI. You can use this rule in your site root .htaccess:</p>

```<code>RewriteEngine On

RewriteCond %{QUERY_STRING} ^[a-f0-9]{16}$ [NC]
RewriteRule ^/?$ /newdir/ [L,R=301,NE]
</code>```

Body:
I'm trying to redirect URLs with a half of MD5 part inside a PHP query and one base64 encoded string after a '#' symbol to a new directory using a .htaccess Rewrite Rule.

URL examples:

A) /?7027fcbbc2a1ccb9#N61/vMSRNqYQBhb+DcaSfv2YGW1HiBbSpMUoSHrtxok=

B) /index.php?f9c4bb60426abaf9#RBmcvFnf5+wFwP54IM8f7pUSvmPn2aOFm1Z6LbIOFK8=

The URL contains two parts:

A half MD5 hash (16 a-f and 0-9 hash)

Followed with one "#" then a base64 encoded string

I'm trying to ask if the URL containts the 16 alphanumeric chars, and if yes, I want to redirect the whole URL (including the #hash followed info) to a new directory.

I'm trying with this Rule:

RewriteRule ^\\?[a-f0-9]{16}$ /newdirectory/$1 [L]

But of course it doesn't work. What is the correct regex for the redirection? Thank you so much!

Body:
What you have in your URL is actually a query string not request URI. You can use this rule in your site root .htaccess:

RewriteEngine On

RewriteCond %{QUERY_STRING} ^[a-f0-9]{16}$ [NC]
RewriteRule ^/?$ /newdir/ [L,R=301,NE]