From e5c67b1c22d37c7b25711a4b64329f66b37cfaad Mon Sep 17 00:00:00 2001 From: Janne Valkealahti Date: Sun, 5 Apr 2015 22:22:45 +0100 Subject: [PATCH] Reference doc updates --- docs/src/reference/asciidoc/appendix.adoc | 39 ++++++++++- docs/src/reference/asciidoc/faq.adoc | 43 ++++++++++++ .../reference/asciidoc/images/statechart2.png | Bin 19109 -> 20635 bytes .../reference/asciidoc/images/statechart4.png | Bin 0 -> 4221 bytes docs/src/reference/asciidoc/index.adoc | 1 + docs/src/reference/asciidoc/introduction.adoc | 28 ++++++-- docs/src/reference/asciidoc/preface.adoc | 2 + docs/src/reference/asciidoc/sm-examples.adoc | 66 ++++++++++++++---- docs/src/reference/asciidoc/sm.adoc | 57 +++++++++++++-- docs/src/statecharts/statechart4.txt | 21 ++++++ .../docs/DocsConfigurationSampleTests.java | 58 +++++++++++---- .../main/java/demo/cdplayer/Application.java | 8 ++- .../main/java/demo/showcase/Application.java | 8 ++- 13 files changed, 289 insertions(+), 42 deletions(-) create mode 100644 docs/src/reference/asciidoc/faq.adoc create mode 100644 docs/src/reference/asciidoc/images/statechart4.png create mode 100644 docs/src/statecharts/statechart4.txt diff --git a/docs/src/reference/asciidoc/appendix.adoc b/docs/src/reference/asciidoc/appendix.adoc index e0c2cdb3..e15bfb95 100644 --- a/docs/src/reference/asciidoc/appendix.adoc +++ b/docs/src/reference/asciidoc/appendix.adoc @@ -29,7 +29,7 @@ Assuming we have states _STATE1_, _STATE2_ and events _EVENT1_, _EVENT2_, logic of state machine can be defined as shown in below quick example. -image::images/statechart0.png[] +image::images/statechart0.png[width=500] [source,java,indent=0] ---- @@ -129,16 +129,53 @@ A transition is a relationship between a source state and a target state. A switch from a state to another is a _state transition_ caused by a _trigger_. +===== Internal Transition +Internal transition is used when action needs to be executed without +causing a state transition. With internal transition source and target +state is always a same and it is identical with self-transition in the +absence of state entry and exit actions. + +===== External vs. Local Transition +Most of the cases external and local transition are functionally +equivalent expect in cases where transition is happening between super +and sub states. Local transition doesn't cause exit and entry to +source state if target state is a substate of a source state. Other +way around, local transition doesn't cause exit and entry to target +state if target is a superstate of a source state. + +image::images/statechart4.png[width=500] + +Above image shows a different between local and external transitions +with a very simplistic super and sub states. + ==== Actions Actions are the ones which really glues state machine state changes with a users own code. State machine can execute action on various changes and steps in a state machine like entering or exiting a state, or doing a state transition. +Actions usually have access to a state context which gives running +code a choice to interact with a state machine in a various ways. +State context i.e. is exposing a whole state machine so user can +access extended state variables, event headers if transition is based +on an event, or actual transition where it is possible to see more +detailed where this state change is coming from and where it is going. + ==== Hierarchical State Machines Concept of a hierarchical state machine is used to simplify state design when particular states can only exist together. +Hierarchical states are really an innovation in UML state machine over +a traditional state machines like Mealy or Moore machines. +Hierarchical states allows to define some level of abstraction is a +sense how java developer would define a class structure with abstract +classes. For example having a nested state machine user is able to +define transition on a multiple level of states possibly with a +different conditions. State machine will always try to see if current +state is able to handle an event together with a transition guard +conditions. If these conditions are not evaluated to true, state +machine will simply see what a super state can handle. + ==== Regions Regions which are also called as orthogonal regions are usually viewed as exclusive OR operation applied to a states. Concept of a region in diff --git a/docs/src/reference/asciidoc/faq.adoc b/docs/src/reference/asciidoc/faq.adoc new file mode 100644 index 00000000..5f00a7ef --- /dev/null +++ b/docs/src/reference/asciidoc/faq.adoc @@ -0,0 +1,43 @@ +[[statemachine-faq]] += FAQ +This chapter tries to give solutions to question user is most likely +to ask. + +== State Changes + +.I want to transit to next state automatically + +{zwsp} + + +There are few choices a state machine developer can choose. + +* Implement an action and send appropriate event into a state machine + which triggers a transition into a proper target state. +* Define deferred event within a state and before sending an event + send a event which will be deferred and thus causing next + appropriate state transition when it is more convenient to handle + that event. +* Implement a triggerless transition which will automatically cause + state transition into a next state when state has entry and its + actions has been completed. + +.How do I defer an event + +{zwsp} + + +For more complete example and explanation, see cdplayer sample. + +== Extented State + +.How I can initialise variables on state machine start + +{zwsp} + + +Important concept in a state machine is that nothing really happens +unless there is a trigger which is causing a state transition which +then can fire actions. However, having said that, Spring Statemachine +always have an initial transition when state machine is started. With +this initial transition user can execute a simple action which within +a _StateContext_ can do whatever it likes with an extended state +variables. + diff --git a/docs/src/reference/asciidoc/images/statechart2.png b/docs/src/reference/asciidoc/images/statechart2.png index 01548282bdb78f1f8ff066b1f8ec7113750db951..a855d1c7da87cb4e584e490d26677efbace0352d 100644 GIT binary patch literal 20635 zcmcJ%c|4Tu`#!Gisi#dPl(h{-C`%$s3#n|8eJ#XfEwT*5v^>f#gp935k}Q+#S*FF3 zG??srwn0RUZLGiZo}p)Ze?H&O@4GyI^m@#_UH7$|=W!h8aov8G)s?qx=Ge@{#I)_= z1w}0;rgfc6Olu7{t%YB74L1G8#B|yGqT(5C_tqaBjwtP!649lzT;)5??f$Ss(SP^Z zZG769e_TGhY5zW@{>ygz9`882W4zYk(x>|em2&rUsn4(+Q95zvn3gc-Wd69`+k8uV$H1%Ibs3LI_f?5h^ki^E=&WIlyXUE9YnZOe`E6aG)+lJGt1m5%VH4uxm&TTt9Fg-USV-8}?uQB9 zb3=~Ud874{7Y6XsOiX_$YfG?nL6xafwH zlNP-4odrdz!s3udXf?r%xb%@(VF4bua-Zc2>_P>0X#l&_gk5YhTb^qoF8**t4*F7% zfAIyV?eFecSy=`1$i201%heW)P)`;T6y)IKbk@uFUYv`U^SqRBvCCn6%E?6s_< zWX`vAUav{bc8{U2Nqyg&oAr%@d~!LF8*Ua76%DyY`;pf*IyAJGg98^GU0LihKmFs@ z@Z{ueCrOdgh9)y?hwC~RKK*OS8VS{wVuZzW7cXA4wH+=kRdlj7juS^!G~AZ4FI?kG zVM;4%X=w=!4ZXjSnSW#6A0yrHp75O0-du7X5>l8`Pd7lr_9=w@G||)yHC8M6O-4or zXS~?8Jdd5{IE=JNh+JD++ttMzUP`D5w%g0a6{z_(Ia#1!syglzyyFcA2X*!MJ?uR; zN3%PSNvPX=cil!CTidG7pD$gyq?J-{~bnD&{=389jdT;K73&67b?B-ib7r7S7JjFxdnnT61ihhU$_B4vjev zR2R>W77pE(X@nyMUh}S_=>`Q`l3%=#r}c&V`}@0p$#*;|?Ky2XeeL1HhZdEi9fesc z9-f}P@2#z^B~j3BOx$^@N|Z>%76#NE4h+he&~=HQCZ7>(GI z#|5-%mg{8=cG;Gjgz+V-$NBTk&y3Y%)RD+0EcL${0S%eGILrl7oMMmsij<>chtLf6F0Wq!~z^NJ|WNl#BNDKWi*baa!8grkE) zaFmR!?82o)baSDb<5A+x?z5JY?h41`HoxNW$8{koTz7fuWrhKxj7L#m#Nii)j` zjYG#OvsXTjeoHfrZZs} z#Zz8UVPs@fRaMn1sa!ugIGB&2O^7AZ-n~1mq*S&LE+8_i*wD~Wna(a^{7GbFXsFUs zto1m30TAMQD?$W#V+Tai($nSKe?ARbM_(eTmaeY3#l>E%pC$zM~!!x+4Hao%DB{YP14D$KaiQHLN_i2Lj$YIr?MriFR;r%%4+o9Q=J z*~`gk>);?FEUcEKRp|Od#%u2O^b3d_=l5qGD?B7p5jG;NLrFMsT*x!3v$NCvXPNiS z-Sma9%o`>G`jYSUj6t-DO())#P;mLKE!&!?9Fna~Z==~I znYiGnx083jnPJA2(z3kfr)NETO8waVDfagEQ&Us8BlK=pP=-}kRNvj*U8W0x#-ns5 z-6&68RkgG$UshheL0Mj&X2Gdgx4-($)K-ds(M1ZVbqhf&+OaU&-uXSh*< zyw@Bh#__yx7lx{497L=P9Sjc--(oe6yb{NL`2vWx9C{WNs2B9yvxMpG?S@n!)nq1mhYF>*vEmui z(GP8Tj$>U!;$(FGqeYkG*KT8-`U<0x%R`aN&yi^SHh=>2yrZK-rTzMFV|wPo(&Bts z(}&0`DTpt3Dj2W(k$fW%hmW*#e0I$qrSYTSEC^ zHHPzUGx;e(SR}rwf|bX~!4dXRy63DhskrHDUbWPT6OHZdTtdlODJF%kaq?a=GmTf0 z)$O}VE zD_-G4A-M}Eo-w(ep!Xx<0vhpwF=2^rl(YiRnbG{%A|Kya?y+q+9M0*=Y;2dFzuQh~ zf)tw-!F#5|&H2MyNIVdRWpJYW1_Jn-#ynhH7&5A}xp|L@LwkOxanP0mg{#?<=~O*Ga^et;7bb3$6Cpl)@z<+`{ATuK zK2J+ig_H;Db%7>5U!QU%R5{Dc)Yw}hWb4~f>vEMY8M8M_T;m_YjOvCacO?W=_~>8D zH0mu@hKT`FX7q|BFM27NQknRpH7B*OaK3^UYiyn+J9CA)q3gt_9{S=FEh?f%>m{Gj z2|+x1SIGe8sN6tf7aIu%xyQ-Otm|GyRE>0_>{$$dcqRYrronZhX*`lw;?YVwdWeKin^>@FvGAet-7tSvzx4ICK2~mu-CPv;GAdwX%U` zjk*{tSwopGJMrQ<((icMa;)NY^&aRBjnP8un)tqe_)5_cOO4(6(B-^8zBi;MB_&Bp zO6ECq_@~|?ynp}xLSJQi3*qk4gz5yUMfrk!@lsEKXwO7Pp<6gtLb0Uu{qD+efnKNV zXL()To|z~f!ik=#$;nAVjXFC^Ro1e`g_1~|tdg#iDOG>qz4)zbuo_#=-TyFXA&!$B!SWHMUE`S!V0JmKSI0YD#_D&DJftpa&#FREf=^ENh_K%2-GVskynX z)z)uq`&rs`yyIHn90&xF=%^9G-D-t9@-t-u32E55p=6I!NZ=So$(zYMM8yx!j`wD& zO+!xkGPOLEuymv`#8bE!Jv=jAj&9uLA;pAFUY{ zn%WXgBgnPzOeysJlBWll5?`W%D>>n5(4_XhZFBehnF8^6X?{mQ_y{u8scmVY^;NQj zOZieh{oEl(Y@!M&L5c~$01O5cAA=+^5m6_mva^u7iX3PJwP5%2OMLu`qY?R zYj#RWiFY)wi>Ns6ArHd6T7XW)A04;oDyKM z{9C<#ECSH}7qD7SEIBQuU*rA#jUaxo;;mVNR|$`8`P>N(U}*8Y&^VXAiB0`2e4)<{ zrV;EUG_td^+Y8-l`bK-=~&1b;gyy%>U3gd`$ZLBurKvMW4AuL zIXdmKo}M-RRcJepV3w9=O+Bw4z|G9e#1w6*7#SJ)^y$<4`y0ctvk#;n#sttGE?{BO z&QWzGrG9Ymr7*pRmA$+c0n|H1VPI`QbQC2j4+IPt{ygj&?soU2$K>F>CD<)>O6T?t1EC0KCW{*9Up2b6o0Sxh z%g48!S3VZQ;|N!7+|KnfJzZExNa)Csi%D9J#Z$UwW@cZEwv?3ZszqMuu|>x{<*ThI z2%G54oaYdAo;}--%x@%+qUC?I<&AZJe27f$AG*j&X&O0gc6sL=SUeTT0_og_U;!NW z;1%Pm0c%)fTRS^<$j1&g+a4(|JuYSGd&R77r<8x!Afs6@9tsUC};VmQx|` z;m=+Bvd^t)?18^Ml{d}Sb1@~r-S{1A*|pbSg?BlQzK`0DTo(hk{q0LKL8vUB2!pFyVoKHhl6_64aU>BZiSFi4K;}33u>kE%(#h<)oUj6*kvU85* z#k9R{7b9b3Tm&OWx`+ye>VVUZN_#K3yIwRgF)=cV=}^AQ{2l?iui>pd@;bLYVOMn4 zEop%iS!VKvH$sWxn+n9JKzy9eA&+A#8lH?KoI)#CRf+g{UKfkbZvti#mV6;e>y~8C z**9m6eG9j4-`?uAdv*txnpDWSXvQ>A>KqAsd0g4m!_>~fd$dn(zyP!z+~PiA+7sa! zREPeqn%P0}!NQQWy!VQcvy`3E=+itycI9q+|<^jP&%NDhP9atR-{b zQ%BMnq+y!dM`67{10g`jDa=TO#A5yA`c^~8x2BF+vOX=#C}Exnhbo)oR} zOegh0>8ixcR<|_2{U@afXrP!*TipN(Yde^m~<>8gAqqvT=~kJ6*YKQJa<^`Ql>^nPF9vv>=0cLU@{TDCR^m;pU_k;fnFz zitvy|C-%n1Mjl!B+F%QlsSU-PNP?9t#NguMfB@IXrHlEl^rWq8YI;tNWSqLS*j{m| zdv+NRa{$;5b|A}XDK_XyEYrysvCtq$U0usdGk_`*t@6G-FdVVbr8AbGGi%70rGWMl zulce7_9+J>9+)-8PEHQh0fu_w3Gu!rL4nY+_+WKiJq6x=m3gyrFjq7V_mv(O7HG~| zPhw*+!|8cnhi*^1rArp}+vS-p-x3@Q4c&QvEuLmhmK|v?ph6;GjEJc1E*TI}j*bit z9)4rRpcKZ2hPX>fu0L8`<|cFM(OqSN7j z?88~xx95+S`mr$XsGxuY99HoG-qqa3^*{0D8*KPK%UpT%ge6eLTWDBQnUs5+Ht&Bx zPk_#1rFdEb>mZ?_h%Is(i)YMk6}7XK6WW40s-%pRlp~{I3mMm@e<*|8&D zUwCDy49Jeq#-q8KHKrR0@bmXL8uRe-no;_=qo300cg;4M8_AgW?0fyt(aXVgzj9l*PD`F+*T;vZk4O3n zkw~zWfDRH?qAo2h(TGpdr*^mYb+ok^85+Kwtl4~TzkB-3=!UU3&9kyHGOe|>m*)^2 zqF}~wu8~$=UXF{2vFHcFYul6oWPYI2<9mGyfR5z4A*n8mGo-Ych%Z=@bL1g~KCYfn zP|-kclo1yf$C5w*1y$y8R8)lxD=X`dA3s`H)Rw3U%hUxk6|Yg(;3*4qyW7wd$zvam z{gMQB_GdT5Ew+U?oAl&b{;{`j-{$6?h+#i>^VZC0Kh`E5^Jt;db4<>AVHW7C-skelqon0WGltcT4jB=lL-eX9Qg_)gt3qrG#i-(5{?Z(#) zygy)FI^)rT5r*oz)t!c#n#ZxEFl(m}{u)7H;h+Y#`Mhp(4fe6)=4b9FU|Lb?@GY2&-QgRHUb27Y%|{^GS?YLK*j$tRwf_m9gXU&t=$ndKR3rFTY{<1 zr0nbwk5+Z%_rDY0{upBu@Ab!ZhXJ~l5JNdFAv#F7>pk6K-QvvePuXx1U14dUtINg` zV;`_Tf6#L#fTuQ0Zo%UHIzzTXm!(8Wh+<(NB5v4XFn1@i&u+Ly9}DTF-DsfbqHk38 z6;x%uiU#;BVKlIl*Rd2>XtJFQN0cE3RrKbU^Q7M2l(~3 zEDIbmQ&EdIr?t_bSQpX{$!<64jD(q|g0zIB=3w!}AKh7ylQIh#_Ug-55W6d^{{pyGWqPn|zZE_#YHvA6%Rpy36* z_qfypDb|j(!DlB}v&z#M3 zYyG581L1JoIf)vVh1v0Deh}hJD09n`8q2$fD~cmKi$FKNMT1NzbJUlzfrGSD`7}_G zC@R|rSA@_1jgK(sO@Y^7sf-dfy%)s?}6&L zd>J`8FOb$D(fxS}LA3NG2XoukuXwk0j3+#*DXDF3L znJ9YlT!8;+{N+$owTB|wkAHd2{gkWP;n(L^%hZp4$b-cpJvtxMFpdRz23Ig zECCmCxqaJGEE>`sM14@9XS%RvyqY@)p9$_F?IdMts0j+LoxDtEnng~E&a5e$0=wbR zk)Of!E8Qqb2%4s>rmaH>xY85q{X2A%k$t)baXUm&JJz4!V#B}>V^OoLS|}b6)`Jm zudmN;KC&UIM90>6+&W~@g^_MEp4pe^;%O7}CFpCy!B#;1ApZb^x-|?!9l5QIbC`V* z#jpADf`qkBOvm38oFyOm@7|-6T&|<-Xb3`h-nF3MB>n*a8mhxXLqm{RT%llAAcSDA zz?|mWIg{zXy^rvkMm-|eH?@m)7W+3vca=Dr>IWnml#WsdYAPl!^dTkew7q{mbqZ$! zwD-&BbLY-MmE(Abu8xkdz(rB4$97IB2iaRaino~8Kygj;gOfbJFqknK=7yidSeRFf_@O2EMbb>58<-JNTYFXoge~No9wzWg<#sUNiGH~j>dDXRZozQtF(L*5&8IW zHo&_gJ{FVO%pkK z{4WLoq?mKBwX(KWK7W2YkL;6$QzySjw;M~;^k!jc{ZZ5qiz5;$0=*F(@jkUPq%F1{ z5&=dQkX|{sxmihkn_&s0sb-}T2t*JTM#IL4%OwE1bTCeAH94iBX-bV}5xc^-Wwa7i zR^BuF$B5rSjEyP1VXn$qeW`euB)~TenG>TGpB*5_>e#qqm#7IAVoM+)g`55ES5WZm zS@);VgF>g|Rum)^Y|6_|hM%BDpslT`xgW>gnuTSgzKj9rTjZV3D`!E-l%P!ym=}PU z`5^Uz#6X@@;ghgar%r`0PgQ7hJ3Eg`eKhs<=*+aJh!E2A_uk~IUk6SClhG#Y0Z z0{uNaJRrwmrU8lZ5hb##Yih%0R;HPwqvOQ>IiD@;@ol^8R4wxT6`i?LUVA$Y!mw5? zG>qnSp54xM@-i@AU0q!*t*}c;ogTwb=q-8Dz!rFvDv&Pe;akQLM7d^T^Sw7j!PS(y zFzrSCV8}&^_q?F58Em!72X5Jjkszd{adB`M)|_MV;UcjB@&ww;LZUXzOnDrm0Fy2V z&gOvVG6T8hDS5~ZKKtjjNK6r({Cq?n(uAUO?Kve#Bgzw> z4aVl{pW_dlW@d%p&Rx0V4k`oRue*M>CK;m8mUE`ih94;h-aR>pOFT$h_#zzr@D zc8>+Zovtp?RM?~=(KK@$nKsH2%h6R7)`h)b+4|wr1 z`n`pbU!?tpUY|60Z3 z7r+g7r0Ry2tiB4dQbP^GA?hdu@P=5 zN@KGu1-_M8b-|sS?B*)lpb}sb;GK#ZGD(+i?>hUEjy7b{{Z|0D7zsY_gWflWV%DG$+5uS<#tfA|ZMd zuAhI z+AhsRx>BYaekX@4?34aEjEkqsOQTGBO%Rx%Tco zEmVZAt526&K|*Dy9*tw-PXCY&QE65$XCUSYf4C| zeP4O;h^Ph8oUAP8>ItX>>wAy3OOqG+%@7wxg3Ys~>gXgar7%mrpf(PM)56MR1&JKP}70F&H1ruS4{N zjXon4%uuS4?1*G_Ic>x<)qXOJ<*rGQyCx*Y966o!^n1h)pyE$D^?jB*Z4My%JjddsC1ZVBKl5?TQi(5Xkwxz#eJ#y@Vps?w6V=If`m zchVb3Q~B{cik)0UB$~n5Cbh5z?KM_%IN^LSfj}_(IsX)SE|h!j@CZWaOx;bAvTMEx zL8q)5e;6K()7H*@@ZfgiW;(cH+f(5-(tNA`a|C|mf}!sY!Ja+oV)<= z2NZ)Njls`-_B0~UhP~PL6&oxS$=WbMAt4Zn{RNY5!+B}Tbsp2H@7^-17&dn!13NR zOWOyeeSh%a!4qeQA)Ha5V0U7d7hevBU>ACwUVP|Reav_!2g%~LZw1$$J-$S+XH{K% zmnzP-+e?BOs$z)a<_jI@Note-&F35>m_g$={u%Yn-&0{}qDoYgJWL=iou$U1GHl32 z&3GCV?0eRL&92vJA*d?Ta!8)o?6?sYq+uvPfb%0}bfUj% zOGY$CizU^MQht*)eHhgV#$RT4$g}xe*j}fjXorLZBF574P-GFq8x@?lM0Zm4x4(5r zMB4@Jd1C=a=2UuD+T!u>IxeT zYiMJ)8^P2&KO%4)U%>MU4>nQ|ZdEQ_0;5&W1e6MUoFICE1qg;cv#&gev$7$7haR|! zBAtgl0w~UpBO*H9x>PZ`Ta)|`b3ob8Ju93rr;t}AelJuaJaXJU!|UgXOHIqWNI~6# zhD7oLxO~P@fIvwiEkrE#sNX#^37o)ydvuoijT=Kw4qh}=i7u`qHfj+XjiiHWkz?!k z;Zk2d67t_Izif*m6pPX8DNUo^s`8Q=+l||EZ1vpSWdWed7|R;=2!Z!9EGGXx*`1B62&Zeid27!eSaVQBZQVD}8Z zU~@B}3Y?p(tCd)^o#xJ3XT4d31@;5*Bwj0FA;A)4*N{kvi%SO=hLBLe?I$t25Ar)e zB}uw&8qqix6FTl~%s%QmT%}CSnU}mw2602lHWjb1Osm;hdhjwoamVfg+25!Km4nml zB)VQ-`v~+eQa+%kwKe2;EAzH(BpTj&f|c+S$~_CYKZS9rh7zLjC~pv%++Vs&DOjT? z%1RNN^JNKMZtfsHD7juN8AL`s-=q734`ZfG--&Fd(3whlg#UryiuO#WiQoGofvg!)#;p(bei7C*qFZ^xU`YI-FHVZ^5;G`OUlEQhGR(a5!zx|N;h zFEpGN*8!@Qya$hNhG^`xJ*DX^a${76*;PV{A-(*o$4UAK3yXb$&w5=#BT8#0Y3kQg zvtN;A$zQ)ZjdjYc9BV?iUlSHX_+N4}+%)?}U9`Bh>Q}?Wi`VUyoXyrXhy_`_(gmdt z%ISUVuc(LdXe^d^SHo5!W#Kn6mI|(ulmoXmdaA**m8dRFp=@9Jp<7fiyxLpH@LoOz zEcO?LSzvPFrIlD$Q(saI{-qBph@X{=S+vvQvUS)BS37ebQE;wdSYHlYxPcty60U>p zpc7(RAO!{#T+Dv-hx<}c(Twb7to*sH3X~vF55#^VSJjIBV03c#!Gx6oftP(LdMEM* zqmQ=nB0Qa~OsEMN9E<5})x>BdPqzQ;27TaTs=XE9K%)D&`I_7>tPAm{85M9CQlWm> zS<(S91*)2Y5m06ETAXTP<~oTOVPwMef>GOrc3=?`P^7%V2rhWVq6=e2@Ws-iuzt!* z9b?{7P)^bl5D);RudTlR(4UvGkUqj@j;L9koE$LUtCsc#1_tgSX)jJd6}I;pC@f74 z-n&UY`w3k0+5zS{zr0$yudfIH2i|_=uLcwql`6mh?3io+X_LZ8Y+v@@2s?C#StkT6 zUglFWG6-m4yd2>KPT;_SE{OU4MihpHwucOX9d_z$=a$($!@XzEC$I0H8X-sowR1WC zPEq_$OTY=Jn3M8V-t+-B&$NVO)#3tnYx7EQFl4DfWflR2DCi(aVD8PB;yM@weH;1`EiT$32E@v|e`I4fq-44|eI~_`Zm3OT(L4BAK?&O{Tn(75fG1QtmAI-wNAv^chn3D<#d- zL6{OCdweC#Zx z>LsX7U{?aT>M;BB^G;HC63*Zdg|@LeqaZRG^Tme0#rE3P5 zZ);{$>6<*NVpkk7H)P6L6hTxFR)pyl8Ahn{PI;McWCh?%CJwf6ITh^n?;jo+F{T{1 z!xwa)gRm}K%@#rMF99bb?0SoeiUK=3^cMmH-`!m|t=X-&*v^uB2ujLO+Yi)h6%=hf zv|5LNX3T3#n8__qh%WD{nJ?^G6p?68ri67{Z!|W9* zBOT#8c-rSZJUqbyU_{6X@qhY#Ln3;;kN!z9G4rCYx-@$_t#S4<+si`Afk=rwYA=Y= z-m*hrZ}fUhcvV3!vBR_l$76;`A)=ud4?!PQYUEi)mGELtq1yeq#5 zi6kLMMF#FfG79bYBXU0j5>T9Mgd+@{6HgNgy_CeZpcxY}*C9{Fz@`ng%n1lkSq8Eh zV6(B-%LnKYDQqMbt(tZP_V+|tRGJ%LmP`Xmc~zjQx=puLP-qwF;|sNz>R9Q6xGav3 z6}F<+q?0eyoy{(f(7^~$s+y81p_|ybww1=|nYc_eqJp99#Lx>Cv@b8jQLB_|f+)y# zDrHZof4{d;nl=oSCS;B(NsNt+v6BpvP^03%kJP#3$U%TVrts5`lB(+>6X!j;Mu~2z z*@akYE;qq`s@&Y%xj7Fx6{G$AmZ(iV7Fyuwpi2Bk5&* z2TPhh+TGnflQqMP$TRNsH&s9!r`#hdBn0m1x~yy+Q~6&`(l{j$2Qa>rCtvJpB5omq zS>jVzlzqKzzV`ukYJ2?`%a}h8w!TaP#0ylOhaE6IHVbOOiV3l?#>WEa%e!x3a=$Ce zIOyq9>l>*>mJ(fz8bPF~!Jm)Y>0F6y_Pbsc2|ajQ26iX{f&lS3$tUe>17oL5<(cKs zbVwCYHH&TEUAXUG+hj%xM;Ho0q7nT$3YgiS;b1^3d;?2*2kCfpOT3`g6rQnl23ZS- zdO9W+2tB?alRf#;7|?TSKy_T_xmmMq8Vm49PjGZhw1uo(`yR>TwD#re!|dn9vw2s# z{(b|hkCDdl-q$47AweO0Z(l(ugBPOfCbuN+ZT)qN?@H9yFy%I2?G=f~aL?$`7r7wK zMuHj2X0g=p*f}5aRz*lnP@dg7v4gZy_o@>OwAzO|2xEO8Q50^}y%4vq9)yN~Yu1|_ zn^VsLTNxHOcE|Zr78e)GWt@j`l)T+Y49Y&QZ}BTpyfTAKU)%|paT_mQ`hm-*bAQ3? z$P28XAmo^P&T0TB!^0792BnTOJ0|v$n0e(Fz@xtS0rkR$UQ*bze!pW-(VI6;DAWab zF9f~9qWas1S=PApbBB z{t(>(km62~nx5goK5?9enpzo5s&s&_e&CkG)7nceg_8M>^r4nOnntv*udS_ueb*RA zrQg{oQ>DSE4B`VH{FrVfF$2`cSXt~?W{F*Ak%5w+;V~9V0y60nL*)JWAmXr2yl&D> zen=U=Ld68(A*z3Tx4!yQD*pQQdrSLSWG5P@Hkbgzu;y5Erz z-t6IzRS|$A6c_@NhM%Q_LGET(iP!LtqaCYfkQ7&^{2rBn!u0Liw(02VW_;wWJ%hZY zuxp2o#PX)Ql85M|Au~I_?K?QE3SJl;5jt#m52o#Q*b^{e_5s6S4E6eks`gWWI~{Fo zCQ_tp>=lsVI^m7o#`wkwR-3Jq^;D%GW-s3<=FrYJbw4|gA%@CItK^Z~8D%y+mH5JdX7O=se zd-uQ0f!I?ZglwX8dUr3z&CV_jJno3FJYUY~h&Xi<5!%LDj7P;AdxNR>+qbI#2yPdH z!J#dr*%k^7T;wA62X{tCM-T6}n)|m|LRrS_CiT2!h~#K|~aX~{L6c3a# zIk!MY8&MvSL@LQB(?jP@1M7SI69iANTW#I8P1sfOvvVR1cKfG2Qcuo7=)JDMs=0Xc zU!QXm-bs}|eDUraWKbxXeQFWqAoZGNo;5Lv1A?we{;o*11VZ_SH?s*Uq|$iw_|`R0 z@`55b6vR}wJN)jvT?#zMA@lq@uid__4cJvXTZY`8Oj+%mPY>^a1S;Zg{CO8ymUiF< zm~H{8Wh2GyR5lW~ZE&#_)Khkn0x+BON1XG^PK+@&p=6<)Km*20?j#`&2(Vq&?KOP8 z(gw|KYrr!LNsHX??d56-9O|leeO+BvED2aZ45rk(`@;r+*;+{JH}xY(${02=$%9Vv zYbNyUUHhNS0iOn)PuOMfIS2+X9RT6&SR#5tJs*!Z2TnX*-b}d5m`aVNSu9AZ2p81K zVF)TaNo1s+pTe=KUL$xi*V!nSH(J%UB3aBglej6Hj0@DR8dXRq8f!5SPknD{YEqzcAs+Pc!{-mI5ODTi;ZhQbx~X(c3}Gf)gy1{*1pk@<0P zFx4GA*%Xyl4H$nvKq2BGQz5|*QXL(V*t*htGv$B|Cn;Np4mt=Ue!AZa7?cR6sj(6a zA2gSK481Cf7=k>0fOS>vQbfMIFnE>z<%Pc=X>^qMcS&?Iw$JN7ni7VZ!~Un+YyR<= z8xkvyg!Q9-etv)q&OO{-=C$#+-<+IXEr${6?jV1wr!@A0-0~Ib|HzS$dO=ClP|~|i zpWziramS;<4xARdxDNwWdW7Z-sC&{azUO5^Qg`;lM-~zhVpa^Kr+paqu2o(EYhXTy z<8NWCJ!jjm-@JJ_9E9QL2aX|Xo%P~*>V-Y2e4Y*jOr|*KqikAkF73|ge=*;^?dV;tv@L7Ct1A1xPnPsh!_On6H?7E{p z2>%2^Q|F)lJA)>25o{^c<>BG+P6F21Q7DCYzxRuI6!AWZk5`YZD7^RP&6|=E`5$T$ zdZGUB_GEy)$%UIl_^-SM{9}OO@^NxD7(bLe?7go_ef6rx(bIE2wx9eyTMC&nYw6Xn zMi&X@Uz_o75qw)$Yz9^mynFV%eEISTcA|7c!b@;`6->eY^cEiwf#CxT7Jv4WG7xas z#iJpAvc^Q;$jB4EcoFnxE4j#+2!OS@d3giz65M}2SCQJ#xN0jf7D2KnqdkgLy(vYN zgx7pzhWSRx5Ahn&Uzm#wmBu2**F*w#k)RC7=yITE_L(#d?l=K9*k_N@q#K0jLkLa# z{O_-eWJz($x*y{aWV8A&I64H(3rbfRZk{EDzq-_q!=8Y_+Gp+IF9B`~7yuOrhy4_* z1^q-CApi_%jE{v#|Fz-t4?p}5_&4k^XYg-H0dhN(K=*vqL7;;uU&N*26B^*=8I^&J za~j@)hnE0HkB5Y65HJv;C6RD;&wv>2zF37?1+M=|=rtL3+(L-lF zl&_FrTth~_B*4tfESmcP_Q@YCafBj~x%mNjH!z`Ghn29v_*_V97(}mE4BO~VQbO{;1#A`_B(=&z$c zz{$(&Xm2kJUkCD3%4O{4`dd{TV}JX7xWEI(?ygnNyZ^79z50QOzxH6Fq>bh;>nlCM zT!9gmf;R`58-Zesy0_#h$OK5oBjyOmi=fg&DVO0zBdG(jL%Iy{%qTjCXE#FNUvZ2n zBlcRPE=@;L?T6AOq2~O&={~(4EdzdIdZ!_-5nl@bjdU^?+z?Y5-7UM)nmcsMgA#II z04$-V3~$Zwg_Yos7~T-FbkPv%0xvHRHqz_#F3&OYPS(}~!1U=A1*JcocKx(ai+;e= zW<~Dgf3!y{J`vpmHb@AT|7^?z7hNKE>@2zg#y)^*Ux&{yqU#Z;@~_BN|KXw)t}cGj z7Qvan+<=b(_=X;4xeG(O=vzC9pQiJDSDipp&$Gt9tiU@DJYRmKNCu2T7*al$3 zXzr-Lp)b-=43|KG)r`%rJ-z>Ic*3e!di9bU z28%so`~KfN`~S`M;J@rh{(rUufL$YN-RcJi;IjpXA2aLzAAG)G<-2f*bnxGQ=iq;N zqW%E#eTBxDvw@Uu_%6i~)Ivdgls|D|IvGCE248~t>qob`&-zioH;#O8tH@-w%4}&D zVN7AozfOS~f7kMK9#RccFf}N0oE3!^b`AABxOo1z;6q&K{L6S6_?C+_eVcZV?eT^W z%E3qSPG<(Ra}G&~-8|I&>7&ms((*iU`IM?V1Me8eaXKJdqMQAu4f@iu!+Ff_qLI{~Gg_0$bJ&cM- z3?^B|T9!dZn6ZuZIj)&e_wsw+=lQ&!=l!S8Cv#orbzbLroX7D!zQ^~t0?uoxZ(Pr} zo`Zv9qsD2~3mhD)x;Qvi9{z15{AKB=r~(Ja89NQt|S-pAuq|up=LK14t+)?cd>Sx0CZi~uoZSV~6 zKRrk}v)iPDyZ^$CJN_Sq^9?v@b-^?{?$PTOz|OTkc;_q8!HDkcLZ zzGy3FO0A~$3XWSYU-v$SDXC&PIIfzYmdZFd-r~0sS8)7+TF3e;H~fc#B*6L)^RLK% zkiY)_cggbOxQY4-__Ea;9CxkaPSI01IL@CIUbQsQsJ(UT*0On8&6h7QUs@81#}GKM#})uBosZpm8e6F^ah7I6mu9k-X0w(U2}_JB zmBsPiP?bQqX*WIy{`IH8xSaU-cx9)aijZB37gBW<;v^*`($mu)m%fMLrboL?=hG`I zD+_IsR=~qDNhAHzCGW7M$Zz)S2Y=6ikVlx z3J(w85w&mMKHieaPPgu0BPmlttnsd$I|I_Q8(dexh8SFX_UxJT!Lr5K;kdZCRjXDt zHa6xsb{1i+IuvAOBaMSOohJLEP4hdE-M(bt>+35Pfg3Un3=G6Seq2>m6=Br-J@&X_ z=JQ7D_KmQ)SNn;zwHr2W+$HZUDqpzQoJ)?ExB_l*R_3k!?t zras#z<>lqoO-qZTOH;Dv!Deph=@=QcH#TmKsAx0|wHq294$^s(lOt0!Sr@0+o^Nl9 z!JO8L-@)5sb1;`Rsn(|_{nFCYHP4)ZSzSo|Vw+Xk+}XKnr&96zV1Bu&(e8vrJu@>i z<2(}6V!4TGV7Dw=gt@USl7wtL%VOzy$o`ziG@GHgR2C*03%Y$g7iK5J!otcHC$pBo zuo;rhj>+90--i7q!j%<`QI?h-2WzNkzgxDnFgiZF$jQM$yVBQnx-9HZk>Aw?O{7Tk z(WX9(@hYLRxgW*u7UP6(zF+~}YCnP}_;(%)ztMNC3crfu4+pQgkph+Zv6FqYfPjG1 z)B{!+IBXrUPt}-{W7?*#8r{VsqsSXBf2u~GbicP94Eff|`;_7F63Ut_#E8*vnIBK? zQuZoLOFMICEk|p^w;M`}d@nGICF0`Z3JMA+47{f?s@?(>8pj(dgF+=AUj=q}m!GJ9 z>J%RzUtmzs#ndnHN}jWGa|5EI^nv;^2IcY4O@(G_JG&C^xhbkqj-^y=Z0!8kJ6xYW zed>|!C1m$?6k*AJy95O8@AaJiL6jW&{ylJALQD+l$qEit`pRHRw3Ml&xOm`OC1qu0 zB_;2PL6UoaX=!N=*42Et*lqNbgR=MRMC@s$rHgcPjf|ac8d0(GSg|MpwEN*=Eh8hN zgYqulbzQ3o-gAbAhPjsT3MDs^aNgeDC10rPzFoX{(JAlsYiHLwf>ZA)XW7p<E zwHQH9;bPGrk=5osCUB6n(z5H zB(J)h*kew@bJ9549uKgasb+&M^)qANPQKg;wj$MmiPuW$eJ1JpVET+29hv(~W@ctc z&D`{8D39{eJe~UT(4j-Jvad?aNOsr zjg9za!O`_+&YXEuTr6vWywsBajFMi%U21d zAt9TBd0^dmiP(rQTeHose`{!XP`RGz|1@{*+-Z%$?3a|(dUnBciaInpTHkfE?_=10 z(e0Me75xU`N-3Y_8^tUwMn5+-@o*7Zxk6Sl?_3(D_1D1b2L}iD_V$9yQV$i3^WGAf znwlyarrN7wgW zx_;JnUS54Yz0Nl-5}C>#6ECu|vNAIzizcfh_GJ-fZNAXJXID1OJQfH5@05LYyOfkv zX!_=!h;;C_PO`4|Em`YOfAr|l=8g_yLqonS`PVMscn1eD&W+#7{mia`Wx4kE*(Pzu zqopU9=3~L@>gsBFWT*W$)`n)hd85GJvjW-ee|c2IuP*-;`3;PO2?mgV!TCsyb#m1* zu9%ea-!dk0CgPr|WBFImUP}#ja_~EC;~~l_LL@9z;uQTAc)!PTj`)(6rx2%G zXTZnE$jE?uGWDKpT3nd3%4%q6;0BbzYp$m%80s=PISFRu-yim|+k3jxK!!bdthK#; zu&VOm!-u7%H}8Ctn0S3ibfJWVw(BZkObj)OjZQvKP8L17=)Cyyn$YjB#f3+!-lUZI z5Cm;2XOHs15sl|J^%_^}qy5%T-W&E*BqPfXrHwjzw5!;yzOU5hVN_IQrSHOIi=v`p zZz=iuQaKNC&1D{)-^{M;5E2TNZ5+xCzK4;-4^;9ymPj8vcFa?wV&bJyLFOqGmr=f* zyysL#wP)NQoL2KA|mu5^1 zWj7N&Jv`2K4Of9XfmH|-Q4jZ>xhL=UIEZpPBXIwNY)OaU{#0EXclXxqClP;<^!z!c zEzdS5+KWz<{<{>(HHR-3X_IcW!+Myu>3sKG0j|(j_ruoWv)UZ@5(E z4>P7xj6-yEQT3(%y(1$dMgd0id{$EIQIuud+rJ>xTd6}MCy-U zobB!+5D2ZjfT0qLcBc!kx5^m){{4)yYMJ|ZqWxWDu=c2j$6TofG+YVXsc>`fyo-yA zhK7cYj*fVw$4Fia9B{KP!?8nAw~%!#5g6W%UfFmGSqb{fy^+z;TpKn#Dml(N7g%s~ zL+|da6LaJyj$A^HMGN&0)AO5e!Go&$HqPGe+K8M2{H{Sx@s-GWz@4TI#Q?-e#yP9J zkE?N<(jf^%$PIFO$lZdSwsmEmvy$ET9Oq)8k2T%9b5E`~+5`XhRR3+}ivULgj3(yT zz^l9ZDx6Pg+#Sp&(yE^J$zj*V6d%i;N&MK70~1UzomY+me}= zpKp02MpryiE2Y4(+h?$0PpQ%9^9SmW*C=Y5EWW*sJB~^@FE+{wBAyRix_B4o2UMy= z)KO*F0WIS=JpRp%Z|~t$O*)kF!xBV?sbXp7w2(?Z1lE{yy^fzd@%cPIKR@!jDwcj5 zQK)XrkL;$-j#f?k%Em4fCX^# zQoKAoA0DEA;hw*`y1K~aXKD#_lrd}>tf}%YHkulKf03g z^5vnZSOpjHVsnTH04iLChP{51Jaj1758nNA@uUMc5xl3oL^t*O@NlmrIrNh-wxS6z z8M*uuAm8wGY2T`*N7Mv)oO(@-WPqo|k(k1kg}Ld7l+({HILY>$czwdyzj$JDlI)#9 z-*XJ_u*vU8DStB-WqN-^1TmjZta`Bg>qh!@EL~>bsC>OM96IVc>*^}IoY3arz2o<} zgp_mV3rRX;qvYJGz5 zB5tZVDk=((=bHkbwf&|_;aA&c`{wQiGWjF{#4 z=?&!iT_SQ1A3nV4=GN|(v9!nCEbgh=C9ro&>5H>DyRhO z0;!Y{rNfvBovI=wrMGP4;;N#7QT4?(V58K{@)#gLo61n5Lah@#L{6kncUXiE~Mg<;kF9FZZb!& zJFoou$Qh;r@4PhTr{cA=FpclL&2N*Pe%X&pC^IeX$o}2&t9$e2%^lmgiM-U~-)6>pBO)SLo}|wiC-?za6_uQdv`bE%p?S&4>5-`T1yDR}m4BjT<+@E`g`7 zk5^h)SRg+R5s=@)wSzN9v&Z>hb-c^9#ek;QuicnAgei63@5fQ~Z6!GRP-6;fC45~` z3E;NxLITP7LX|Wn7()bVZ9Vq$h>=q+`-ex6XB)Lug44(4BuC+_HXGkKd8n`x;!?}! z&(~G|K>1ptv{ije+(zSBE1`MrL^TbZkv1_C@ZOK``OIrmBkJ%B*SoM{cJ29xBC0DC z`uqEx^w!i%-TWTUjwDngW1Tv%UH3&|LvRaoDgBWt#<`sx*8jk+;Wb08@=b;0vN+Wjb4IoM#pJY zU5QfGorus@*3cT??mHmx+Z?asNXi$1W+Cy zwO7E=`mS5)eEB(??@30CjFoV7bW~Iw!_QF=HTeIEL3P~G6i9h@>i0T2XMC@ysJNZu zg2O>pX02SLfJO`GC+*?GaP!6QB)W~Xx%7YHDdjKSFmeWLpEph_!gN(1 zVctN{N@BpgVT@eOReO;**(TZ+iHWbl`1F5@yi)8s^nLA_2HpvW_2?6arpkTE{XubS z=jIu7sj_)zi0SbzG5rZ+bK1VM7c&^e-3yY%ea$b8Iy*bFfNHtT<%}ePJErkVH`6_$ zoJd|*)agS*LlOJ59lA>7_XWTG_MnPV5&O0kh%bqxm z4EZ_Z7n?sV%~YwJ`onbWc;=Pj?VN7Z)^Xv{b*l7|K#H7WS4L`T^|v`0WcK2>=lv-R zKGCSlEe#FlGo~ny9hF<|RLo}2_k0L~_g~CSNwHd#vg98<3y6EL)1Ok$Pvi~S3fV$l zUfzeYKu#x@snRHd3xO3r4df%wjF59u%F2AFURu?~l7TN$i1V3j()aZAjP@a7qeROT z1$)9IBqX$Bk4Xba@+FQE<}zQte3_ezx&(i=wYMk6^G+_!CoIVbt0}Vk#T1o7i`G(`8b>2xN80h@QtK-ToU7UO$1lC?{smulE=j0K!R@wr<3e< z$$@6Z-yMNq5o3^)l;f4+V{hjgp^@3iVXO&OJkn6>QeBtf zrAtSBiHW8}Wjs2)u<+QWAoC?-61vN*f)*aWh50b61n;9u$F@g_#8 zO+2~{=p3MaUaJ@^)@GEozNB{_MZ09+j;qnfh;rScj!ND(4z#u2$4BpN+)RuZD{Za% zEVYGbYirxSvI(Yn7!v~$dYq&# zWKkcpp9u*YimzED;hZ06OpS%E;lf;|HZww-A@R{%yKWt?SHGrELwKyc68|s+3HiBZ zdB-h1dzEs!{J#MGn4>bLrF?$Lz6x(eU${Q3_~hB{L`I{j_KTSL&kr!{Sw;p^z%sMV zmlhYQd6gneTdU*u-xx9)P-*)odD3eF30T<22%{X+RSOLL>Ld%HJ&X{_z67r=(W70Z zkNak*FROQMKv=#)ffWvQQmcssfvl*uo zCR9LP7{d5ceP3Un=VJP62oR9j2RoB9#&N zH+0V<^8Q<4|bx-2>rY$cJi*gO47^aM}0hJ zI+n@^)L)%p1zrvagJwt5(;>16OGeEe1%U{!5Jc%~(j6%OJ)tmTiSTv9A@P*~Cm;+R zc!+VBwhkU%B1h2i1-ZE$K*8Agt!&;EWDkGbAzKxq(XL~#B76!8n2ca*DPNwF@qjq4Md{KQ9+yaUIns9wn!wq<|BKX@xLztr~!c-@jXC9ac~&^&jJi1q%mP&*_~?JAw45Fg`&h>8jdiGM+Q91{}*c`L$CfwAW3V=x&1 zownI~?1qfg=#k!2mGw*CfQBEJ+7C`KFIL9m*g3ugME-mDEYa5Z2ZM zzRGbKZl0t!o|f;3mmi&@+})^zS6Z0FHUjrjKSw&7Xix(wG%t};0q;Bhfmd3tsv`Ev z7CPo^tAwJ`K0bbaz>?8f5jWv5KOBRNcXM?;)f__?G9h^>q32j3tGPWZielrL=|^xh zX>CZlyv(U!Om+ucw}-?V2(UrSB9JQ^Hf^di*>cgPgx@51NZyY8x}QqU!R;i@&CSWg zoX!87n3xDA|ENHf?n0x69sX2P!)qI}rckNnWVf7@-5}{;1b^-h=b5!5~n}7P_G{3F1K6doXDICw34;*8^`?$0u7{wlLx-z0-Go zysA3uFV(E{moJrk=4U=>)w99pXH)S{IoprO%JT34I~zb59wDpD4kl5_g!Q-!m$|&V zOI{sU&tZ`@1J{e7o-r!j0p^(VhA8>GZ)$3)uS{23uc`w*_xPHWveIZ<-tebLiD7hQ zX`#RDGG|lv6^!!5i=3Q`C{w?BpOLn_KDi_7y)IPakmao)Wk7n*;9dZTRB!kDQAnl-$R5FI``U+fGba^r(D`IPIxg4Y+I%SET@~u9lCMi=lt>3$@hW8cxD7 zG0vfX+Dx?9=2=lGKoZzh4W7nEM|>sIgSCW}IICjYFRI;=R!6C;AJMQ4HhdU3;la95 z-7qUFc0Nh!#c9+!CFD@Jh-Sr}=uQ#i;aTDF0(|}O>3cxG@*FAWbp;2qKPFAzWYU8}(vDU?2y3xRXE_F(0QViWk9~CE#^+R}VgA`pKOuxruto zEq4Udgdx2bnER5PDEtQ(5BPneLsBV?2aWv*EHzX~a^Ktrx)048Y<;179n*KqDw4c( zz!~h?waf6zic{Fq;WW5+LFzKpi)kc)~{ zbd#KWb?45VY;!;t}UtaIfZdVxi{iKB&WI_kDeLhwK7m=Jjge4_<4s z^4Y}d0E)*nUN3p{4s0YsAh=9_8Xg`t>!&lZ;+# z_L#(+75m`={hn(SZTS zDC+8xR_a{s5RP3j)45DLZus|#Sun0Mzw(*qCr($BMsqFk&(rT7A-ocQhSRnaDD9NS zY})m89+_VzyrzG2KDq@=O)m}TJhQv?DobcjTVUPKoePdK#+1Lo#J2}dcps)PgDBxg zz6NBp8R%oj3ey^~$8LQ6;~>zi*J~TYeut8Hcz@UiRz90&PU@I4uKCBE)&E3@udcwK>WRnbF*@8JQHGe2Wl4 zT=hSRAWP#%aM8gB?2GWl7y@Cr0_Sujv1sJ-Z#+YDS8F#DW!*?#-la4M5jPd$s?BSO zwmI7S#Kb^HV3`ynHtEeg#$Nqub*Hu7@%#3^#t?i=7&6*z4~}`w+|bjDe2TN58j6(A zcO7Z#-&lg2A2Wo!%L*);@0ZeXrbQ+}o}`QFzCkJh*Oru2-cZsuchkdTwy!z@P(t0e z7KzEtaD0&4;sNzMz2KWWuCGQ39#k@ZK@X{A+I`$e6 z1n8OTDheM1sg3dR@lc?U%;!9O?mKgB08x-Y1TYz|;PM@S+gsUzmR?mlFRq_eiMFw` z6A%(g0O18>k<_gR&YnBBm+s^&paVrWsNn?54rteF^D_D%`9_%6%6`4J6fQwD#>U3O zde2e(ueEvwko=KKcz0~E?~;#kJpGw4X|cq2nY8ylMq zpVAAo5dlD7uXY0du~>qwx3|!JdGH2{Uf1jPLs{{_foj3dnTeLhavok@N1(|Rll&=C zv`_qeeAoNmy?giJQlZa+$JuY~1&%^cTq<+I+1c44ub$NEjV18EwV^hKD$nlstWza* zpikOdh)#$vw{rXuZ!37Hc;deD1yaBkTXA$^9rJDH2f~qePYg5`j=SF-Gq`s>2%jt;<*U6zejWN z`y~i?9EYkpIUrWHJq4VXqAT_AnMccK6snr5AIy0xfRJRW-LW0>T!R_v=q{bdSS;^B z2##&>?5JJu)O%WMwd>I5y+~Y~(%t;T50V62ND{7x#ndLsPo<8evce@&hG$nL11YU3 z`6=w+ixnW213Dj=uZY8hc-wfUvCsl~9SKcpZFL{*Qu_DcfbMI^IaX>|>O}-GFhjaj zZiI=kDm^}45U##?9C*w;B|TOMCv2A|Jb!NaZuAcF+@F{sOXp_=PBADEdGrMx(ptXH zj`ih^7WswCsDfIqG$ujcf5Hv5y@BiT?N z!>aP}M9UDcJ=OAz^VM1yDB=;jAx8+<%RgzKO@Ci5Lk0 zbrq>^5>PGo{LY&Z^#Dk73RQkt3=^nd5Onm9=*thcL=4OM>B+|9t{y^#LK!C0o@2%ohOtFvG zyJBR-j|D{G)=Qh2nL%uwXMs`gYf`6M7#ncGNG}gV&`HAG-!%RRNYwEH0>MZAcX#{B z+a;ltYrtPcLA_-M0>*Ox6#r+<8{MMbS%05$4T3l4;ud3{(JCnH$cuY0`lAzU30sM< zjsr%_S{?c-)H;nr$`IzB;Lm}?y>fQKs zOp@-Gwl=;1ud7$DUcWAU&Y+BrBl zc-vMi;Y)>0Vi91zHM@w##l^iVwBr+@H@-7AdI9DP2IW>Kd6>D_O8VQNRNsO!WtZxY{_r`gEUUfAxFg3(TV1_sy4zR9 zDo$IOA$r;Bote8TR!LWF%{F3$@v-i?(K0D~7BQOwN}L+t(rr+MsbwTu(Ri}PAY3fwj~&9N8=~qHFg`#wxW90hQ?bI)K2(78O+_Ci z1W<4$7>NtSNPD)Z?s!_1sNH@K3 z?%X+JpK+lQZeq6fIdSn%kpRBeaS84izHga!DGXEh=ErH+;+pyH%%L;3sMHsy%ifw? z%wy(_>2pV1e{|p=gsnyWUY|SN1fCwAk+UL^8Ot;i)N5}(lf~;c`=Sa$ zb?s3X^8%s9zX$IJ?o4XnfyW_L7}%e(93hNzj5;xbM*(Yom6GS5$vqVjh{;@z5H88G z!IS`y(!!zL$@PlCNoYfwD<~t{zC~x?@^tlZT z-4f=!lNh>7acXAVjJaN$iKHVVvaoZBMIjG!qIFD6Kr3|hYa`tC#G;KE^swdXk}S61 z?b{UD@0`E>?x!Du$yCe!4#*-JR~sK?4XX;9!mo^Q0S29x`4EpZqa|OKM-|=f-pWoD zNN1ZQ`T=1nfJ*`HOFU9sQql(;J@C4stkgaPvq^&6w;aMww6Y5IUI>MifuEAm%kuAD zTAUvLI9j%}2(mWgIAA&5ei$Qp0>UAf$S2BYoJDbgl+vU}zv-w0D)jJXrh)@?aWaS> zG^Kv_4i1tp7WU&gPnrO<+5W*0Fb$4QX-v`1x>_Uf9}!^!{mVdof-k6s5OmuJa0Zb0 z8q-$l-Tx-+4qDD_#cqzS8q92>w)Q@}snm~`1zmxDy95ORJz#fLOQ@s#n!tAaKSHSU z9FM{QnFR@vd+zx7I8^PD)I%%1q3&g+;=&fQh7_#E3Qx{!6C?I!TXyWd47&Lk1Lv`? z@2Cn8tFrsPq+TTNg*n+;TW2Tfl?tB$ec3haq?R@SnTJypkJ>o)aEG+t|DJ-GuYc00WwR-n|g|2J;Q$eB?wP72(gZ7SEouael9#wtSeuF@Jkd4eV(7ok;T)~!W z3|#ITQg0X$|QHcF$>3h_!dUI7y_ zP_3?kVp@-*t?h7Z|7I~Nrnh=MB$c|f`e&G{)hc(Pq>h|l_5%*$g#g>bDUj$oQdL2)6)4@SRcsQUfH-?D{lcsN^R{~m^wA$xf%24mJ_+B4%r+iQW%L2 zq!n8nm6JQ{uL>11 zo%KphEXo&#TqlqsVFoIz_*{Tt%Af9}@!qFw-o}&;kDoE>FHmEqG<$t40A*c*nO-D$ zSs)Ud@noQ_r*tyY1png`Si<7I6om6aR3;ZK7Ol7D{8X8&QbUz1pwsg9_aV5HV%f&7GeE_E*saaIK(>K z(gxP)C09Xb;#dkg6HExCJK{jEfb#5XXj{gY(J2@hmLoJ06d7^E9z?@_r1(8>B0v>H zRhwUrL+nsMb9+q>ecDiTk;xUj`h4kf*iX3$DK>A1vWdrv8hJH5#FWg8c|~c{Ol8?n z)xxis-9Iv1o2reHM4za`xLe)ROu+surMpK|{wGJ< zEp#a-Ju`2Cnzk?K9=SYPjh>hB26XV31poIc=gEWikx=UXr9#;T zJ`w7SGVNFkL=DH-k8yWD#+W(U^8`aUs%Kj2kyls<-45RYIXg|lz5w?E=|=TSZBRCW zBB7T=fUciHKHmrt60l?2YkLq8kF30kxBo6aeUbfxm)pdpcCdvgk;nFl=9lkP4v{*EqqMw6iS~<1oWbl#Y4V#yU)EeC<`s4&$FL_=6`yZpg4k zaRJE}PmhS5y-V7liY@np0_p~5ZsJym1`r4vrS4nqMrivZcMy(&m6?2piGU>42g)R0 z_&|j>yQMFV37RSuu*3H#1>01C0na_vdNtUK04{1Tfh)~)2T}J51`rbR+;WA!-FU~g z+#yI#G!xWxU`ovN-bEDoEyDrDW(VLMm}nFp&;6J2DK;-)z`Pux`Q_Ih|9Dvh=qX?X z8epObAcf<1oZFeLoP~Ef+XRHeW}@_Ow|)L(0WFBWD_T?RYLCX~>FVkl8<)VjR9P6( z1`Zz}W?P$XX=@hrRRQV}h1X8vPQp!nhZ6+-DP|h#>V7axeiZa@OaY6>THM!1-hKI^ zd+@-410<KYo=5U~G3Q}aM+Nmwfm=xMFk`Wi5Nz2w9-GRLRBgMz3FQIdnc zXvH2bPkVb0%qA7t`X(qc@hfjQ`}KZ_xZx$SNAd9?dqIOYB{F50`R3Z5hlnk1I6KG* zLTqrSEI6x%Jsg>a5mBX6R~!P=0@t!8dM8y^%{K0L%cb3ez%(l;D#D?ns#Eh~ZP_T{(N;)a@#7K93^9F5}BwtUPgd4t{@ z03dNlz0 zzzT8>=-xs`c=90)vr3h&3Z5SNNA5qn+i*z;?cM;}h_M9Wd7qRhVALO)YZ1X<;K#v4i_uS*7acG?LP|kinO?uW#p9zvW z87meDlV!f}{%MjIED}fpq@%V|+?|m+X7oMeps8ZH&GjDkVtlBr*$`m)nQIms>or&247kh^q%><7reJ3>IRo0{R2UitKxcLf&ZU=;JF2so_3nO-iBh37}8UO!S7}7;h)g#6M-zZ zVwYY!JJ+eYcc0>#fD}D{CYiRbU^7KPgMuCIWUfVH1~U<_G`~sKe?E)8&?uk1IGG zx}dNDB;DuFp9@FXGK$dWkR$5mo*|)&=E2_q`bLt+a9h<$#EiX`h`;96hWptPYowPdQzcHDKgGMN9@EF<ibkD!6i{;{0IXIut1dmd{^XrzL`WKjW2SH0Ox>-^Ef4SatO| zBZQGK9{Tm_L6DLrlY5mthZ4S(P|5Q2@JOryVaUfQ*cC(~fR%q-fXD&-5jlWi()MS_ z>^Fa^2ep1tNp9}Vt5@IpRG7#x&m==;H6%1IAeBf?P6p%qF*;BDLEi!ug5?Erl$pHkX_U0Ce7F)%uy1E}A4i3IQ!)Q+GKjg>RK zf3%s*8g!Qib5J=GHMVv%2fKaeFneGKc*wx~8Hw@CN*kqnNcGpqZKp}G^JYNgWAzY# z0z8nHQezp$fkn-`BnNLJjvz^`cwgY!wQIrMw0vtv&q3*s8LDA5^$d8tr^r_HP&2YY z&m=#aK|%s{LvlD5k2j?9&?==YTg4)fY+Z{&DL|Zn4UH}94$W8(lP&I0#TIKr4y60A z&~?O+1_YZtdj)c~GFL!AA0;o(=<*y5p!{<^Th!E8r5RwfT6B@Dk+l(?6hb0f9|wEP zWJ`W|7k*-{9)K5rO8S(l#H2AxYXA8=a6YNabQT!kF?PCx0nI_6Zn6!OADG|+yOa1g zHNvl74s>9Yj~w|7VqIh7*fY7kVzzm$sm-*>3sV={ROFLdwN8Klz3! zF?{-IwW}NS!!TOM)#?8a%6NyE>SC6{fX`GI&&BRSnSlbQf)(!O;gNI5#=K>ck+(xA z*Zw9h&?$cT(jNLTVn`+Iwv+0uyzI6U;6E(cZJEKpMi3x*jWBbiuU=E{;Y~%W}@*;JN(wm-`H7|2h-^U>6D) z);fRxt=#ONdcG3|uX zp^srAjo4XnR4{vuA49Er=3|Wl4#Q3lPT5`k^pwmE&&w zG9#ll^9Jw}&;$&PQU)ooS1^+guV>~lf&nT~&?aTA_4oHSJp+Av*6~0Dl8228Z|q^D zKABO3md$~Hs1OQh;sew@XU3jVM8R$ToH)`FY=9eD^-cxyXag&F+W0gyfYtL5S>^WJ zy&(P21$8J>5Tybu$CA0Uu5ZaQ4V?iI>J+^241Y8vpHVxZIT@-W&P9 z-&^M69w+BPvEY~VjTtLhnmI%^fsCu6rskoIX^r3+;Znf~L>CNn zJ>w%g#X)KbJUl~_%o072^}XsLk#4NY$G_(zA3|a0Hu!%{=93eX9Vg)E&ovC0m6R;D zATJroyje{6zuy3ET5kCT$sgcML`=t&;avcw0GnF=_j{E#h?EsF^YwqfQu7asT73}k zR7@Yw<7U3?vKp@`iShj0W36~}(ZuC#|N6~kxdwJUycvoU;-80)Gc|m>4n&jYTeHoO zEb!k;^s}DvpIg|u2>g9=&961>iv)cBe*RgF}1nY+Xc*nd+c*t$wgeyUc1o*Pvx zTl~1v``u5;;jZ5&*6WrV7BTay|T=91~pdK>;{Qs>!VOF02BE+Z9Tf6>oVs!290qC&Z#KAG#e~0H+w?A~~ z|NIgF@~xHs>5D7uj|2SQzHmJn`KZd%%b_InJbeDA+h=YBzNiCVIa!>A&-K9PUiykZ zmWKI=tWw_+f-W&hMEboTKj3!cU0j?ls~Vn@;^6q`7Un6kaB6Lcr~uBrRFw{&ap{L9 zka_qnP*3ECxqI+Am|I@FMRK1V&A*<0ALiGh$xMah){o7wz0Cha1{+}yg&HitGH0js3ZGNuwe}|9S4Bu?HC9q}ri#Ut@ORKghZmj3o7G4A2 Qdg9Pf(^AbmarO590tMacoB#j- diff --git a/docs/src/reference/asciidoc/images/statechart4.png b/docs/src/reference/asciidoc/images/statechart4.png new file mode 100644 index 0000000000000000000000000000000000000000..c606455359cc41c01c918e03bde94873ee4de13c GIT binary patch literal 4221 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 more detailed state machine samples +<> frequently ask questions + <> generic info about used material and state machines diff --git a/docs/src/reference/asciidoc/sm-examples.adoc b/docs/src/reference/asciidoc/sm-examples.adoc index 84142d79..c5d44e72 100644 --- a/docs/src/reference/asciidoc/sm-examples.adoc +++ b/docs/src/reference/asciidoc/sm-examples.adoc @@ -15,7 +15,7 @@ simples form there are only two states, `LOCKED` and `UNLOCKED`. Two events, `COIN` and `PUSH` can happen if you try to go through it or you make a payment. -image::images/statechart1.png[] +image::images/statechart1.png[width=500] .States [source,java,indent=0] @@ -79,7 +79,7 @@ Event PUSH send Showcase is a complex state machine showing all possible transition topologies up to four levels of state nesting. -image::images/statechart2.png[width=200] +image::images/statechart2.png[width=500] .States [source,java,indent=0] @@ -93,19 +93,31 @@ include::samples/demo/showcase/Application.java[tags=snippetB] include::samples/demo/showcase/Application.java[tags=snippetC] ---- -.Configuration +.Configuration - states [source,java,indent=0] ---- -include::samples/demo/showcase/Application.java[tags=snippetA] +include::samples/demo/showcase/Application.java[tags=snippetAA] ---- -.Guard +.Configuration - transitions +[source,java,indent=0] +---- +include::samples/demo/showcase/Application.java[tags=snippetAB] +---- + +.Configuration - actions and guard +[source,java,indent=0] +---- +include::samples/demo/showcase/Application.java[tags=snippetAC] +---- + +.Action [source,java,indent=0] ---- include::samples/demo/showcase/Application.java[tags=snippetD] ---- -.Action +.Guard [source,java,indent=0] ---- include::samples/demo/showcase/Application.java[tags=snippetE] @@ -133,14 +145,25 @@ and probably few nested if/else clauses, that will do the job, but what about if you need to make all this behaviour much more complex, do you really want to keep adding more flags and if/else clauses. -image::images/statechart3.png[] +image::images/statechart3.png[width=500] Lets go throught how this sample and its state machine is designed and -how those two interacts with each other. +how those two interacts with each other. Below three config sections +are used withing a _EnumStateMachineConfigurerAdapter_. [source,java,indent=0] ---- -include::samples/demo/cdplayer/Application.java[tags=snippetA] +include::samples/demo/cdplayer/Application.java[tags=snippetAA] +---- + +[source,java,indent=0] +---- +include::samples/demo/cdplayer/Application.java[tags=snippetAB] +---- + +[source,java,indent=0] +---- +include::samples/demo/cdplayer/Application.java[tags=snippetAC] ---- What we did in above configuration: @@ -160,9 +183,14 @@ needed to automatically track elapsed time within a playing track and to have facility to make a decision when to switch to next track. ** With event _PLAY_ if source state is _IDLE_ and target state is _BUSY_ we defined action _playAction_ and guard _playGuard_. -** Lastly with event _LOAD_ and state _OPEN_ we defined internal +** With event _LOAD_ and state _OPEN_ we defined internal transition with action _loadAction_ which will insert cd disc into extended state variables. +** _PLAYING_ state defined three internal transitions where one is +triggered by a timer executing a _playingAction_ which updates +extended state variables. Other two transitions are with _trackAction_ +with different events, _BACK_ and _FORWARD_ respectively which handles +when user wants to go back or forward in tracks. This machine only have six states which are introduced as an enum. [source,java,indent=0] @@ -227,5 +255,19 @@ disc has been loaded. include::samples/demo/cdplayer/Application.java[tags=snippetJ] ---- -Now lets see how this cd player works and we can go a little deeper in -its state machine logic. +_PlayingAction_ is updating extended state variable _ELAPSEDTIME_ which +cd player itself can read and update lcd status. Action also handles +track shift if user is going back or forward in tracks. +[source,java,indent=0] +---- +include::samples/demo/cdplayer/Application.java[tags=snippetK] +---- + +_TrackAction_ handles track shift action if user is going back or forward +in tracks. If it is a last track of a cd, playing is stopped and _STOP_ +event sent to a state machine. +[source,java,indent=0] +---- +include::samples/demo/cdplayer/Application.java[tags=snippetL] +---- + diff --git a/docs/src/reference/asciidoc/sm.adoc b/docs/src/reference/asciidoc/sm.adoc index 4ef176af..ec5ee568 100644 --- a/docs/src/reference/asciidoc/sm.adoc +++ b/docs/src/reference/asciidoc/sm.adoc @@ -14,7 +14,6 @@ that Spring Statemachine provides to any Spring based application. [[sm-config]] == Statemachine Configuration - One of the common tasks when using a Statemachine is to design its runtime configuration. This chapter will focus on how Spring Statemachine is configured and how it leverages Spring's lightweight @@ -22,10 +21,10 @@ IoC containers to simplify the application internals to make it more manageable. === Configuring States - We'll get into more complex configuration examples a bit later but lets first start with a something simple. For most simple state -machine you +machine you just use `EnumStateMachineConfigurerAdapter` and define +possible states, choose initial and optional end state. [source,java,indent=0] ---- @@ -33,6 +32,9 @@ include::samples/DocsConfigurationSampleTests.java[tags=snippetA] ---- === Configuring Hierarchical States +Hierarchical states can be defined by using multiple `withStates()` +calls where `parent()` can be used to indicate that these +particular states are sub-states of some other state. [source,java,indent=0] ---- @@ -40,6 +42,9 @@ include::samples/DocsConfigurationSampleTests.java[tags=snippetB] ---- === Configuring Transitions +We support three different types of transitions, `external`, +`internal` and `local`. Transitions are either triggered by a signal +which is an event sent into a state machine or a timer. [source,java,indent=0] ---- @@ -47,13 +52,26 @@ include::samples/DocsConfigurationSampleTests.java[tags=snippetC] ---- === Configuring Guards +Guards are used to protect state transitions. Interface _Guard_ is +used to do an evaluation where method has access to _StateContext_. [source,java,indent=0] ---- include::samples/DocsConfigurationSampleTests.java[tags=snippetD] ---- +In above two different types of guard configuration is used. Firstly a +simply _Guard_ is created as a bean and attached to transition between +states `S1` and `S2`. + +Secondly a simple spel expression can be used as a guard where +expression must return a `Boolean` value. Behind a scenes this spel +based guard is a _SpelExpressionGuard_. This was attached to +transition between states `S2` and `S3`. Both guard in above sample +always evaluate to true. + === Configuring Actions +Actions can be defined with various steps within a state transitions. [source,java,indent=0] ---- @@ -127,19 +145,44 @@ include::samples/DocsConfigurationSampleTests.java[tags=snippetG] ---- === State Machine Listener -For using _StateMachineListener_ you can either extend it and +Using _StateMachineListener_ you can either extend it and implement all callback methods or use _StateMachineListenerAdapter_ class which contains stub method implementations and choose which ones to override. -=== Limitations and Problems -TBD ctx events may create too much traffic, etc. - [source,java,indent=0] ---- include::samples/DocsConfigurationSampleTests.java[tags=snippetH] ---- +In above example we simply created our own listener class +_StateMachineEventListener_ which extends +_StateMachineListenerAdapter_. + +Once you have your own listener defined, it can be registered into a +state machine via its interface as shown below. It's just a matter of +flavour if it's hooked up within a spring configuration or done +manually at any time of application life-cycle. + +[source,java,indent=0] +---- +include::samples/DocsConfigurationSampleTests.java[tags=snippetM] +---- + +=== Limitations and Problems +Spring application context is not a fastest event bus out there so it +is advised to give some thought what is a rate of events state machine +is sending. For better performance it may be better to use +_StateMachineListener_ interface. For this specific reason it is +possible to use `contextEvents` flag with _@EnableStateMachine_ and +_@EnableStateMachineFactory_ to disable Spring application context +events as shown above. + +[source,java,indent=0] +---- +include::samples/DocsConfigurationSampleTests.java[tags=snippetN] +---- + [[sm-context]] == Context Integration It is a little limited to do interaction with a state machine by diff --git a/docs/src/statecharts/statechart4.txt b/docs/src/statecharts/statechart4.txt new file mode 100644 index 00000000..408bb72f --- /dev/null +++ b/docs/src/statecharts/statechart4.txt @@ -0,0 +1,21 @@ ++---------------------------------------------------------+ +| | +| LOCAL EXTERNAL | +| +-------------------+ +-------------------+ | +| | +----------+ | | +----------+ | | +| | | | | +-------->| | | | +| |----->| | | | | | | | | +| | | | | +--| | | | | +| | +----------+ | | +----------+ | | +| +-------------------+ +-------------------+ | +| | +| | +| +-------------------+ +-------------------+ | +| | +----------+ | | +----------+ | | +| | | | | +---------| | | | +| |<-----| | | | | | | | | +| | | | | +->| | | | | +| | +----------+ | | +----------+ | | +| +-------------------+ +-------------------+ | +| | ++---------------------------------------------------------+ diff --git a/spring-statemachine-core/src/test/java/org/springframework/statemachine/docs/DocsConfigurationSampleTests.java b/spring-statemachine-core/src/test/java/org/springframework/statemachine/docs/DocsConfigurationSampleTests.java index 3d08a084..2ce64e51 100644 --- a/spring-statemachine-core/src/test/java/org/springframework/statemachine/docs/DocsConfigurationSampleTests.java +++ b/spring-statemachine-core/src/test/java/org/springframework/statemachine/docs/DocsConfigurationSampleTests.java @@ -79,10 +79,10 @@ public class DocsConfigurationSampleTests extends AbstractStateMachineTests { states .withStates() .initial(States.S1) - .end(States.SF) - .states(EnumSet.allOf(States.class)) + .state(States.S1) .and() .withStates() + .parent(States.S1) .initial(States.S2) .state(States.S2); } @@ -100,22 +100,23 @@ public class DocsConfigurationSampleTests extends AbstractStateMachineTests { states .withStates() .initial(States.S1) - .end(States.SF) - .states(EnumSet.allOf(States.class)) - .and() - .withStates() - .initial(States.S2) - .state(States.S2); + .states(EnumSet.allOf(States.class)); } @Override public void configure(StateMachineTransitionConfigurer transitions) throws Exception { transitions .withExternal() + .source(States.S1).target(States.S2) + .event(Events.E1) .and() .withInternal() + .source(States.S2) + .event(Events.E2) .and() - .withLocal(); + .withLocal() + .source(States.S2).target(States.S3) + .event(Events.E3); } } @@ -130,10 +131,15 @@ public class DocsConfigurationSampleTests extends AbstractStateMachineTests { public void configure(StateMachineTransitionConfigurer transitions) throws Exception { transitions .withExternal() - .source(States.S1) - .target(States.S2) + .source(States.S1).target(States.S2) .event(Events.E1) - .guard(guard()); + .guard(guard()) + .and() + .withExternal() + .source(States.S2).target(States.S3) + .event(Events.E2) + .guardExpression("true"); + } @Bean @@ -280,4 +286,32 @@ public class DocsConfigurationSampleTests extends AbstractStateMachineTests { } // end::snippetL[] +// tag::snippetM[] + static class Config7 { + + @Autowired + StateMachine stateMachine; + + @Bean + public StateMachineEventListener stateMachineEventListener() { + StateMachineEventListener listener = new StateMachineEventListener(); + stateMachine.addStateListener(listener); + return listener; + } + + } +// end::snippetM[] + +// tag::snippetN[] + @Configuration + @EnableStateMachine(contextEvents = false) + public static class Config8 extends EnumStateMachineConfigurerAdapter { + } + + @Configuration + @EnableStateMachineFactory(contextEvents = false) + public static class Config9 extends EnumStateMachineConfigurerAdapter { + } +// end::snippetN[] + } diff --git a/spring-statemachine-samples/cdplayer/src/main/java/demo/cdplayer/Application.java b/spring-statemachine-samples/cdplayer/src/main/java/demo/cdplayer/Application.java index b8c46df2..15e8796b 100644 --- a/spring-statemachine-samples/cdplayer/src/main/java/demo/cdplayer/Application.java +++ b/spring-statemachine-samples/cdplayer/src/main/java/demo/cdplayer/Application.java @@ -23,12 +23,12 @@ import org.springframework.statemachine.guard.Guard; @Configuration public class Application { -//tag::snippetA[] @Configuration @EnableStateMachine static class StateMachineConfig extends EnumStateMachineConfigurerAdapter { +//tag::snippetAA[] @Override public void configure(StateMachineStateConfigurer states) throws Exception { @@ -53,7 +53,9 @@ public class Application { .state(States.PAUSED); } +//end::snippetAA[] +//tag::snippetAB[] @Override public void configure(StateMachineTransitionConfigurer transitions) throws Exception { @@ -97,7 +99,9 @@ public class Application { .withInternal() .source(States.OPEN).event(Events.LOAD).action(loadAction()); } +//end::snippetAB[] +//tag::snippetAC[] @Bean public ClosedEntryAction closedEntryAction() { return new ClosedEntryAction(); @@ -127,9 +131,9 @@ public class Application { public PlayGuard playGuard() { return new PlayGuard(); } +//end::snippetAC[] } -//end::snippetA[] //tag::snippetB[] diff --git a/spring-statemachine-samples/showcase/src/main/java/demo/showcase/Application.java b/spring-statemachine-samples/showcase/src/main/java/demo/showcase/Application.java index 12294276..3757eeb2 100644 --- a/spring-statemachine-samples/showcase/src/main/java/demo/showcase/Application.java +++ b/spring-statemachine-samples/showcase/src/main/java/demo/showcase/Application.java @@ -14,12 +14,12 @@ import org.springframework.statemachine.guard.Guard; @Configuration public class Application { -//tag::snippetA[] @Configuration @EnableStateMachine static class StateMachineConfig extends EnumStateMachineConfigurerAdapter { +//tag::snippetAA[] @Override public void configure(StateMachineStateConfigurer states) throws Exception { @@ -53,7 +53,9 @@ public class Application { .initial(States.S211) .state(States.S211); } +//end::snippetAA[] +//tag::snippetAB[] @Override public void configure(StateMachineTransitionConfigurer transitions) throws Exception { @@ -112,7 +114,9 @@ public class Application { .source(States.S11).target(States.S12).event(Events.I); } +//end::snippetAB[] +//tag::snippetAC[] @Bean public FooGuard foo0Guard() { return new FooGuard(0); @@ -127,9 +131,9 @@ public class Application { public FooAction fooAction() { return new FooAction(); } +//end::snippetAC[] } -//end::snippetA[] //tag::snippetB[] public static enum States {