问:
Authorize attribute failure redirects to logout in API rather than returns 401
I'm using Identity Server 4. When my API receives a token expiry (IDX10223: Lifetime validation failed which is expected) at the point where it validates access to an API, it appears to redirect to the logout page rather than just return 401. I'm trying to find out where this is controlled since this results in the client being sent the HTML for the logout page which isn't desirable.

The API code has:

```<code>[Authorize]
public IActionResult API() {
}
</code>```

The API and IdentityServer also run on the same server. Is this a function of AuthorizeFilter and is the answer to create a custom authorize attribute?

Relevant parts of the log file

```<code>2017-08-02T10:27:28.8366946+01:00 0HL6PFUCMUMHG [INF] Request starting HTTP/1.1 GET http://localhost:55742/v3.0/User/recent?conversationId=21680095&sortFlag=2 (e5be5b71)
2017-08-02T10:27:28.9641697+01:00 0HL6PFUCMUMHG [INF] Failed to validate the token "eyJhbGciOiJSUzI1NiIsImtpZCI6IjA3NTMyYzdlZDVmZjc1MGQ5YWE0ZjYyNjQ0YjczMjY5IiwidHlwIjoiSldUIn0.eyJuYmYiOjE1MDE2NjIxNDUsImV4cCI6MTUwMTY2NTc0NSwiaXNzIjoiaHR0cDovL2xvY2FsaG9zdDo1NTc0MiIsImF1ZCI6WyJodHRwOi8vbG9jYWxob3N0OjU1NzQyL3Jlc291cmNlcyIsImNpeEFwaTMiXSwiY2xpZW50X2lkIjoiY2l4Rm9ydW1zRGV2Iiwic3ViIjoic3BhbG1lciIsImF1dGhfdGltZSI6MTUwMTY2MDk0MSwiaWRwIjoibG9jYWwiLCJyb2xlIjoiZnVsbCIsInNjb3BlIjpbIm9wZW5pZCIsInByb2ZpbGUiLCJjaXhBcGkzIiwib2ZmbGluZV9hY2Nlc3MiXSwiYW1yIjpbInB3ZCJdfQ.jcGNgeGSY72SRODAnWQWJI5XXRZaM0SSO3DAFp7QQeDzXbxNDIgkDqRUkQAJoGU52C4svk6DQwKGrsFDATzI52g8iuD8JAugaOen4DfEx_g6CP3JdImUn6aT379rjH5_d1ePXVaSwBMU9L3q1mkA20EotWA6mcIdYZw54Xvsp-TGnWbMKAL-yv8_Vh7gQn-_vBy7sfTB4s_37SZtSmpi7ig7WPa2XbAVwNN_vmApL0ZgP8QsotyTiIDEloXov5XYkAe7JvunpHyaATg8RCirNu6zp38yBHzkJ0IJh7BJZ47IDImE-AxfvZY8_EW6m1LJosVjgrjSnG5nIFu_mPvASA". (f3081a27)
Microsoft.IdentityModel.Tokens.SecurityTokenExpiredException: IDX10223: Lifetime validation failed. The token is expired.
ValidTo: '08/02/2017 09:22:25'
Current time: '08/02/2017 09:27:28'.
at Microsoft.IdentityModel.Tokens.Validators.ValidateLifetime(Nullable1 notBefore, Nullable1 expires, SecurityToken securityToken, TokenValidationParameters validationParameters)
at System.IdentityModel.Tokens.Jwt.JwtSecurityTokenHandler.ValidateLifetime(Nullable1 notBefore, Nullable1 expires, JwtSecurityToken securityToken, TokenValidationParameters validationParameters)
at System.IdentityModel.Tokens.Jwt.JwtSecurityTokenHandler.ValidateTokenPayload(JwtSecurityToken jwt, TokenValidationParameters validationParameters)
at System.IdentityModel.Tokens.Jwt.JwtSecurityTokenHandler.ValidateToken(String token, TokenValidationParameters validationParameters, SecurityToken& validatedToken)
at Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerHandler.d__1.MoveNext()
2017-08-02T10:27:28.9701726+01:00 0HL6PFUCMUMHG [INF] "Bearer" was not authenticated. Failure message: "IDX10223: Lifetime validation failed. The token is expired.
ValidTo: '08/02/2017 09:22:25'
Current time: '08/02/2017 09:27:28'." (48071232)
2017-08-02T10:27:28.9761723+01:00 0HL6PFUCMUMHG [INF] Authorization failed for user: null. (a4ab1676)
2017-08-02T10:27:28.9831738+01:00 0HL6PFUCMUMHG [INF] Authorization failed for the request at filter '"Microsoft.AspNetCore.Mvc.Authorization.AuthorizeFilter"'. (8b6446cb)
2017-08-02T10:27:28.9951674+01:00 0HL6PFUCMUMHG [INF] Executing ChallengeResult with authentication schemes ([]). (f3dca807)
2017-08-02T10:27:29.0231698+01:00 0HL6PFUCMUMHG [INF] AuthenticationScheme: "Bearer" was challenged. (d45f1f38)
2017-08-02T10:27:29.0281709+01:00 0HL6PFUCMUMHG [INF] Executed action "API3.Controllers.UserController.Recent (API3)" in 52.7575ms (afa2e885)
2017-08-02T10:27:29.0371704+01:00 0HL6PFUCMUMHG [INF] Request finished in 200.5214ms 401 (15c52c40)
2017-08-02T10:27:29.1141679+01:00 0HL6PFUCMUMHH [INF] Request starting HTTP/1.1 OPTIONS http://localhost:55742/connect/endsession?post_logout_redirect_uri=http%3A%2F%2Flocalhost%3A62784%2Fsignout-callback-oidc&id_token_hint=eyJhbGciOiJSUzI1NiIsImtpZCI6IjA3NTMyYzdlZDVmZjc1MGQ5YWE0ZjYyNjQ0YjczMjY5IiwidHlwIjoiSldUIn0.eyJuYmYiOjE1MDE2NjIxNDUsImV4cCI6MTUwMTY2MjQ0NSwiaXNzIjoiaHR0cDovL2xvY2FsaG9zdDo1NTc0MiIsImF1ZCI6ImNpeEZvcnVtc0RldiIsIm5vbmNlIjoiNjM2MzcyNTg5NDM0Njg3NzM4LlpUbGxaRGxpTVdZdE5EVmlZUzAwWkdNeExXRTNOVFl0WldRM1pUY3lZV0ptTVRZelpHRTBNRGd4WmpjdFl6QTRPQzAwTldZMUxUa3daVGt0TjJRMU1UQmhNR0ZpWW1NNCIsImlhdCI6MTUwMTY2MjE0NSwiYXRfaGFzaCI6ImFXMFB6eEdPVVAza1pIcGFHR1RYLVEiLCJzaWQiOiI3NDdhODA5ZTE5NjZmOGY5Y2U5ZWExZDcwYmQ3Y2M2MSIsInN1YiI6InNwYWxtZXIiLCJhdXRoX3RpbWUiOjE1MDE2NjA5NDEsImlkcCI6ImxvY2FsIiwiYW1yIjpbInB3ZCJdfQ.btHqukWt1stWHFyUCqwJu8PS9e9hPUH2N6oqCqtpp_bjalPK5Ub-4uJTwp0_CYiuPt-Atl_XI1H3BI9p7ENIu6YHLgB6Hyr1l7G6e8S64HMsaKTEcQaSSVjUWwF4U1IV6YFVuZ5VjLR-M5FK4mYIcT-xsdDF4kkJTvs1lCqldeg9exLTnca8FsC3E__eIjIhRd8oYHhMUazkQ34FsyqYFESAgRHqIl9IITfeoPYNFMRtuz3P09zCKPCSSrg9t-0UecJ5ccwf1cTfU3tLv9j1rknBYjFjeDah38dHhJLjAEfH5r_fytKEr44kwB2xeu030x1vw1vDPiHi3fbRc72pGA&state=CfDJ8AdS2WFU56FEplHeLVGDdfl3IlfIaWI00-bPygyle9qi0Hnqf-jsZ5pqtwO-dVU2ujH5OkhQRpQyn0OpsXCRVVeul2QTBwi1q40y1QwiXTuftRutLkxADzyrjqrzshvHz479t13919PZIj09GABirToAXtrMUXHu6J0eExJcF8eB (e5be5b71)
2017-08-02T10:27:29.1401709+01:00 0HL6PFUCMUMHH [INF] Request finished in 33.4959ms 204 (15c52c40)
2017-08-02T10:27:29.1501730+01:00 0HL6PFUCMUMHI [INF] Request starting HTTP/1.1 GET http://localhost:55742/connect/endsession?post_logout_redirect_uri=http%3A%2F%2Flocalhost%3A62784%2Fsignout-callback-oidc&id_token_hint=eyJhbGciOiJSUzI1NiIsImtpZCI6IjA3NTMyYzdlZDVmZjc1MGQ5YWE0ZjYyNjQ0YjczMjY5IiwidHlwIjoiSldUIn0.eyJuYmYiOjE1MDE2NjIxNDUsImV4cCI6MTUwMTY2MjQ0NSwiaXNzIjoiaHR0cDovL2xvY2FsaG9zdDo1NTc0MiIsImF1ZCI6ImNpeEZvcnVtc0RldiIsIm5vbmNlIjoiNjM2MzcyNTg5NDM0Njg3NzM4LlpUbGxaRGxpTVdZdE5EVmlZUzAwWkdNeExXRTNOVFl0WldRM1pUY3lZV0ptTVRZelpHRTBNRGd4WmpjdFl6QTRPQzAwTldZMUxUa3daVGt0TjJRMU1UQmhNR0ZpWW1NNCIsImlhdCI6MTUwMTY2MjE0NSwiYXRfaGFzaCI6ImFXMFB6eEdPVVAza1pIcGFHR1RYLVEiLCJzaWQiOiI3NDdhODA5ZTE5NjZmOGY5Y2U5ZWExZDcwYmQ3Y2M2MSIsInN1YiI6InNwYWxtZXIiLCJhdXRoX3RpbWUiOjE1MDE2NjA5NDEsImlkcCI6ImxvY2FsIiwiYW1yIjpbInB3ZCJdfQ.btHqukWt1stWHFyUCqwJu8PS9e9hPUH2N6oqCqtpp_bjalPK5Ub-4uJTwp0_CYiuPt-Atl_XI1H3BI9p7ENIu6YHLgB6Hyr1l7G6e8S64HMsaKTEcQaSSVjUWwF4U1IV6YFVuZ5VjLR-M5FK4mYIcT-xsdDF4kkJTvs1lCqldeg9exLTnca8FsC3E__eIjIhRd8oYHhMUazkQ34FsyqYFESAgRHqIl9IITfeoPYNFMRtuz3P09zCKPCSSrg9t-0UecJ5ccwf1cTfU3tLv9j1rknBYjFjeDah38dHhJLjAEfH5r_fytKEr44kwB2xeu030x1vw1vDPiHi3fbRc72pGA&state=CfDJ8AdS2WFU56FEplHeLVGDdfl3IlfIaWI00-bPygyle9qi0Hnqf-jsZ5pqtwO-dVU2ujH5OkhQRpQyn0OpsXCRVVeul2QTBwi1q40y1QwiXTuftRutLkxADzyrjqrzshvHz479t13919PZIj09GABirToAXtrMUXHu6J0eExJcF8eB (e5be5b71)
2017-08-02T10:27:29.1591678+01:00 0HL6PFUCMUMHI [DBG] CORS request made for path: "/connect/endsession" from origin: "http://localhost:62784" but rejected because invalid CORS path (2bd60464)
2017-08-02T10:27:29.1601680+01:00 0HL6PFUCMUMHI [DBG] Request path "/connect/endsession" matched to endpoint type EndSession (b74352b0)
2017-08-02T10:27:29.1611695+01:00 0HL6PFUCMUMHI [DBG] Mapping found for endpoint: EndSession, creating handler: "IdentityServer4.Endpoints.EndSessionEndpoint" (67a7e1a4)
2017-08-02T10:27:29.1671697+01:00 0HL6PFUCMUMHI [INF] Invoking IdentityServer endpoint: "IdentityServer4.Endpoints.EndSessionEndpoint" for "/connect/endsession" (f7642de5)
2017-08-02T10:27:29.1791689+01:00 0HL6PFUCMUMHI [DBG] Processing signout request for "anonymous" (02b52180)
2017-08-02T10:27:29.1871689+01:00 0HL6PFUCMUMHI [DBG] Start end session request validation (8af7241a)
2017-08-02T10:27:29.1931688+01:00 0HL6PFUCMUMHI [DBG] Start identity token validation (5fcce1be)
2017-08-02T10:27:29.1961697+01:00 0HL6PFUCMUMHI [DBG] Client found: "myclient" / "ClientName" (bb32274b)
2017-08-02T10:27:29.2021686+01:00 0HL6PFUCMUMHI [DBG] Calling into custom token validator: "IdentityServer4.Validation.DefaultCustomTokenValidator" (467e6def)
2017-08-02T10:27:29.2091719+01:00 0HL6PFUCMUMHI [DBG] Token validation success
"{
"ClientId": "myclient",
"ClientName": "ClientName",
"ValidateLifetime": false,
"Claims": {
"nbf": 1501662145,
"exp": 1501662445,
"iss": "http://localhost:55742\",
"aud": "myclient",
"nonce": "636372589434687738.ZTllZDliMWYtNDViYS00ZGMxLWE3NTYtZWQ3ZTcyYWJmMTYzZGE0MDgxZjctYzA4OC00NWY1LTkwZTktN2Q1MTBhMGFiYmM4",
"iat": 1501662145,
"at_hash": "aW0PzxGOUP3kZHpaGGTX-Q",
"sid": "747a809e1966f8f9ce9ea1d70bd7cc61",
"sub": "spalmer",
"auth_time": 1501660941,
"idp": "local",
"amr": "pwd"
}
}" (997b5fde)
2017-08-02T10:27:29.2361731+01:00 0HL6PFUCMUMHI [INF] End session request validation success
"{
"ClientId": "myclient",
"ClientName": "ClientName",
"SubjectId": "unknown",
"PostLogOutUri": "http://localhost:62784/signout-callback-oidc\",
"State": "CfDJ8AdS2WFU56FEplHeLVGDdfl3IlfIaWI00-bPygyle9qi0Hnqf-jsZ5pqtwO-dVU2ujH5OkhQRpQyn0OpsXCRVVeul2QTBwi1q40y1QwiXTuftRutLkxADzyrjqrzshvHz479t13919PZIj09GABirToAXtrMUXHu6J0eExJcF8eB",
"Raw": {
"post_logout_redirect_uri": "http://localhost:62784/signout-callback-oidc\",
"id_token_hint": "eyJhbGciOiJSUzI1NiIsImtpZCI6IjA3NTMyYzdlZDVmZjc1MGQ5YWE0ZjYyNjQ0YjczMjY5IiwidHlwIjoiSldUIn0.eyJuYmYiOjE1MDE2NjIxNDUsImV4cCI6MTUwMTY2MjQ0NSwiaXNzIjoiaHR0cDovL2xvY2FsaG9zdDo1NTc0MiIsImF1ZCI6ImNpeEZvcnVtc0RldiIsIm5vbmNlIjoiNjM2MzcyNTg5NDM0Njg3NzM4LlpUbGxaRGxpTVdZdE5EVmlZUzAwWkdNeExXRTNOVFl0WldRM1pUY3lZV0ptTVRZelpHRTBNRGd4WmpjdFl6QTRPQzAwTldZMUxUa3daVGt0TjJRMU1UQmhNR0ZpWW1NNCIsImlhdCI6MTUwMTY2MjE0NSwiYXRfaGFzaCI6ImFXMFB6eEdPVVAza1pIcGFHR1RYLVEiLCJzaWQiOiI3NDdhODA5ZTE5NjZmOGY5Y2U5ZWExZDcwYmQ3Y2M2MSIsInN1YiI6InNwYWxtZXIiLCJhdXRoX3RpbWUiOjE1MDE2NjA5NDEsImlkcCI6ImxvY2FsIiwiYW1yIjpbInB3ZCJdfQ.btHqukWt1stWHFyUCqwJu8PS9e9hPUH2N6oqCqtpp_bjalPK5Ub-4uJTwp0_CYiuPt-Atl_XI1H3BI9p7ENIu6YHLgB6Hyr1l7G6e8S64HMsaKTEcQaSSVjUWwF4U1IV6YFVuZ5VjLR-M5FK4mYIcT-xsdDF4kkJTvs1lCqldeg9exLTnca8FsC3E__eIjIhRd8oYHhMUazkQ34FsyqYFESAgRHqIl9IITfeoPYNFMRtuz3P09zCKPCSSrg9t-0UecJ5ccwf1cTfU3tLv9j1rknBYjFjeDah38dHhJLjAEfH5r_fytKEr44kwB2xeu030x1vw1vDPiHi3fbRc72pGA",
"state": "CfDJ8AdS2WFU56FEplHeLVGDdfl3IlfIaWI00-bPygyle9qi0Hnqf-jsZ5pqtwO-dVU2ujH5OkhQRpQyn0OpsXCRVVeul2QTBwi1q40y1QwiXTuftRutLkxADzyrjqrzshvHz479t13919PZIj09GABirToAXtrMUXHu6J0eExJcF8eB"
}
}" (8a893fca)
2017-08-02T10:27:29.2381718+01:00 0HL6PFUCMUMHI [DBG] Success validating end session request from "myclient" (e682f926)
2017-08-02T10:27:29.3242185+01:00 0HL6PFUCMUMHI [INF] Request finished in 176.7054ms 302 (15c52c40)
2017-08-02T10:27:29.3301739+01:00 0HL6PFUCMUMHJ [INF] Request starting HTTP/1.1 OPTIONS http://localhost:55742/account/logout?logoutId=ee47b7921636973f6c169a7c7472f7fc (e5be5b71)
2017-08-02T10:27:29.3351682+01:00 0HL6PFUCMUMHJ [INF] Request finished in 8.0939ms 204 (15c52c40)
2017-08-02T10:27:29.3421709+01:00 0HL6PFUCMUMHK [INF] Request starting HTTP/1.1 GET http://localhost:55742/account/logout?logoutId=ee47b7921636973f6c169a7c7472f7fc (e5be5b71)
2017-08-02T10:27:29.3431703+01:00 0HL6PFUCMUMHK [DBG] CORS request made for path: "/account/logout" from origin: "http://localhost:62784" but rejected because invalid CORS path (2bd60464)
2017-08-02T10:27:29.3531756+01:00 0HL6PFUCMUMHK [INF] "Bearer" was not authenticated. Failure message: "No token found." (48071232)
2017-08-02T10:27:29.4273094+01:00 0HL6PFUCMUMHK [INF] Executing action method "API3.Authentication.Account.AccountController.Logout (API3)" with arguments (["ee47b7921636973f6c169a7c7472f7fc"]) - ModelState is Valid (ba7f4ac2)
2017-08-02T10:27:29.4881722+01:00 0HL6PFUCMUMHK [INF] AuthenticationScheme: "idsrv" signed out. (d3f50c8d)
</code>```

答:
How about modifying OnRedirectToLogin Event and avoid the redirect when it's  an API request?

```<code>.AddCookie("Cookies", options =>
    options.Events.OnRedirectToLogin = ctx =>
    {
        if (ctx.Request.Path.StartsWithSegments("/api") &&
            ctx.Response.StatusCode == int)System.Net.HttpStatusCode.OK)
        {
            ctx.Response.StatusCode =(int)System.Net.HttpStatusCode.Unauthorized;
        }
        else
        {
            ctx.Response.Redirect(ctx.RedirectUri);
        }
        return Task.FromResult(0);
    }
)
</code>```

Body:
I'm using Identity Server 4. When my API receives a token expiry (IDX10223: Lifetime validation failed which is expected) at the point where it validates access to an API, it appears to redirect to the logout page rather than just return 401. I'm trying to find out where this is controlled since this results in the client being sent the HTML for the logout page which isn't desirable.

The API code has:

[Authorize]
public IActionResult API() {
}

The API and IdentityServer also run on the same server. Is this a function of AuthorizeFilter and is the answer to create a custom authorize attribute?

Relevant parts of the log file

2017-08-02T10:27:28.8366946+01:00 0HL6PFUCMUMHG [INF] Request starting HTTP/1.1 GET http://localhost:55742/v3.0/User/recent?conversationId=21680095&sortFlag=2 (e5be5b71)
2017-08-02T10:27:28.9641697+01:00 0HL6PFUCMUMHG [INF] Failed to validate the token "eyJhbGciOiJSUzI1NiIsImtpZCI6IjA3NTMyYzdlZDVmZjc1MGQ5YWE0ZjYyNjQ0YjczMjY5IiwidHlwIjoiSldUIn0.eyJuYmYiOjE1MDE2NjIxNDUsImV4cCI6MTUwMTY2NTc0NSwiaXNzIjoiaHR0cDovL2xvY2FsaG9zdDo1NTc0MiIsImF1ZCI6WyJodHRwOi8vbG9jYWxob3N0OjU1NzQyL3Jlc291cmNlcyIsImNpeEFwaTMiXSwiY2xpZW50X2lkIjoiY2l4Rm9ydW1zRGV2Iiwic3ViIjoic3BhbG1lciIsImF1dGhfdGltZSI6MTUwMTY2MDk0MSwiaWRwIjoibG9jYWwiLCJyb2xlIjoiZnVsbCIsInNjb3BlIjpbIm9wZW5pZCIsInByb2ZpbGUiLCJjaXhBcGkzIiwib2ZmbGluZV9hY2Nlc3MiXSwiYW1yIjpbInB3ZCJdfQ.jcGNgeGSY72SRODAnWQWJI5XXRZaM0SSO3DAFp7QQeDzXbxNDIgkDqRUkQAJoGU52C4svk6DQwKGrsFDATzI52g8iuD8JAugaOen4DfEx_g6CP3JdImUn6aT379rjH5_d1ePXVaSwBMU9L3q1mkA20EotWA6mcIdYZw54Xvsp-TGnWbMKAL-yv8_Vh7gQn-_vBy7sfTB4s_37SZtSmpi7ig7WPa2XbAVwNN_vmApL0ZgP8QsotyTiIDEloXov5XYkAe7JvunpHyaATg8RCirNu6zp38yBHzkJ0IJh7BJZ47IDImE-AxfvZY8_EW6m1LJosVjgrjSnG5nIFu_mPvASA". (f3081a27)
Microsoft.IdentityModel.Tokens.SecurityTokenExpiredException: IDX10223: Lifetime validation failed. The token is expired.
ValidTo: '08/02/2017 09:22:25'
Current time: '08/02/2017 09:27:28'.
at Microsoft.IdentityModel.Tokens.Validators.ValidateLifetime(Nullable1 notBefore, Nullable1 expires, SecurityToken securityToken, TokenValidationParameters validationParameters)
at System.IdentityModel.Tokens.Jwt.JwtSecurityTokenHandler.ValidateLifetime(Nullable1 notBefore, Nullable1 expires, JwtSecurityToken securityToken, TokenValidationParameters validationParameters)
at System.IdentityModel.Tokens.Jwt.JwtSecurityTokenHandler.ValidateTokenPayload(JwtSecurityToken jwt, TokenValidationParameters validationParameters)
at System.IdentityModel.Tokens.Jwt.JwtSecurityTokenHandler.ValidateToken(String token, TokenValidationParameters validationParameters, SecurityToken& validatedToken)
at Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerHandler.d__1.MoveNext()
2017-08-02T10:27:28.9701726+01:00 0HL6PFUCMUMHG [INF] "Bearer" was not authenticated. Failure message: "IDX10223: Lifetime validation failed. The token is expired.
ValidTo: '08/02/2017 09:22:25'
Current time: '08/02/2017 09:27:28'." (48071232)
2017-08-02T10:27:28.9761723+01:00 0HL6PFUCMUMHG [INF] Authorization failed for user: null. (a4ab1676)
2017-08-02T10:27:28.9831738+01:00 0HL6PFUCMUMHG [INF] Authorization failed for the request at filter '"Microsoft.AspNetCore.Mvc.Authorization.AuthorizeFilter"'. (8b6446cb)
2017-08-02T10:27:28.9951674+01:00 0HL6PFUCMUMHG [INF] Executing ChallengeResult with authentication schemes ([]). (f3dca807)
2017-08-02T10:27:29.0231698+01:00 0HL6PFUCMUMHG [INF] AuthenticationScheme: "Bearer" was challenged. (d45f1f38)
2017-08-02T10:27:29.0281709+01:00 0HL6PFUCMUMHG [INF] Executed action "API3.Controllers.UserController.Recent (API3)" in 52.7575ms (afa2e885)
2017-08-02T10:27:29.0371704+01:00 0HL6PFUCMUMHG [INF] Request finished in 200.5214ms 401 (15c52c40)
2017-08-02T10:27:29.1141679+01:00 0HL6PFUCMUMHH [INF] Request starting HTTP/1.1 OPTIONS http://localhost:55742/connect/endsession?post_logout_redirect_uri=http%3A%2F%2Flocalhost%3A62784%2Fsignout-callback-oidc&id_token_hint=eyJhbGciOiJSUzI1NiIsImtpZCI6IjA3NTMyYzdlZDVmZjc1MGQ5YWE0ZjYyNjQ0YjczMjY5IiwidHlwIjoiSldUIn0.eyJuYmYiOjE1MDE2NjIxNDUsImV4cCI6MTUwMTY2MjQ0NSwiaXNzIjoiaHR0cDovL2xvY2FsaG9zdDo1NTc0MiIsImF1ZCI6ImNpeEZvcnVtc0RldiIsIm5vbmNlIjoiNjM2MzcyNTg5NDM0Njg3NzM4LlpUbGxaRGxpTVdZdE5EVmlZUzAwWkdNeExXRTNOVFl0WldRM1pUY3lZV0ptTVRZelpHRTBNRGd4WmpjdFl6QTRPQzAwTldZMUxUa3daVGt0TjJRMU1UQmhNR0ZpWW1NNCIsImlhdCI6MTUwMTY2MjE0NSwiYXRfaGFzaCI6ImFXMFB6eEdPVVAza1pIcGFHR1RYLVEiLCJzaWQiOiI3NDdhODA5ZTE5NjZmOGY5Y2U5ZWExZDcwYmQ3Y2M2MSIsInN1YiI6InNwYWxtZXIiLCJhdXRoX3RpbWUiOjE1MDE2NjA5NDEsImlkcCI6ImxvY2FsIiwiYW1yIjpbInB3ZCJdfQ.btHqukWt1stWHFyUCqwJu8PS9e9hPUH2N6oqCqtpp_bjalPK5Ub-4uJTwp0_CYiuPt-Atl_XI1H3BI9p7ENIu6YHLgB6Hyr1l7G6e8S64HMsaKTEcQaSSVjUWwF4U1IV6YFVuZ5VjLR-M5FK4mYIcT-xsdDF4kkJTvs1lCqldeg9exLTnca8FsC3E__eIjIhRd8oYHhMUazkQ34FsyqYFESAgRHqIl9IITfeoPYNFMRtuz3P09zCKPCSSrg9t-0UecJ5ccwf1cTfU3tLv9j1rknBYjFjeDah38dHhJLjAEfH5r_fytKEr44kwB2xeu030x1vw1vDPiHi3fbRc72pGA&state=CfDJ8AdS2WFU56FEplHeLVGDdfl3IlfIaWI00-bPygyle9qi0Hnqf-jsZ5pqtwO-dVU2ujH5OkhQRpQyn0OpsXCRVVeul2QTBwi1q40y1QwiXTuftRutLkxADzyrjqrzshvHz479t13919PZIj09GABirToAXtrMUXHu6J0eExJcF8eB (e5be5b71)
2017-08-02T10:27:29.1401709+01:00 0HL6PFUCMUMHH [INF] Request finished in 33.4959ms 204 (15c52c40)
2017-08-02T10:27:29.1501730+01:00 0HL6PFUCMUMHI [INF] Request starting HTTP/1.1 GET http://localhost:55742/connect/endsession?post_logout_redirect_uri=http%3A%2F%2Flocalhost%3A62784%2Fsignout-callback-oidc&id_token_hint=eyJhbGciOiJSUzI1NiIsImtpZCI6IjA3NTMyYzdlZDVmZjc1MGQ5YWE0ZjYyNjQ0YjczMjY5IiwidHlwIjoiSldUIn0.eyJuYmYiOjE1MDE2NjIxNDUsImV4cCI6MTUwMTY2MjQ0NSwiaXNzIjoiaHR0cDovL2xvY2FsaG9zdDo1NTc0MiIsImF1ZCI6ImNpeEZvcnVtc0RldiIsIm5vbmNlIjoiNjM2MzcyNTg5NDM0Njg3NzM4LlpUbGxaRGxpTVdZdE5EVmlZUzAwWkdNeExXRTNOVFl0WldRM1pUY3lZV0ptTVRZelpHRTBNRGd4WmpjdFl6QTRPQzAwTldZMUxUa3daVGt0TjJRMU1UQmhNR0ZpWW1NNCIsImlhdCI6MTUwMTY2MjE0NSwiYXRfaGFzaCI6ImFXMFB6eEdPVVAza1pIcGFHR1RYLVEiLCJzaWQiOiI3NDdhODA5ZTE5NjZmOGY5Y2U5ZWExZDcwYmQ3Y2M2MSIsInN1YiI6InNwYWxtZXIiLCJhdXRoX3RpbWUiOjE1MDE2NjA5NDEsImlkcCI6ImxvY2FsIiwiYW1yIjpbInB3ZCJdfQ.btHqukWt1stWHFyUCqwJu8PS9e9hPUH2N6oqCqtpp_bjalPK5Ub-4uJTwp0_CYiuPt-Atl_XI1H3BI9p7ENIu6YHLgB6Hyr1l7G6e8S64HMsaKTEcQaSSVjUWwF4U1IV6YFVuZ5VjLR-M5FK4mYIcT-xsdDF4kkJTvs1lCqldeg9exLTnca8FsC3E__eIjIhRd8oYHhMUazkQ34FsyqYFESAgRHqIl9IITfeoPYNFMRtuz3P09zCKPCSSrg9t-0UecJ5ccwf1cTfU3tLv9j1rknBYjFjeDah38dHhJLjAEfH5r_fytKEr44kwB2xeu030x1vw1vDPiHi3fbRc72pGA&state=CfDJ8AdS2WFU56FEplHeLVGDdfl3IlfIaWI00-bPygyle9qi0Hnqf-jsZ5pqtwO-dVU2ujH5OkhQRpQyn0OpsXCRVVeul2QTBwi1q40y1QwiXTuftRutLkxADzyrjqrzshvHz479t13919PZIj09GABirToAXtrMUXHu6J0eExJcF8eB (e5be5b71)
2017-08-02T10:27:29.1591678+01:00 0HL6PFUCMUMHI [DBG] CORS request made for path: "/connect/endsession" from origin: "http://localhost:62784" but rejected because invalid CORS path (2bd60464)
2017-08-02T10:27:29.1601680+01:00 0HL6PFUCMUMHI [DBG] Request path "/connect/endsession" matched to endpoint type EndSession (b74352b0)
2017-08-02T10:27:29.1611695+01:00 0HL6PFUCMUMHI [DBG] Mapping found for endpoint: EndSession, creating handler: "IdentityServer4.Endpoints.EndSessionEndpoint" (67a7e1a4)
2017-08-02T10:27:29.1671697+01:00 0HL6PFUCMUMHI [INF] Invoking IdentityServer endpoint: "IdentityServer4.Endpoints.EndSessionEndpoint" for "/connect/endsession" (f7642de5)
2017-08-02T10:27:29.1791689+01:00 0HL6PFUCMUMHI [DBG] Processing signout request for "anonymous" (02b52180)
2017-08-02T10:27:29.1871689+01:00 0HL6PFUCMUMHI [DBG] Start end session request validation (8af7241a)
2017-08-02T10:27:29.1931688+01:00 0HL6PFUCMUMHI [DBG] Start identity token validation (5fcce1be)
2017-08-02T10:27:29.1961697+01:00 0HL6PFUCMUMHI [DBG] Client found: "myclient" / "ClientName" (bb32274b)
2017-08-02T10:27:29.2021686+01:00 0HL6PFUCMUMHI [DBG] Calling into custom token validator: "IdentityServer4.Validation.DefaultCustomTokenValidator" (467e6def)
2017-08-02T10:27:29.2091719+01:00 0HL6PFUCMUMHI [DBG] Token validation success
"{
"ClientId": "myclient",
"ClientName": "ClientName",
"ValidateLifetime": false,
"Claims": {
"nbf": 1501662145,
"exp": 1501662445,
"iss": "http://localhost:55742\",
"aud": "myclient",
"nonce": "636372589434687738.ZTllZDliMWYtNDViYS00ZGMxLWE3NTYtZWQ3ZTcyYWJmMTYzZGE0MDgxZjctYzA4OC00NWY1LTkwZTktN2Q1MTBhMGFiYmM4",
"iat": 1501662145,
"at_hash": "aW0PzxGOUP3kZHpaGGTX-Q",
"sid": "747a809e1966f8f9ce9ea1d70bd7cc61",
"sub": "spalmer",
"auth_time": 1501660941,
"idp": "local",
"amr": "pwd"
}
}" (997b5fde)
2017-08-02T10:27:29.2361731+01:00 0HL6PFUCMUMHI [INF] End session request validation success
"{
"ClientId": "myclient",
"ClientName": "ClientName",
"SubjectId": "unknown",
"PostLogOutUri": "http://localhost:62784/signout-callback-oidc\",
"State": "CfDJ8AdS2WFU56FEplHeLVGDdfl3IlfIaWI00-bPygyle9qi0Hnqf-jsZ5pqtwO-dVU2ujH5OkhQRpQyn0OpsXCRVVeul2QTBwi1q40y1QwiXTuftRutLkxADzyrjqrzshvHz479t13919PZIj09GABirToAXtrMUXHu6J0eExJcF8eB",
"Raw": {
"post_logout_redirect_uri": "http://localhost:62784/signout-callback-oidc\",
"id_token_hint": "eyJhbGciOiJSUzI1NiIsImtpZCI6IjA3NTMyYzdlZDVmZjc1MGQ5YWE0ZjYyNjQ0YjczMjY5IiwidHlwIjoiSldUIn0.eyJuYmYiOjE1MDE2NjIxNDUsImV4cCI6MTUwMTY2MjQ0NSwiaXNzIjoiaHR0cDovL2xvY2FsaG9zdDo1NTc0MiIsImF1ZCI6ImNpeEZvcnVtc0RldiIsIm5vbmNlIjoiNjM2MzcyNTg5NDM0Njg3NzM4LlpUbGxaRGxpTVdZdE5EVmlZUzAwWkdNeExXRTNOVFl0WldRM1pUY3lZV0ptTVRZelpHRTBNRGd4WmpjdFl6QTRPQzAwTldZMUxUa3daVGt0TjJRMU1UQmhNR0ZpWW1NNCIsImlhdCI6MTUwMTY2MjE0NSwiYXRfaGFzaCI6ImFXMFB6eEdPVVAza1pIcGFHR1RYLVEiLCJzaWQiOiI3NDdhODA5ZTE5NjZmOGY5Y2U5ZWExZDcwYmQ3Y2M2MSIsInN1YiI6InNwYWxtZXIiLCJhdXRoX3RpbWUiOjE1MDE2NjA5NDEsImlkcCI6ImxvY2FsIiwiYW1yIjpbInB3ZCJdfQ.btHqukWt1stWHFyUCqwJu8PS9e9hPUH2N6oqCqtpp_bjalPK5Ub-4uJTwp0_CYiuPt-Atl_XI1H3BI9p7ENIu6YHLgB6Hyr1l7G6e8S64HMsaKTEcQaSSVjUWwF4U1IV6YFVuZ5VjLR-M5FK4mYIcT-xsdDF4kkJTvs1lCqldeg9exLTnca8FsC3E__eIjIhRd8oYHhMUazkQ34FsyqYFESAgRHqIl9IITfeoPYNFMRtuz3P09zCKPCSSrg9t-0UecJ5ccwf1cTfU3tLv9j1rknBYjFjeDah38dHhJLjAEfH5r_fytKEr44kwB2xeu030x1vw1vDPiHi3fbRc72pGA",
"state": "CfDJ8AdS2WFU56FEplHeLVGDdfl3IlfIaWI00-bPygyle9qi0Hnqf-jsZ5pqtwO-dVU2ujH5OkhQRpQyn0OpsXCRVVeul2QTBwi1q40y1QwiXTuftRutLkxADzyrjqrzshvHz479t13919PZIj09GABirToAXtrMUXHu6J0eExJcF8eB"
}
}" (8a893fca)
2017-08-02T10:27:29.2381718+01:00 0HL6PFUCMUMHI [DBG] Success validating end session request from "myclient" (e682f926)
2017-08-02T10:27:29.3242185+01:00 0HL6PFUCMUMHI [INF] Request finished in 176.7054ms 302 (15c52c40)
2017-08-02T10:27:29.3301739+01:00 0HL6PFUCMUMHJ [INF] Request starting HTTP/1.1 OPTIONS http://localhost:55742/account/logout?logoutId=ee47b7921636973f6c169a7c7472f7fc (e5be5b71)
2017-08-02T10:27:29.3351682+01:00 0HL6PFUCMUMHJ [INF] Request finished in 8.0939ms 204 (15c52c40)
2017-08-02T10:27:29.3421709+01:00 0HL6PFUCMUMHK [INF] Request starting HTTP/1.1 GET http://localhost:55742/account/logout?logoutId=ee47b7921636973f6c169a7c7472f7fc (e5be5b71)
2017-08-02T10:27:29.3431703+01:00 0HL6PFUCMUMHK [DBG] CORS request made for path: "/account/logout" from origin: "http://localhost:62784" but rejected because invalid CORS path (2bd60464)
2017-08-02T10:27:29.3531756+01:00 0HL6PFUCMUMHK [INF] "Bearer" was not authenticated. Failure message: "No token found." (48071232)
2017-08-02T10:27:29.4273094+01:00 0HL6PFUCMUMHK [INF] Executing action method "API3.Authentication.Account.AccountController.Logout (API3)" with arguments (["ee47b7921636973f6c169a7c7472f7fc"]) - ModelState is Valid (ba7f4ac2)
2017-08-02T10:27:29.4881722+01:00 0HL6PFUCMUMHK [INF] AuthenticationScheme: "idsrv" signed out. (d3f50c8d)

Body:
How about modifying OnRedirectToLogin Event and avoid the redirect when it's  an API request?

.AddCookie("Cookies", options =>
    options.Events.OnRedirectToLogin = ctx =>
    {
        if (ctx.Request.Path.StartsWithSegments("/api") &&
            ctx.Response.StatusCode == int)System.Net.HttpStatusCode.OK)
        {
            ctx.Response.StatusCode =(int)System.Net.HttpStatusCode.Unauthorized;
        }
        else
        {
            ctx.Response.Redirect(ctx.RedirectUri);
        }
        return Task.FromResult(0);
    }
)


来源: stackexchange

问:
Why have this Filter here? Should it be in the controller?
I saw this code. I removed some of the irrelevant code to make it simpler (like the identical validator that checks that the passwords match).

```<code>$password = new Zend_Form_Element_Password('password');
$password->addFilter(new My_Filters_Sha());

$password2 = new Zend_Form_Element_Password('password2');
$password2->addFilter(new My_Filters_Sha());
</code>```

My question is about the filter. My guess is that whoever wrote it is saving the password in the database as a hashed and that's why they hash the password with the filter. But what's the point of having a filter handle the hashing? Shouldn't this be done once in the controller when he account is being created? When the input is received, process it to a hash and save it then. Is there a point to having this done as a filter?

答: The responsibility of your controller is to handle the request and delegate to the appropriate Model. Hashing a password is business logic. Business logic has no place in a controller but belongs to the Model. Your Form class is a Model class and thus it's appropriate to put the filter there.</p>

ContentLicense: CC BY-SA 2.5

Body:
I saw this code. I removed some of the irrelevant code to make it simpler (like the identical validator that checks that the passwords match).

$password = new Zend_Form_Element_Password('password');
$password->addFilter(new My_Filters_Sha());

$password2 = new Zend_Form_Element_Password('password2');
$password2->addFilter(new My_Filters_Sha());

My question is about the filter. My guess is that whoever wrote it is saving the password in the database as a hashed and that's why they hash the password with the filter. But what's the point of having a filter handle the hashing? Shouldn't this be done once in the controller when he account is being created? When the input is received, process it to a hash and save it then. Is there a point to having this done as a filter?


问:
Need to add @Inject decorator manually in constructor
I set up a new Angular 5 project and it seems @Injectable decorator doesn't work. I have to inject manually with @Inject decorator for each parameter of constructors.
I'm using Angular 5.0.5 with TS 2.4.2.
This is my tsconfig.json:

```<code>{ "compileOnSave": false, "compilerOptions": { "outDir": "./dist/out-tsc", "sourceMap": true, "declaration": false, "moduleResolution": "node", "emitDecoratorMetadata": true, "experimentalDecorators": true, "target": "es5", "typeRoots": [ "node_modules/@types" ], "lib": [ "es2017", "dom" ] } }
</code>```

I lost a lot of time on it and i really don't understand what happens.
Do you have an idea of the problem ?

答:
My bad, i just found the problem...
I commented the 'core-js/es7/reflect' import in my polyfill.js.

Thanks to you

ContentLicense: CC BY-SA 3.0

Body:
I set up a new Angular 5 project and it seems @Injectable decorator doesn't work. I have to inject manually with @Inject decorator for each parameter of constructors.
I'm using Angular 5.0.5 with TS 2.4.2.
This is my tsconfig.json:

{ "compileOnSave": false, "compilerOptions": { "outDir": "./dist/out-tsc", "sourceMap": true, "declaration": false, "moduleResolution": "node", "emitDecoratorMetadata": true, "experimentalDecorators": true, "target": "es5", "typeRoots": [ "node_modules/@types" ], "lib": [ "es2017", "dom" ] } }

I lost a lot of time on it and i really don't understand what happens.
Do you have an idea of the problem ?


问:
how to use oauth2 token permanently?
I would like to use the oauth2 token permanently in my website.

Using google API, when the user giving permission to manage their google calendar, I am getting the access token from google API. I want to save it in database and use it for the last long.

But it is getting invalid. I tried to refresh the token using the oauth2 refresh token API. But getting the error as follows.

Array ( [error] => invalid_grant [error_description] => Token has been expired or revoked. )

I don't want the user to give the permission each time when he enters the website.

I would also like the admin need to access the user's calendar using this token or any other way if it is.

How can I achieve this?

答:
Bottom line is you can't get a permanent token - but you can mitigate the need for your user to re-supply credentials.

The solution depends what grant type you are using (which depends largely on whether your application runs on a server or or a end-user's machine). You mention a website so hopefully you use a grant type which returns a refresh code too.

If your app runs on a server and you get a token via the authorisation code grant then you should be able to also get a refresh token when you get an access token. You can use that refresh token to request new refresh/access tokens on a back-channel, without need of your user, or their credentials.

Effectively you should then have long-lived access to your user's google resources providing the user doesn't revoke access.

If you use other grant types, like implicit grant, then you can't get a refresh token. You will need to regularly obtain a new access token. If your user remains logged-in to google on the device your app is running on then they should not be required to supply their google credentials when you request a new access token, so you won't be constantly pestering them for credentials.

Title: how to use oauth2 token permanently?


问:
How to pick target server for Migrating an application from JBoss 4.0.4?
I am looking for the reasoning which version of JBOSS or WILDFLY I should choose for migration. Can somebody tell I should go for JBOSS AS5 but not JBOSS AS7 or even WILDFLY 8. My application is using EJB 3 and struts 1.2.8 with EAR packaging. </p>

答:
You should ask yourself which are the reasons why you want to migrate.

Did you hit a critical bug?

Do you need new features?

Do you need support?

JBoss 4 and 5 rather similar, but both outdated. Support for EAP5 ended 2013. You won't get much community-support either. If I decide I had to migrate, i would migrate to the latest EAP or stable WildFly version depending on the needs for support.


问:
Order of thread activation in a c# program on a 4 cores PC
I am confused about the thread activation order of the following C# code. It creates 10 threads, starts them randomly, each thread simulates to execute a time-consuming work 10 times, if you check the debug output, the thread seems not to be picked up not randomly, please see below output example, notice thread #3, #5, #6 is always picked up, when #3 #5 #6 is finished, then #10 #2 #8 is always picked up, etc... (I know the design is bad, please focus on the phenomenon)

My PC has i7-7820HQ cpu which has 4 cores, and is running windows 10.

Could someone explain why these threads are not picked randomly and they seemed to be grouped somehow.

Thanks a lot!

---- Debug output ----

```
Thread #10 acquired the lock and is working for task #0
Thread #5 acquired the lock and is working for task #0
Thread #3 acquired the lock and is working for task #0
Thread #6 acquired the lock and is working for task #0
Thread #5 acquired the lock and is working for task #1
Thread #3 acquired the lock and is working for task #1
Thread #6 acquired the lock and is working for task #1
...
Thread #5 acquired the lock and is working for task #9
Thread #3 acquired the lock and is working for task #9
Thread #6 acquired the lock and is working for task #9
...
Thread #8 acquired the lock and is working for task #0
Thread #2 acquired the lock and is working for task #0
Thread #8 acquired the lock and is working for task #1
Thread #2 acquired the lock and is working for task #1
Thread #10 acquired the lock and is working for task #1
...
Thread #8 acquired the lock and is working for task #9
Thread #2 acquired the lock and is working for task #9
Thread #10 acquired the lock and is working for task #9
...
```

```<code>using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace ConsoleApp1
{
    class Program
    {
        static Hashtable _sharedBetweenThreads = new Hashtable();

        static void Main(string[] args)
        {
            Random random = new Random(DateTime.Now.Second);
            var startOrders = new int[10];
            for (int i = 0; i < startOrders.Length; i++)
            {
                startOrders[i] = i;
            }

            //shuffle the array
            for (int i = startOrders.Length - 1; i >= 0; i--)
            {
                int j = random.Next(0, i);
                int temp = startOrders[i];
                startOrders[i] = startOrders[j];
                startOrders[j] = temp;
            }

            Thread[] threads = new Thread[startOrders.Length];
            for(int i = 0; i < startOrders.Length; i++)
            {
                threads[i] = new Thread(new ThreadStart(ThreadProc));
            }

            for (int i = 0; i < startOrders.Length; i++)
            {
                threads[startOrders[i]].Start();
            }

            Console.ReadLine();
        }

        static void ThreadProc()
        {
            // simulates there are 10 tasks needs to do.
            for (int i = 0; i < 10; i++)
            {
                lock (_sharedBetweenThreads.SyncRoot)
                {
                    Debug.Print(string.Format("Thread #{0} acquired the lock and is working for task #{1}", Thread.CurrentThread.ManagedThreadId, i));

                    // simulates a work.
                    Thread.Sleep(500);
                }

            }
        }
    }
}
</code>```

The screenshot of debug output

--- Additional infos ---

The program is not a parallel program at all because there is lock shared among 10 threads.

If the count of the loop is changed from 10 to infinite, the 3 threads are always activated and the rest 7 threads cannot get a chance of activating, and they are something like "deadlocked" forever.

答: I guess your confusion stems from the fact, that you are using the .NET thread pool - e.g. a managed pool of threads - but you expect to deal with threads on system level, which is not quite the same. The internal thread pool gives you the thread it decides to be appropriate. This has nothing to do with the question, which core is running which thread at which moment.</p>

Body:
I am confused about the thread activation order of the following C# code. It creates 10 threads, starts them randomly, each thread simulates to execute a time-consuming work 10 times, if you check the debug output, the thread seems not to be picked up not randomly, please see below output example, notice thread #3, #5, #6 is always picked up, when #3 #5 #6 is finished, then #10 #2 #8 is always picked up, etc... (I know the design is bad, please focus on the phenomenon)

My PC has i7-7820HQ cpu which has 4 cores, and is running windows 10.

Could someone explain why these threads are not picked randomly and they seemed to be grouped somehow.

Thanks a lot!

---- Debug output ----

Thread #10 acquired the lock and is working for task #0
Thread #5 acquired the lock and is working for task #0
Thread #3 acquired the lock and is working for task #0
Thread #6 acquired the lock and is working for task #0
Thread #5 acquired the lock and is working for task #1
Thread #3 acquired the lock and is working for task #1
Thread #6 acquired the lock and is working for task #1
...
Thread #5 acquired the lock and is working for task #9
Thread #3 acquired the lock and is working for task #9
Thread #6 acquired the lock and is working for task #9
...
Thread #8 acquired the lock and is working for task #0
Thread #2 acquired the lock and is working for task #0
Thread #8 acquired the lock and is working for task #1
Thread #2 acquired the lock and is working for task #1
Thread #10 acquired the lock and is working for task #1
...
Thread #8 acquired the lock and is working for task #9
Thread #2 acquired the lock and is working for task #9
Thread #10 acquired the lock and is working for task #9
...

using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace ConsoleApp1
{
    class Program
    {
        static Hashtable _sharedBetweenThreads = new Hashtable();

        static void Main(string[] args)
        {
            Random random = new Random(DateTime.Now.Second);
            var startOrders = new int[10];
            for (int i = 0; i < startOrders.Length; i++)
            {
                startOrders[i] = i;
            }

            //shuffle the array
            for (int i = startOrders.Length - 1; i >= 0; i--)
            {
                int j = random.Next(0, i);
                int temp = startOrders[i];
                startOrders[i] = startOrders[j];
                startOrders[j] = temp;
            }

            Thread[] threads = new Thread[startOrders.Length];
            for(int i = 0; i < startOrders.Length; i++)
            {
                threads[i] = new Thread(new ThreadStart(ThreadProc));
            }

            for (int i = 0; i < startOrders.Length; i++)
            {
                threads[startOrders[i]].Start();
            }

            Console.ReadLine();
        }

        static void ThreadProc()
        {
            // simulates there are 10 tasks needs to do.
            for (int i = 0; i < 10; i++)
            {
                lock (_sharedBetweenThreads.SyncRoot)
                {
                    Debug.Print(string.Format("Thread #{0} acquired the lock and is working for task #{1}", Thread.CurrentThread.ManagedThreadId, i));

                    // simulates a work.
                    Thread.Sleep(500);
                }

            }
        }
    }
}

The screenshot of debug output

--- Additional infos ---

The program is not a parallel program at all because there is lock shared among 10 threads.

If the count of the loop is changed from 10 to infinite, the 3 threads are always activated and the rest 7 threads cannot get a chance of activating, and they are something like "deadlocked" forever.


问:
Discretizing continuous variables for RandomForest in Sklearn
I want to use Random Forest for feature selection based on Gini index. My dataset has mix of numeric (contiuous) and categorical(String) data. This is an example of the dataset

Var1            Var2

198             zcROj17IEC
336             DHeTmBftjz
252.3           crIgUHSK8h
252             ZSNrjIX0Db

I know trees works on discrete data (categorical) but does RandomForest in Sklearn require continuous numeric data to be discretized first or it can handle it?? For categorical string variables I used the following to encode the strings into numeric columns with zeros and ones

```<code>pandas.get_dummies(X['Var2'])
</code>```

and it works but for the numeric I tried the following to discretize

```<code>pandas.qcut(X['Var1'], 2 , retbins=True)
</code>```

but I keep getting an error of non-unique bins!

Do I need to discretize? How can I do it?

答:
Trees and Forest work worse when you make dummies from you categorical values.

You need just label you categorical features - that's all!

Body:
I want to use Random Forest for feature selection based on Gini index. My dataset has mix of numeric (contiuous) and categorical(String) data. This is an example of the dataset

Var1            Var2

198             zcROj17IEC
336             DHeTmBftjz
252.3           crIgUHSK8h
252             ZSNrjIX0Db

I know trees works on discrete data (categorical) but does RandomForest in Sklearn require continuous numeric data to be discretized first or it can handle it?? For categorical string variables I used the following to encode the strings into numeric columns with zeros and ones

pandas.get_dummies(X['Var2'])

and it works but for the numeric I tried the following to discretize

pandas.qcut(X['Var1'], 2 , retbins=True)

but I keep getting an error of non-unique bins!

Do I need to discretize? How can I do it?


问:
JDBC ResultSet: I need a getDateTime, but there is only getDate and getTimeStamp
I would like to get the DATETIME column from an Oracle DB Table with JDBC. Here is my code:

```<code>int columnType = rsmd.getColumnType(i);
if(columnType == Types.DATE)
{
    Date aDate = rs.getDate(i);
    valueToInsert = aDate.toString();
}
else if(columnType == Types.TIMESTAMP)
{
    Timestamp aTimeStamp = rs.getTimestamp(i);
    valueToInsert = aTimeStamp.toString();
}
else
{
    valueToInsert = rs.getString(i);
}
</code>```

I have to identify the column type first. The field I am interested in is recognized as a Types.DATE, but it is really a DATETIME in the DB since it has this format: "07.05.2009 13:49:32"

getDate truncates the time: "07.05.2009"
and getString appends ".0" to it: "07.05.2009 13:49:32.0"

Of course I could just remove the final .0 and work with getString all the time, but it is a dirty workaround.

Any ideas? I was looking for a getDateTime method.

答:
this worked:

```<code>    Date date = null;
    String dateStr = rs.getString("doc_date");
    if (dateStr != null) {
        date = dateFormat.parse(dateStr);
    }
</code>```

using SimpleDateFormat.

ContentLicense: CC BY-SA 4.0

Body:
I would like to get the DATETIME column from an Oracle DB Table with JDBC. Here is my code:

int columnType = rsmd.getColumnType(i);
if(columnType == Types.DATE)
{
    Date aDate = rs.getDate(i);
    valueToInsert = aDate.toString();
}
else if(columnType == Types.TIMESTAMP)
{
    Timestamp aTimeStamp = rs.getTimestamp(i);
    valueToInsert = aTimeStamp.toString();
}
else
{
    valueToInsert = rs.getString(i);
}

I have to identify the column type first. The field I am interested in is recognized as a Types.DATE, but it is really a DATETIME in the DB since it has this format: "07.05.2009 13:49:32"

getDate truncates the time: "07.05.2009"
and getString appends ".0" to it: "07.05.2009 13:49:32.0"

Of course I could just remove the final .0 and work with getString all the time, but it is a dirty workaround.

Any ideas? I was looking for a getDateTime method.

Body:
this worked:

    Date date = null;
    String dateStr = rs.getString("doc_date");
    if (dateStr != null) {
        date = dateFormat.parse(dateStr);
    }

using SimpleDateFormat.


问:
Haskell Best Practise: Early termination in Haskeline
I am using the Haskeline package and I want to get three strings in a row from the command line before I do anything and I have come up with what seems to be a neat solution to me. But I am sure that there might be a better way to do it. I am looking for best practices while using the Haskeline package. Please evaluate the merits of the following example code:

```<code>import System.Console.Haskeline
import Control.Monad.Trans
import Control.Monad.Maybe
import Data.Maybe
import Control.Monad

main :: IO ()
main = runInputT defaultSettings (runMaybeT getStrings) >>= print

getStrings :: MaybeT (InputT IO) (String, String, String)
getStrings = do
   mone <- lift $ getInputLine "food> "
   notNothing mone
   mtwo <- lift $ getInputLine "drink> "
   notNothing mtwo
   mthree <- lift $ getInputLine "dessert> "
   notNothing mthree
   return (fromJust mone, fromJust mtwo, fromJust mthree)
      where
         notNothing a = guard (a /= Nothing)
</code>```

As you can see it accomplishes the task of early termination but it looks a bit yucky still. I'm thinking of trying to convert the notNothing's and the getInputLine's into a single line like:

```<code>mone <- notNothing =<< lift $ getInputLine "food> " -- does not type check
</code>```

Which I think does not look that bad. I think that is pretty clear and concise (though it does not type check so I will have to write a version that does).

However, this is the best I have come up with and my question finally is: How would you go about improving this code to be neater and more readily readable? Am I even on the right track?

Edit: If your guard is something other than 'a /= Nothing' then a nice helper function that I just discovered is:

```<code>myGuard s = guard (someConditionFunc s) >> s
</code>```

Because then you can write (as luqui suggested):

```<code>mone <- myGuard =<< (lift $ getInputLine prompt)
</code>```

Which is pretty cool. But if you are matching against only Nothing then TomMD's answer is better.

答:
How about a helper function?

```<code>inputLine :: String -> MaybeT (InputT IO) String
inputLine prompt = do
    m <- lift $ getInputLine prompt
    case m of
        Just x -> return x
        Nothing -> mzero
</code>```

This can be shortened considerably using various tricks, but I wanted to be clear.  Now you can just forget that getInputLine can fail, MaybeT takes care of that for you.

Body:
I am using the Haskeline package and I want to get three strings in a row from the command line before I do anything and I have come up with what seems to be a neat solution to me. But I am sure that there might be a better way to do it. I am looking for best practices while using the Haskeline package. Please evaluate the merits of the following example code:

import System.Console.Haskeline
import Control.Monad.Trans
import Control.Monad.Maybe
import Data.Maybe
import Control.Monad

main :: IO ()
main = runInputT defaultSettings (runMaybeT getStrings) >>= print

getStrings :: MaybeT (InputT IO) (String, String, String)
getStrings = do
   mone <- lift $ getInputLine "food> "
   notNothing mone
   mtwo <- lift $ getInputLine "drink> "
   notNothing mtwo
   mthree <- lift $ getInputLine "dessert> "
   notNothing mthree
   return (fromJust mone, fromJust mtwo, fromJust mthree)
      where
         notNothing a = guard (a /= Nothing)

As you can see it accomplishes the task of early termination but it looks a bit yucky still. I'm thinking of trying to convert the notNothing's and the getInputLine's into a single line like:

mone <- notNothing =<< lift $ getInputLine "food> " -- does not type check

Which I think does not look that bad. I think that is pretty clear and concise (though it does not type check so I will have to write a version that does).

However, this is the best I have come up with and my question finally is: How would you go about improving this code to be neater and more readily readable? Am I even on the right track?

Edit: If your guard is something other than 'a /= Nothing' then a nice helper function that I just discovered is:

myGuard s = guard (someConditionFunc s) >> s

Because then you can write (as luqui suggested):

mone <- myGuard =<< (lift $ getInputLine prompt)

Which is pretty cool. But if you are matching against only Nothing then TomMD's answer is better.

Body:
How about a helper function?

inputLine :: String -> MaybeT (InputT IO) String
inputLine prompt = do
    m <- lift $ getInputLine prompt
    case m of
        Just x -> return x
        Nothing -> mzero

This can be shortened considerably using various tricks, but I wanted to be clear.  Now you can just forget that getInputLine can fail, MaybeT takes care of that for you.


问:
Basic program to convert integer to Roman numerals?
I'm trying to write a code that converts a user-inputted integer into its Roman numeral equivalent. What I have so far is:

The point of the generate_all_of_numeral function is so that it creates a string for each specific numeral. For example, generate_all_of_numeral(2400, 'M', 2000) would return the string 'MM'.

I'm struggling with the main program. I start off finding the Roman numeral count for M and saving that into the variable M. Then I subtract by the number of M's times the symbol value to give me the next value to work with for the next largest numeral.

Any nod to the right direction? Right now my code doesn't even print anything.

答:
Here's a lambda function for integer to roman numeral conversion, working up to 3999. It anchors some corner of the space of "unreadable things you probably don't actually want to do". But it may amuse someone:

```<code>lambda a: (
    "".join(reversed([
      "".join([
          "IVXLCDM"[int(d)+i*2]
          for d in [
              "", "0", "00", "000", "01",
              "1", "10", "100", "1000", "02"][int(c)]])
          for i,c in enumerate(reversed(str(a))) ]))
     )
</code>```

This approach gives an alternative to using arithmetical manipulations to
isolate decimal digits and their place, as OP and many of the examples do.
The approach here goes straight for converting the decimal number to a string.
That way, digits can be isolated by list indexing. The data table is fairly
compressed, and no subtraction or division is used.

Admittedly, in the form given, whatever is gained in brevity is immediately
given up in readability. For people without time for puzzles, a version below
is given that avoids list comprehension and lambda functions.

Stepthrough

But I'll explain the lambda function version here...

Going from back to front:

Convert a decimal integer to a reversed string of its digits, and enumerate
(i) over the reversed digits (c).

```<code>....
for i,c in enumerate(reversed(str(a)))
....
</code>```

Convert each digit c back to an integer (range of 0-9), and use it as an index into a list of magic digit strings. The magic is explained a little later on.

```<code>....
[ "", "0", "00", "000", "01",
 "1", "10", "100", "1000", "02"][int(c)]])
....
</code>```

Convert your selected magic digit string into a string of roman numeral
"digits". Basically, you now have your decimal digit expressed as roman
numeral digits appropriate to the original 10's place of the decimal digit.
This is the target of the generate_all_of_numeral function used by the OP.

```<code>....
"".join([
    "IVXLCDM"[int(d)+i*2]
    for d in <magic digit string>
....
</code>```

Concatenate everything back in reversed order. The reversal is of the order
of the digits, but order within the digits ("digits"?) is unaffected.

```<code>lambda a: (
    "".join(reversed([
    <roman-numeral converted digits>
    ]))
</code>```

The Magic String List

Now, about that list of magic strings. It allows selecting the appropriate
string of roman numeral digits (up to four of them, each being one of three types 0, 1, or 2) for each different 10's place that a decimal digit can occupy.

0 -> ""; roman numerals don't show zeros.

1 -> "0"; 0 + 2*i maps to I, X, C or M -> I, X, C or M.

2 -> "00"; like for 1, x2 -> II, XX, CC, MM.

3 -> "000"; like for 1, x3 -> III, XXX, CCC, MMM.

4 -> "01"; like for 1, then 1 +2*i maps to V, L, or D -> IV, XL, CD.

5 -> "1"; maps to odd roman numeral digits -> V, L, D.

6 -> "10"; reverse of 4 -> VI, LX, DC.

7 -> "100"; add another I/X/C -> VII LXX, DCC

8 -> "1000"; add another I/X/C -> VIII, LXXX, DCCC

9 -> "02"; like for 1, plus the next 10's level up (2 + i*2) -> IX, XC, CM.

At 4000 and above, this will throw an exception. "MMMM" = 4000, but this
doesn't match the pattern anymore, breaking the assumptions of the algorithm.

Rewritten version

...as promised above...

```<code>def int_to_roman(a):
    all_roman_digits = []
    digit_lookup_table = [
        "", "0", "00", "000", "01",
        "1", "10", "100", "1000", "02"]
    for i,c in enumerate(reversed(str(a))):
        roman_digit = ""
        for d in digit_lookup_table[int(c)]:
          roman_digit += ("IVXLCDM"[int(d)+i*2])
        all_roman_digits.append(roman_digit)
    return "".join(reversed(all_roman_digits))
</code>```

I again left out exception trapping, but at least now there's a place to put it inline.

Body:
Here's a lambda function for integer to roman numeral conversion, working up to 3999. It anchors some corner of the space of "unreadable things you probably don't actually want to do". But it may amuse someone:

lambda a: (
    "".join(reversed([
      "".join([
          "IVXLCDM"[int(d)+i*2]
          for d in [
              "", "0", "00", "000", "01",
              "1", "10", "100", "1000", "02"][int(c)]])
          for i,c in enumerate(reversed(str(a))) ]))
     )

This approach gives an alternative to using arithmetical manipulations to
isolate decimal digits and their place, as OP and many of the examples do.
The approach here goes straight for converting the decimal number to a string.
That way, digits can be isolated by list indexing. The data table is fairly
compressed, and no subtraction or division is used.

Admittedly, in the form given, whatever is gained in brevity is immediately
given up in readability. For people without time for puzzles, a version below
is given that avoids list comprehension and lambda functions.

Stepthrough

But I'll explain the lambda function version here...

Going from back to front:

Convert a decimal integer to a reversed string of its digits, and enumerate
(i) over the reversed digits (c).

....
for i,c in enumerate(reversed(str(a)))
....

Convert each digit c back to an integer (range of 0-9), and use it as an index into a list of magic digit strings. The magic is explained a little later on.

....
[ "", "0", "00", "000", "01",
 "1", "10", "100", "1000", "02"][int(c)]])
....

Convert your selected magic digit string into a string of roman numeral
"digits". Basically, you now have your decimal digit expressed as roman
numeral digits appropriate to the original 10's place of the decimal digit.
This is the target of the generate_all_of_numeral function used by the OP.

....
"".join([
    "IVXLCDM"[int(d)+i*2]
    for d in <magic digit string>
....

Concatenate everything back in reversed order. The reversal is of the order
of the digits, but order within the digits ("digits"?) is unaffected.

lambda a: (
    "".join(reversed([
    <roman-numeral converted digits>
    ]))

The Magic String List

Now, about that list of magic strings. It allows selecting the appropriate
string of roman numeral digits (up to four of them, each being one of three types 0, 1, or 2) for each different 10's place that a decimal digit can occupy.

0 -> ""; roman numerals don't show zeros.

1 -> "0"; 0 + 2*i maps to I, X, C or M -> I, X, C or M.

2 -> "00"; like for 1, x2 -> II, XX, CC, MM.

3 -> "000"; like for 1, x3 -> III, XXX, CCC, MMM.

4 -> "01"; like for 1, then 1 +2*i maps to V, L, or D -> IV, XL, CD.

5 -> "1"; maps to odd roman numeral digits -> V, L, D.

6 -> "10"; reverse of 4 -> VI, LX, DC.

7 -> "100"; add another I/X/C -> VII LXX, DCC

8 -> "1000"; add another I/X/C -> VIII, LXXX, DCCC

9 -> "02"; like for 1, plus the next 10's level up (2 + i*2) -> IX, XC, CM.

At 4000 and above, this will throw an exception. "MMMM" = 4000, but this
doesn't match the pattern anymore, breaking the assumptions of the algorithm.

Rewritten version

...as promised above...

def int_to_roman(a):
    all_roman_digits = []
    digit_lookup_table = [
        "", "0", "00", "000", "01",
        "1", "10", "100", "1000", "02"]
    for i,c in enumerate(reversed(str(a))):
        roman_digit = ""
        for d in digit_lookup_table[int(c)]:
          roman_digit += ("IVXLCDM"[int(d)+i*2])
        all_roman_digits.append(roman_digit)
    return "".join(reversed(all_roman_digits))

I again left out exception trapping, but at least now there's a place to put it inline.


问:
Timeout for multiprocessing?
This code pings various machines. Could you please help me change this code so if a process of pinging hangs for more then 7 seconds it shuts down and returns some flag?

(I'd like to pull various data from machines using WMI. For that I'll change ping function to something else. The issue is on some machines WMI is corrupted and process of pulling data hangs indefinitely. Timeout is needed.)

```<code>import multiprocessing.dummy
import subprocess
import numpy as np
import time

start_time = time.time()

def ping(ipadd):
    try:
        response = subprocess.check_output(['ping', ipadd])
        return True
    except subprocess.CalledProcessError as e:
        return False
#print(ping('10.25.59.20'))
machine_names = \
'''
ya.ru
microsoft.com
www.google.com
www.amazon.com
www.nasa.com
'''.split()

np_machine_names = np.array(machine_names)
p = multiprocessing.dummy.Pool(7)
ping_status = p.map(ping, machine_names)
np_ping_status = np.fromiter(ping_status, dtype=bool)
print(*np_machine_names[np_ping_status], sep = '\n')

run_time = time.time() - start_time
print(f'Runtime: {run_time:.0f}')
</code>```

UPDATE:
While I appreciate for the tip on adding timeout to subprocess the question remains. How do I shutdown hanged function? Let's say I've changed pinging to pulling WMI data from a machine (this one pulls list of installed software from Windows machine). There is no subprocess to set timer on:

```<code>#pip install pypiwin32
import win32com.client
strComputer = "."
objWMIService = win32com.client.Dispatch("WbemScripting.SWbemLocator")
objSWbemServices = objWMIService.ConnectServer(strComputer,"root\cimv2")
colItems = objSWbemServices.ExecQuery("Select * from Win32_Product")
for objItem in colItems:
    print( "Caption: ", objItem.Caption )
</code>```

答:
use asyncio it's available in python since 3.5.4

https://docs.python.org/3/library/asyncio-task.html

Title: Timeout for multiprocessing?

Body:
This code pings various machines. Could you please help me change this code so if a process of pinging hangs for more then 7 seconds it shuts down and returns some flag?

(I'd like to pull various data from machines using WMI. For that I'll change ping function to something else. The issue is on some machines WMI is corrupted and process of pulling data hangs indefinitely. Timeout is needed.)

import multiprocessing.dummy
import subprocess
import numpy as np
import time

start_time = time.time()

def ping(ipadd):
    try:
        response = subprocess.check_output(['ping', ipadd])
        return True
    except subprocess.CalledProcessError as e:
        return False
#print(ping('10.25.59.20'))
machine_names = \
'''
ya.ru
microsoft.com
www.google.com
www.amazon.com
www.nasa.com
'''.split()

np_machine_names = np.array(machine_names)
p = multiprocessing.dummy.Pool(7)
ping_status = p.map(ping, machine_names)
np_ping_status = np.fromiter(ping_status, dtype=bool)
print(*np_machine_names[np_ping_status], sep = '\n')

run_time = time.time() - start_time
print(f'Runtime: {run_time:.0f}')

UPDATE:
While I appreciate for the tip on adding timeout to subprocess the question remains. How do I shutdown hanged function? Let's say I've changed pinging to pulling WMI data from a machine (this one pulls list of installed software from Windows machine). There is no subprocess to set timer on:

#pip install pypiwin32
import win32com.client
strComputer = "."
objWMIService = win32com.client.Dispatch("WbemScripting.SWbemLocator")
objSWbemServices = objWMIService.ConnectServer(strComputer,"root\cimv2")
colItems = objSWbemServices.ExecQuery("Select * from Win32_Product")
for objItem in colItems:
    print( "Caption: ", objItem.Caption )


问:
React Popin open close on outside click
I have some trouble to create my popin with all actions linked

I use REACT JS

I have a button like this:

```<code><button className="b-circle" onClick={() => this.openPopin()}></button>
<div className="u-200">Frequence</div>
{OpenPopin ? <PopinComponent />: ''}
openPopin() {
    this.setState({ openFrequency: true })
}
</code>```

In the popinComponent I have a cross , when I clicked on it I need to close the popin and I need to detect click outside popin to close it too

Do you have any solution to achieve this ? What is the best way ?

Thanks

答:
You can pass prop 'clickevent' to PopinComponent and than trigger onclick on cross button from there and call this prop in that function. Something like this :

```<code><button className="b-circle" onClick={this.openPopin.bind(this)}>
        </button>
        <div className="u-200">Frequence</div>
        {OpenPopin ? <PopinComponent clickevent={this.closePopin.bind(this)} />
           : ''}

  openPopin() {
    this.setState({ openFrequency: true })
  }

  closePopin(){
   this.setState({openFrequency: false})
  }
</code>```

Now in PopinComponent you can pass this.props.clickevent in onClick -

```<code><button onClick={this.props.clickevent}>Close</button>
</code>```

Title: React Popin open close on outside click

Body:
I have some trouble to create my popin with all actions linked

I use REACT JS

I have a button like this:

<button className="b-circle" onClick={() => this.openPopin()}></button>

Frequence

{OpenPopin ? <PopinComponent />: ''}
openPopin() {
    this.setState({ openFrequency: true })
}

In the popinComponent I have a cross , when I clicked on it I need to close the popin and I need to detect click outside popin to close it too

Do you have any solution to achieve this ? What is the best way ?

Thanks

Body:
You can pass prop 'clickevent' to PopinComponent and than trigger onclick on cross button from there and call this prop in that function. Something like this :

<button className="b-circle" onClick={this.openPopin.bind(this)}>
        </button>
        <div className="u-200">Frequence</div>
        {OpenPopin ? <PopinComponent clickevent={this.closePopin.bind(this)} />
           : ''}

  openPopin() {
    this.setState({ openFrequency: true })
  }

  closePopin(){
   this.setState({openFrequency: false})
  }

Now in PopinComponent you can pass this.props.clickevent in onClick -

<button onClick={this.props.clickevent}>Close</button>


问:
Unable to Build and Compile Toree
I'm having errors when running make dev and make release and make jupyter in toree when building from master.

My machine is Ubuntu 16.04

```<code>root@ubuntu-2gb-sgp1-01:/home/incubator-toree# uname -r
4.4.0-47-generic
</code>```

when running make release in toree root i get

```<code>root@ubuntu-2gb-sgp1-01:/home/incubator-toree# make release
APACHE_SPARK_VERSION=2.0.0 VERSION=0.2.0.dev1-incubating IS_SNAPSHOT=true sbt toree/assembly
Unrecognized VM option 'MaxPermSize=1024M'
Error: Could not create the Java Virtual Machine.
Error: A fatal exception has occurred. Program will exit.
Makefile:110: recipe for target 'target/scala-2.11/toree-assembly-0.2.0.dev1-incubating-SNAPSHOT.jar' failed
make: *** [target/scala-2.11/toree-assembly-0.2.0.dev1-incubating-SNAPSHOT.jar] Error 1
root@ubuntu-2gb-sgp1-01:/home/incubator-toree#
</code>```

make jupyter

```<code>root@ubuntu-2gb-sgp1-01:/home/incubator-toree# make jupyter
APACHE_SPARK_VERSION=2.0.0 VERSION=0.2.0.dev1-incubating IS_SNAPSHOT=true sbt toree/assembly
Unrecognized VM option 'MaxPermSize=1024M'
Error: Could not create the Java Virtual Machine.
Error: A fatal exception has occurred. Program will exit.
Makefile:110: recipe for target 'target/scala-2.11/toree-assembly-0.2.0.dev1-incubating-SNAPSHOT.jar' failed
make: *** [target/scala-2.11/toree-assembly-0.2.0.dev1-incubating-SNAPSHOT.jar] Error 1
</code>```

I installed java through apt-get install default-jdk

```<code>root@ubuntu-2gb-sgp1-01:/home/incubator-toree# java -version
openjdk version "9-internal"
OpenJDK Runtime Environment (build 9-internal+0-2016-04-14-195246.buildd.src)
OpenJDK 64-Bit Server VM (build 9-internal+0-2016-04-14-195246.buildd.src, mixed mode)
root@ubuntu-2gb-sgp1-01:/home/incubator-toree#
</code>```

make release

```<code>root@ubuntu-2gb-sgp1-01:/home/incubator-toree# make release
APACHE_SPARK_VERSION=2.0.0 VERSION=0.2.0.dev1-incubating IS_SNAPSHOT=true sbt toree/assembly
Unrecognized VM option 'MaxPermSize=1024M'
Error: Could not create the Java Virtual Machine.
Error: A fatal exception has occurred. Program will exit.
Makefile:110: recipe for target 'target/scala-2.11/toree-assembly-0.2.0.dev1-incubating-SNAPSHOT.jar' failed
make: *** [target/scala-2.11/toree-assembly-0.2.0.dev1-incubating-SNAPSHOT.jar] Error 1
root@ubuntu-2gb-sgp1-01:/home/incubator-toree#
</code>```

I have docker installed

```<code>root@ubuntu-2gb-sgp1-01:/home/incubator-toree# docker -v
Docker version 1.12.3, build 6b644ec
</code>```

答:
You don't need to build and compile Toree, since it's provided a built package already.

Dev snapshots of Toree are located at https://dist.apache.org/repos/dist/dev/incubator/toree. To install using one of those packages, you can use the following:

```<code>pip install <PIP_RELEASE_URL>

jupyter toree install
</code>```

where PIP_RELEASE_URL is one of the pip packages. For example:

```<code>pip install https://dist.apache.org/repos/dist/dev/incubator/toree/0.2.0/snapshots/dev1/toree-pip/toree-0.2.0.dev1.tar.gz
jupyter toree install --spark_home=$SPARK_HOME
</code>```

Title: Unable to Build and Compile Toree

Body:
I'm having errors when running make dev and make release and make jupyter in toree when building from master.

My machine is Ubuntu 16.04

root@ubuntu-2gb-sgp1-01:/home/incubator-toree# uname -r
4.4.0-47-generic

when running make release in toree root i get

root@ubuntu-2gb-sgp1-01:/home/incubator-toree# make release
APACHE_SPARK_VERSION=2.0.0 VERSION=0.2.0.dev1-incubating IS_SNAPSHOT=true sbt toree/assembly
Unrecognized VM option 'MaxPermSize=1024M'
Error: Could not create the Java Virtual Machine.
Error: A fatal exception has occurred. Program will exit.
Makefile:110: recipe for target 'target/scala-2.11/toree-assembly-0.2.0.dev1-incubating-SNAPSHOT.jar' failed
make: *** [target/scala-2.11/toree-assembly-0.2.0.dev1-incubating-SNAPSHOT.jar] Error 1
root@ubuntu-2gb-sgp1-01:/home/incubator-toree#

make jupyter

root@ubuntu-2gb-sgp1-01:/home/incubator-toree# make jupyter
APACHE_SPARK_VERSION=2.0.0 VERSION=0.2.0.dev1-incubating IS_SNAPSHOT=true sbt toree/assembly
Unrecognized VM option 'MaxPermSize=1024M'
Error: Could not create the Java Virtual Machine.
Error: A fatal exception has occurred. Program will exit.
Makefile:110: recipe for target 'target/scala-2.11/toree-assembly-0.2.0.dev1-incubating-SNAPSHOT.jar' failed
make: *** [target/scala-2.11/toree-assembly-0.2.0.dev1-incubating-SNAPSHOT.jar] Error 1

I installed java through apt-get install default-jdk

root@ubuntu-2gb-sgp1-01:/home/incubator-toree# java -version
openjdk version "9-internal"
OpenJDK Runtime Environment (build 9-internal+0-2016-04-14-195246.buildd.src)
OpenJDK 64-Bit Server VM (build 9-internal+0-2016-04-14-195246.buildd.src, mixed mode)
root@ubuntu-2gb-sgp1-01:/home/incubator-toree#

make release

root@ubuntu-2gb-sgp1-01:/home/incubator-toree# make release
APACHE_SPARK_VERSION=2.0.0 VERSION=0.2.0.dev1-incubating IS_SNAPSHOT=true sbt toree/assembly
Unrecognized VM option 'MaxPermSize=1024M'
Error: Could not create the Java Virtual Machine.
Error: A fatal exception has occurred. Program will exit.
Makefile:110: recipe for target 'target/scala-2.11/toree-assembly-0.2.0.dev1-incubating-SNAPSHOT.jar' failed
make: *** [target/scala-2.11/toree-assembly-0.2.0.dev1-incubating-SNAPSHOT.jar] Error 1
root@ubuntu-2gb-sgp1-01:/home/incubator-toree#

I have docker installed

root@ubuntu-2gb-sgp1-01:/home/incubator-toree# docker -v
Docker version 1.12.3, build 6b644ec

Body:
You don't need to build and compile Toree, since it's provided a built package already.

Dev snapshots of Toree are located at https://dist.apache.org/repos/dist/dev/incubator/toree. To install using one of those packages, you can use the following:

pip install <PIP_RELEASE_URL>

jupyter toree install

where PIP_RELEASE_URL is one of the pip packages. For example:

pip install https://dist.apache.org/repos/dist/dev/incubator/toree/0.2.0/snapshots/dev1/toree-pip/toree-0.2.0.dev1.tar.gz
jupyter toree install --spark_home=$SPARK_HOME


问:
movie atom problem in mp4 conversion
In our project, we convert any given video file into mp4 file which works fine when we publish it via our site.

But when we publish the stream link in our itunes-rss and try to download and play the files in Itunes or quicktime, we get an error on the movie-atom in some of the movies and those don't play as they're downloaded to local machine.

After some research, we got that the problem is in the framerate value, to be more specific, the problem is related with 32bit - 64bit value differences. And the conversion should be done with the following formula:
newFrameRate = (int(oldFrameRate)+1)*(1000/1001)
- as we found so far.

We tried to learn the framerate value through ffmpeg and movieinfo, but the results were always different and not accurate.

What's your suggestion to solve this issue?
Tolga

答:
I found one useful way to solve this problem and wanted to report.

I installed MP4Box, and used
mp4box -frag 1000

which solves all the moov-atom related problems.

I tried other values for fragmantation but in larger values, second half of the movie loose its movie track and turns into white.

FYI,
Tolga

Title: movie atom problem in mp4 conversion


问:
How can i Show / Hide Div when i navigate from initial page to another and then come back to initial page?
I have multiple html pages
I have some specific content in Home page, its content should not be changed when the page is refreshed or reloaded.
But when I navigate to other pages and then come back to Home page, I would like to show / hide div or section of html in the Home page.
How this can be achieved?</p>

答:
Link from page B to page A with a url querystring. Something like

```<code>https://mywebsite.com/a?myParam=1
</code>```

Then on page A.

```<code>var myParam = location.search.split('myParam=')[1]
if(myParam == 1){
document.getElementById('hideDiv').style.display = 'none';
}
</code>```

Body:
Link from page B to page A with a url querystring. Something like

https://mywebsite.com/a?myParam=1

Then on page A.

var myParam = location.search.split('myParam=')[1]
if(myParam == 1){
document.getElementById('hideDiv').style.display = 'none';
}


问:
Multiple density plot with plotly in R
I really like this python example:https://plot.ly/python/distplot/ scroll to Plot Multiple Datasets. I would expect the exact same thing is available for R, but it's not documented. Does this mean it's not possible? I came across this example https://community.plot.ly/t/r-plotly-overlay-density-histogram/640/4 which I find far less nice.
This doesn't work but would give an idea about the data I use.</p>

```<code># Add histogram data
x1 = data.table(a=rnorm(n = 200,mean = 0,sd = .1), by='Group1')
x2 = data.table(a=rnorm(n = 200,mean = 1,sd = .15), by='Group2')
x3 = data.table(a=rnorm(n = 200,mean = 2,sd = .2), by='Group3')
x4 = data.table(a=rnorm(n = 200,mean = 3,sd = .25), by='Group4')

agg <- rbind(x1,x2,x3,x4)
plot_ly(data = agg, type = "histogram",histnorm, name = "Histogram",group_by='by')
plot_ly(data = agg, type = "density",histnorm, name = "Density",group_by='by')
</code>```

答:
I'm not entirely sure which critical element you are missing in R, but here is a plotly-based density plus rug plot example based on your sample data.

This is the static ggplot version.

```<code>require(ggplot2);
gg <- ggplot(agg, aes(x = a, colour = by)) + geom_density() + geom_rug();
</code>```

And the interactive ggplotlyed version including screenshot.

```<code>require(plotly);
ggplotly(gg);
</code>```

You can also add a histogram with e.g.

```<code>gg + geom_histogram(aes(y = ..density.., fill = by), alpha = 0.2, bins = 50)
</code>```

Title: Multiple density plot with plotly in R

Body:
I really like this python example:https://plot.ly/python/distplot/ scroll to Plot Multiple Datasets. I would expect the exact same thing is available for R, but it's not documented. Does this mean it's not possible? I came across this example https://community.plot.ly/t/r-plotly-overlay-density-histogram/640/4 which I find far less nice.
This doesn't work but would give an idea about the data I use.

# Add histogram data
x1 = data.table(a=rnorm(n = 200,mean = 0,sd = .1), by='Group1')
x2 = data.table(a=rnorm(n = 200,mean = 1,sd = .15), by='Group2')
x3 = data.table(a=rnorm(n = 200,mean = 2,sd = .2), by='Group3')
x4 = data.table(a=rnorm(n = 200,mean = 3,sd = .25), by='Group4')

agg <- rbind(x1,x2,x3,x4)
plot_ly(data = agg, type = "histogram",histnorm, name = "Histogram",group_by='by')
plot_ly(data = agg, type = "density",histnorm, name = "Density",group_by='by')

Body:
I'm not entirely sure which critical element you are missing in R, but here is a plotly-based density plus rug plot example based on your sample data.

This is the static ggplot version.

require(ggplot2);
gg <- ggplot(agg, aes(x = a, colour = by)) + geom_density() + geom_rug();

And the interactive ggplotlyed version including screenshot.

require(plotly);
ggplotly(gg);

You can also add a histogram with e.g.

gg + geom_histogram(aes(y = ..density.., fill = by), alpha = 0.2, bins = 50)


问:
Verify amount in bash
Currently i'm writing a script that checks whether an amount is higher than the other.

```<code>if [ "324,53" -gt "325,00" ]; then
  echo "Amount is higher!"
else
  echo "Amount is lower."
fi
</code>```

Obviously i'm receiving the error: "integer expression expected" when running this. I tried to use sed 's/[^0-9]*//g'` but i need the full number again for further use. Problem is that I don't know the correct way how to do this. Can anybody give some advice?

答:
Bash can't handle floating point numbers. You need to use an external tool, e.g. bc, but you need to use decimal point, not comma:

```<code>if (( $(bc <<< '324.53 > 325.00') )) ; then
</code>```

bc prints 1 when the condition is true, and 0 when it's false. $(...) takes the output of the command, and (( ... )) interpret it as a number, returning false for zero and true for anything else.

Title: Verify amount in bash

Body:
Currently i'm writing a script that checks whether an amount is higher than the other.

if [ "324,53" -gt "325,00" ]; then
  echo "Amount is higher!"
else
  echo "Amount is lower."
fi

Obviously i'm receiving the error: "integer expression expected" when running this. I tried to use sed 's/[^0-9]*//g'` but i need the full number again for further use. Problem is that I don't know the correct way how to do this. Can anybody give some advice?

Body:
Bash can't handle floating point numbers. You need to use an external tool, e.g. bc, but you need to use decimal point, not comma:

if (( $(bc <<< '324.53 > 325.00') )) ; then

bc prints 1 when the condition is true, and 0 when it's false. $(...) takes the output of the command, and (( ... )) interpret it as a number, returning false for zero and true for anything else.


问:
How to Sanitise CSV
I have a raw csv from which I am creating a dataframe to do so some data cleaning and then convert it back to csv. But the final output I am getting is not in a proper format. so I wanted to know the way on how I can sanitize the csv.

For example I have the raw csv in the form:

```<code>id,text,value
1,'hello',4
3,,2
</code>```

I wanted the csv to be in the normal form

```<code>  +----+----------+-------+
  | id |   text   | value |
  +----+----------+-------+
  |  1 |    hello |     4 |
  |  3 |    0     |     2 |
  +----+----------+-------+
</code>```

Santizing can be done before or after processing inside the dataframe

答:
I'm not exactly sure what you mean by proper format as your first csv is already in csv form. But to fill your na results, you can do this:

```<code>df.fillna('0')
</code>```

Title: How to Sanitise CSV

Body:
I have a raw csv from which I am creating a dataframe to do so some data cleaning and then convert it back to csv. But the final output I am getting is not in a proper format. so I wanted to know the way on how I can sanitize the csv.

For example I have the raw csv in the form:

id,text,value
1,'hello',4
3,,2

I wanted the csv to be in the normal form

  +----+----------+-------+
  | id |   text   | value |
  +----+----------+-------+
  |  1 |    hello |     4 |
  |  3 |    0     |     2 |
  +----+----------+-------+

Santizing can be done before or after processing inside the dataframe

Body:
I'm not exactly sure what you mean by proper format as your first csv is already in csv form. But to fill your na results, you can do this:

df.fillna('0')