Success sold out.
Unwatchable anyway.
Failure tickets available.
One please.
Popcorn and soda.
A moment's pleasure.
Remain seated for the entire performance.
For Death hangs overhead.
Continuous playback enabled.
Enjoy the show.
Success sold out.
Unwatchable anyway.
Failure tickets available.
One please.
Popcorn and soda.
A moment's pleasure.
Remain seated for the entire performance.
For Death hangs overhead.
Continuous playback enabled.
Enjoy the show.
/// Shuffle an array using a fair shuffle algorithm with the provided ratios. /// ratios is an array of values between 0.0 and 1.0, having at least the same length as a, minus 1. /// a is the array to be shuffled. /// Returns a shuffled copy of the input array. let shuffle ( ratios : float array ) ( inArray : 'a array ) = let n = Array.length inArray if n = 0 then Array.empty else let copy = Array.zeroCreate<'a> n copy.[0] <- inArray.[0] // copy first element over for endIndex = 1 to n - 1 do let randIndex = ratios.[endIndex - 1] |> Ratio.scaleBetween 0 endIndex if randIndex <> endIndex then copy.[endIndex] <- copy.[randIndex] // move element at randIndex to end copy.[randIndex] <- inArray.[endIndex] // move next item to randIndex copy
let private fx_generateRandoms count = use rngCsp = new RNGCryptoServiceProvider() let buffer = new RandomBuffer( rngCsp.GetBytes, count ) Array.init count ( fun _ -> buffer.GetRandomRatio() )
AsyncResult.retn request |> AsyncResult.bind (fun request -> getHandler request.Path |> AsyncResult.bind (fun (handlerPath, handle) -> getUser request.User ))
let (>>=) x f = AsyncResult.bind f x
let run connectionString (request:Request) (readJsonFunc:ReadJsonFunc) = let correlationId = Guid.NewGuid() let log = Logger.log correlationId let readJson = fun _ -> readJsonFunc.Invoke() |> Async.AwaitTask AsyncResult.retn request >>= fun request -> log <| RequestStarted (RequestLogEntry.fromRequest request) getHandler request.Path >>= fun (handlerPath, handle) -> log <| HandlerFound handlerPath getUser request.User >>= fun user -> log <| UserFound (user.Identity.Name) authorize handlerPath user >>= fun claim -> log <| OperationAuthorized claim getJson readJson () >>= fun json -> log <| JsonLoaded json let jsonRequest = JsonRequest.mk user json handle connectionString jsonRequest >>= fun (resultJson, count) -> log <| QueryFinished count toJsonResponse resultJson |> AsyncResult.teeError (ErrorEncountered >> log) |> AsyncResult.either id Responder.toErrorResponse |> Async.tee (ResponseCreated >> log) |> Async.StartAsTask
let run connectionString (request:Request) (readJsonFunc:ReadJsonFunc) = let correlationId = Guid.NewGuid() let log = Logger.log correlationId let readJson = fun _ -> readJsonFunc.Invoke() |> Async.AwaitTask let logErr = tee (ErrorEncountered >> log) >> Responder.toErrorResponse let logResponse = ResponseCreated >> log async { log <| RequestStarted (RequestLogEntry.fromRequest request) match getHandler request.Path with | Error err -> return logErr err | Ok (handlerPath, handle) -> log <| HandlerFound handlerPath match getUser request.User with | Error err -> return logErr err | Ok user -> log <| UserFound (user.Identity.Name) match authorize handlerPath user with | Error err -> return logErr err | Ok claim -> log <| OperationAuthorized claim let! jsonResult = getJson readJson () match jsonResult with | Error err -> return logErr err | Ok json -> log <| JsonLoaded json let jsonRequest = JsonRequest.mk user json let! outEventsResult = handle connectionString jsonRequest match outEventsResult with | Error err -> return logErr err | Ok (resultJson, count) -> log <| QueryFinished count return Responder.toJsonResponse resultJson } |> Async.tee logResponse
|> Async.StartAsTask
let run store request (readJsonFunc:ReadJsonFunc) at = let readJson = fun _ -> readJsonFunc.Invoke() |> Async.AwaitTask let logErr = tee (ErrorEncountered >> log) >> Responder.toErrorResponse let logResponse = flip tuple DateTimeOffset.Now >> ResponseCreated >> log async { log <| RequestStarted (request, at) match getHandler request.Path with | Error err -> return logErr err | Ok (handlerPath, handle) -> log <| HandlerFound handlerPath match getUser request.User with | Error err -> return logErr err | Ok user -> let tenantId = getClaimOrEmpty Constants.TenantClaimKey user let userId = getClaimOrEmpty Constants.UserIdKey user log <| UserFound (tenantId, userId) match authorize handlerPath user with | Error err -> return logErr err | Ok claim -> log <| OperationAuthorized claim let! jsonResult = getJson readJson () match jsonResult with | Error err -> return logErr err | Ok json -> log <| JsonLoaded json match deserializeMeta json with | Error err -> return logErr err | Ok meta -> log <| RequestMetaDeserialized meta match checkTenancy user meta.TargetId with | Error err -> return logErr err | Ok x -> log <| TenancyValidated x // TODO page result from event store let! loadResult = loadEvents store meta.TargetId match loadResult with | Error err -> return logErr err | Ok slice -> log <| EventsLoaded (slice.FromEventNumber, slice.NextEventNumber, slice.LastEventNumber) match checkConcurrency meta.Version slice.LastEventNumber with | Error err -> return logErr err | Ok version -> log <| RequestVersionMatched version match deserializeSlice slice with | Error err -> return logErr err | Ok inEvents -> log <| EventsDeserialized inEvents let! outEventsResult = runHandler (meta:RequestMeta) (request:Request) user json handle inEvents match outEventsResult with | Error err -> return logErr err | Ok outEvents -> log <| HandlerFinished outEvents match outEvents with | [] -> log <| NoEventsToSave return Responder.noEventResponse () | _ -> let eventMeta = createEventMeta tenantId userId match serializeEvents meta.TargetId meta.Version meta.CommandId request.CorrelationId eventMeta outEvents with | Error err -> return logErr err | Ok eventDatas -> // bad grammar for clarity! log <| EventsSerialized let! eventSaveResult = save store meta.TargetId meta.Version eventDatas match eventSaveResult with | Error err -> return logErr err | Ok write -> log <| EventsSaved (write.LogPosition.PreparePosition, write.LogPosition.CommitPosition, write.NextExpectedVersion) return Responder.toEventResponse () } |> Async.tee logResponse |> Async.StartAsTask
type PipelineState = { Request: Request ReadJson: unit -> Async// everything else optional! HandlerPath: string option ... ... ... ... ... }
let step events = match events with | EventsSaved _ :: _ -> createResponse Responder.toEventResponse () | NoEventsToSave :: _ -> createResponse Responder.noEventResponse () | ErrorEncountered error :: _ -> createResponse Responder.toErrorResponse error | [ RequestStarted (request, _, _) ] -> Async.lift getHandler request.Path | [ HandlerFound _; RequestStarted (request, _, _) ] -> Async.lift getUser request.User | [ ClaimsLoaded user; HandlerFound (handlerPath, _); _ ] -> Async.lift2 authorize handlerPath user | [ RequestAuthorized _; _; _; RequestStarted (_, readJson, _) ] -> getJson readJson () | [ JsonLoaded json; _; _; _; _ ] -> Async.lift deserializeMeta json | [ RequestMetaDeserialized meta; _; _; _; _; _ ] -> loadEvents meta.TargetId | [ EventsLoaded es; RequestMetaDeserialized meta; _; _; _; _; _ ] -> Async.lift2 checkConcurrency meta.Version <| List.length es | [ ConcurrencyOkay _; EventsLoaded es; RequestMetaDeserialized meta; JsonLoaded json; _; ClaimsLoaded user; HandlerFound (_, handle); RequestStarted (request, _, _) ] -> runHandler meta request user json handle es | [ HandlerFinished es; _; _; _; _; ClaimsLoaded user; _; RequestStarted (request, _, _) ] -> save request user es | _ -> Async.lift unexpectedSequence events
retn (firstStepGroupFn request readJson at) |> apply (getHandler request.Path |> Result.tee logHandler) |> apply (getUser request.User |> Result.tee logUser) |> apply (authorize handlerPath user |> Result.tee logAuthorize) |> bind ( retn (secondStepGroupFn ...) >> apply ... )
Actions describe the fact that something happened
http://redux.js.org/docs/basics/Reducers.html
As your app grows, instead of adding stores, you split the root reducer into smaller reducers independently operating on the different parts of the state tree.
http://redux.js.org/docs/api/Store.html in A Note for Flux UsersEssentially, different properties off of the Store's state represent different views. A reducer is responsible for updating its own view.