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.
(function () { angular .module('myModule') .directive('dateFormat', dateFormat); dateFormat.$inject = []; var isoUtcDateFmt = /^([0-9]{4})-([0-9]{2})-([0-9]{2})T[0\:\.]*Z?$/; var inputDateFmt = /^(\d{1,2})[^0-9A-Za-z](\d{1,2})[^0-9A-Za-z](\d{4,})$/; var dayFn = { 1: 31, // Gregorian rules // 29 days if divisible by 4 but not 100 unless divisible by 400 2: function (y) { return y % 4 === 0 && (y % 100 !== 0 || y % 400 === 0) ? 29 : 28; }, 3: 31, 4: 30, 5: 31, 6: 30, 7: 31, 8: 31, 9: 30, 10: 31, 11: 30, 12: 31 }; function loadUtc(iso) { if (iso === undefined || iso === null || !isoUtcDateFmt.test(iso)) return ''; var month, day, year; iso.replace(isoUtcDateFmt, function (match, y, m, d) { month = m * 1; day = d * 1; year = y * 1; return ''; }); return '{0}/{1}/{2}'.format(month, day, year); } function leftPad(char, len, value) { var s = ('' + value); while (s.length < len) s = char + s; return s; } function saveUtc(ymd) { if (ymd === null) return null; var y = leftPad('0', 4, ymd.year), m = leftPad('0', 2, ymd.month), d = leftPad('0', 2, ymd.day); return '{0}-{1}-{2}T00:00:00Z'.format(y, m, d); } function inputToYmd(input) { if (input === null || input === undefined || !inputDateFmt.test(input)) return null; var month, day, year; input.replace(inputDateFmt, function (match, m, d, y) { month = m * 1; day = d * 1; year = y * 1; return ''; }); return { year: year, month: month, day: day }; } function validate(ymd, maxAge, minAge) { if (ymd === null) return [null]; var year = ymd.year, month = ymd.month, day = ymd.day; var errors = []; var maxDays = 31; // basic checks var monthValid = 1 <= month && month <= 12; var dayValid = false; // calculate max days in month if (monthValid) { var maxDaysFn = dayFn[month]; maxDays = angular.isNumber(maxDaysFn) ? maxDaysFn : (angular.isFunction(maxDaysFn) ? maxDaysFn(year) : maxDays); } dayValid = 1 <= day && day <= maxDays; if (!monthValid) errors.push('Month must be 1 to 12'); if (!dayValid) errors.push('Day must be 1 to {0}'.format(maxDays)); // min/max range checking if (errors.length === 0) { var now = new Date(); var d = new Date(now.getFullYear(), now.getMonth(), now.getDate()); var todayTime = d.getTime(); var todayYears = d.getFullYear(); var minTime = d.setFullYear(todayYears - maxAge); var maxTime = d.setFullYear(todayYears - minAge); var testTime = new Date(year, month - 1, day).getTime(); var dateValidMin = minTime <= testTime; var dateValidMax = testTime <= maxTime; if (!dateValidMin) errors.push('Max age is {0} years old'.format(maxAge)); if (!dateValidMax) errors.push('Minimum age is {0} years old'.format(minAge)); } return errors; } function dateFormat() { var me = this; return { scope: { dateErrors: '=' }, require: 'ngModel', link: function (scope, element, attrs, ctrl) { var maxAge = attrs.maxAge || 1000; var minAge = attrs.minAge || -1000; //View -> Model ctrl.$parsers.push(function (data) { if (data !== undefined && data !== null && data !== '') { var ymd = inputToYmd(data); var errors = validate(ymd, maxAge, minAge); // set validity if possible if (attrs.name) ctrl.$setValidity(attrs.name, errors.length === 0); // set errors if possible if (scope.dateErrors) scope.dateErrors = errors; // send ISO date string to model return saveUtc(ymd); } else { // set errors if possible if (scope.dateErrors) scope.dateErrors = []; return null; } }); //Model -> View ctrl.$formatters.push(function (_) { var data = ctrl.$modelValue; if (data !== undefined && data !== null && data !== '') { var inputText = loadUtc(ctrl.$modelValue); // load from ISO date string var ymd = inputToYmd(inputText); var errors = validate(ymd, maxAge, minAge); // set validity if possible if (attrs.name) ctrl.$setValidity(attrs.name, errors.length === 0); // set errors if possible if (scope.dateErrors) scope.dateErrors = errors; // send input to view return inputText; } else { // set errors if possible if (scope.dateErrors) scope.dateErrors = []; return ''; } }); } }; } })();
<input name="dob" type="text" required date-format max-age="110" min-age="14" date-errors="ctrl.dobErrors" ng-model="ctrl.dob" /> <div ng-repeat="obj in ctrl.dobErrors track by $id(obj)">{{obj}}</div>