### Clojure: Integrate Pavlov with Portal using tap subscriber Source: https://github.com/thomascothran/pavlov/blob/master/README.md This example shows how to integrate Pavlov's b-program execution with Portal for visual debugging. It sets up Portal, adds its submission function to the tap, and then runs a b-program using the 'tap' subscriber for real-time visualization of program state and events within Portal. It requires importing libraries for Portal, the tap subscriber, and b-program execution. ```clojure (require '[portal.api :as portal]) (require '[tech.thomascothran.pavlov.subscribers.tap :as taps]) (require '[tech.thomascothran.pavlov.bprogram.ephemeral :as bpe]) ;; Set up portal (def p (portal/open)) (add-tap #'portal/submit) ;; Run the program @(bpe/execute! [[:bthread-1 {:request #{:event-a}}] [:bthread-2 {:request #{:event-b}}]] {:subscribers {:tap taps/subscriber} :kill-after 50}) ;; <- add the tap ``` -------------------------------- ### Clojure BThread Requesting a Simple Event Source: https://github.com/thomascothran/pavlov/blob/master/README.md Creates a bthread that always requests the ':a' event. This is a basic example of event subscription. ```clojure (b/bids [{:request #{:a}}]) ;; => the event is the same as {:type :a} ``` -------------------------------- ### Follow Execution Path with Multiple Branches in Pavlov (Clojure) Source: https://github.com/thomascothran/pavlov/blob/master/doc/navigating-bprograms.md This Clojure code uses `pnav/follow` to navigate a Pavlov program by specifying a sequence of branch event types. It automatically traverses linear paths and allows explicit selection at decision points. The examples show following paths with single and multiple steps, and handling cases where a path does not exist. ```clojure (-> (pnav/follow root [1]) :pavlov/event e/type) ;=> 1 (-> (pnav/follow root [1 3]) :pavlov/event e/type) ;=> 3 (-> (pnav/follow (pnav/root {:linear (b/bids [{:request [:a]} {:request [:b]} {:request [:c]}])}) [:a :c]) :pavlov/event e/type) ;=> :c (-> (pnav/follow (pnav/root {:linear (b/bids [{:request [:a]} {:request [:b]} {:request [:c]}])}) [:a :d]) :pavlov/event) ;=> nil ; no matching branch at that decision point ``` -------------------------------- ### Clojure Step Function for BThread Execution Source: https://github.com/thomascothran/pavlov/blob/master/README.md Defines a step function to manage a bthread's state. It takes the previous state and an event, returning the next state and a bid. This example limits execution to three calls of the ':test' event. ```clojure (require '[tech.thomascothran.pavlov.bthread :as b]) (defn only-thrice [{:keys [count done?] :as state} event] (cond (nil? event) [{:count 0} {:wait-on #{:test}}] done? [state nil] (< count 2) [{:count (inc count)} {:wait-on #{:test}}] :else [{:count (inc count) :done? true} nil])) (def count-down-bthread (b/step only-thrice)) ;; b/notify! will never be called in real application code, ;; but it is useful at the REPL to see what the bthread does. [(b/notify! count-down-bthread nil) (b/notify! count-down-bthread {:type :test}) (b/notify! count-down-bthread {:type :test}) (b/notify! count-down-bthread {:type :test}) (b/state count-down-bthread)] ;; => [{:wait-on #{:test}} ;; {:wait-on #{:test}} ;; {:wait-on #{:test}} ;; nil ;; {:count 3, :done? true}] ``` -------------------------------- ### Clojure: Simulate Pavlov Bthread lifecycle with notify! Source: https://github.com/thomascothran/pavlov/blob/master/doc/what-is-a-bthread.md This example shows how to interact with a defined Pavlov bthread using the 'b/notify!' function. It simulates sending events to the 'three-ticks' bthread and observes its lifecycle, including initial waiting, state increments, and eventual request for a completion event. ```clojure [(b/notify! three-ticks nil) (b/notify! three-ticks {:type :tick}) (b/notify! three-ticks {:type :tick}) (b/notify! three-ticks {:type :tick}) (b/notify! three-ticks {:type :tick})] ``` -------------------------------- ### Explore Bthreads with Portal REPL (Clojure) Source: https://github.com/thomascothran/pavlov/blob/master/doc/designing-business-programs-with-behavioral-threads.md This snippet demonstrates how to use the `nav` function with Portal's API to open bthreads in an interactive REPL. It allows users to explore diverging execution paths by selecting events. Dependencies include `portal.api` and `pavlov.explorer`. ```clojure (comment (require '[portal.api :as portal]) (require '[pavlov.explorer :as pvp]) (do (def p (portal/open)) (add-tap #'portal/submit)) (-> (reduce into (safety-bthreads-v1) [(make-bthreads-v1) (make-environment-bthreads-v1)]) (pvp/bthreads->navigable) (tap>))) ``` -------------------------------- ### Clojure: Bthread for Account Opening on Funding Source: https://github.com/thomascothran/pavlov/blob/master/doc/designing-business-programs-with-behavioral-threads.md This bthread defines the business logic for opening an account. It waits for the ':initial-deposit-paid' event and then requests the ':account-opened' event. ```clojure (defn make-open-on-funding-bthread [] (b/bids [{:wait-on #{:initial-deposit-paid}} {:request #{{:type :account-opened}}}])) ``` -------------------------------- ### Require Pavlov Navigation Libraries in Clojure Source: https://github.com/thomascothran/pavlov/blob/master/doc/navigating-bprograms.md This snippet shows how to import the necessary Clojure libraries for working with Pavlov behavioral programs and navigation. It includes `tech.thomascothran.pavlov.nav` for navigation, `tech.thomascothran.pavlov.bthread` for bthread management, and `tech.thomascothran.pavlov.event` for event handling. ```clojure (require '[tech.thomascothran.pavlov.nav :as pnav] '[tech.thomascothran.pavlov.bthread :as b] '[tech.thomascothran.pavlov.event :as e]) ``` -------------------------------- ### Create Account Bthread - Clojure Source: https://github.com/thomascothran/pavlov/blob/master/README.md This snippet defines a bthread using Pavlov's `on` function to handle a `:create-account` event. When triggered, it inserts a new account record into a database using `next.jdbc.sql` and then requests a `:account-created` event. The `on` function ensures that errors within the handler are caught and reported as a specific event type. ```clojure (require '[next.jdbc.sql :as sql]) (require '[tech.thomascothran.pavlov.bthread :as b]) (defn create-account! [db-conn {:keys [account]}] (sql/insert! db-conn :account account) {:request #{{:event-type :account-created}}}) (def make-create-account-bthread [db-conn] (b/on :create-account create-account!)) ``` -------------------------------- ### Create Environment Bthreads for System Inputs (Clojure) Source: https://github.com/thomascothran/pavlov/blob/master/doc/navigating-bprograms.md This snippet demonstrates how to define environment bthreads in Clojure. These bthreads represent external system inputs and are used to introduce intentional branching during exploration. They utilize the `b/bids` function to define requested events. ```clojure (defn make-env-bthreads [] {:submit (b/bids [{:request #{{:type :application-submitted}}}]) :pay-deposit (b/bids [{:request #{{:type :initial-deposit-paid}}}])}) ``` -------------------------------- ### Create Navigable Root Node for Pavlov Program in Clojure Source: https://github.com/thomascothran/pavlov/blob/master/doc/navigating-bprograms.md This Clojure code demonstrates how to initialize a navigable root node for a Pavlov behavioral program. It takes the bthreads generated by `make-test-bthreads` and passes them to `pnav/root`, creating an entry point for interactive navigation through the program's execution states and branches. ```clojure (def root (pnav/root (make-test-bthreads))) ``` -------------------------------- ### Clojure: Bthread for Requesting Initial Deposit Source: https://github.com/thomascothran/pavlov/blob/master/doc/designing-business-programs-with-behavioral-threads.md This bthread simply requests the ':initial-deposit-requested' event. It represents a step in the application process that can be triggered by various conditions. ```clojure (defn make-request-initial-deposit-bthread [] (b/bids [{:request #{{:type :initial-deposit-requested}}}])) ``` -------------------------------- ### Access Bthread State Snapshots in Pavlov Navigation (Clojure) Source: https://github.com/thomascothran/pavlov/blob/master/doc/navigating-bprograms.md This Clojure code shows how to access the snapshot of bthread states at a given node in a Pavlov program. It retrieves the `:pavlov/bthreads` map from the root node and then explores its keys, specifically looking at `:pavlov/bthread-states` to see the states of individual bthreads like `:letters` and `:numbers`. ```clojure (keys (:pavlov/bthreads root)) ;=> (:pavlov/bthread-states :pavlov/bthread->bid :pavlov/bthreads-by-priority) (keys (get-in root [:pavlov/bthreads :pavlov/bthread-states])) ;=> (:letters :numbers) ``` -------------------------------- ### Inspect Next Branches After Navigation in Pavlov (Clojure) Source: https://github.com/thomascothran/pavlov/blob/master/doc/navigating-bprograms.md After navigating to a specific node in the Pavlov program (e.g., `at-1`), this Clojure snippet inspects the subsequent available branches. It accesses the `:pavlov/branches` of the current node and maps over them to display the event types of the next possible steps. ```clojure (->> (:pavlov/branches at-1) (mapv (comp e/type :pavlov/event))) ;=> [3 :a] ``` -------------------------------- ### Clojure: Environment Bthreads for Application Submission and Deposit Payment Source: https://github.com/thomascothran/pavlov/blob/master/doc/designing-business-programs-with-behavioral-threads.md These environment bthreads simulate external events like application submission and initial deposit payment. They are used in testing contexts to drive the system's behavior and explore execution paths. ```clojure (defn make-environment-bthreads [] {::application-submitted (b/bids [{:request #{{:type :application-submitted}}}]) ::pay-deposit (b/bids [{:request #{{:type :initial-deposit-paid}}}])}) ``` -------------------------------- ### Clojure: Define Bthread for Requesting CIP Verification Source: https://github.com/thomascothran/pavlov/blob/master/doc/designing-business-programs-with-behavioral-threads.md This bthread initiates the request for CIP (Customer Identification Program) verification after an application has been submitted. It's a core step in the customer onboarding process. ```clojure (ns demo.bank.domain (:require [tech.thomascothran.pavlov.bthread :as b] [tech.thomascothran.pavlov.viz.portal :as pvp] [tech.thomascothran.pavlov.model.check :as check])) (defn make-request-cip-verification-bthread [] (b/bids [{:wait-on #{:application-submitted}} {:request #{{:type :request-cip-verification}}}])) ``` -------------------------------- ### Define Test Bthreads for Pavlov Navigation in Clojure Source: https://github.com/thomascothran/pavlov/blob/master/doc/navigating-bprograms.md This Clojure function defines a set of test behavioral threads (bthreads) for Pavlov. It includes a 'letters' bthread that emits events sequentially (':a', ':b', ':c') and a 'numbers' bthread that introduces a branch on its first step, offering event choices of #{1 2} before proceeding to #{3}. ```clojure (defn make-test-bthreads [] {:letters (b/bids [{:request [:a]} {:request [:b]} {:request [:c]}]) :numbers (b/bids [{:request #{1 2}} ; unordered → branch {:request #{3}}])}) ``` -------------------------------- ### Construct Model Checker Domain (Clojure) Source: https://github.com/thomascothran/pavlov/blob/master/doc/designing-business-programs-with-behavioral-threads.md These functions define the components for the Pavlov model checker: domain bthreads, environment bthreads, and safety bthreads. They are used to construct the system under test. Each function returns a map of bthread names to their definitions. ```clojure (defn make-bthreads-v1 [] {::request-cip-verification-bthread (make-request-cip-verification-bthread) ::request-ofac-screening-bthread (make-request-ofac-screening-bthread) ::cip-failure-rule-bthread (make-cip-failure-rule-bthread) ::ofac-hit-rule-bthread (make-ofac-hit-rule-bthread) ::request-initial-deposit-bthread (make-request-initial-deposit-bthread) ::block-deposit-until-cip-verified (make-block-deposit-until-cip-verified) ::block-opening-until-ofac-cleared (make-block-opening-until-ofac-cleared) ::open-on-funding (make-open-on-funding-bthread)}) (defn make-environment-bthreads-v1 [] {::application-submitted (b/bids [{:request #{{:type :application-submitted}}}]) ::pay-deposit (b/bids [{:request #{{:type :initial-deposit-paid}}}])}) (defn safety-bthreads-v1 [] {::account-opening-requires-ofac-screening (make-account-opening-requires-ofac-screening-bthread)}) ``` -------------------------------- ### Bthread Macro - Mimic Case Option - Clojure Source: https://github.com/thomascothran/pavlov/blob/master/doc/design/003_bthread-macro.md Proposes a Clojure bthread macro using a syntax similar to `case`. It requires an initialization step (`:pavlov/init`) and allows defining event triggers and their corresponding actions. This format is more amenable to linting tools. ```clojure (def my-bthread (b/thread [prev-state event] :pavlov/init ;; required! [{:initialized true} {:wait-on #{:fire-missiles}}] #{:fire-missiles} ;; set of all events to trigger body (let [result (missiles-api/fire!)] [prev-state {:request #{{:type :missiles-fired :result result}}}]) ;; optional default, if not provided returns {} - no requests, ;; waits or blocks [prev-state {:wait-on #{:fire-missiles}}])) ``` -------------------------------- ### Create Bthreads with Priority/Non-Deterministic Event Requests - Clojure Source: https://github.com/thomascothran/pavlov/blob/master/doc/designing-business-programs-with-behavioral-threads.md Demonstrates how to create bthreads in Clojure that request events with varying priority. It shows how to define bthreads that lead to deterministic or non-deterministic event selection based on the collection used for event requests. ```clojure (require '[tech.thomascothran.pavlov.bthread :as b]) (defn make-bthread-a [] ;; b/bids creates a bthread that requests the bids in the vector (b/bids [{:request #{:event-1 :event-2}}])) ;; <- non-deterministic (defn make-bthread-b [] (b/bids [{:request [:event-3 :event-4]}])) ;; <- ordered priority (defn make-bthreads-with-priority [] [[:bthread-a (make-bthread-a)] [:bthread-b (make-bthread-b)]]) (defn make-bthreads-without-priority [] {:bthread-a (make-bthread-a) :bthread-b (make-bthread-b)}) ``` -------------------------------- ### Define General Purpose Bthreads with `b/thread` Macro Source: https://github.com/thomascothran/pavlov/blob/master/README.md The `b/thread` macro provides an expressive and safe way to create general-purpose bthreads. It simplifies bthread creation by mimicking `defn` with `case` logic. The macro handles state transitions and event handling, preventing common beginner mistakes in behavioral programming. Each form within `b/thread` must return a tuple of the next state and a bid. ```clojure (require '[tech.thomascothran.pavlov.bthread :as b]) (b/thread [prev-state event] :pavlov/init [{:initialized true} {:wait-on #{:launch-rocket}}] :launch-rocket (let [result (rocket-api/launch!)] [prev-state {:request #{{:type :rocket-launched :result result}}}]) [prev-state {:wait-on #{:launch-rocket}}]) ``` -------------------------------- ### Coordinate Multiple Prerequisites with `after-all` Source: https://github.com/thomascothran/pavlov/blob/master/README.md The `after-all` function coordinates several prerequisites, allowing downstream work to commence only after all have occurred. It takes a set of event types and a function `f`. The bthread waits for each event type in the set, then invokes `f` with a vector of the events in arrival order. The value returned by `f` becomes the next bid, after which the bthread terminates. ```clojure (require '[tech.thomascothran.pavlov.bthread :as b]) (def order-ready (b/after-all #{:payment/authorized :packing/completed} (fn [events] (let [order-id (->> events (keep :order/id) first)] {:request #{{:type :order/ready :order/id order-id :sources (mapv :type events)}}})))) ``` -------------------------------- ### Inspect Next Branches from Pavlov Root Node in Clojure Source: https://github.com/thomascothran/pavlov/blob/master/doc/navigating-bprograms.md This Clojure snippet inspects the available next steps (branch event types) from the root node of a Pavlov behavioral program. It accesses the `:pavlov/branches` key of the root node, maps over each branch to extract the event type, and displays the possible next events that can be chosen. ```clojure (->> (:pavlov/branches root) (mapv (comp e/type :pavlov/event))) ;=> [1 2 :a] ``` -------------------------------- ### Navigate to a Specific Branch in Pavlov Program (Clojure) Source: https://github.com/thomascothran/pavlov/blob/master/doc/navigating-bprograms.md This Clojure code navigates from the root node of a Pavlov program to a specific state by selecting an event. `pnav/to root 1` moves the navigation to the state reached after event `1`. The subsequent expression then retrieves and displays the event type of the current node. ```clojure (def at-1 (pnav/to root 1)) (-> at-1 :pavlov/event e/type) ;=> 1 ``` -------------------------------- ### Clojure BThreads for Event Blocking and Cancellation Source: https://github.com/thomascothran/pavlov/blob/master/README.md Demonstrates event cancellation using `:wait-on` and `:block`. `bthread-two` blocks `:a` until `:c` occurs, allowing `:a` to succeed if `:c` happens first. If `:b` occurs before `:c`, `:a` is cancelled. ```clojure (def bthread-one (b/bids [{:wait-on #{:b} :request #{:a}}])) (def bthread-two (b/bids [{:block #{:a} :wait-on #{:c}}])) ``` -------------------------------- ### Bthread Macro - Mimic Defrecord Option - Clojure Source: https://github.com/thomascothran/pavlov/blob/master/doc/design/003_bthread-macro.md Presents an alternative Clojure bthread macro inspired by `defrecord` syntax. It uses `init` for initialization, `on` for event handling, and `default` for fallback logic. This structure aims for enhanced readability and maintainability. ```clojure (def my-bthread (b/thread [prev-state event] (init []) ;; required! [{:initialized true} {:wait-on #{:fire-missiles}}] (on [:fire-missiles] ;; set of all events to trigger body (let [result (missiles-api/fire!)] [prev-state {:request #{{:type :missiles-fired :result result}}}]) ;; optional default, if not provided returns {} - no requests, ;; waits or blocks (default []) [prev-state {:wait-on #{:fire-missiles}}])) ``` -------------------------------- ### Inspect Crumbs, Branches, and Path in Pavlov Node (Clojure) Source: https://github.com/thomascothran/pavlov/blob/master/doc/navigating-bprograms.md This Clojure snippet demonstrates how to inspect the navigation history (crumbs), available next steps (branches), and the event path to the current node in a Pavlov program. It navigates through several states and then extracts and displays the event types of the crumbs, the event types of the branches, and the full path vector. ```clojure (let [n1 (pnav/to root 1) n3 (pnav/to n1 3)] [(mapv (comp e/type :pavlov/event) (:pavlov/crumbs n3)) (mapv (comp e/type :pavlov/event) (:pavlov/branches n3)) (:pavlov/path n3)]) ;=> [[nil 1] [:a] [1 3]] ``` -------------------------------- ### Clojure: Execute B-program with a logger subscriber Source: https://github.com/thomascothran/pavlov/blob/master/README.md This snippet demonstrates how to execute a Pavlov b-program with a custom logger subscriber. The subscriber, defined as a function, will print each event and the bthread-to-bid mapping to the console. It requires importing necessary libraries for b-program execution and pretty-printing. ```clojure (require '[tech.thomascothran.pavlov.bprogram.ephemeral :as bpe]) (require '[clojure.pprint :refer [pprint]]) (def subscribers {:logger (fn [event bthread->bid] (pprint {:event event :bthread->bid bthread->bid}))}) @(bpe/execute! [[:bthread-1 {:request #{:event-a}}] [:bthread-2 {:request #{:event-b}}]] {:subscribers subscribers :kill-after 50}) ``` -------------------------------- ### Clojure: Coordinate multiple event sources with b/after-all Source: https://github.com/thomascothran/pavlov/blob/master/doc/what-is-a-bthread.md The 'b/after-all' constructor is designed to coordinate bthreads that depend on the occurrence of multiple, independent events. It waits for all specified event types to be received before executing a provided function, which can then use the collected events to generate a final bid. ```clojure (def ready-when-packed (b/after-all #{:payment/authorized :packing/completed} (fn [events] (let [order-id (->> events (keep :order/id) first)] {:request #{{:type :order/ready :order/id order-id :sources (mapv :type events)}}})))) [(b/notify! ready-when-packed nil) (b/notify! ready-when-packed {:type :packing/completed :order/id 42}) (b/notify! ready-when-packed {:type :payment/authorized :order/id 42}) (b/notify! ready-when-packed {:type :extra :order/id 42})] ``` -------------------------------- ### Execute Ephemeral Bprogram - Clojure Source: https://github.com/thomascothran/pavlov/blob/master/README.md This snippet demonstrates executing a behavioral program (bprogram) using the ephemeral executor in Pavlov. It defines three bthreads: one for adding hot water, one for cold water, and an alternator to interleave them. The program is configured to log each selected event and its bids, and it will terminate after a specified duration or upon deadlock. ```clojure (ns water-controls.app (:require [tech.thomascothran.pavlov.bthread :as b] [tech.thomascothran.pavlov.bprogram :as bp] [tech.thomascothran.pavlov.bprogram.ephemeral :as bpe])) (defn log-step [event program] (println "selected" event) (println "bids" (bp/bthread->bids program)) (println "---")) @(bpe/execute! [[:add-hot (b/repeat 3 {:request #{:add-hot-water}})] [:add-cold (b/repeat 3 {:request #{:add-cold-water}})] [:alternator (b/round-robin [(b/repeat {:wait-on #{:add-cold-water} :block #{:add-hot-water}}) (b/repeat {:wait-on #{:add-hot-water} :block #{:add-cold-water}})])]] {:subscribers {:logger log-step} :kill-after 50}) ;; if program has not exited by 50 ms, kill it ;; => prints each selected event with its active bids ;; => {:type :tech.thomascothran.pavlov.bprogram.ephemeral/deadlock, ;; :terminal true} ``` -------------------------------- ### Defining Bthreads with Ordered and Unordered Requests Source: https://github.com/thomascothran/pavlov/blob/master/doc/what-is-a-bthread.md Demonstrates how to define bthreads using the `b/bids` function, showcasing how to specify event requests with different priority mechanisms. Ordered requests (vectors/lists) provide explicit priority, while unordered requests (sets/maps) result in non-deterministic selection. ```clojure (def bthread-a (b/bids [{:request #{{:type :a1} {:type :at}}}])) ;; event selected non-deterministically (def bthread-b (b/bids [{:request [{:type :b1} {:type :b2}]}])) ;; :b1 has priority over :b2 ``` -------------------------------- ### Clojure: Rule Bthread for CIP Failure Event Source: https://github.com/thomascothran/pavlov/blob/master/doc/designing-business-programs-with-behavioral-threads.md This bthread defines a business rule that triggers the ':application-declined' event when a ':cip-failed' event occurs. It ensures that applications failing verification are promptly handled. ```clojure (defn make-cip-failure-rule-bthread [] (b/on :cip-failed (constantly {:request #{{:type :application-declined}}}))) ``` -------------------------------- ### Run Model Checker and Check for Violations (Clojure) Source: https://github.com/thomascothran/pavlov/blob/master/doc/designing-business-programs-with-behavioral-threads.md This snippet shows how to invoke the Pavlov model checker with the defined bthreads and environment. The `check/check` function analyzes the system for deadlocks or invariant violations. If a violation occurs, it is returned; otherwise, `nil` is returned. ```clojure (comment (require '[pavlov.checker :as check]) (-> {:bthreads (make-bthreads-v1) :environment-bthreads (make-environment-bthreads-v1) :safety-bthreads (safety-bthreads-v1) :check-deadlock? false} (check/check) tap>)) ``` -------------------------------- ### Clojure: Block Opening Until OFAC Cleared Source: https://github.com/thomascothran/pavlov/blob/master/doc/designing-business-programs-with-behavioral-threads.md This bthread implements a rule to block the ':initial-deposit-requested' event until the OFAC screening is cleared (':ofac-clear'). This prioritizes compliance checks before financial steps. ```clojure (defn make-block-opening-until-ofac-cleared [] (b/bids [{:block #{:initial-deposit-requested} :wait-on #{:ofac-clear}}])) ``` -------------------------------- ### Clojure: Block Deposit Until CIP Verified Source: https://github.com/thomascothran/pavlov/blob/master/doc/designing-business-programs-with-behavioral-threads.md This bthread enforces a business rule that blocks the ':initial-deposit-requested' event until the ':cip-verified' event has successfully occurred. This ensures identity verification before financial transactions. ```clojure (defn make-block-deposit-until-cip-verified [] (b/bids [{:block #{:initial-deposit-requested} :wait-on #{:cip-verified}}])) ``` -------------------------------- ### Create a Repeating Bid Bthread Source: https://github.com/thomascothran/pavlov/blob/master/README.md The `b/repeat` function creates a bthread that repeatedly issues the same bid a specified number of times. This is useful for scenarios requiring an action to occur multiple times, such as setting off fireworks 10,000 times. ```clojure (b/repeat 10000 {:request #{:fireworks}}) ``` -------------------------------- ### Create Bthread from a Sequence of Bids Source: https://github.com/thomascothran/pavlov/blob/master/README.md The `b/bids` function creates a bthread from a sequence of bids, suitable for finite and relatively short sequences. This bthread will return a bid twice, after which it will be deregistered. The entire sequence is realized in memory. ```clojure (b/bids [{:wait-on #{:good-morning} :block #{:good-evening}} {:wait-on #{:good-evening} :block #{:good-morning}}]) ``` -------------------------------- ### Create a Round-Robin Notification Bthread Source: https://github.com/thomascothran/pavlov/blob/master/README.md The `b/round-robin` function creates a bthread that notifies other bthreads in a round-robin fashion. It takes a list of bthread configurations, cycling through them to send notifications. ```clojure (b/round-robin [{:wait-on #{:good-morning} :block #{:good-evening}} {:wait-on #{:good-evening} :block #{:good-morning}}]) ``` -------------------------------- ### Clojure: Create a bthread from a sequence of bids using b/bids Source: https://github.com/thomascothran/pavlov/blob/master/doc/what-is-a-bthread.md The 'b/bids' constructor creates a bthread that executes a predefined sequence of bids. This is useful for replaying finite, scripted behaviors. The bthread automatically removes itself once the sequence is exhausted, requiring no external state management. ```clojure (def staged-requests (b/bids [{:request #{:prep/begin}} {:request #{:prep/finish}} {:request #{:ship}}])) [(b/notify! staged-requests nil) (b/notify! staged-requests {:type :prep/begin}) (b/notify! staged-requests {:type :prep/finish}) (b/notify! staged-requests {:type :ship})] ``` -------------------------------- ### Clojure: Define Bthread for Requesting OFAC Screening Source: https://github.com/thomascothran/pavlov/blob/master/doc/designing-business-programs-with-behavioral-threads.md This bthread initiates the OFAC (Office of Foreign Assets Control) screening process after an application has been submitted. It ensures compliance with sanctions lists. ```clojure (defn make-request-ofac-screening-bthread [] (b/bids [{:wait-on #{:application-submitted}} {:request #{{:type :ofac-screening-requested}}}])) ``` -------------------------------- ### Clojure: Rule Bthread for OFAC Hit Event Source: https://github.com/thomascothran/pavlov/blob/master/doc/designing-business-programs-with-behavioral-threads.md This bthread implements a business rule where an OFAC hit ('ofac-hit') results in the ':application-declined' event. This enforces compliance with sanctions screening. ```clojure (defn make-ofac-hit-rule-bthread [] (b/on :ofac-hit (constantly {:request #{{:type :application-declined}}}))) ``` -------------------------------- ### Define Step Function with If - Clojure Source: https://github.com/thomascothran/pavlov/blob/master/doc/design/003_bthread-macro.md An alternative Clojure step function definition using `if` to differentiate between initialization (nil event) and other event types. It demonstrates handling multiple potential events within the `else` block, though this can obscure specific event logic. ```clojure (def my-step-fn (fn [prev-state event] (if (nil? event) [{:initialized true} {:request #{{:type :event-a}} :wait-on #{:event-b}}]) ;; handle :event-a OR :event-b OR event-c OR event-d [(update prev-state :called-times inc) {:request #{{:type :event-c}}}) :wait-on #{:event-d}}]))) ``` -------------------------------- ### Clojure: Define a bthread to react to a specific event using b/on Source: https://github.com/thomascothran/pavlov/blob/master/doc/what-is-a-bthread.md The 'b/on' helper is used to create a bthread that triggers a specific action upon receiving a single, designated event type. It does not maintain state between events and is ideal for stateless reactions to incoming events, extracting data from the event to form its response. ```clojure (def review-on-receipt (b/on :invoice/received (fn [event] {:request #{{:type :invoice/reviewed :invoice/id (:invoice/id event)}}}))) [(b/notify! review-on-receipt nil) (b/notify! review-on-receipt {:type :invoice/received :invoice/id 17}) (b/notify! review-on-receipt {:type :invoice/reviewed :invoice/id 17})] ``` -------------------------------- ### Define Step Function with Case - Clojure Source: https://github.com/thomascothran/pavlov/blob/master/doc/design/003_bthread-macro.md Defines a step function using Clojure's `case` statement to handle different event types. It initializes the state and specifies event dependencies. This approach can become verbose with complex event handling. ```clojure (def my-step-fn (fn [prev-state {event-type :type :as event}] (case event-type ;; Initialize nil [{:initialized true} {:wait-on #{:event-a}}] :event-a [(update prev-state :a-called inc) {:request #{{:type :event-c}}}) :wait-on #{:event-d}}]))) ``` -------------------------------- ### Clojure BThread Blocking Until Event Occurs Source: https://github.com/thomascothran/pavlov/blob/master/README.md Illustrates using `:wait` and `:block` together. Event `:c` is blocked until `:b` occurs, after which the bthread terminates. ```clojure (b/bids [{:wait-on #{:b} :block #{:c}}]) ``` -------------------------------- ### Clojure: Implement a Pavlov Bthread with a step function Source: https://github.com/thomascothran/pavlov/blob/master/doc/what-is-a-bthread.md This snippet demonstrates how to define a Pavlov bthread using the 'b/step' function. The step function takes the previous state and the current event to produce the next state and a bid map. It's a pure function with no external dependencies, suitable for managing stateful bthreads. ```clojure (require '[tech.thomascothran.pavlov.bthread :as b]) (def three-ticks (b/step (fn [state _event] (cond (nil? state) [0 {:wait-on #{:tick}}] (< state 2) [(inc state) {:wait-on #{:tick}}] (= state :finished) [:finished nil] :else [:finished {:request #{{:type :counter/done}}}]]))) ``` -------------------------------- ### Define Door Alarm Bthread with b/thread Macro (Clojure) Source: https://github.com/thomascothran/pavlov/blob/master/doc/what-is-a-bthread.md Defines a bthread named 'door-alarm' using the b/thread macro. This bthread manages states related to a door being opened or closed, responding to specific events and requesting actions like 'alarm/check' or 'alarm/reset'. It also includes a default clause for unhandled events. ```clojure (def door-alarm (b/thread [state event] :pavlov/init [{:door :closed} {:wait-on #{:door/opened}}] :door/opened [{:door :open} {:wait-on #{:door/closed} :block #{:door/opened} :request #{{:type :alarm/check}}}] :door/closed [{:door :closed} {:wait-on #{:door/opened} :request #{{:type :alarm/reset}}}] ;; remember this! This is easy to forget. This will be called ;; when an event is received that doesn't match any other clause. [state {:wait-on #{:door/opened :door/closed}}])) [(b/notify! door-alarm nil) (b/notify! door-alarm {:type :door/opened}) (b/notify! door-alarm {:type :door/closed}) (b/notify! door-alarm {:type :door/locked})] ;; => [{:wait-on #{:door/opened}} ;; {:wait-on #{:door/closed}, ;; :block #{:door/opened}, ;; :request #{{:type :alarm/check}}} ;; {:wait-on #{:door/opened}, ;; :request #{{:type :alarm/reset}}} ;; {:wait-on #{:door/opened :door/closed}}] ``` -------------------------------- ### Define Step Function with Nil Event Error - Clojure Source: https://github.com/thomascothran/pavlov/blob/master/doc/design/003_bthread-macro.md Illustrates a potential error scenario in Clojure step functions where a `nil` event case is not properly handled, leading to an error if a subsequent event is not explicitly managed. This highlights the need for clearer bthread definitions. ```clojure (def my-step-fn (fn [prev-state {event-type :type :as event}] (case event-type ;; Initialize nil [nil {:request #{#{:type :fire-missiles}}}] :fire-missiles (do (missile-api/fire!) [nil {:request #{{:type :missiles-fired}}}])))) ``` -------------------------------- ### Capture Model Checker State in Clojure Source: https://github.com/thomascothran/pavlov/blob/master/context/model_check_state_restore.md This function captures the current state of the model checker, including bthread states, current bids, the last processed event, and the priority ordering of bthreads. It serializes individual bthread states and saves crucial bprogram state components for later restoration. ```clojure (defn capture-model-checker-state [bprogram-state bthreads] {:bthread-states (into {} (map (fn [bt] [(b/name bt) (b/serialize bt)]) bthreads)) :bthread->bid (:bthread->bid bprogram-state) ; Current bids! :last-event (:last-event bprogram-state) :bthreads-by-priority (:bthreads-by-priority bprogram-state)}) ``` -------------------------------- ### Explore Paths with State Restoration in Pavlov Source: https://github.com/thomascothran/pavlov/blob/master/context/model_check_state_restore.md Explores possible execution paths within the model checker by capturing and restoring state. It detects cycles, explores each event, and recursively calls itself with the restored state. This function is key for the backtracking mechanism in path exploration. ```clojure (defn explore-path [state path-so-far make-bthreads] (if (seen? state) nil ; Cycle detected (let [checkpoint (capture-model-model-checker-state state bthreads)] ; Explore each possible next event (for [event (possible-events state)] (let [next-state (step state event) ; ... check properties ...] (if violation? {:violation true :path (conj path-so-far event)} (let [restored (restore-model-checker-state checkpoint make-bthreads)] (explore-path restored (conj path-so-far event) make-bthreads)))))))) ``` -------------------------------- ### Define Safety Bthread for Invariant Violation (Clojure) Source: https://github.com/thomascothran/pavlov/blob/master/doc/designing-business-programs-with-behavioral-threads.md This code defines a safety bthread that enforces an invariant: an account should not be opened unless OFAC screening has cleared. It uses `b/bids` to specify wait conditions and invariant violations. The `:invariant-violated true` flag signals a rule that should not be triggered. ```clojure (defn make-account-opening-requires-ofac-screening-bthread [] (b/bids [{:wait-on #{:account-opened}} {:wait-on #{:ofac-clear} :request #{{:type :account-opened :invariant-violated true}}}])) ``` -------------------------------- ### Clojure BThread Terminating After Event Source: https://github.com/thomascothran/pavlov/blob/master/README.md Configures a bthread to terminate the bprogram when a ':c' event occurs. It also includes a ':finis' event upon termination. ```clojure (b/bids [{:wait-on #{:c}} {:terminate true :type :finis}]) ``` -------------------------------- ### Restore BThread State in Pavlov Model Checker Source: https://github.com/thomascothran/pavlov/blob/master/context/model_check_state_restore.md Restores the internal state of bthreads captured during model checking. It utilizes a factory function `make-bthreads` to create fresh bthread instances and then deserializes saved states into them. This is crucial for backtracking and exploring alternative execution paths. ```clojure (defn restore-model-checker-state [captured-state make-bthreads] (let [; Create fresh bthreads using the factory fresh-bthreads (make-bthreads) ; Restore internal states _ (doseq [bt fresh-bthreads] (when-let [saved-state (get-in captured-state [:bthread-states (b/name bt)])] (b/deserialize bt saved-state))) ; Reconstruct bprogram state using SAVED bids ; ... build event maps from saved bids ...])) ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.