ogma-cli-1.7.0/0000755000000000000000000000000014767604252011412 5ustar0000000000000000ogma-cli-1.7.0/ogma-cli.cabal0000644000000000000000000001732714767604252014100 0ustar0000000000000000-- Copyright 2020 United States Government as represented by the Administrator -- of the National Aeronautics and Space Administration. All Rights Reserved. -- -- Disclaimers -- -- No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY -- OF ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT -- LIMITED TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO -- SPECIFICATIONS, ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A -- PARTICULAR PURPOSE, OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE -- SUBJECT SOFTWARE WILL BE ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF -- PROVIDED, WILL CONFORM TO THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN -- ANY MANNER, CONSTITUTE AN ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR -- RECIPIENT OF ANY RESULTS, RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR -- ANY OTHER APPLICATIONS RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, -- GOVERNMENT AGENCY DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING -- THIRD-PARTY SOFTWARE, IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES -- IT "AS IS." -- -- Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST -- THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL AS -- ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS IN -- ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH USE, -- INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, RECIPIENT'S -- USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD HARMLESS THE -- UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL AS ANY -- PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. RECIPIENT'S SOLE REMEDY -- FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, UNILATERAL TERMINATION OF THIS -- AGREEMENT. cabal-version: 2.0 build-type: Simple name: ogma-cli version: 1.7.0 homepage: https://github.com/nasa/ogma bug-reports: https://github.com/nasa/ogma/issues license: OtherLicense license-file: LICENSE.pdf author: Ivan Perez, Alwyn Goodloe maintainer: ivan.perezdominguez@nasa.gov category: Aerospace extra-source-files: CHANGELOG.md synopsis: Ogma: Helper tool to interoperate between Copilot and other languages. description: Ogma is a tool to facilitate the integration of safe runtime monitors into other systems. Ogma extends , a high-level runtime verification framework that generates hard real-time C99 code. . Some use cases supported by Ogma include: . - Translating requirements defined in structured natural language into monitors in Copilot. . - Generating the glue code necessary to work with C structs in Copilot. . - Generating applications that use Copilot for monitoring data received from the message bus. . - Generating message handlers for NASA Core Flight System applications to make external data in structs available to a Copilot monitor. . - Generating applications that use Copilot for monitoring data received from different topics. . - Generating components that use Copilot for monitoring. . - Generating monitors from state diagrams specified using a graphical notation. . The main invocation with @--help@ lists sub-commands available. . >$ ogma --help >ogma - an anything-to-Copilot application generator > >Usage: ogma COMMAND > Generate complete or partial Copilot applications from multiple languages > >Available options: > -h,--help Show this help text > >Available commands: > structs Generate Copilot structs from C structs > handlers Generate message handlers from C structs > cfs Generate a complete CFS/Copilot application > fprime Generate a complete F' monitoring component > ros Generate a ROS 2 monitoring application > standalone Generate a Copilot file from an input specification > diagram Generate a monitor from a state machine diagram . For further information, see: . - . . - . . - . . - . . - . . - "", Perez, Dedden and Goodloe. 2020. . - "", Dutle et al. 2020. extra-source-files: tests/fcs-example1.json tests/fdb-example1.json tests/reduced_geofence_msgs.h tests/reduced_geofence_msgs_bad.h -- Ogma packages should be uncurated so that only the official maintainers make -- changes. -- -- Because this is a NASA project, we want to make sure that users obtain -- exactly what we publish, unmodified by anyone external to our project. x-curation: uncurated source-repository head type: git location: git@github.com:nasa/ogma.git subdir: ogma-cli executable ogma main-is: Main.hs other-modules: CLI.CommandCFSApp CLI.CommandCStructs2Copilot CLI.CommandCStructs2MsgHandlers CLI.CommandDiagram CLI.CommandFPrimeApp CLI.CommandROSApp CLI.CommandStandalone CLI.CommandTop CLI.Result build-depends: base >= 4.11.0.0 && < 5 , optparse-applicative >= 0.14 && < 0.19 , ogma-core >= 1.7.0 && < 1.8 hs-source-dirs: src default-language: Haskell2010 ghc-options: -Wall test-suite test-ogma type: exitcode-stdio-1.0 main-is: Main.hs build-depends: base >= 4.11.0.0 && < 5 , HUnit >= 1.2.0.0 && < 1.7 , process >= 1.6 && < 1.7 , test-framework >= 0.8.2 && < 0.9 , test-framework-hunit >= 0.2.0 && < 0.4 , unix >= 2.7.2.2 && < 2.9 hs-source-dirs: tests default-language: Haskell2010 ghc-options: -Wall ogma-cli-1.7.0/LICENSE.pdf0000644000000000000000000034634714767604252013210 0ustar0000000000000000%PDF-1.3 % 4 0 obj << /Length 5 0 R /Filter /FlateDecode >> stream x\[~ׯ1%c d`3$PCHW崻ղ-˓ksεk]koyoq﷟lUT͇_E/zvu7(68wUW&f2+Ⲏ;y)?;~pv(]QYآU}\SX(ǽJb8)퇏,^ߗb8Jok~JO|xyCs*J_Џ͊berxݕ,/^w_Y\.kWYu "SWzH^QTqW|=xHU7ĜSkͅ~J^ӡ?yU\b)viL_,4-ʇh*Û|D$Ęi8((^ \ x&]Pr%@5 DU4 B)bȊ_{֠Cޒ/jl-!łV5pEG"Χ& łzZ, }4#i%*9;ǵE30Q'Y`?|h %?q%5n@F n PPըJ0wQO {_ic.Jv4_));(U#(XM](M5#&t~*oJnS&DVhNdITӌ2Kc|I6y^*`8T֨U٢&ȁ%!OY&+T^ьQ(,R1F>-e?e>Ks) E7J5ĢtأU,.Vp(︎TDa W GG ^pmʛ>B-mߔv$쉦(>F]FT2pNk餚?i _5y׆/($X.h[}B4էc+*`9xyX!(X\eKKJq@f UrL_@T2x]y"#WK|Z 2EuuPRKֳV#|^ IBB2ʬdUͪ 0ULcv4#d(il,C8hx B m`|=kb*>i\I_j}+%>&fJ &=%ԈbyA"1<р ^f20ꓗ0aUbJ ؄&$P5(Q >XCj(bkN=S \؆ͪq-U.I(H#)Jr &ڄ$:`6xS5RzeE0s<ϽѶD-rUfY/-wfn Q/(Ap ܅XS+w Brb->BqATˢ77顔K'01nq$Ɓ~? Z?vxtk9(v,#Wej.^*l\JPm?^Ld1~! n$vtYXa&Jm3jm*ڵb| 8[?tۼ,VYUK`MZգ=@p g-*FBaa"9eK7X#YGy9)#gC͠8a/9+`a7c>[UfDzrkK+4_ErJJr6+&< >+Abٙ=Ggy# `H«k);SzxV#4 P6ACA6 P1!xޕrR;Z'6@x['(Ek \9+My)͎q/np<1st1˳r@ẓxIw=aw[a+(uk[ 'l@A9 H+JQcr+F"HTeffT r?ҹ9ġ ?#\~N-P6){DGNLLi8nizkf朴6)y6\%A"%7z4ˁC.Ըљ=Ð?a<^m= 4Ñي}/nUhb_l k'0W c2x½ Ae߱"qݠÛ2 f#.`{Mې٪Sca6Qzu-mN\@|ԚjP=>%r&n0깜s)fB"fC>E&X1PCg/-f'_xoQ%Z1 6Db¿g52}6I5 SFy_sIo_}tʅ=$x-mb44fm֏ىb˝0c@I?XK#wLg[”yÜ2'I!-@y9'@;-Z-VaBX8tI)+tYY0mC`Q|.xM(=G:^8w!PǔWՋӆ_A֊3bId7k\xdRˀ 1o,H\D$yw"x8 endstream endobj 5 0 obj 4763 endobj 2 0 obj << /Type /Page /Parent 3 0 R /Resources 6 0 R /Contents 4 0 R /MediaBox [0 0 612 792] >> endobj 6 0 obj << /ProcSet [ /PDF /Text ] /ColorSpace << /Cs1 7 0 R >> /Font << /TT6 13 0 R /TT2 9 0 R /TT4 11 0 R >> >> endobj 14 0 obj << /Length 15 0 R /N 3 /Alternate /DeviceRGB /Filter /FlateDecode >> stream xwTSϽ7" %z ;HQIP&vDF)VdTG"cE b PQDE݌k 5ޚYg}׺PtX4X\XffGD=HƳ.d,P&s"7C$ E6<~&S2)212 "įl+ɘ&Y4Pޚ%ᣌ\%g|eTI(L0_&l2E9r9hxgIbטifSb1+MxL 0oE%YmhYh~S=zU&ϞAYl/$ZUm@O ޜl^ ' lsk.+7oʿ9V;?#I3eE妧KD d9i,UQ h A1vjpԁzN6p\W p G@ K0ށiABZyCAP8C@&*CP=#t] 4}a ٰ;GDxJ>,_“@FXDBX$!k"EHqaYbVabJ0՘cVL6f3bձX'?v 6-V``[a;p~\2n5׌ &x*sb|! ߏƿ' Zk! $l$T4QOt"y\b)AI&NI$R$)TIj"]&=&!:dGrY@^O$ _%?P(&OJEBN9J@y@yCR nXZOD}J}/G3ɭk{%Oחw_.'_!JQ@SVF=IEbbbb5Q%O@%!BӥyҸM:e0G7ӓ e%e[(R0`3R46i^)*n*|"fLUo՝mO0j&jajj.ϧwϝ_4갺zj=U45nɚ4ǴhZ ZZ^0Tf%9->ݫ=cXgN].[7A\SwBOK/X/_Q>QG[ `Aaac#*Z;8cq>[&IIMST`ϴ kh&45ǢYYF֠9<|y+ =X_,,S-,Y)YXmĚk]c}džjcΦ浭-v};]N"&1=xtv(}'{'IߝY) Σ -rqr.d._xpUەZM׍vm=+KGǔ ^WWbj>:>>>v}/avO8 FV> 2 u/_$\BCv< 5 ]s.,4&yUx~xw-bEDCĻHGKwFGEGME{EEKX,YFZ ={$vrK .3\rϮ_Yq*©L_wד+]eD]cIIIOAu_䩔)3ѩiB%a+]3='/40CiU@ёL(sYfLH$%Y jgGeQn~5f5wugv5k֮\۹Nw]m mHFˍenQQ`hBBQ-[lllfjۗ"^bO%ܒY}WwvwXbY^Ю]WVa[q`id2JjGէ{׿m>PkAma꺿g_DHGGu;776ƱqoC{P38!9 ҝˁ^r۽Ug9];}}_~imp㭎}]/}.{^=}^?z8hc' O*?f`ϳgC/Oϩ+FFGGόzˌㅿ)ѫ~wgbk?Jި9mdwi獵ޫ?cǑOO?w| x&mf endstream endobj 15 0 obj 2612 endobj 7 0 obj [ /ICCBased 14 0 R ] endobj 17 0 obj << /Length 18 0 R /Filter /FlateDecode >> stream x\[~ u,;tt#guiI&- ;@P39CQ*^~23%|xQ>wt)MBPYX6mfa K$JܶUȲ6MpSGrC/_YaC_ 1܇?ysF\co .7[IY~"M4͂;KySh5e_G(Ț$-T 5?2?anOnC<\68\ym>oC/ 4pOw#P)-2_ʰ͝Tnkpp]G2>bY=1Wx/5coU1tAQe\3ݚ|r#8[MRW 1/6ӁNZQVC)t^*i˺ uM3x4[q#yV{|^wܗ{ DFwKxdGB׆h}4E~w5N$,+$K &Rc~+8m;V+ˀy1N3Β Eޟz/ |bM­ S\=YUjƒ:Κ^ l x,yTi ,iGV;2262Se%e땦GҫK 4) rcDρw[ALK*-$H,4j3L㏎ZTX@{VS܄j'I_<Nֲ~H% OЩUm R ]+mWsmt _|I??H",!fU>?MzhŸBjl4X.6Pb#.ϡ1ܢ\=hLG,н 4U=ECqtoP6f#p-$+We0dDHܝ](yVs1W)UFAR,Ui&]zHWjvڇ5,n&Tr W>8#aTYG"6*cr4eωA?'YUP.1 9`2x0/~Z_ĕXA%w#Va'rT};39h;:H Q+ 17 ;{h;tb+^u1 `TqŠ˃aE^'eS )~ЈɻG-4YJ|[\\kQYxnV9_3QKUԺ7>|c%uH.Y(S)̔t^?,3)#JcG>Q!Sy0X hh@Yai^Xfe8BVLZf`b.nuKڤ]W1A#ѷCQ^(o c}{x}РM`AZv\R+0kY GG;ӂpWfȋ>v}w +AػTDޓ&ZBh?8HOGaOEefjn5iЇUB uAߢF I˰LNWۘ-NaߨooU۪k|fX`Ki$W(4`q^Zt<.cgQӑUU٤|d*IkjN[YfuxINFUIYPpNNS#q)xԩS5$as,$9g/ܨMKP)Z:Kwz0f؟KQQ(~ӮD8\ϛL /xjS,>US&vS;'2I =%h{QM+y/ƫlf5.m]ʏkHDjRH<S:ʘ%96PxUJ{sGE&2$Ffƃ89)30k ֚S)-sʦ!(n4Y5t( sm! ykP3;*J ;[FfEKLqFHL) >I 1E67 ~4fwFZL<srqKkem]9٨n=Iu3fbS$dyBQ z8s7vݎ ,f7| 3,@tx /SOHūxd>ّ5)܆pQG]o<Igf*8*I%p4.AIզ<2Wm}^K2 H.EmQh sF4gdPN?Ӟp %8/$VjH/pd0!̩S㿞 r#K)LnaCSآE[㲛 0Hͫh?Bd^aMP̴Bvȴbwl1!aT(۱Xe^ ! $"79@?y˲L8&T`N]"Ѯ1K X$A0ILܬ’1 ;.!XgN4D^}Mjg=̦arF%"9Džk7!މtIF U!&CW?1_#5Z#r{c ~CBI1»^؞Ӯ2UIQҞL50}< [^Y$۷Oh;1L endstream endobj 18 0 obj 3774 endobj 16 0 obj << /Type /Page /Parent 3 0 R /Resources 19 0 R /Contents 17 0 R /MediaBox [0 0 612 792] >> endobj 19 0 obj << /ProcSet [ /PDF /Text ] /ColorSpace << /Cs1 7 0 R >> /ExtGState << /Gs1 20 0 R /Gs2 21 0 R >> /Font << /TT2 9 0 R /TT6 13 0 R >> >> endobj 20 0 obj << /Type /ExtGState /AAPL:AA false >> endobj 21 0 obj << /Type /ExtGState /AAPL:AA true >> endobj 23 0 obj << /Length 24 0 R /Filter /FlateDecode >> stream x\ko_An#-F4"m݂)uSrnEI)9wȡdJ2A2g}f__›f_t'y&yidyX5d~mXUxZ<_f,UO&6EE6(ߏsvsjk/\Bo^]QZ/bYIٱ>C㟯:0}*\'WW+),@ 3 =~gAan} Qڵ"nwOѷ;phWFj/֬kؒc`f tFk !8,#yœnI{Yd+-XoVCFtx˦4V/p{ \bl1&lp*q25kK2N2|QB{R3.= M uAGP5ibeƫb sy/f0K"&}\HsaƼsdee RBϡ{P-؇w ;ra  ,~$ @"323$̳$M{ijZQ$K``, 1\]g\'xtYJh3F',--gudN`ZkƩ3: ƹg5WF쯉VZl.o&Q3*I@]˚5MR1 J'Euå *b2N+ZCifه+GЈUBfE6{kqhNƈFZEhRR.jBN#zJ7 h:uϪ9J $PnŌڒ+,.A< N#"VN>˛|C#%Lι {FNH&u %5xK.j /&^ 2)zz$N*5(;΄&k 8/0 (UWАwy,_.)}%jDdRԛdBx2<6ND $q1}p>8Qjj^Qwg*_Xa` !1S/T`.ui@ϕx+`B٪rEbd[<'}9..YU[m ڊu*H퓉^)!-K `[)e@b^D}’p5laT'B7D)_XPX]'A;A܊U[qxVq\YuRxmJ>s67cMdbFAkfBwWBF îwn bOjju)M&-h;S.ՍE6ddr{O1BD'^G>b|W*ְk~_N-U]C#ڑ}쉁ͼ(W6(m-DD 8^0\"1]["R>p1phB(2=P𩲑C>;`s``Q4@o֊%j>]!Tͅłi&wnAL80Dd768z,D,/ʰ}F *Dз fJQ"Q8O~BbjUGZl &SdS3$Q(4LXZ=dFa%@K8v>A(Jl7DD ^%9AΆҤ[ ay?hYBj2GN( ӱ`'G0S™ge$i 44Yl4)FQ2ѡmE+}="66ݽetU]ώtJZ:'ǥjRs$ nsqpSҽ=zL#Îq=d 8)rw;4L(5&Fԃy[.8N$s@x`u o u^ȷ#A$> 6:V$W$ɛ` vMh ٤[D0ӂձfŢ̥ewԺQQ;!`;xBC}Poo4#10LFOխ` .}*1:L.U5QAC`Hˆ&:ƴj=Z2?6v٠Tu`@ ow PP7U?o\PˏO"'Qƽ&H[Z*Tyt2z6$KN-A \n7_۔x S'Gf>96bIܒZoL{J]CXeKR*;ƯIܓ@Vu(=bNv;!{:ra'؀]4 ݜ<*e.g/AXm3=/B0aoiX*}j $e{]ul&lC?o-tuLő=/ Ρ~4=A hHA2JM9O 80e 1*ESTHz:55A8ì6,'Vfu(<` Y.Q37*-$d}卥7$l?ey&WZFNI"=y-0 Q;X VϚ4@LJ29Z,^ۄYt:,g$ 3S{}?>LpKA%lgkʱ5q.V&Ꮀ5ʹcG*ŐZ.y{8&Ĕ_9 y0\a Qa+!IHɔaF^ ɔCUӰ%LuUWORB512gx [^cYΕChH&1VLĉ8|;A+ap( 0\Pv&pn FX  |F'eUp.s4I+.^?xo {qZKjͦϐ^`ڔL WQ[@7W.Z$SE> endobj 25 0 obj << /ProcSet [ /PDF /Text ] /ColorSpace << /Cs1 7 0 R >> /Font << /TT8 27 0 R /TT2 9 0 R /TT6 13 0 R /TT10 29 0 R >> >> endobj 31 0 obj << /Length 32 0 R /Filter /FlateDecode >> stream x\kD_a xXG;h£NY1F0`%vש:]IЊ˷g9 o>yoޅwoV w{^"|GåY)K^yQ`GxaE-ev2+rRߟ§?gx;qװ\#oQV]AY"K,+Ge0]VIGߪ'lQ*CM5ܲtms{>mQY,Wcw*8*ek8A7UP .ĭ-0kVIf=#0"oE[Bz%$}zq,kV Ш[PUZۆ1xlT2 ` q Jj Gn4'Ho_& W>Ѿd񴁉7[JCqsĆ^  QN=b"6(hFqdʨ*,L2_JX,Ęc$*Nd@  +:ekmGLU01X R8ԆU\C\ྐvڕ#-l|Xk!ra yd@}#><2MM֞#1/Ϭ@ b(&آuz]x _4hU PxIJѦmƧW^i-=Dz3a`4{,fϧ=2ۑϦb"V~?]X#@G#FRDK)E D*#pʵDk|׆@AH0oPFJqzA`t=OUy 9 )8ڲ`WeDId:rfG#冉83C e! GJB3~%yYH~xr^Er|3ˀ"֓vN)bB8Ng''r. CcA9)^$c4O>J(ks%00` h)}bY c/h%h9"(" oZgj:/2K c5.f,EK U^ s&^!hOeA镘2pe2ď' DOI6H65`}_㢪-ΎxEv g| uY;<Դp71vg0fBl\턬B]TH!#+9D;`ctae;D`ADoP KU tFŊuYRRZ1} }]_avC|P8pr&&@&Q œX13`>\noϚ;ɂujCpm^n]%$Dx=7a]V .W A.ҷeWR9 wޜF&ҹ+O *@lADɔ)ʱ^7.Z BiNft”@s+#("/|1 }I |8ipN`cJqGcwwNwgk勎,LY·,@QFTJ"&|{( uE}YC1vRZq: fqFmcARf T|DUWu֥9ЇJIA;3Om0^E]@Q-P.qHD11dheX&,8.IA=KaFZ,jǎxF \ƻ)Ov??YI<XYlMkfF1y &`oY?!y]QCgUgMt$ԙx\-{Ӣ8I \ ^#Z)AZ!:ryFvUZV2le>6>Cꈍz[5 D"`OKt7 )S_&!-֌wy'*d*0.Lo-E5›׷|!Spe5;ݬ d\(ZsO($ڸOm ck E0? *|Q~1\G򂏈*d u.LwQ@aX<Uo(7*֣\ɦSh:QìYBDZ܊>QC+T.-n)30CAS 4f:Za2|r-#ܖ @bv8[MV͉άhN4|bIXݘbmaSZبZf܀{S ]=%a,xX5&?cU P >P<0R[hʈz 4<4GO\*O萤D=^k vJ߫Mg-*tGW%J*tR{$Y$s^$F=&P@O-7"Yޱ`KddBTi).sGz?崙XNDl"'sΉs2w+Gsﳺ=nǨ$9(:Rԃk8v܅/vFA~>/x_ԛgEVmb &({"x>JOhcObdFx~b5d]FT;F#2ngTҹ|&?ce^ؿXZj{2}|\yU`SEJ2ZvvQ+4mKh2 Tir-]*E y%|ßIs dHd,@?8߃d[O84pZq +#R?w/Eċ"A G̣rWeחTUg|sYs:q%Ʈ~3ا7@҇9ӯ۾}JUA-jR2cE 3c竆*iazhߎt 5Mcj&?wÓJKRڛ(c.瘃ŠM+`gSE>jޔQX( EOc540"*$V끞'A{ i1XEj1ߨ.G#GeU&!yc#U7 rH]d3 ?BhT Ԑ-7}?tNSߢ< 9'kW4+i/8cՠuɝUu°Vޡ3/b%00eq>2'NiVI3&ҶJ Tא 6Y"Hx:;+H~h=UG ^%47ȥ5% Jť)/kqL;;!6^qronh:9N1ޫUS endstream endobj 32 0 obj 4631 endobj 30 0 obj << /Type /Page /Parent 3 0 R /Resources 33 0 R /Contents 31 0 R /MediaBox [0 0 612 792] >> endobj 33 0 obj << /ProcSet [ /PDF /Text ] /ColorSpace << /Cs1 7 0 R >> /ExtGState << /Gs1 20 0 R /Gs2 21 0 R >> /Font << /TT2 9 0 R /TT6 13 0 R >> >> endobj 35 0 obj << /Length 36 0 R /Filter /FlateDecode >> stream x\ko_A&QJZGZ]WĖ&nڨӦvΜs]@̝~P/GOga{ZI^"ê._ ]XUp]ޅv<ݛ0ݯz' iUʤ?rଡ଼ VUZ5zKTEiXZ5٘?qw>&_ۋ/'QrC>x\D/c\^X3ԁ]pE(|hī]L"7t٧n CV.pq$j`Q妠rʑJ"d/@Z9XEȍKr!IFd~++\S_ruQyH-|PjʪI-$^ 8#MD>Q@3(.A_ƒnCN b 1%M8Eqf#B%* qUe"C\x%O*2'DFxUt{r8뢔8.p߫I9Thhgó7eˍOfqTQS3Ir)-1MJ&i*9y^O '' ,NP} [yf/qFxv# 2I[6Lۃ4/bpd /orrFF o}C.6|?s 9d8AUGO}iRu'ޅY%u}نre  R>@:Z/XPz܅PA Xe OY0 ]+1w0B@(*{GK֗2݌`' 5'z%bWcs wHwzOUUlN-* 씅;JDDw&ܸ6f!:=܍Jre?PF0 !4A\}R: %]2^|bR1m5[8H;~)>-'InǤ͒.ʄ <${at Ste1%0X\HM.jHWX" Fk:pi$z (1xwA06+ 9=; 뽕  4iK;?NTCc 2WPws0eڞ(ݦVRYĴ;Y,H|M aF iyNyg,YY6I{*\%0P3a|h!~ acT`zƵXU8Y&Rt!P j1kb;)^ #|r1#2я287=Gx !/ӕk0>,SAQK' A0qB@n=˝ʺ(NLWթSF?5Zo&/fVhvqNҪINݡgi@҈T֓ :^-HeH@U)A|cG-ֿ 0le[IsI<0Єi~f^-5=)𫵽^P R`%Z Gjl0/^r~wH<ьTHZy$l0UJ]l5.;~g_'+~SJr=xƻ'',bgl.;V&ҒXzVh ( L훈B3]{ L/ ֐t_t4981M";ہ)j&eДJ"Id%Wa`G2{D=S)0 /ƭ=E.{+S%: aa;2XA|baY]3Htv8Tso. vbhW pSϨ5sI}qb˚9J E]FҺE8p+{w=tԴ@,Ssc}E 8Mq#wec>Gri߆9a_m`6~ު!KdAq-إE)Ix0y̩Ztdi/32yȗXb3H!X)fSxa0v~xƲƍmݔn[}BM'n]2ٰ*q OnvaqPK-om]?v ۡ}к׺S9Wm1nv} F-~hqxi&O~΋#Q"־$S9P623_>R소;8[hFеJC$-œ19Ps9A )lA7m.-T͡OшniAPKt+]`uޓcU@Oqlmt۽\PF 6JUPbV4áuˉ'6܍ {6\՘,-a8L t5^@:ɤIj:{ z;CdQW zi˽Vrm&6@Jib(=IA//-N=NOږȑdN T8$ޣl y2=AbpL 5{P!73{FKm5] $%4&2ua7ON|_%_$E܃A&MɖGdy=LC8j*Q`<&5 :CRDu0UO=Ga}m'Mʞ@{#iv)6w?1V z(4@w4PDE[ YU_7KP K9I^V,3ǧ,y21bS h9Wi?r߶".KֲVkQr(ݓf{t}ط tH1gȇd/SJ8ys+ʌr ʄűՄ0d!DŽ{E 8Q%M V>PbJS*ն7lC:V˓Һ˒(:]i;X4w;\iEJNY =H~YAsS:#" jpiBQR4)!wV%N50N?_=YݚzB|dAʃ0EE V恞ɐr*a'zBfA&ZAzc̊ 9֝$ 0WCT K`4y8G"s~~HrYr3ǝdhxZtul&'!R󷛞'L_J? 4u&f9|ӟ?-r/mf olUbh30O²AgSpcI#%viE==(E`a% c|sxp C_O\`Q DhO%E5p(~mz_:=jB4D~(n'Ehn夙B|_ endstream endobj 36 0 obj 3808 endobj 34 0 obj << /Type /Page /Parent 3 0 R /Resources 37 0 R /Contents 35 0 R /MediaBox [0 0 612 792] >> endobj 37 0 obj << /ProcSet [ /PDF /Text ] /ColorSpace << /Cs1 7 0 R >> /ExtGState << /Gs1 20 0 R /Gs2 21 0 R >> /Font << /TT2 9 0 R /TT6 13 0 R >> >> endobj 3 0 obj << /Type /Pages /MediaBox [0 0 612 792] /Count 5 /Kids [ 2 0 R 16 0 R 22 0 R 30 0 R 34 0 R ] >> endobj 38 0 obj << /Type /Catalog /Pages 3 0 R >> endobj 9 0 obj << /Type /Font /Subtype /TrueType /BaseFont /XUXIPR+TimesNewRomanPSMT /FontDescriptor 39 0 R /ToUnicode 40 0 R /FirstChar 33 /LastChar 108 /Widths [ 250 500 611 722 333 556 722 556 611 722 722 667 667 722 722 889 333 444 444 333 722 556 250 667 944 611 722 722 408 250 333 722 389 500 500 444 333 500 778 278 500 444 500 278 278 444 278 333 722 389 500 500 500 500 500 500 278 500 500 500 722 500 500 500 500 500 500 333 278 444 180 278 722 500 500 921 ] >> endobj 40 0 obj << /Length 41 0 R /Filter /FlateDecode >> stream x]ˎ@E|E/'lFEXH1 [L&,R]u޼>~q~hxos)!I3[sdaFWsl.=<)~ҷos~8_/GrMx|RU}%m}<Ȯ+~ާ計ZR3:M|}8B_wYZ2˰,esl!eXD4{vOXB"l=a{-`6S"VUEFHEh0|Ȃ }Fb4v+ b \XUdNf+b h + \0@QI$RspVD9pOLY(yUie">s& NEsNa&(UbxsX%Ɋ^nպV6q2 &2z&95/e"0?tG(hJr&QI6HXB* $J$lA$ώ bq-hQ¡ӫq&K{L2c2 6a54)(Y kuoSsg%{K͜I7T endstream endobj 41 0 obj 644 endobj 39 0 obj << /Type /FontDescriptor /FontName /XUXIPR+TimesNewRomanPSMT /Flags 4 /FontBBox [-568 -307 2046 1039] /ItalicAngle 0 /Ascent 891 /Descent -216 /CapHeight 662 /StemV 0 /XHeight 447 /AvgWidth 401 /MaxWidth 2000 /FontFile2 42 0 R >> endobj 42 0 obj << /Length 43 0 R /Length1 56856 /Filter /FlateDecode >> stream xw|\?<3nowWeU*+ijdٺ%X2nAXrXrSbQcC"46 ЂI51b}l yz?sgΜs3s֯ݰH/HlnD%RiBwXJQO߶kTx.!޹rYTAX4-CrSK ]kG՝=iߥ'kVB,?O?\El;@ɫDCL~JCcBk8wdp Se?#_fwGn.FROO6&A\ /Yz2W{dp } ބɐP୩NC[x nGTGwJH}$xq|0ӭun,R1!*(*9^JDŽ I^ꮡjMȠOR%_HYx{('\I% nܣp"EyW؋~Q5p;D@a_}Aa ϕ]H "c_߅t&ww ߍHFar_X7Jbpb"v+@w+R> ,AS!fAPΒ~jj@j@j"Ug\S$\:WUsy0au;Ϗ? w N Sec>zMX5KjԲ|ș]Nq<ZxeJeC:#]6NuIYXBc$~\\=(,̉zj-lYܬcPBZ@^bH.n Nh!'\pY\| %C| ) YPς\ r-%yI \\7/U+9{/E- C;f#7)R&LuA%>8AF lYlr/vF.=O?̧ruMmgٶ'g2S\4s3ѣCXB<<0tNdg;'/(\ 8= A#}4-SGp>/e<7JG\ V6מ>n7}JTQ%?Xo^;w'^jué+}^nGDa!}lP(exIf&xͪj%fĤ胊oSϑ3L_0=1\DX *_6ԚךkM&f'~bb>Xg)~7}7o/~S4YXOoW ^s^iTk(@ߣn[-Dԣ=:XM0tt֛Fw!v7TY-藃9'4.b N'{ jBkxp/ h}t˱,\=X O)'mn,Bc0;j[k+Hu=9ih 驩 ] :e08A.4HZy IP\ *vE鼉P;Nx~|A-{㛏{t^難9&hǼ$A„O&=A+=AbwWy.Bz{Md5F<m3zC bުZo%'$q9 ޕ{['~oy㏰rBzb|lDMHdk4ZVҚF^ժi6=1:,GԔx'DT r0exĚѸ4ͭ4%4'Dږ Z( 8!AY[q۔Ä薛\5`ݨFy FtH6Si h㕞y%JJ% {o<$Gi+yx5 F13jQX4 yZƇPa 4^)}qP)>Lph<'D^aӢΏ5E tK4, 6tuķo\.Bc<\spY}|i7Щ/Kxqg~,i:D^V?)w6;ۆ]L'Zt5fa xP#4 ĨAMU)Q]UoTqQ13ʧeuCݭUTu;;5m5gdCAPѭ0ڰ-Kuנ ޫ{9""SZkd c YJ# '>!# E 9 aJb%;9 SaìTX][@`MQ#_{#oTBP4(^GE(EZϽu4帳~]$ < ( {S?Bm `TR ;Co%BT7CIpY܄ wdr%$\5:,a9zd"$|FǑQ,PCk!(1ME3A?/Fb*ry\H֒04&WjC; f QKO GhCOcE=J$o7%yi}@#6A^E^<@Bh 2o2 MG63rӣGN -]Kn@QV,LQ IdD-F hh]}|"9A~DtD4^'' h9%݋UMl W^~ܻ8f0|2e;<MO {TdhhGGIiEw4:x֋qdp)uW 5-. <`- d6YH֐2+_;CWgUW> :혥A:Fi>bEϧ+z;Mз[LX?‹Ÿ j -erX о}Utẑ$rV+ 7 ~/o:U{5K6^X@CrI!)#?ˁMݸ֒5 |CO'O/~b<}5n ]t}>K/XaSX#[ຕcB\.ª#\TU_iik_:sj`mIt%/Hޞ|*)"V.\K SFUx  1k5t*D<:<\ B\t1]k3&zr݉у#DGs$f9rYUbSTǵֲ;^҄m#%B1*Vu+w*ARKڭ.SSRߩ~T}R}Fִ@ JfT-}s/~S ЭJbj6WnZN?|m'\,\2zȾI*n$t/{f3\!F5kx :Io*v5=ʞߐ*.z\J|0K#A[beŀCZ &" AOkLg9"VIP9E{H71Ɍ83&^5AOxie'<>&C;F@wRP,<䏴8szSxvPH'1^$Uq¶\Bo 1v'j.?($J vm3֋L/\G ~\F}$O%7 Lq-%HCnQP4S;!/ Xgr֜.XvX^{p=iDS"ejy2E{*bQ3&>O.Lܝ?zvh }w [Uml*">Oz= ~@'#}57 0zr qG%vq9$F{j_߿!o!oБ쐷ba!q@3}Md*!L3 RLFH3!g5㚃kt6hB^jd:RHa+y]Hyk mT Y/tk!!mmfC2S?t 탔3"A' =B-$ȋ^"Gow t5 yttu%.^b6ϒk&OXU9a|EyYiɸX0R~דv94UMF^ըU †`c/iE<DF2:>d5NDяjʨ_jʩTUB_C>KЅ[>拟R)J܄ߏ| 857k/*eB27 j@,nvPdDj C qg!й42%qM <&(]hv@ѾY1. .5.t5Wp|D0na[胁+mg^ֆ6,׈߈yj8[@{CʘRK٢C|q].oU&'o\ajm 5`[g}@:;ӐS9\RT8 YS`0["F#TSXJyaГ 4{&%~(/|\M蓪/a4 IA_<ɏs:r! 9C841G" )Qq./*ܘ``CS>il;۪ϧw{B&nM}d{QY/9z$c/=[r x? dĵs)3aeUf?/K7 6k٦?J9@7hF<. P|֑?U1pq4O*1.<Oy[bH҄F Vr1.uLKmzo7%F?w)9^Uj?J{>i.kOF𽾾Ơ31ڻ8蓂}V+5#0\- Bhnk\vP%2~xs-_ *b혂#uAz0gaalcn:(Q6>Bd%\ɫxj>hii2!Jd(%TRGl+yRo :B{Qjj?hL |[:4}G:7 =ۗ`[03,{T fwX!+oig8UB*q4'MLqjJ E닯(\|  ?jbJ'߈WqL"w*w %'%Ad@u1 _WߒN&=)~iGMV?P:| :틫w`''<-U:^҆p˂+ M23x8'`_FTF:<;q1u.SmDwy A;ha1Z{G|}v^2|>e;Hy *B"WՑvM%M$UYo9{& 3*4zn~/toք[c9c!GM`!zCK3xZ"Bf1B=l0 WKA3VIṕ-k wlԍݬt~K$|xP)?x ٤5٨y9!zq:ҋHl.MLwz3n3LK5]IJbE׀AX&c)ӑfpVmB3|)ܡS<Ȱ B? sʞM>ah$9 'twvTUpZJZJ!4:K-j<4%ZKݜ@h` 8~d+q1Ҡ!Ő?lS 23k`a7=Gmډgu'O 7|kjk41]fvE{\{{fwz8X3%t{ FgG^+IȄ}U'7yWq 6qw;:5bw/n,,YRH'' {r{b@9@SV=rFOtzqD/GgI&5Kgм1E@%h$k[<%3>YEzE)<]^lP;WFz(*S¢XM*(/#و8\}eY[+*L.3t$&^4#"g\v~J[YW]cD_|yj`e?5n2:+x@9Т.%jNþ mw4wpesì\"3jn0vvCKr,k5F^t҂O?}êjҫ|@;M%;Vt+ P:=:!{3Z[S4zSiL[D4bV|$_MW4-%yٟ/$饡%)wҧK{wF>嶱63<thDѢ6h,ތ !#A pв,N=&(S [%았v>Pm6#aZ-3ޢ`@!=:j[#0%ͤKUk\hZaoSf/ج `\h Tjl1w!v>Sy'#BB"3sj;fO V<- Hid\Uknݣ:b)}$jeh4inlDڧ8*Q 'd`0FM:zѻre &bB- ÂZx>^tqN騮ު*\-=A.?f-cW= =)RĚCcT0Aɕ٦sfr#a+6/Il3`cIsPc 7@=_3e<s98 Tքn[P-!C;/Zڵ4"C}[ &e,&N=<=D q| GT*SFB`ɄGj .gZ$7<^gT+Sxfܸ~a=W}?}g*{*{c9Uخ&$y*yrεhɻ$05`Z/tw ;Dl#̅\3X!J\x |i.>e-8liLqP}l3-O:u6h%E$pv~ .3P5=3Ӟ/9p8~FgӪ/L zM{w[NPeNjb{1zMk5Cݑ5!srTkkҨeBKm~i˺ϰyor gdlѩrg83lFg78 eΩm>ɘ4:&TjX=楉])trWGu T6J*'|ɜGR!ʌI6{i֤mNT#d_OtkG56I9%=c-hDuJHO`Ps=}R L9UV2)UeΛ(o3WoTW?cyӞUs* !Ixc%.LmMr2 2LZ TT.:3 soץKwCW،Lw-htQUw>tz?+~u i ia4VjceAhh h~|앲ᲯRFkuW?s8HǃC0dO$`'h,!TR&LH,G$S~ct%DfNDbNe0Cq#5&NEEi6 h29N>$=Ҝf|IO9}ų¾0ԁ. ͛* vY~0 kӬeRH?˶%~]g_ZqK;Zd% puxjen[2Ƈ/dH9E}o(9z'gBNXP{2DZ tuD6uM/ٛM6l21&D?]K& &<\U#PGAD z~58#$e#geEUbjYu T$%o5_i֫֫W]Zz=!$.<#>L{F!{bsKU3>!>.0^:a*VHRoiA+^c}m7WcАqPg0ejM̥4]!SDoי"扤E-^XU+KWn,tCի^kֶ#}G[μ?H# CG~X1raJTZbt劊'}F*L)VG:.5C"r9;ˇ( @l] vgS:0S'Nθ(׃D5Sf TMbZ^۰D,D2:MoHr45]jUZQB`WYʱ+ K{ZRQ4O7'NBij-t۽/=uW|{੮˗rkS_ڙ.a/n\p/lcsh{:*WE=챓\ҟK}KF\qIu eM.m^ ;D*uOH$8?k58քnA v;198sQ >( |6|AqvRTOޙ#_FRkSSNsc2S3[Za)&bmJ1M / F0Єti4fd@q2~JٹgZ1׌tLMdu];j/7xi=p-}'Xnym?m]T@s]C{M׬bx|lS'3۴bL4F,<9,q 7 *rhS\AR+XE~~XG0Z[C!2׎)uͰ`%3HCvCOYWTcfq%YVdo%&UVՕ֑2"DWAsm)aud:y%B u҈Z4Y ux[z`5F{B-Wh*'7osn_92w:`Z/ ȁpΛ7_\H ,R1Hb#55/GW2E$=U2ð;i$Uli Ī*. Ba_ A|4}=i?=b6L/ Cđ {׆C4tI!'gs.jLΘ03bبG4I߮JԘoYOv ,\0X) /`W̄V?5yJBW. 'b*'4'wy,aKBs|+M{\WFs 2y؇΁0^RI+e \d#% dSb$˴pal Fջ6+-{+̶nzoYw6ty=-V0]x"3|y:mp/ E7*F>֚--~u%MrY]nw#[xy0k-SH槲}T˓ʶ+كJ !,4^iai{mҼV* ig+n5YJ[m<7x-esrXE _cySrR:M7Bͼ0H$ҙn]fݝe6Úθc|'++`ҭؗYBs=/[Fj7{5p z@6j%Y,[,6졞D6ds3`~wI8]WPGSvs#VHt[TOQ]>dg,^dc ƞ.(СLs~!"cQxZJSRekFya`y/AfegW]'כsQM(dq~.^ݝ7VBbp5?T[0?6{E-$ = mw~ϵ/CG'+r7=9z3B{UؼB# M&ЁEb,>쪬zJD2_"ğiG>ć&j€kyHdbsp8Q OJnW- 9/í6b&lgn]1f:UETo7hRZl 1$)!Kߕ%Ss.%uԤ}2Y\s7ޮ>r!xUwn}ꍧMK>z w.d+%_;H~~{̋tc21A. }^m!mҟ$FicVδ2w?uXmAAn<ڋ7Nolb<|IUl)E2fm*[b9mۦ9O\Sۧ/Hܾ*v+`W(+L߯;F@أ82ߓ~YRry,R(=dͧ xV|Ns?;mɟ2zzO4My<d ''D!Ŭ0|lKdfqۓTr;矤%p]hеWK>O86i'`]ۏ+;Wd]uw!Ǿcr|g[YY׫rl uGA^[S9?c^[% B.%{"ŤH[;X #=YYZ>|dh_ !IӬr}oQv 2f!HTKʬJTKP29Jf29ʆӭJ̧Ykj'F08H7@O* $N*qS: plti)..reG(S(͎"ʜGXv(lbΉڱ A&6$ ?-<rUs"sԡl;^u)oV&mX,⳻r KnFiI29,^[K.̵N %ys'/|㒖 +{ErMP<>B'pgH[# Uw{[Fle֭sUnY.<^wFQŀDX;&yR8A lF|Jc0.uæSW5IHu@.&fG :1< d+ d*o{Ok(V(ŧZ`ǑZ!6z&Jja f9G{8@W% -bP!,۹be;przWMmʤƍ ;Lz/DLAWòU@$˛gW6G(4wЕ'__ԖgVㇱN1W/63g+I|rEGnG򂝎θ#4E7GEFqB4 ?5i1ˎle39geޖ쥻/LHKs #x:y03/eUg~Я`)hGM9I(1>ƣe =)] rN pF0bU+v W+A4L"99œXqbKx&O>Q<5/c#DZrOǦOӦʒ+Ze[?2h'i^2Y{ݓA@!u6!Eb1VIH9aHR4n1^ր9~eC٥ڥgn]_&|.A5^) w+R_A>WwZVhn8n??͊GcLZ2"[g@׭kQ-i[ZaVЊVa-N$"9j;}ݰuY9 R5p=nUʼ8LW Šak]/~BpVb軂P Rʼn 6(mQ:[jo1 l !Ҧ`tdINTKYK:_geg%FU`f<"9x:]L+kwhwkժ׎4 (3y]+tp>u9n?+hT ^`8wʊ}V\ne̚H z9`Vx2?ޟNM?>e҉#MA x9֊ 綆RUQ_ ;zE]N4מ*pW*'nj\PQ7Wu?k53ç W03h vyclSOꏘ @ 6-cl%'%& fTl'[Kv}jm0ѫ F׬1Bs#4$V6En5^r[nl<՞ crNCݹs>xңlDGrڤqD<v[nS$^w?8ʍHlJ"YKpHyyn,=+#TVj2ʄ#x['ֈMfszļIUU:vZTꟋX,*hllM-&kqJo¨E9-dQ+K 1F] j<(UʒV1h[::(I)N[j\j^} <9C# BQXxg̖umV'7`eKRzX0reUiZyP'~G 4K?/rfYre\#\F_I6`ZppYdgZ.؃3kZ}hGUh -aO,.c}|47˥؅UG2ǻz[}^^4a{2A b L:^A4}zc".r(<4?%Q} v8Y!M`npn Y .X`9MQJzxn.Eio XkO2\䞟i;C|K"D Mgfoxs1D'qXLvӔgɷ1mms+w_D_t8I?vLԱƘPᨈMu\G8&.DH>R8bt;c5%%+񝲍M>ͱ%v#?_/yhɟqX)G%_o_B 1GW/w>x6cubkAJ)[_X\!48:ή&Ǣ1=u tZ|C?.l|>?rİ_% x^6IʭaGF@1DO;# W4 C9J8MSTpX+hJ{,9gñ@ذe#uD3o98Ku.*0\rA1GNC-d^ ts^Z7PKthlA0s qÙW{ B2Za¼wJL߹:GЇg,W V6٨mLn.-\V6!;q|if[`~|{)tAJ6[W%w (s6̤6jI1I wӊHJp$*v8 &|F`8姥sdcz4-JњZgUpuBtR`GpDQH@9˭c±[l(L rh80arV%n%uY ɜGߔ-J[ '3P4TcL A;Q4fuZ`.s9^vAK/M0qldL+j*F97&q4or9s; l7q쉪g4,~}M?)ц4J\wAC$2IޠhMyDS[ 9ITlr_Ͳ,ufz߿8O[|P uw\ᴰh-±cGM BLқi3]CG]}߅p"T|q+ުw GK^L^':x鶛W=ͶKaX|-br%먦S^C$ "F@^äyUyxc{}Uyŷei69{N9jgT UN̋/̽87Ur޲x?Qg<-LZz?$پ‚켚`3g5`Z ^sIة].kz1"eb*NjNJcoU ׭^zj^%uKjYJJQ,BXvk c`fa q;!D€3{a  segtRuuu׹;1Tˌ/挛s+ ) b4ٞţ)יs؜Z}K=IeWU,S BBD3S>òQDty+oӔZz#]D-"P:\pq(:9G?/Q L5,mT; '+>IZyԱwJ,1 , _iC:?^6ܼ<~Z3"1sDF&f-w' /N)(1f ur[q>[+}('eJװ[=lR=ׯѥ 0jp?Oh59j!n0˲PLzk^<]\ ȠPˑD.rq )~4 TniќwTXt)˔/Q7ڱag<*7Qxdۀh@uF8O$0E ~ .jWD\&Ce,TKs'sSZ/ya7L}'(Ж}~ƝKZϺ>jWM跑fe^o?噽3%6N܆FQ0 BCk3eBU򙳳y=~bXy"5Z,}3w;7tܚ(۩>P3upY},sW#+⣙'+U^r+4fs@u~M'T-DEP0l&!2LRF,>“hAh$F10)Qzq}BsuuC}kuHM!dJ\cPLTz^CoCD濃5s ;\|QFnn#P(EKIkls0p@JwjdVڈ%^%U2t%@_IzXWOՎrr7r߈p }fCXձcxҪ+.,\~23)X)a +dһ6Ǻy>699&.AW@)O R:2YI#DMׁݺ٣:J,w^>_cny"o|`Efn[4ۏfg]4{;D]8+ _|k3eqQaX B@;1DC#f:7nr5O{l;;wv7>ޣx=7M`TjBM,dzu:WV;(K@%hO]Z^Y}eϕ+Wsl-mb}`gwWڃkSowP8=TWUIcv6~Cs4Bd4x:D?;}vdts<{~dː.iuObiMsp_OL=U\ճXQ;UVXoqXE80mD׭)!"qꑙٜ@٥QlRL]rG(hI㥵blr)`Qv9Yff٣c[*GEvZExPZ}"춐eZ=x.yͮpK _W!nB6w|XˡN.̦)I$ С'!$˴$4kYׯo|뾥Fpڃo ?O-;OoFRV_㲋{nW,!哟k}5woO[3QDb؃{d >w@/OnoߐkԊJ"'Tb3TZ fU\r8ysら9z-"[εpj: $K Z!$6&NO!p-F~Yξ_݄ űP&`ՠ!('9 <SO#y EN99):7|ʬEQ^\0k$"/r6oڕM/o,4H9Ŵl;+3}evw( ٓp=^YkVby|˘Mg#yoőM;\˿3:TG'O< JJ*fog c7EE-t\G+F}>dxQ6ӛi!=CWj*u6^~n'U~U~U~gm2/_s Okg{eJ@!ٝ䓑N-춧d,Tꦚf;g/"lM)يP`V/:h­ QDhQ6kDas.dKOYȐWV nR N/_ X Ǘ]@ =&NC^'ѳl6Ԋn[r,b4g=|Gs2'EI~  {3)$}9>|H>qbn()m'K!jQӍ<2<<z&7DoJ&8zzɴAZ'o^\7it:]clRS ciʚRA. T)S;E):䠯ugNʎ ϻasHT &M2N䑳;5w@2$o2IXCI IA̖w,z@ LN~??718g#⛇gS J ;5 @qZu*࿇Sa+Y RoB%i:Rm0~e-xiOxHކpII E1 لvfd*2^giƢl8JxbUUjMvӲ#w>dz_2 ~6oě6Hi쯤ҖrR]>YX1#KA*YQ#PA-qEZq-;Qҏm,^ǠҬ-3]\嫶F>j~i|z$r_ލE]r]}vY͉-ɿ'ObXjY\TXZ3]V7H#zPbX1%lø3[bF[eY1H(%YQb2"]B̘,ވ/-Ԋтz $[]֑6zW%nu{Fbjh ;b,wP^2Kweד/Rз m%˜/}b$|;`OYkk˰kcX8qtiQEA_5fcs߯OF*N+3U+M{g|I|v=|j ]2CjB!,(4}J %I)؆Yb|"DftCFk=zf#j>ۓXGYPnJۛ$|{ |b͟jW7E%ߨ0#@"L\#};~|(@ޑд$ܶ;uxd$ŞI;A^2iz`pyMpmBp0)9wJs~1':ov&Zw)67`U`j?9]`a ٝL7nnu1^PǃG٣':H?ZyL3 <}^}55SOտN<5EtRZ]=uuN7_/-V'/TM;kwvՌsKRK:\<4427o,S}_#Uc{=0F;WBjf駈F~h??g;-5VI5N0Tv XvYWoWn]ד@yEz`<ܿxU#uc9xGm) :_Hd2AC"/.H| V 1 7v'؄.DD}O痁y~,ɺzy``̩ѤPF N@އB Z^)X+Hu s!SRaZF8, =wIEPCod>gauB5yM5_kx~"?G #RmD2_Y[;UnbMc.𱮸 G7` FHcl"񷓭J Oy,,nC5nH ȇ6 MnRBr$m,y 66`?D6]>8s46]R[ˉ({{UWgzz볮97uljf)UX9⳧ O"}W2M!rUT6e;:vzt^;t{=-o%dpU ނҸX7'k8='кDKA b!7ď)ل4X6Rr1cb9^q`{]_Jǔ'HeTb}G\<+Vl-ZaHbBƄوn Eg#8xDl$R`t,H2NPmiom0T^3DUD~=w@c ?!.LEH֚+9915RkV/?kޭ3(TՓ%g9>1ybXkxijq̰?O%@tlDL>qIS5]^)08CA(Zd;} WZluP/J!}|iOTӜQÒ'{c yUH$yWaaeSU@iF۟w>L)9!AI)71ګn6bǰkPb/&|BApMES箤+i4c ӛv2vtca^(.)E\pq!9?6c,SwZ37Bf~ۆɅBX5ؤjH,b ńpfx4TE`"5Z׭ " 6#mYy2*/!C;8R\٤= ٜ}_ydK :[@k?f g& ?(ǧ >EjYX9[5*%v퓍LhOҘYEK#E/!Z],$X$JCNqa:NOyx鍝;t11JﭔFƤkM&8X'ԓ¯M>t]Zۘ n m}q{2(ROߐ_V=Bfqg}DtZr⑄Zo=:dg,5"&N9R_Aj{E{Sh-äﶋqc+L {)4Tzc#q$DX8tڌ~ÊY6v=*~BS趭[G_ESFۺUO{Z_1nTZ:̟~t`&"A*1iL2 4=4feI(d?"ǀTm #fk;)E|Pkie) _f4,ɾϿ؁*Imś.싻{i_]y̹{yߒL,ymwUe?DPEv^i9)HE1"i\l^H7<ݠmM%H Q'I$x5ФT.꺰}cE{f $Y')6gZ|  V μ W *-xI?]/Z㼨b)_"_>>*\Q#4iqdm&i(**yeZH3g]h]m}X5iv$@jI?PRnVoW{ԯJG:m9ٛ{yx>0K%6Zl);! h.#鼄sr|PXr "uK}AS馌l[͝XٓoP+T Z͜a .g ?\/.[^7Zq݋$x|(;pVZ+P6[]D$Ak`hn¶ -uKTSMpKa5. FJZ5E]7? qTJ}?."O+3$ꊤJ{%40*C>iqHQ/!-}[lb k<@_k=@7V\)M - c kE's4$-< j#j[z lk^~ry1NG_:3ϕ31iLǷe봄Sr%,4̘OKz- ąɕJ{|wWAW,_ZZ'F٧wEH72HPmlK`G`7rbg| *:j^ M(3_u.+CYԝidSuN;Ă971m3}Y>Z8'TrZ1p01'a!?a~\b a+{fHc7QA§-Vi9@yj_!]/k꯬,洴 h4Sm*zrI۪ʩ(ڋ6|Y9Ej)f,MX8JJĺ!Eu8J{ffJt Un_f`~C !F<[f;s+c,6 KU܇T"PL, Vl^hAʯkQ#,ZK8Wpq0.](^ sU WxLN̑{c?⺕4kU+rBu"\Zv3DQf+d6$̒2scZ M .J(!60Qo ;gQ0btBy&PG;a5|Zw{`͕?Pcp>y T=6F|6wS(ɦye3v>_i<+viS=̖`j2/8˵|n31~֫?7^b:ٕL_%/d{_3X0c[M0|^ Vx?dԝYVL[CzE: N!'C9Z˓4rF3"W9RB!ڋy}&c梷W* >0HBY< xWB/HE9fAq< ݀)O 1 >yU? N[q` vjC},ŏL)~d 4cG^f"ۅAmSp=]"hD):jZg?ou&'{OJf6??N~ʡb$'%bBYN(vjt3_n$v+p(cV沎[Xl5)^Ȓ Ȍ/GhXk aQ4'g'K騐JԖ[0Њ[T@(CC*pͥ| g}3}`g>{h=P&}_:R'Nx22ÙɈ=eh1nm>F_Ijp](&_.RF;HwC %@ϰM^DDoVMyٜRfnTQ  t;ae s'9+A Z Mȩ[+ .Ʌ!@=zGSV3fTmLl#KS/@Î2CA\u-cV3Iۤsܟݛ 7`ʨID5 ۴D` EĴդ˪(!kW,d!аpj'i;;a?iS IOՄJp*7TDue[GحSv5~Pn/U%5ȤYoˑּ:C݃X?;&Il۶sڀ_`t,Y𴀅j5^`_n ;B^})0q7+:,Րfú!_yZ8K"C4HBCI{cdA4: w##oKr*>~|L♹ha7ꂴr)'F'SׄhA@kN96 Mn20ń|z2KVe@Z91ig#v6fOP14x*EqId8L~C@=ŊRg$6|ᚵ7 U#d(R@^熐ABB)ce2?\c/XGn~ݫꩯ!XڣKRW߂٣0Џ=ZZ0p7Eh2ʈ;}@?հ +fY^FA!>N?xb_Np}3p~y]?Zc;9N:^\9(_ y@=uUS[Vڲj+6/ e6L:]@(\:Lc۷|rgI@Y˜Kh8=nLUPB7 nwK|_o毆{>|m4o-L@[lٺ) .\9`")h齎+>X|Q,-3 ,Pű. fc6lZ"1;P4ix[rYXu` ;$DfȐ6'>rs! w#dKɥՀuc5/-6'M]߂. c=mM2۷~x&>cn.V>(BD63%I (MA;ǛQL# 4/4ÌA,N}<9JR1젡 89 '9l/y4q!|τ=8x}r,3+[dX㿛}̲ԺFٓd/$[,^7໬ z1ǍƽF-j8=;!;KKXwOJ_~x$NR;w7>C ^bG t#d͚snO,ס,jT OS @\;r DY|v[7nɨ ?,1݊\lz*rQ 6%j70'}LF/Ex9( xǏovhpɞC/4An+,UV\k/׺^\ *<;-**y}:q16!EOP2>W@I?dC௖X٠r)99Kw||]#_,=FmRT¼ ᅑO Ԋ|B'zJ (l/<ZJG߂VRZ1{ca~tz?@4J$ HJg!I2;Q!tRĽI&If`2} fK ~-Ϣx KNI~C7 )H,#0/ɪX f~9{͒3$tImF'^[ DlHB!OCx %n,} ._ﻭ@#MC9W|皵ݱlV`o^h$obַNQdÐrX:؜ ܜ·GF^`N$y"ɍn?I<.H)#Ҝ+[;I!;gCɓ??7œ=^gSi:]bف8AȌ+=u7> * ~˝mp$_2YۍEaC ɧG)َ AnۥFId;Y(I%Sf MPOAzbx )Os5:7=IM( <)Ա"v w7nCD`NB9ERNB \JE8:Zo0tT dr&.[.ELzԽK.)-[M[~4+^5xY&f&ī(Ff&6}U)d d*etQxv6s8 qU>p08u̸$9J=%6{?[cuJ&_U#l dbjji5lExSئr\ ~v\yHx&KO,5LwDSS`7E?jPU.WOwDvPj^tsD7 T(C1; EUejV!:OgLV űSP?py,s,2?+f|-Z捲3T-]e{y7-6L'"щخE@1kŎ!n-?hy9SOelP^R^ѳ{yZ^³b%Y #OxJ&"S"*n1,A&ftƔ`.G|(F/PV1~OxEOؘk52۫T X\ޓgcܠ6\?K7Sݘ@Ǒ'ӄ>vUC羳 CBw DgW 3%W6×5ܲ@Y["ڂ5*v 趝*=o­ a,D@IMG$xiGpeDUs Nx1xm!߆d`sb5 TtDzN.X;g봀)NOtmœ 'S^`<{)БJžk3Jsw.q+ə?%B/m0aeWMl} r|g -D/Gs+l1 y02|b08 N`:M.>4E X@fO c(/fk]χA:;DѸ #2>z40>e&֘x`W.@AJʊwz+k׼ MRŮ@P [FQ?~0aiO튠Lqc}O!De nXb~4x?ʰ0 N{CQ݆"P[ nWk5r"n^/%Vf䥗z ļOX ߞXwqޫ{6^-^ \(>ȟδBV\{< Ivm:F#@18Ád̬{ e62NHAG$l9_Pw;Юe%w5^c6rgOikQ&ZF`R\FTuUKd:QDNv[_jt0 _%( ":OA (cknk ےU6kP.dpͩYtǝ-5 [SX<`^ʦ6[e.p;2F%l2ӄBLnN]h){Pe  qz,FO~ꬅA5cu<6r%VhAg r)#S bC@n;W[ƫod(}`yFZ-nꍇ1T\MgQf} 'IdDM1hJyK\l*s#˥աˋl{C»fMT;-w :An#fni6kV)AwBQө* eu&\p"`= vzvMCp)S,D",[`kgfq Bp1*3Պ { -ڟd.7R'"*g[1Cϰ YAfjEM}>ᱧL +H̯Ek#ap=qOfjPê+ "ƋP%})@ 욵1Ǵeol䧡dVD4c[ KB#E6A}{SE8V9gBppٶvE f8zZm h$N_8q19SD'ǩ4`vOA3jAFO'x樕RTK8u:ѫ-!E8CAt)@K0g |#]P jEAۚ q ,ǞoAv`Q5[,8gy Ș%`s0$;|?wzUoBf׿xA\܃#s 4*Vί=g 5rƊ(Z*b?J­+&l8_&=Zwz[nnnK?"fd-iHr F}`m½ 8 Ύ ,Pvwv?#Q =K8M.vJҝ,`m Efpݷ-K_R!QwHTV:@%z\\N>qhZa#I\if=5њ0bbڝfp@؞|~M4lX2ͬ|QY|6lBV!5Av53r*ӈ%qOjU!0nZjDar%[}-0չ_ 3LSphZxodtH;h?#_Į׬O =ۨO哣#%hiva'0#2 &Z->_U{P<= F :UCGMe|LF^zP f6J+^>ly"+N]͐g}]C$9Y~M0QY"^ W9mPZ!W+ȸ RMĦCPD&HLY<>F b6|͓pDFA7eOHLC}S NpZ[U@C"n9ЂqvRZE͍M|r>z,ЗQ n)!d,٭hi |`u r2f6ؿ9Q%XqY6|'L$ @ *O&/_b*m /]ԑc]U_]53RA=W4ͭƒ.CJu]ǡB9r[!9c6Cy11<>:;@u.sK ZB Hf:\g3Eۨ6~tYXL9,G,%_$gx2gft:uD^WUz[wYwlD4,RieܣRn!9Y G"NK%:Έh؆a+jN\mn] dDw[+Ӕ x`GݩK/ǥAg2b9x GWA;}1ѭmWK=A7 vRK-믤̚l+ykY s<DVm8> endobj 45 0 obj << /Length 46 0 R /Filter /FlateDecode >> stream x]n0F<"ƒH$%4U}~a=MJ]|Hk>^Ӹ:wǸa5^E8%c}͒4o-0JKr֛{6~ѻokq:_G{s.x|R׮ӽ5]j7mѱ{R74]\z}8{G;| vux: $N@>sxy,l ,AB^z Af6 a܂,U@$ a#WRaa )T. F.` U`| U`E* U\K\Ъ-lW- q [خp [+*,Y8 m#UAߪr {>qU@}WԺ| s\2ĕK57ߢ`\.l,l0|hMeF7j03[?}ޓ\v{t+)~e^4q} endstream endobj 46 0 obj 500 endobj 44 0 obj << /Type /FontDescriptor /FontName /NAAOAC+TimesNewRomanPS-BoldMT /Flags 4 /FontBBox [-558 -328 2000 1055] /ItalicAngle 0 /Ascent 891 /Descent -216 /CapHeight 662 /StemV 0 /XHeight 457 /AvgWidth 427 /MaxWidth 2000 /FontFile2 47 0 R >> endobj 47 0 obj << /Length 48 0 R /Length1 29300 /Filter /FlateDecode >> stream xy|T?~νw&owf$dB2Y ͆l (dSP7⮨낊Ժۖa%ZmֶZB+uiEH[%܉[zers{9Y<\HO_t(-tQwX9p|#B4۲=MHV,='VYت .*^~D}l1,dm.`EN +&i/!%uOk"~KDC8" 93ɽ@ȳz-!W\kg:Nywk}c7-ni#.s2m&2_#A"8T%*4lT3/qWea&d#VĭKx%DV#"XSk|Uهݞjv`bPgy[~QܦWٰ+|ŖfήS▉M5b[ 2nO4d##k6]4ly]ͯP#(sROUlsJlU*:2T_H2l&#zs6?i`YDXGGxq0q>_w);z00lTQ+?N'I[T!pXwz)1A?h![d;H0-y Cݖ|9VB8(rXoa#0,Aaz_<<=oaӔ՚wF11PYP+ICU,*M>#=g1ydpCSu!~T,ΗxԼHWI0YKaZl&e5 _5Â_̨# !Ѽ8&ǔ+_֑q#"@H+m!CP+Hq(oGcyЏ0 aS-9̧4ZW!B!EPWG|aV^n%[Vn+UUUjɵjy *YT_?UzYߣ}XύM5]Tfߺ?5۵6 0-G[>iw?w>y?>$%t=Jo*fh+CUKV6^%7|Q6y6rۍ9Qӌjhi>ը{4͐ffF#j3VQ}E݅8!ەQG<+:(yqWD!|J^B\fvV'11z$v,b1n{w!!Q'YJB\RFuc?xڅQ6ʈ{RDK?p^"Wr"bD,s V`' #E*%mV(( E ˉ,7>ݛdmO)mEP%82J*UI9)5w))XD U}܋F\P6};_mG2` pyE'ENO6#OJ_W>ϯ ʯ|d%n?+H떾Oܓ#V_|;KZhyhُI >O] 6*|qtuӕ$ti~eK&&GʔŤV|7[63횘H'`zm{^| Z5Wkȗai}X3E);$w=Xn2qJ$X^|lxzY=ɔ#$7w[īW/Iܘ ek؋*L|6Q%&<];]t1au<եԣEH!Z" >&Rb[1ѻ˳E~ީI*ʻމY+ʾKQWY7?hGSQhGA-GZG;G9?>>'F^b_.Nm2[eȡF,e@!Ubu,M;2UJ ɍ!PJ" {b=kJCD,%; F8AaiZ"֌K c0᥋k}@&ϑ>+]!^F2K&jj H"3I\3_&Tr9~膳a.z*]MӏQnYtQ2;Lv,j;a#$ dG 3Ʌb3 ɅJry7QzԒedZ_=iPj#pP^G\J5uc"Tt|RυAM= |8܄ݼe!̦,'[AVQ.~CĎe1m!S<;zJZ"]xӵzyZiNG??G rJZ]=vS$c:Y@֑9x~n3w%L}۪2' ÍӜ\M~M^M7w%?~27CVaגUS=5Q Z]FG韹 'q2~-㷒hk5:&!''Ofd+T~;/wdݪ'U?SV?+p "R>ϓ7)O4i ]I/]D'?;ĽA>w"7U_h >7kƷ?  'Ե a]{XU{Qs| |A5&/F-K7m93=NOs3qQ|\7[]}ĝ ķ;򟫶yRSqm\cHauZТW˒v `<2l]!2ykS8IHr) msDg'>75zK?Üڸ30%r*fn/>x/|>#{W%TmiŢoV@CԿTWk<|5h=PMo>=}[;+=ucr;9 s#E;hA0`Tp߻|;?&Dթ) y~MT@^|c;ܳ0=N QNFKYKGu6X k:{>sy<"0 ZѝG">L##r2c\m4CL#oϦi#,Y:z͌ЩڀN"0i |d)pɫ4J5͛>r9;IUa]gW@>p+<֐@E5Hh"y|5E9H/Vnp-"dpžqZ j:ޤޮ~BWU$r v'rF.Z aӰϐ#eXEFr50_O@g7|9ޯC?3YF5t%h! >Zhwݐ=Hqe\t21^Hl24b_!M /~ІGw)G* 3ԅ} (q9pz{G0vv'T-Pqdx/OɿϚ/LiP_TLWexLFb((l2:F$J*\?JHӦY^Z(υQ4mraRT}+\l)Ւ fҜwIܫRx.ۋpVەH<:9Mݴj[Wg1:tc0"iD*Pw UiGtfL1:r^ >޵\ޮN$0]˥e9”҄t(i:rZ59̆S1,OΓ[7/E]9[ ̹/=:ΡZ? jr5޶pno<돰.DxO6LwWfU_. Rjۚ~Ʒ-G|c6WZ¥=-^9vMb`+.u"a23^SRJsyW+K9%DYH'T@ A@?[lwk$Iu4OYHOE RwE[_+KЗ ІabBLзWFH%n#":aٚCPk!>؎*jIM@a @V_ ráaV01@;`u%[_`7LC'|ƻLךZcFQzWY^ $nO|]";3R.-&KZ }H{t%1sziM}'H+{jF&juL]kRU@W2 r*`횧}x_tv8`%Z E&V/(KqŪ#j"=$ɂc]om+z=gA:ùQec>VNh_ 9\g֖M$4tMb f5U_٢gb{Ô ]H}BD-9oo{ \9Ҳn_!ę y+ݎS©}'O 'lD3NRqḽ1wވ#}*+RWWVI$ZP\SUס l蕷,eY|ڟݺs.j9HPxkFǤH6i~mysmWzcYkeEŋnz S 1WנGqyS}}'Ji{j56RxCeJuj-M 8%0\>bᮽ ' Υ;ЪN]ݲjNd 8')(ZӎГ` Ǎ>^"&+٠kvFNu'͠>l沃VN D.s+D.17fC1=65DTt-,Db_Vh Bßä4dD<#&U(2JlIh}vf5ܵ;cO9L{4lWziMNMq1ekPԐ+h%' >Y?_nh&%NI YqCcNs iV'Y1Z|eyYqWYO䠳j2yޗFE8޶V%e9d-,驞Q[èF8p"c)^zc#Ke/6%VjoZ, /Nb2"-DS|q:\Faxwx{?8_7c NfGjafy\aS?o?U_>ڥӦr-]?ܭ k~.얣?ѿlRunIs.ŝ MdUML K|Imo([5-/TnBdN@:VѤ-r/G-|A'i e4G*jQQP(~FIbL*bvSQeEٚj5Nl}- {uoݕrCғUJSKĝo~'}B?.98p־-(w&?RN~ Swy V!Ci(%vmٯ_HQUE*I.#xuƕdVT"D4>CAgh~=(+CMWҙ Nk#P}Sn_䟢0"ԚfK&bTxg\^+`CSqN0 XZЊԃE*=1:r2Y줞m ΓL +{pG HrIp`7ŸG ݷ|g^ekKYKXkn8n\wj.+geU6y> ? N)A+SxgOa4u-V{F9x=7uY>*PzQ)Lu\> F{JaYA^z¼_m6s4&q$*I4#!ztHԵQ aDH&8l6AWf:,+B-Km4%El[FceYJ `Rల HRoUb 1ؕ88'DJ'r m`Nz}c'Bski}cſN}Pap{!"h1fF+47kAꊠNüXWWUTEK)Hcҿ0e]%éh؀Nإk~y^}m{/q򝪦/~]B^o'}1w(1<@\CzC6{A4 Q`u%ݾ]7nЭomd{TaK_ ItC W 2Uf&&%z E\Buu#E-5A޲ƩK26j $hV̎^Yo5?\LX8[;t76~t QC_L9o˞j$IИM w\9?avD@dXDSgbh dY3w2wcL]eE޳wZp7m,+g=hk ɑiǁ};pśN]<@A stlKsᚪ5_w~/~"7uo2cAvt9嚞- \0ީ_'Gj%ڹ&ӯtAm8D&"̥W&G%!&8])Żnװ3VLrΣh9ZmڣZY[ݩR\&՚ZZښ-@JFp xO5j͜%VOyi o{B +XWlNh>?DD eL6TIEeyfׁlط5R\DԽriIiOb]zrg1 D{Z>\p0ƃkΚܸ/_J;BvܪG *gƐ|B0$ ~aqazO2\s{ ԧ K8Jp&VTpe`ŠC>d}qp0tZm31ssh8r 5[-Vp% zgEY+eЉcKIY<9uʧq  $Әi>dQJ,\+ F`"&c_tц9&I*y|m1=6*ҪK-/h~zn肱?tU4%XpMa7y41:RC.qK%⵱k㷖ߘ4H_2ded**fYՈflb)M-7_Tߛؑ|TCc*ΰxQ5ࡡQ7@V7tGo(YTx*$RA4=6śkzh6BCZ$dkeltpu!=p5dwG>^ =n&@Sa `cDR2FѹADb:XxiD$)%hJqb ۉ\SJc-%pؤᜎU&0d-vEF AxGrWot~k1s?_?BĮ[=Pʓ_›ۜ@T&~r'i5}D,oWl>jhڣQ8H1E% בu>_s3Uj=fU0`5 pUFYLaɗ "I8NfqUb7{1Z?>͌mr2\iL(Um_OzV8]`K1Bć= H%P]{t-^oT.UOe'OA0OCɾff e@Q)Lbdkb,Ͻ6YG۾:C.ľߵѢЮޫ]bCՇ. qU ]u= "ds`szrCǂ ~4 4kDX":్vkF\_zʦ`":bS02`m2FaJHYt0CZ'$nR|b8ldxBo`KhQb K񖺀 )?Bjtu6V5c}6/+TYҳˌ*S\XxV)+sWTfί)3BGp]n_;ond@lj榠Nvw45QfM%؃#BM`KGj4Y,fLWHTle=~J!5*/|LRRl-v(N @(("Jox;d<'JjU֓ Px(r;nKF̪*T%IF?'_R \bg7tW ':vHmv)A1Yotn"guZGF7wP )eJ9m <楐}OgODO].T{z88Ҝ/vV~3EgbuQ.Mr*aU={x=]hCncr܁RQ3Y1x(b3JCBZQwл{560?=bzIf34z>tmr]AJ%ͦMM}}g[,Fx!y20E;g4Ao5wƪN,T614m4$ă (q:ԩCʭAfĩ9!%WTRf|D2%xNcoTFco4!xmP>@1=r{8[X @ZGhK6gZ=@Kv];^.QmK\zֽw.;ozpa᷅ ~i%cֳ.@~Scqbc9>OT5QjN*MjtBFw -_4#Qа;a>J,!QldE Tm$}5+w-sn Vxh#Kne p!?RG騇glw=;na+ȴ?b%|,=N^'y3gDGvhQUeoo(t$;<_x3:+ Hȍl* Inn$Pxd=#QHF@TJ+#/[2ҕ%@RH4 uR"Gxfbql 83zrWG, h* EoQ }p DŽt[$fsƽ |uՑR+D̷Xd"6g e K135<%Z@Au5sC%p QٿE8tu]өpVaƛ͹ܚµ~^"jD>έIukwQ%WE iiZnT-(5jS*՝J[SB- buɺ7ߔ|<;<-iʺ.;"kX=> ZϢ0~B8DZD|=,OYu j V&ևO_jRVJRNZ~n  HBoVEE{IަڸgB?:<^4*f;p2}8 F5K[ח_#!/VRf/.A9O8aG89L`; b*uX|ڕA9,yUW|qu5=jo̰~8|i)SU?/(+^:jܶsォ-P:53G1|QT$ɦ6³;KV;cMEhM- [G_kRj{7]Vj!H%x(1FeҭHWq.Gx @>`y썲,jiHBY,=bgjtZfNFE5 WI4=ֿӴ&*%ȉWTUU=UUU:V'IWd&tɉ; 2ȴJ (@FYM$▸1ː2$`oKMb"¢B*=P͆PY}Q/+M ]N➖L_D0}&}qz\5|YHEcm'op̶𼱱O~/?sqc&Rhwy"¼hj$঍#nvz^ B;-AIg "^-r[ iCMw;Mۋ׉ˮ*ڋ ةS\6?==+>|)ղ=lQo&oTZIWUZYmWu_I*Ӳ߲}s7}9zŠs\4v'7dZ]-TEY"(oyP R]sEͭ5晚_Dq^P_wY]DBwN&f.ݤ{@euzίb }LU } SYG,y( lin Ek=aw) ^e K">Y_"B(YWǫ8Xn#tnB8  }8`F:!L%JmLUM57{֌Z\֖' f~emg"Öɥozێs>sԗ*5f5Sۓ; w!1.xܺJ gM%C3 B#7_8AG+cRIɰ!G%?…}ҋq;Ko 8|uѦ"%fOmwO¨LSn(haʠ۲A]4'|㟀1WI{DodXw3r u>A1#O  "w#;gSL@`*8tz"VO ^_\޸ɮz-VEϜ[ݾ;gt?p?&p|?T1?f>`R:qn1yC/J=q~>Vץ5AC\"{[" ] Cp?堶2XZ'O25K's$ dveO3dTvGZሠ W)0[ S܉F#K'&a_]iSX,4Re奜$JIҌ(nRkt&lA82恒@2h,[[׻1pxd ː&C7#z#ʌ=aB.-Ƀ!cN)% g{ o5tC3O^5S:VM֛o6giwYl/^3γ[v]̎O.ͶQZW0;y"QH|xI´Vg:+<[ڸQ|p0'oaFuf~kz8Iݸ#.BFh^DP zîuhֵή} `{$,VK|hktI*./Ռ:*0d/DUVFodx0b2 O1%dq*bP` 9\iۉhA54RƢdW/XmV1> .|ظ~Qe Y#[={c)u,pjU:?|;%,E;LӔXPM5VLbFM0Lvb)&j_ҘvVIӖk*ܐa1s4gpQ[*? Ge̛G4B'=i:k8 ^O0:bPΔWgæ#&4dne o K1}jҚp|_*3 <7!{*pyOc An=q잂5k3 ~lRmMm)ڊW@v8QG?:n3d@ERn5\OŨjwӲ >`: ֪ݛq'݅[*2߻~M^֊ w?:ϗ4YP4j&gu`r} No]ܩ4hQk=&mRnΘZv;w@-ENf[BdZ({-#Jv:Q&S0rfR20&hA4i sx642~D&Tـ D-Ͱ=N"fک]lڧEV "^-;*+֬r$`QZ!g+eX_q[Sq Eyraxo4hRNqm׃S9,2C#l#fba/%&\O `kT 9%1gM=< (S2U_X\S-aN_ܹo\<<ij )-?Ug]ؕGu{_r,7gN]sO:|H&w<Ξκ92i҂^yCUv-۪ܵM7k %]dWhnڈDܬwLF1'&)?}lٺn 4vnQ9Ң~-&S^J=;720 ,q+PΤ97 [g29PhW(ReBې  iGA byE*JV$$M} %0`Ń1$#ˋRQжuJ,S<_^Ÿ{9E2i룪Grv6}}nV>c"FY͛mC[-<˛Z> evu %U ZUq]Z$F8Ѹss⋭c/~u137^*Im ` ‰Xĕ@ EWyLI3nzbL$ U)I8xjjzn0ҀՌok8qƠX6XoI aOq[r9 G>V*l&N}&pepZɮ@5(PH,ޓI&|`$)-?R~\UT=MyܷM[_p|ɓ}c 'SɓlPjvʼ*P}ֈMt:8X\d_C- `02er' #R!6/fA)h3y쵕ckp: (cd[[4aZ~ߚN9aoFq1О;;~;~B"NAcƯ-4hZ[(K“a-4W\p:U AY{6#%F'◉][Gj;{nR6te֦0g*7-T/\^Ypb #&ZGd[4#R-7Ź7eTSk[wWiq:d,=t LgA%#mоAÎ!wu :DUmrih tZ,ز4`:ΥLzl#Բ9VT!zSA e8vJK̂~o%Fq{gEMYBYV胱l[ Ċ{ |T1Ul>?_ 0ne\ fU,5kE h8o1f .MPB7>?Y\@n=P:A[fbfヅ;ױH.66G.+W7w/ $СD|󒏖}Β0㲴;@V) 1p모)"hUp,+cJGO]WEyۻK{?$#$`S((D6T :"T ڙhQ;!vfZZZa=!!e֤h[ cLfŅ~D$5HnVҜX|mI|:% u>)ft-"15f!~GwXޫ a{D"%B`w@/lro{덓?1sQ%/lirN6ʝ^c7 .X&VƃV4Duhr #ʀ#] cB! 5w/<鲄<QdK>F+Vae"VJebxMX3mu~1@6ں#G> _,t( AQPyӊٔe4RkJh2J$iRXS3lR8cY B9ǚbil'ܴѽpxX7աm '@!Ƀ_ㄘ,;אl `l[u89>f N ne.7coYc}VÙZc#1&we׽'#oXs#k @0, +w~b.)(d,D$ӣ>5k¥JEYEʴ;h8MK,(Mq=MTZ슧f /6۽^2B^ A ֫QCos{cqͻC:MvǒlaϤ?Ib 0r̠Aɠu6YpGŁher3̇@6xOOYK x$H0>i*5d[-ꋺ-o+ozClD[0ѥS'71F3ăVn#{1oAS=d J[.R .p,8$CF ]'{ewݏ˜]:e|Q-R 꾨E=ʢ xlղ^ dz+:~/-Ff z1d]5.:Z\^_JUo]:d_{H. geA=QII*4>^P u FY@ `78> (pszѸ pH E_ʌ02ҿD!& tѩ?8D :&'8yˋ6 mZgPl}3}w]6|?xA -/Nx騚+/3X]s 6_C5>Z'PA$˻"AeG1>V)2)!, ].#n:"QfO`tTw([~)+|! c Q/RuaN <t.(pؔ8;3GvOöo=subډ_]Z [ە˾H Qb/$} i\ciuñј$1iLDg}ΦTdSY5IHT5 | #_"#_"^"^"^"K_"^"KH'$FIѐ&! ;?M+ p~}Opo̿F$ Ʊ4Orz(-y@Mfs +KX$ cC+\59@yN9"<U;Lj*y 7Is^8%QoM,o&wλv_>7.HBt{+xm%_phH;S }?.#E ڪ sqCs1#ӫ bwv+hѰ2Gt)t66X""s#hD.b.24Bڒ -.I1AKm@,F: \U3±qͪhi܇-ai|+ zfL{s<D> 5p.IzxA_|V\4wc:5Ҡu3`wp a@p цLGR:ӓHGeOYlFLE@U?e;Rۮ$rIasIa%]HYR{2^P;B+m++Ͷ ӮoVyoڪݚ%{_]J 6|*$YrYǪ--kZ9{OhP:|VDҋMzΌ X=| \/5FnXDx[u(Jz¯ P/H(5jVK=</$`__E["VPe!`%(-4K WL4riHŠ3IWGNe)9u&{5{WFZ|-lhi+N;&>5qľr• kcKǍ@&2basad ʖMMэ-wGGF]M&?Fz^i}“T'zuKr Pz@Vf \S*{#?Q\EIN刊=+ iI*SR#2^b!/p+wp(.#djn>*Xlc.WJ / d2!)5kF.CT#MT8 i %pVPtȃZH B'_>4湕 XG˜\ 3sMmYGbd8;4y>07SNu=3d?Vϛs1/+^0(>* K{zz]y֥y v%˄ mn endstream endobj 48 0 obj 21801 endobj 13 0 obj << /Type /Font /Subtype /TrueType /BaseFont /JZRJDW+ArialMT /FontDescriptor 49 0 R /ToUnicode 50 0 R /FirstChar 33 /LastChar 33 /Widths [ 278 ] >> endobj 50 0 obj << /Length 51 0 R /Filter /FlateDecode >> stream x]n D|C!U"6j@k|J=쁙y0,?ww 1%\Jayִ`Ijf֑ ےp@J3$fÀǢ}Er~W_c}cCO=#:}S-"FhLDmI!\CoY;0{m,#D+j|UɬDMC-Z 8U˃u~n4p endstream endobj 51 0 obj 223 endobj 49 0 obj << /Type /FontDescriptor /FontName /JZRJDW+ArialMT /Flags 4 /FontBBox [-665 -325 2000 1039] /ItalicAngle 0 /Ascent 905 /Descent -212 /CapHeight 716 /StemV 0 /Leading 33 /XHeight 519 /AvgWidth 441 /MaxWidth 2000 /FontFile2 52 0 R >> endobj 52 0 obj << /Length 53 0 R /Length1 464 /Filter /FlateDecode >> stream x+)*Me`h``f`HM,` %Si6 @MJFnI9ra5@>[nb|;@B^bn*T| Pޠ(>複#\bb`pAA$@>vx~`Eյ@W~.rcp`W\H0,\F,PDȇBAeB`,*  F? 82fP`9T BPl | ^QA^.ڎE9!> endobj 55 0 obj << /Length 56 0 R /Filter /FlateDecode >> stream x]j@EYF"m5OFKB;qS.{9?wCm۽-8y̭![.r=5S3;ntU9bWw=o?hs?ݟ}LӻlXE8~4'syErg_d1R;F;OMks3-:!W Cwk-Vux.* 07$op  /܀N >t#H Hh^  Z[P] #H(4(@BUyfr U]# qUhQUYW4!  *TQ仑`UYW9 א|B5.!(\C-S3!:Ux2_[^晅JvM;8途: endstream endobj 56 0 obj 415 endobj 54 0 obj << /Type /FontDescriptor /FontName /XEVFZL+TimesNewRomanPS-ItalicMT /Flags 68 /FontBBox [-498 -307 1333 1023] /ItalicAngle -8 /Ascent 891 /Descent -216 /CapHeight 662 /StemV 0 /XHeight 430 /AvgWidth 402 /MaxWidth 1340 /FontFile2 57 0 R >> endobj 57 0 obj << /Length 58 0 R /Length1 21048 /Filter /FlateDecode >> stream x xU0|NUU{WwW;$VـL**;Gwu%$7Qg>;.w3838#S{=ߕSoλTlںNDu7 9ޥo-ZaR"$ͬ\mE)\PU\ JYXn˕k/wz!ߺnG,N ^TN꿝4/pCGu^$EbQAzyR/C|pk].v}y\檻4$c)ȓZ!'O+!1dqF/jJñGMJzD# )TjA!h~~F/bq$FA:AͽD×`r, AS )S:d_)^XϽo&/7b+y)PeZP!a'K,AWC|=AHS>է^'1NO{F=/VM%Y}рx֒D%u3N8384) (BS`Kh(&}biiZ]2<֣t`֧m eR`, B XV7$X=i[ k u@A9XNǑ(L[m_{' ⠑^(;,JK)!h8AP)?E^iP4-?C/)fJCiԶO)_9ANCTJ!"^[az9P^ iG^ޥ}ae]Y4G'Fz(x!Apn^haD 87W$Jl!!zcOpTc0F L!9ZArIE]M(4^l52e 5yyj%Bb!8cTIxgB1n?SɘMf4 AbGRÇ!Aē M. U@ڡM\_ $^b6 Ҽq?y{hh7Cܿ#r<+0B>`} u q+!'?Vr7  ýas>9BhH#ݥb`2 Fzxin -( ϋO03qnxFZ,"ɕ+I\K;\sP~Nsռ=恗'pAnv u$BllllC&jdUr_擙9+r\.9%GrHc!NI &FRW15Kk8QXNhHwP̓Yq`McP5wSKQ7VΜ;(u4۠ k\$=nrZzAa۝t{_\hk44sZ"pQkvR<Lcprw~ j;uu[ zOIYOj; hD 4ہ<Pq4`Yiĉ84idF9ȵm &(6}&LŠMN}Ghp$g^KK.TKJL[׶͸5ha74t?Vy*7U|3jl:藪P&DȦgyA0夹5UMM șTiX7^e7yzb=踢Ҷ"|knqnݺy8o =B3 Zmխ[Y@1H:dmtڼ9.Ƿ.`lr_[JeqN? 0#=.QmxD+#4i߇70Zi rn#Ǒ$EoD6@9 ª ' XQJћRD M(4,x1!w߄y/@܏`+ Z^sFTFŕ(B7#AOP,)Gww;% t݆8k5(p%zX18^B! BS/g!PAYp/D^M>[\J;-F'[\|qpt𤷡{z sJЋ$?.|h=@ѷrǯPIZ<"Q&+-h'k؋#8PZJGR_һ#bKOaοϊ#fVg14~Bga&[| 2QPfI~'px2# 38ó\LA@FN[7`$~HC`&Ŭ*X:SpOb4.Z 4z Ő6k,|%_}j ZOm1y:Lb8 U[ B_BԐJZx^8p0z3/F( qx^W1|JS{RQAHM?Hӿ LQ]:[[,["{JXlcs!\.Xx[xESgCVtihE|9x'q%K5xJgLY|,<-J}*QLx'Mq}%vߎ)PK=LM&Yi/3~ ,B6I,c x?N܁O6Rf,P'@7g=ҷ|*V! qa6*\t? 0CvcJ@㿃csM-ݗ 2~ 迠gޤ~I)~πgpAarz-bIzQs2wQԇ^SS1z  [8n@}_%V06@WQ$R >^w5Q~Kk .VXQو/J3]ʊIz/l@5/dh]EQ 0a̝}GDn+58V|WP'q*P5 ۍR3,0+0Up<7f5چv_mz<' ? / \71tOAh#46s5L:ULTcH8 ~]NfMFi5jR!I% ^RY?iw0h S< _Th EfK-R(ηĬՕyx;wϝ ׷}QSSmUA68UmZoY,/CG*Tՠp[xAYGG+:Vx f:}Aܲ_26ҖAxAxtH٩FXdQ\_x~ hᾭ֫N.dapVoI%n{Q_c@_*8i$m)lKÑ'Rz|)Y;Uk>h6ߐ!(~mށ^7mvk~MyV_#ZZsrRx%6'WO'&Oķy;]'Ejiy XZ> V*Z yRS%A|/Y<^" _#RI<} &x|0#t!kD36ly#_ Ln}̹Gz눀@fpRދ8ZDjNMԘg5/|yP:c-ƶUAl_;pmI{R=P74N6\QNZJ?| IEJ^6")%;i]4tS|4Rn1?hk3TG܁&{' ,Xg"ANT-Tl[ 0̧*x-vč j>VuXmp-9C1^ pmFF~%/ 1L7~Ҡr+>}[ntxM>7fBMAhTv` ~#g6C(ifg#ts~`"%hfA64 $= (ɞ폟ǿ~9!Xg%FmE\}- =u,|NedNV~ԏ6⍘MV%-US@/> -V(g1Jԩu*%[f aԩ US7nc%~w {v.c6o 1 c_uQX6D0(rMΔlkXmQll]Q}wS4MDNv$Sʠ{>_G"80%e]U Z,p„Q0U! ,2pר0#]^|:x7gGOƺ/>%nWĵ0rre8y便z!6\THK?@e3tj!$,)kfoR#2Iv}hSf_քλ$fw[ß RKFw8Q׆Ŋq/Ie A?+~"A\.[eF!b2CPayzܦ1^n;joXePUG4qG­tYI 1M&LƼ`2bd4bTJ%.ɨclaq LB$썂iiiUaD6 * i`! ,/C vG2òòr"\SS G^%SWIE׸pغ8{09H.`vB?0yv*)QGW͠xB?ǘ ?À^* C,A"WS?2>n%^_'Bߜ9.g`MoJ2iǒ` Xg%~#sËҡ,wٵr:H 38n@@@F^^ݮ١ݡY!ڇtl4eȯn-9vs{Ogԇu'*~8_R}88[TTu5{RjX!Օk*Y=B{ed?iy\j8zY:A 6nP&I* M]~cc+Q P p&k>G}An>1X9hkUW>Gѳ,x8/Y,aMXVcWr (q'Q i7eoax{WO֤YyVBV]ߍVjSQ?ۓ=*gJRPU]v>ytʟu]=`}ӂAըcltFJ6H]wb!ND>U>c!-X'T<p*\J &D^h;'P)xE xE(l>a<ï\y*>*q39 8d͉1 B><'l (7֝cD&\\8.jb@XHDO`"z'"A/x\Hׇ/-M 3+cC*;[if4]FC]w'ӺM/,'`ˇ:c_up?>ytKfq57BjÌSXJ zae(U(5$=r@e844"QvRqC%0WOh<%E}*#9(eAdA{r0Bo6@PBӨYatNCi1QHQ:CP^JOIߓJh|h.wu~1-8*Hxo,l$ 18C88q0D<3HFtvw;}[rE.4KNڲlߺqļ2cTfi`s9?(+v] J(Ied3*!l*q*ժiB7>Smή%{~It(fC#6h"z!\&BƵJT% B(RLtt.rxm$[i2t+ˍ?rDrl6X Y0a0 ^/HF5sU-dCj^ddB 'AW h@NxHΖ[$K~Ɖ:XL=U\ w1W{·qt"NAx΄KǙHGSȨ%i'rT* &Y&b/4(nSxڥWh .'+fuLCWZfSs4W@Wrwymy5ɲܢk>S{˖x֚eiU]FwB8\a W6hngI;*>`I*73sfb2akPj 0>Cq_ <菗(#1Ēu <Q>e* $?PhFo,(Œ&`{4 *yҳkNoܽfE%?:[S-^{q3sj-:b-Pؽ΀Ba܎x!;N!M43|ᨖp3^\ _4JFZ#aʃiS(0dԌP&3kU~?΅gF(L lw[^}U-Um1'K.oI'\0:O#%ԙ>rj6W1x"QЧcDSŸ-„ꅞ-peSWo?.ƥΠ)S}gv7WVM}lʴ.Ph썩s Q葏f7oo2DVu_'M}WRGg9 ل\+SFk IL4; aQAc-L4 [5욎m춎:uH:00Uo4l܀|N!෻.z:P&k ti `dU{),P$ZfJAUѦ0@(X6JTd(~/':ߚF}STL% rYYs' Ow5Fa cX¶ 1R^+h/"*#r 1 kCLqdMWͤ}q5ok+fpuzcQygߔw/h.m|3<筎tǪč+Weӗ2ٶY:ke@<2|%w|>5Ww.ɯxdlkpKMsaqgxE X! Ux#},JV\Yަ:tuXލ. QYb!d0b2d4UU̍dU/'1+Z9&'|Tʸ Syy_˔6:uV#ha,{Cꠓ2e9wL^!!WV,@C>{۫rZP1p@z" _@J.Z K1=vTn` ,*RئU@KFS_}J4x^MuHjB&2Y+IuUC v?7[&w϶+|3͒;ehsuB4֠)nLˮwvM6KlI0W^H0ϩ ֯8 峖YC\0ddIOkBhEf@. ܄4"rV-t0>3.2Npd{P /+*AեbT6܈+14g0CˬS<p$~ j:h@|2W)(= Q^”xD9 e:4`O-&l@E$' :“шp#K+K-.@h9®l(:_(bM1;Ϥ3s?>YodA_\rnM|]S 5k͞ʸڲlz媲+vӷZaAU<jqg>vxU״ҳP_Y]sWUm_zr“H||z"R^ۛ4J׀TUt9b+`J,@PH\!tT ?M̄q +(5dDi/zJ72 ~l>l]3gT. (J=w K 2EjW,oj9cΩ{J|\S Jy‚3̔RnW<~a |pC7ʉ1]h*E0 MbX,9SˈRa@iXpoyJ@@=O,Ff* d^O52 >w+e-/9jOH lݲ¼vVkoʅCɭn+˟6mZ|4 h`3BRR%Y~aM:gxmaY1oll_"c1ʔj>5˂A;#}2Jfw a1CBKON$~Sg)PZC|$88DĐQLd`;/ų w?cƃOΛr?Oz7zvR¼ďV?YZ1߮~X$g@Sb˵["'/DOph[]h~g&PjaMZ 4m@|'!q'}b+fJ9#q:زɀ+85-7+ `~)Dv]NtG s,kӝ9YV:JYSE;@\_-B\[ډFCY` nxLGK;܈;| jQku-\`Mɝr|@c3'C8V =Tq VAOOut61 DU*YUR [`7Y~XWZ n~9gbY_Ofe"^ûP2{XBπ|jȕ%@:a VI&lqEx8zE+S%5b ]hW2Ά5`F_ӂXZqB_o2oNX&.,KlJfNZ}/;`{¡ɱQ s?Cy8H4:aWpa_Ba h7ZE7q^녯M*EV%HB>ʲ^! /rg#>gE]^kJΎ_<h7MzX4.VG!xǍAC\dWȸYsAˈE;rdr^v/ybR':\CϬ)8pprVXPs&Ժ5/''$zEp0aGbt6YK"*^w? aMn݇ #6X4L#1n0@cy c6cW^zw)//χ: 0Aϟo;elTĭx5Mc `* p k'Tf'7-R֋|5dUgCi8ePn Nc]{ڕ;7_՚UqQw솈Wkoϥuն` @`:ΣyZZu{@Tiud8$v0h?DȌ*08vX,v [X]*GkL7= ;8d *9eyBAXN9{^8Yj! I0}Ӱھ}%qw]1w¬c8a_ >L䑤?Y!T<DwAP:bU7VMԽ\WqlhKoM+7WU! n2zh+(![9ne*!kf슞5 ܃ie|h:PcdFdak7s2Sm]Q kryU6Cag}E:=`39cc,XA:#P,{Q3F3 {#xBząP6 Ivd.a!I:~X+VnM+S}N@{ }xAЁD"VΧ0 ~F"&%F,=٦ʙAZϯR~$0*Xř9Ή]ƄTFtJaM5aJN4lǁOTexJsl*#Taٷ& qMAϭn P ήwE-D‹7Fk>wOԀB;9#jHlKg1QW >cB&ao$83$ "FӅm$CE e؊6kl;mw޵Il7EN )Zz9Ą^y $QV!Z @/]ޝ;Az^KEpC1O4+Q$ND:;;j&0 W Jo xA0DY))QagtM>?q#7ihڹ|\6q:ZcT[:/m"8^fN +|(՚KݱE9ᬳLq.tΏ]\˭?>WĈw2_Wp&R:ĕR2ې z<_r:vT;JU xLrN#tƟl;S~xt3 T`N >uMA8 *2.MWv5GJ(c"iT;M8N㋋*5v2r$‚ȀN`Aa><9xmxbvqm8hC"AbB۳L"<:TXZ& x{]:6#ëx}:S>gc/jcZ OຝIX.,cAd1B &O O,+n/Ћp‚ʌ2!H!vz~L h.^Zi7D{e!;ֹfpm9UWj|">|phď )V; cVY i ֕[xzgj|zYcG r[2 .55({WYaORG̛7vgsf8*z|gr_D*R˭Lvuވ=:ɞ+ʐ9=ZhӺJuYwZך2ڞi7VϨ^XMWмa>$VO%z* ZAYL%UV&+J܄h%Dk?1~cK"YES2b^-Bx KBJLZR}+4 hawh6UϬTIdam{WK4LQ.Iu*j5*Z`д^5۵ 3* ‚BKKn7D# |6gioY-}⵫v@3 endstream endobj 58 0 obj 15748 endobj 27 0 obj << /Type /Font /Subtype /TrueType /BaseFont /SYUCES+TimesNewRomanPSMT /FontDescriptor 59 0 R /ToUnicode 60 0 R /FirstChar 33 /LastChar 33 /Widths [ 250 ] >> endobj 60 0 obj << /Length 61 0 R /Filter /FlateDecode >> stream x]n D|C!U"6j@k|J=쁙y0,?ww 1%\Jayִ`Ijf֑ ےp@J3$fÀǢ}Er~W_c}cCO=#:}S-"FhLDmI!\CoY;0{m,#D+j|UɬDMC-Z 8U˃u~n4p endstream endobj 61 0 obj 223 endobj 59 0 obj << /Type /FontDescriptor /FontName /SYUCES+TimesNewRomanPSMT /Flags 4 /FontBBox [-568 -307 2046 1039] /ItalicAngle 0 /Ascent 891 /Descent -216 /CapHeight 662 /StemV 0 /XHeight 447 /AvgWidth 401 /MaxWidth 2000 /FontFile2 62 0 R >> endobj 62 0 obj << /Length 63 0 R /Length1 11452 /Filter /FlateDecode >> stream xZ{|TŽ9%;ɆnL Vyl!n1%VR>kQ+XnnJhj} ^mmUB~O⦅3~{o~gflNyC[:|iԭexǟ7\>ûaYU OA/YAgS@Vjj[њ{O}5>^*=c 뼺=ga3ijIr&?DV}H@#Jz™dshY{{Ff^gns\i[6Ǵ  }_: P`"^ddĊ>H[c?HHy;YS\2=TZq:WMp8A%R%UC h NfoQqޣEQY칤}H* EýTPu>8 8PC2-~eYB tL,źTt iXE: _>yF>tQRak[M\eOڟk\dx U.yǪ mG"1mWnR,7·8ObsM\s/u٧v1x;%f=_O9O+$,WRl Lҿ?]O3k>M>fs|=߲l t%g'7JP[G6Y~j0esLw従o'}עoI{ ;䮤oȎG:&VRғygu/&}Tl jd 'N fsnvrscI7vǤY鼝 MjK7c\Bv>a=wD76'yR Wu̗b]Пp=[bK~_Q_îl]|+]v-^^2}I׍'=^u75UI1~4uUWf@<=pM.JIWQǁ]bWsM]x>lcgXXZgZ/Z58XpP66Ȗk,6mdJ xi!+1#;1LA3150chBM54o(eM/2{C+cwD|[QS8Ri ce[owJy jьOѓ܅ U) 2)y?1vɩ<2&bTtqY<7`]$c ERή3B 3K"zPQ!5晵a@6Ga=c407Ⱥ$OEf]E|4T7+DfecQA{>H81g>p^>!iG1af;*J26 Yn25Xo쭶`v@ؾiUӢiB3Dquv-hD,Vu j 6d, 걺H[jCu빶jje[T?( ɶBmհPC8aH-^%}`MѣY nKEtMgk]tC4e/ :NcssVOJ$N!z E=AIsFmK*jtcTlC,<#O$Kﳢtf#[sG5|Z޸Q =6iveOt~B]NתƶNzbS$6x~~UFt)ͧ_706Y5 }>^Sa^Ct;ݏhJaǦH/?÷m?Mf(l|9z8C^:B,bZ>P]:M( hcV E2^V+܈w8{^O36 ~ߒ^~8>|aS42Mt }o }s`yLyVN= -֍{;RRHC^Lg"`YƧ/KT5]F?FRZ7p}0=KϱG|&CzobrZɁ?|㾪.h>(ޅ;cbp]LբID6Krr@ySU/C li-D6Ӎ;0^}ȧ(=GПjn+>v=͞eϱwا2B~ ⵼[vU{1VbAڃ7QZ4[ݮ>dyZbmmx3Dμ=@c2{ߥ*->H`$>N?5׏g*F|1|xkU2lBHK2kauvξi{ѷq#Hb'oG f _EH+yR'oz>&W]jP]Q8-S,-k,ZY~o9mX l}Śyb >wz)c]pEToa1 o vJhM&:~ Z(ww?`%ʝGCr܆`M}Yܤר_)cTiI>N`VA_|;)qU{&W=pl܍UlRį3gxmNM 'oX [Clep;υ"r)"}d|kb帘q%]+9 UiA&/ *{<\g -r@#q\AG0Q96{X˱~rXVQm #y!f4؟afS"5)ALQۑ pߡ,՗iEh{0ߢ+yMXW|Zʼ%30Hߠ,e6V5j|NCxw7SsrcݔN%tKT2ks'mǺ=zaYW^Y-+̖>3sz?#nE?]<0'_0PriUzV'iUCەN ^m~|/#e2"0gQo`v"vp22m`1 'ؿ>RbjnbY {9KW`gԌ3lva+qZ6k;u-Hqf7vF`g[;]N/N)꣧pz<7>ϰ{^^EΟqx~t؟6tkw:;ZnիVhobqӂYgVΘ>풩S.\^vQ;ibɄbO^\Ǎu]0jaC8جU룚Q5b}R1b_D m MAue+2 dOR5ubNhƇfr3ۑwQ@  ՂFU`yzm{ny!g;l,ff`e͎.c1ZGQT#spkh< tڧSu:'PhXmFJ"3TC޿.IJ I%zv^1i ZQ8䧖6w:4\SbT!n|Sjc, gxZI ʛGfb99W\ ƣ1je@79)ǰxzpTO\aa@SUa._v>Ʉɺm) ؔ0pDggp$NP*}J2b>l2}4f^_ޠ5au⡦exz{xǣX*Ӣk='" bʼTvQ[]Y*K}X!oK43̴c7-^ݭD% r7EkTٶָ,܇1mM$g6ZIAӈKJM28c.%ʹwzLb LkdZ)svbZSJF8[-#Xdm8~nō9$4YCD( d; gD ǸϬ)#:z`)e=0kI}"4bl/ "obXGp";jqc/Ma Guj}nzL`!_ʭE.G|e*uϬ<Y&L*ō UzsQfVa_~OU;NM.w&HIY_]G XǨ[-qq DJジtzoI#kަۻ_c}쪆˛ Fl endstream endobj 63 0 obj 6419 endobj 1 0 obj << /Title (Microsoft Word - 19874_NOSA 1.3.docx) /Producer (macOS Version 10.15.7 \(Build 19H524\) Quartz PDFContext) /Creator (Word) /CreationDate (D:20210504165905Z00'00') /ModDate (D:20210504165905Z00'00') >> endobj xref 0 64 0000000000 65535 f 0000116325 00000 n 0000004879 00000 n 0000025920 00000 n 0000000022 00000 n 0000004859 00000 n 0000004983 00000 n 0000007840 00000 n 0000000000 00000 n 0000026081 00000 n 0000000000 00000 n 0000067871 00000 n 0000000000 00000 n 0000090990 00000 n 0000005104 00000 n 0000007819 00000 n 0000011747 00000 n 0000007876 00000 n 0000011726 00000 n 0000011854 00000 n 0000012005 00000 n 0000012059 00000 n 0000016529 00000 n 0000012112 00000 n 0000016508 00000 n 0000016636 00000 n 0000000000 00000 n 0000109056 00000 n 0000000000 00000 n 0000092125 00000 n 0000021499 00000 n 0000016771 00000 n 0000021478 00000 n 0000021606 00000 n 0000025662 00000 n 0000021757 00000 n 0000025641 00000 n 0000025769 00000 n 0000026031 00000 n 0000027294 00000 n 0000026554 00000 n 0000027274 00000 n 0000027540 00000 n 0000067849 00000 n 0000068825 00000 n 0000068229 00000 n 0000068805 00000 n 0000069076 00000 n 0000090968 00000 n 0000091472 00000 n 0000091153 00000 n 0000091452 00000 n 0000091720 00000 n 0000092105 00000 n 0000092940 00000 n 0000092429 00000 n 0000092920 00000 n 0000093195 00000 n 0000109034 00000 n 0000109548 00000 n 0000109229 00000 n 0000109528 00000 n 0000109794 00000 n 0000116304 00000 n trailer << /Size 64 /Root 38 0 R /Info 1 0 R /ID [ <1e09b0eac13c245fe408d6f294fe8466> <1e09b0eac13c245fe408d6f294fe8466> ] >> startxref 116552 %%EOF ogma-cli-1.7.0/CHANGELOG.md0000644000000000000000000001007514767604252013226 0ustar0000000000000000# Revision history for ogma-cli ## [1.7.0] - 2025-03-21 * Version bump 1.7.0 (#269). * Add all auxiliary test files to distributable Cabal package (#216). * Remove extraneous EOL character (#224). * Update installation instructions to use cabal install (#149). * Update README with new cFS template variables (#229). * Expose handlers-file argument to cFS backend (#234). * Expose template-vars argument to cFS backend (#106). * Document new template variables in README (#237). * Fix formatting of template variables in README (#222). * Update README with new ROS template variables (#244). * Update README with new FPrime template variables (#246). * Adjust CLI to match new backend API (#248). * Expose template-vars argument to ROS, FPrime, standalone backends (#250). * Expose spec processing arguments to cFS backend in CLI (#252). * Use new sample spec with ROS backend in CI job (#107). * Update examples, Github Actions, README to use new variable DB format (#256). * Update README, ROS example with ability to pass data to handlers (#219). * Update README, Github Actions with new dependencies (#263). * Update to support boolean expressions in the Lustre language (#267). ## [1.6.0] - 2025-01-21 * Version bump 1.6.0 (#208). * Update contribution guidelines (#161). * Provide ability to customize template in fprime command (#185). * Provide ability to customize template in standalone command (#189). * Add repository information to cabal package (#148). * Add version bounds to all dependencies (#119). * Introduce new diagram command (#194). * Provide ability to preprocess properties via external command (#197). * Extend support for file, property formats across backends (#204). ## [1.5.0] - 2024-11-21 * Version bump 1.5.0 (#178). * Provide ability to customize template in cfs command (#157). * Provide ability to customize template in ros command (#162). * Introduce new standalone command (#170). * Update README to demonstrate robotics (#172). * Remove unused resources (#174). * Add version bounds to base (#180). ## [1.4.1] - 2024-09-21 * Version bump 1.4.1 (#155). * Constrain version of dependency in CI jobs (#151). * Replace homepage (#147). ## [1.4.0] - 2024-05-21 * Version bump 1.4.0 (#145). * Introduce CI test job (#139). * Introduce test job for ROS package generation (#136). * Add a float and a double input variable to ROS example (#138). * Document format of variable DB (#143). ## [1.3.0] - 2024-03-21 * Version bump 1.3.0 (#133). ## [1.2.0] - 2024-01-21 * Version bump 1.2.0 (#117). * Re-structure README around on backends (#75). ## [1.1.0] - 2023-11-21 * Version bump 1.1.0 (#112). * Document cabal update step in README (#100). ## [1.0.11] - 2023-09-21 * Version bump 1.0.11 (#103). ## [1.0.10] - 2023-07-21 * Version bump 1.0.10 (#98). * Correct test case (#96). ## [1.0.9] - 2023-05-21 * Version bump 1.0.9 (#93). * Rename ROS2 to ROS 2 (#83). * Allow customizing the names of the C files generated by Copilot (#80). * Re-order README's TOC to match order of contents (#88). * Fix rendering of quotes in URLs in package description (#72). * List FPrime backend as supported use case in package description (#91). ## [1.0.8] - 2023-03-21 * Version bump 1.0.8 (#81). * Introduce new F' (FPrime) backend (#77). * Mark package as uncurated (#74). ## [1.0.7] - 2023-01-21 * Version bump 1.0.7 (#69). * Replace tabs in cabal file (#69). * Introduce new ROS2 backend (#56). ## [1.0.6] - 2022-11-21 * Version bump 1.0.6 (#64). * Update license in cabal file to OtherLicense (#62). * Add empty file to keep directory structure in distributable package (#65). ## [1.0.5] - 2022-09-21 * Version bump 1.0.5 (#60). * Update README to reflect that GHC 9.2 is supported (#55). ## [1.0.4] - 2022-07-21 * Version bump 1.0.4 (#53). * Address all hlint suggestions (#51). ## [1.0.3] - 2022-05-21 * Version bump 1.0.3 (#49). * Enable CI (#47). * Conformance with style guide (partial) (#45). ## [1.0.2] - 2022-03-21 * Version bump 1.0.2 (#43). * Address HLint warning (#41). ## [1.0.1] - 2022-01-21 * Version bump 1.0.1 (#39). * Merge imports (#33). ## [1.0.0] - 2021-11-22 * Initial release. ogma-cli-1.7.0/Setup.hs0000644000000000000000000000005614767604252013047 0ustar0000000000000000import Distribution.Simple main = defaultMain ogma-cli-1.7.0/tests/0000755000000000000000000000000014767604252012554 5ustar0000000000000000ogma-cli-1.7.0/tests/Main.hs0000644000000000000000000001612414767604252014000 0ustar0000000000000000-- | Test Ogma module Main where import Data.List ( intercalate ) import Data.Monoid ( mempty ) import System.Exit ( ExitCode (ExitSuccess) ) import System.Process ( readProcessWithExitCode ) import Test.Framework ( Test, defaultMainWithOpts ) import Test.Framework.Providers.HUnit ( testCase ) import Test.HUnit ( assertBool ) -- | Run all unit tests on Ogma. main :: IO () main = defaultMainWithOpts tests mempty -- | All unit tests for Ogma tests :: [Test.Framework.Test] tests = [ testCase "cli-main-ok" (runErrorCode ["--help" ] True) -- Should pass , testCase "cli-main-fail" (runErrorCode ["hfdsafdkajdfaskl"] False) -- Should fail due to arguments being incorrect , testCase "cli-cmd-structs" (runErrorCode ["structs", "--help" ] True) -- Should pass , testCase "cli-cmd-structs-fail" (runErrorCode ["structs", "--incorrect-argument"] False) -- Should fail due to arguments being incorrect , testCase "cli-cmd-handlers" (runErrorCode ["handlers", "--help" ] True) -- Should pass , testCase "cli-cmd-handlers-fail" (runErrorCode ["handlers", "--incorrect-argument"] False) -- Should fail due to arguments being incorrect , testCase "cli-cmd-cfs" (runErrorCode ["cfs", "--help" ] True) -- Should pass , testCase "cli-cmd-cfs-fail" (runErrorCode ["cfs", "--incorrect-argument"] False) -- Should fail due to arguments being incorrect , testCase "cli-cmd-standalone" (runErrorCode ["standalone", "--help" ] True) -- Should pass , testCase "cli-cmd-standalone-fail" (runErrorCode ["standalone", "--incorrect-argument"] False) -- Should fail due to arguments being incorrect , testCase "cli-cmd-standalone-fcs" (parseStandaloneFCS "tests/fcs-example1.json" True) -- Should pass , testCase "cli-cmd-standalone-file-not-found" (parseStandaloneFCS "tests/file-invalid.json" False) -- Should fail because the file does not exist , testCase "cli-cmd-standalone-parse-fail-1" (parseStandaloneFCS "tests/commands-fcs-error-parsing-failed-1.json" False) -- Should fail because the opening bracket is [ and not { , testCase "cli-cmd-standalone-parse-fail-2" (parseStandaloneFCS "tests/commands-fcs-error-parsing-failed-2.json" False) -- Should fail because a field is missing in an external variable , testCase "cli-cmd-standalone-parse-fail-3" (parseStandaloneFCS "tests/commands-fcs-error-parsing-failed-3.json" False) -- Should fail because a field is missing in an internal variable , testCase "cli-cmd-standalone-fdb" (parseStandaloneFDB "tests/fdb-example1.json") -- Should pass , testCase "structs-parse-ok" (testCStructs2Copilot "tests/reduced_geofence_msgs.h" True) -- Should pass , testCase "structs-parse-fail-1" (testCStructs2Copilot "tests/reduced_geofence_msgs_bad.h" False) -- Should fail because a keyword is incorrect ] -- | Test C struct parser for a particular file. -- -- This test uses the Copilot backend for C header files, so it generates -- Copilot types and instances. It may be convenient to run this action in a -- temporary directory. -- -- This IO action fails if any of the following are true: -- * Ogma cannot be found in the current PATH. -- * Ogma cannot be executed. -- * The given file is not found or accessible. -- * The format in the given file is incorrect. -- * Ogma fails due to an internal error or bug. -- * The output file cannot be created due to lack of space or permissions. -- testCStructs2Copilot :: FilePath -- ^ Path to a C header file with structs -> Bool -> IO () testCStructs2Copilot file success = do (ec, _out, _err) <- readProcessWithExitCode "ogma" args "" -- True if success is expected and detected, or niether expected nor -- detected. let testPass = success == (ec == ExitSuccess) assertBool errorMsg testPass where args = ["structs", "--header-file-name", file] errorMsg = "Result of processing file " ++ file ++ " failed" -- | Test standalone backend for a FCS format and SVM. -- -- This test uses the standalone backend, so it generates a Copilot file. It -- may be convenient to run this action in a temporary directory. -- -- This IO action fails if any of the following are true: -- * Ogma cannot be found in the current PATH. -- * Ogma cannot be executed. -- * The given file is not found or accessible. -- * The format in the given file is incorrect. -- * Ogma fails due to an internal error or bug. -- * The output file cannot be created due to lack of space or permissions. -- parseStandaloneFCS :: FilePath -- ^ Path to an input file -> Bool -> IO () parseStandaloneFCS file success = do (ec, _out, _err) <- readProcessWithExitCode "ogma" args "" -- True if success is expected and detected, or niether expected nor -- detected. let testPass = success == (ec == ExitSuccess) assertBool errorMsg testPass where args = ["standalone", "--file-name", file] errorMsg = "Parsing file " ++ file ++ " result unexpected." -- | Test standalone backend for FDB format and Lustre. -- -- This test uses the standalone backend, so it generates a Copilot file. It -- may be convenient to run this action in a temporary directory. -- -- This IO action fails if any of the following are true: -- * Ogma cannot be found in the current PATH. -- * Ogma cannot be executed. -- * The given file is not found or accessible. -- * The format in the given file is incorrect. -- * Ogma fails due to an internal error or bug. -- * The output file cannot be created due to lack of space or permissions. -- parseStandaloneFDB :: FilePath -- ^ Path to an input file -> IO () parseStandaloneFDB file = do (ec, _out, _err) <- readProcessWithExitCode "ogma" args "" assertBool errorMsg (ec == ExitSuccess) where args = [ "standalone", "--file-name", file, "--input-format", "fdb" , "--prop-format", "lustre"] errorMsg = "Parsing file " ++ file ++ " failed" -- | Test ogma by running it and checking the error code. -- -- This tests just whether ogma finishes with an error code or not. If files -- may be generated for the command being tested, it may be convenient to run -- this action in a temporary directory. -- -- This IO action fails if any of the following are true: -- * Ogma cannot be found in the current PATH. -- * Ogma cannot be executed. -- * The given command is not valid. -- * Ogma fails due to an internal error or bug. -- * Output files cannot be created due to lack of space or permissions. -- runErrorCode :: [String] -- ^ Arguments to pass to ogma -> Bool -> IO () runErrorCode args success = do (ec, _out, _err) <- readProcessWithExitCode "ogma" args "" -- True if success is expected and detected, or niether expected nor -- detected. let testPass = success == (ec == ExitSuccess) assertBool errorMsg testPass where errorMsg = "Testing ogma's CLI parser with arguments " ++ intercalate "," args ++ " failed" ogma-cli-1.7.0/tests/fcs-example1.json0000644000000000000000000000502214767604252015733 0ustar0000000000000000{ "RTSASpec": { "Internal_variables": [], "Other_variables": [ {"name":"param_is_short", "type":"bool"}, {"name":"param_value_short", "type":"real"}, {"name":"param_value_long", "type":"real"}, {"name":"upper_param_limit", "type":"real"}, {"name":"lower_param_limit", "type":"real"}, {"name":"envelope_issue", "type":"bool"} ], "Requirements": [ { "name": "behnazOne", "CoCoSpecCode": "true", "ptLTL": "((H ((((! flight_mode) & (Y flight_mode)) & (Y TRUE)) -> (Y (((O[=10] (((conflict_detected) & ((Y (! (conflict_detected))) | (flight_mode & ((! (Y TRUE)) | (Y (! flight_mode)))))) & (! (( replanning_mode ))))) -> (O[<10] ((flight_mode & ((! (Y TRUE)) | (Y (! flight_mode)))) | (( replanning_mode ))))) S (((O[=10] (((conflict_detected) & ((Y (! (conflict_detected))) | (flight_mode & ((! (Y TRUE)) | (Y (! flight_mode)))))) & (! (( replanning_mode ))))) -> (O[<10] ((flight_mode & ((! (Y TRUE)) | (Y (! flight_mode)))) | (( replanning_mode ))))) & (flight_mode & ((! (Y TRUE)) | (Y (! flight_mode))))))))) & (((! ((! flight_mode) & (Y flight_mode))) S ((! ((! flight_mode) & (Y flight_mode))) & (flight_mode & ((! (Y TRUE)) | (Y (! flight_mode)))))) -> (((O[=10] (((conflict_detected) & ((Y (! (conflict_detected))) | (flight_mode & ((! (Y TRUE)) | (Y (! flight_mode)))))) & (! (( replanning_mode ))))) -> (O[<10] ((flight_mode & ((! (Y TRUE)) | (Y (! flight_mode)))) | (( replanning_mode ))))) S (((O[=10] (((conflict_detected) & ((Y (! (conflict_detected))) | (flight_mode & ((! (Y TRUE)) | (Y (! flight_mode)))))) & (! (( replanning_mode ))))) -> (O[<10] ((flight_mode & ((! (Y TRUE)) | (Y (! flight_mode)))) | (( replanning_mode ))))) & (flight_mode & ((! (Y TRUE)) | (Y (! flight_mode))))))))", "fretish": "Meaning not specified" } ] } } ogma-cli-1.7.0/tests/reduced_geofence_msgs_bad.h0000644000000000000000000000051114767604252020027 0ustar0000000000000000/** * @struct geofence_parameters_t * @brief data structure containing information about the parameters used by the geofence app */ typeduuuef struct{ uint8_t TlmHeader[CFE_SB_TLM_HDR_SIZE]; double lookahead; double hthreshold; double vthreshold; double hstepback; double vstepback; }geofence_parameters_t; ogma-cli-1.7.0/tests/reduced_geofence_msgs.h0000644000000000000000000000050614767604252017225 0ustar0000000000000000/** * @struct geofence_parameters_t * @brief data structure containing information about the parameters used by the geofence app */ typedef struct{ uint8_t TlmHeader[CFE_SB_TLM_HDR_SIZE]; double lookahead; double hthreshold; double vthreshold; double hstepback; double vstepback; }geofence_parameters_t; ogma-cli-1.7.0/tests/fdb-example1.json0000644000000000000000000002257514767604252015727 0ustar0000000000000000[ { "reqid": "test_req1", "parent_reqid": "", "project": "Test", "rationale": "", "fulltext": "during flight_mode when conflict_detected planner_module shall within 10 seconds satisfy (replanning_mode).", "semantics": { "type": "nasa", "scope": { "type": "in" }, "condition": "regular", "timing": "within", "response": "satisfaction", "variables": { "regular": [ "conflict_detected", "replanning_mode" ], "modes": [ "flight_mode" ] }, "scope_mode": "flight_mode", "scopeTextRange": [ 0, 17 ], "regular_condition": "(conflict_detected)", "qualifier_word": "when", "pre_condition": "(conflict_detected)", "conditionTextRange": [ 19, 40 ], "component_name": "planner_module", "componentTextRange": [ 42, 55 ], "duration": [ "10" ], "timingTextRange": [ 63, 79 ], "post_condition": "(( replanning_mode ))", "responseTextRange": [ 81, 105 ], "ft": "((LAST V ((! (Fin_flight_mode & (! LAST))) | (X (((Lin_flight_mode | LAST) V (((! (conflict_detected)) & ((! LAST) & ((X (conflict_detected)) & (! (Lin_flight_mode | LAST))))) -> ((X ((F[<=10] (( replanning_mode ))) | (F[<10] (Lin_flight_mode | LAST)))) & (! (Lin_flight_mode | LAST))))) & ((conflict_detected) -> ((F[<=10] (( replanning_mode ))) | (F[<10] (Lin_flight_mode | LAST)))))))) & (flight_mode -> (((Lin_flight_mode | LAST) V (((! (conflict_detected)) & ((! LAST) & ((X (conflict_detected)) & (! (Lin_flight_mode | LAST))))) -> ((X ((F[<=10] (( replanning_mode ))) | (F[<10] (Lin_flight_mode | LAST)))) & (! (Lin_flight_mode | LAST))))) & ((conflict_detected) -> ((F[<=10] (( replanning_mode ))) | (F[<10] (Lin_flight_mode | LAST)))))))", "pt": "((H ((Lin_flight_mode & (! FTP)) -> (Y (((O[=10] (((conflict_detected) & ((Y (! (conflict_detected))) | Fin_flight_mode)) & (! (( replanning_mode ))))) -> (O[<10] (Fin_flight_mode | (( replanning_mode ))))) S (((O[=10] (((conflict_detected) & ((Y (! (conflict_detected))) | Fin_flight_mode)) & (! (( replanning_mode ))))) -> (O[<10] (Fin_flight_mode | (( replanning_mode ))))) & Fin_flight_mode))))) & (((! Lin_flight_mode) S ((! Lin_flight_mode) & Fin_flight_mode)) -> (((O[=10] (((conflict_detected) & ((Y (! (conflict_detected))) | Fin_flight_mode)) & (! (( replanning_mode ))))) -> (O[<10] (Fin_flight_mode | (( replanning_mode ))))) S (((O[=10] (((conflict_detected) & ((Y (! (conflict_detected))) | Fin_flight_mode)) & (! (( replanning_mode ))))) -> (O[<10] (Fin_flight_mode | (( replanning_mode ))))) & Fin_flight_mode))))", "ftExpanded": "((LAST V ((! ((((! flight_mode) & (! LAST)) & (X flight_mode)) & (! LAST))) | (X (((((flight_mode & (! LAST)) & (X (! flight_mode))) | LAST) V (((! (conflict_detected)) & ((! LAST) & ((X (conflict_detected)) & (! (((flight_mode & (! LAST)) & (X (! flight_mode))) | LAST))))) -> ((X ((F[<=10] (( replanning_mode ))) | (F[<10] (((flight_mode & (! LAST)) & (X (! flight_mode))) | LAST)))) & (! (((flight_mode & (! LAST)) & (X (! flight_mode))) | LAST))))) & ((conflict_detected) -> ((F[<=10] (( replanning_mode ))) | (F[<10] (((flight_mode & (! LAST)) & (X (! flight_mode))) | LAST)))))))) & (flight_mode -> (((((flight_mode & (! LAST)) & (X (! flight_mode))) | LAST) V (((! (conflict_detected)) & ((! LAST) & ((X (conflict_detected)) & (! (((flight_mode & (! LAST)) & (X (! flight_mode))) | LAST))))) -> ((X ((F[<=10] (( replanning_mode ))) | (F[<10] (((flight_mode & (! LAST)) & (X (! flight_mode))) | LAST)))) & (! (((flight_mode & (! LAST)) & (X (! flight_mode))) | LAST))))) & ((conflict_detected) -> ((F[<=10] (( replanning_mode ))) | (F[<10] (((flight_mode & (! LAST)) & (X (! flight_mode))) | LAST)))))))", "ptExpanded": "((H ((((! flight_mode) & (Y flight_mode)) & (Y TRUE)) -> (Y (((O[=10] (((conflict_detected) & ((Y (! (conflict_detected))) | (flight_mode & ((! (Y TRUE)) | (Y (! flight_mode)))))) & (! (( replanning_mode ))))) -> (O[<10] ((flight_mode & ((! (Y TRUE)) | (Y (! flight_mode)))) | (( replanning_mode ))))) S (((O[=10] (((conflict_detected) & ((Y (! (conflict_detected))) | (flight_mode & ((! (Y TRUE)) | (Y (! flight_mode)))))) & (! (( replanning_mode ))))) -> (O[<10] ((flight_mode & ((! (Y TRUE)) | (Y (! flight_mode)))) | (( replanning_mode ))))) & (flight_mode & ((! (Y TRUE)) | (Y (! flight_mode))))))))) & (((! ((! flight_mode) & (Y flight_mode))) S ((! ((! flight_mode) & (Y flight_mode))) & (flight_mode & ((! (Y TRUE)) | (Y (! flight_mode)))))) -> (((O[=10] (((conflict_detected) & ((Y (! (conflict_detected))) | (flight_mode & ((! (Y TRUE)) | (Y (! flight_mode)))))) & (! (( replanning_mode ))))) -> (O[<10] ((flight_mode & ((! (Y TRUE)) | (Y (! flight_mode)))) | (( replanning_mode ))))) S (((O[=10] (((conflict_detected) & ((Y (! (conflict_detected))) | (flight_mode & ((! (Y TRUE)) | (Y (! flight_mode)))))) & (! (( replanning_mode ))))) -> (O[<10] ((flight_mode & ((! (Y TRUE)) | (Y (! flight_mode)))) | (( replanning_mode ))))) & (flight_mode & ((! (Y TRUE)) | (Y (! flight_mode))))))))", "component": "planner_module", "CoCoSpecCode": "((H(((( not flight_mode) and (pre (flight_mode))) and ( not FTP)) => (pre (SI( (flight_mode and (FTP or (pre ( not flight_mode)))), ((OT(10,10,( ( (conflict_detected) and ( ( Y ( not (conflict_detected) ) ) or ( flight_mode and ( FTP or ( Y not flight_mode ) ) ) ) ) and ( not (( replanning_mode )) ) ))) => (OT(10-1,0,( ( flight_mode and ( FTP or ( Y not flight_mode ) ) ) or (( replanning_mode )) )))) ))))) and ((SI( (flight_mode and (FTP or (pre ( not flight_mode)))), ( not (( not flight_mode) and (pre (flight_mode)))) )) => (SI( (flight_mode and (FTP or (pre ( not flight_mode)))), ((OT(10,10,( ( (conflict_detected) and ( ( Y ( not (conflict_detected) ) ) or ( flight_mode and ( FTP or ( Y not flight_mode ) ) ) ) ) and ( not (( replanning_mode )) ) ))) => (OT(10-1,0,( ( flight_mode and ( FTP or ( Y not flight_mode ) ) ) or (( replanning_mode )) )))) ))))", "diagramVariables": "M = flight_mode, TC = (conflict_detected), n = 10, Response = (( replanning_mode )).", "description": "ENFORCED: in every interval where flight_mode holds.\nTRIGGER: first point in the interval if (conflict_detected) is true and any point in the interval where (conflict_detected) becomes true (from false).\nREQUIRES: for every trigger, RES must hold at some point with distance <=10 from the trigger, except if the end of the interval occurs sooner.", "diagram": "_media/user-interface/examples/svgDiagrams/in_regular_within_satisfaction.svg" }, "_id": "fbc0a840-a04b-11ea-b135-098996762962" } ]ogma-cli-1.7.0/src/0000755000000000000000000000000014767604252012201 5ustar0000000000000000ogma-cli-1.7.0/src/Main.hs0000644000000000000000000000734014767604252013425 0ustar0000000000000000-- Copyright 2020 United States Government as represented by the Administrator -- of the National Aeronautics and Space Administration. All Rights Reserved. -- -- Disclaimers -- -- No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY -- OF ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT -- LIMITED TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO -- SPECIFICATIONS, ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A -- PARTICULAR PURPOSE, OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE -- SUBJECT SOFTWARE WILL BE ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF -- PROVIDED, WILL CONFORM TO THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN -- ANY MANNER, CONSTITUTE AN ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR -- RECIPIENT OF ANY RESULTS, RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR -- ANY OTHER APPLICATIONS RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, -- GOVERNMENT AGENCY DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING -- THIRD-PARTY SOFTWARE, IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES -- IT "AS IS." -- -- Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST -- THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL AS -- ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS IN -- ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH USE, -- INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, RECIPIENT'S -- USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD HARMLESS THE -- UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL AS ANY -- PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. RECIPIENT'S SOLE REMEDY -- FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, UNILATERAL TERMINATION OF THIS -- AGREEMENT. -- -- | Ogma: Tool to interoperate between -- and other languages. -- -- Ogma is a tool to facilitate integration of safe runtime monitors into other -- systems. It takes information from a system created in a language (e.g., -- Lustre) and produces specifications for the runtime verification -- framework . Currently, features -- supported are: -- -- * Translation properties defined in structured natural language into -- corresponding expressions in Copilot. -- -- * Translation of C headers declaring structs into the corresponding Copilot -- Struct definitions. -- -- * Translation of C headers declaring structs into CFS message handlers that -- copy data in global variables. -- -- * Generate NASA core Flight System (cFS) applications for runtime monitoring -- using Copilot. -- -- * Generate Robot Operating System (ROS) applications for runtime monitoring -- using Copilot. -- -- * Generate F' (FPrime) components for runtime monitoring using Copilot. -- -- More information can be obtained by calling ogma with the argument @--help@. module Main ( main ) where -- External imports import Options.Applicative (ParserInfo, execParser, fullDesc, header, helper, info, progDesc, (<**>)) -- Internal imports: CLI parsing, handling, and processing of results. import CLI.CommandTop ( CommandOpts, command, commandDesc, commandOptsParser ) import CLI.Result ( processResult ) -- | Ogma: Helper tool to interoperate between Copilot and other languages. main :: IO () main = execParser fullCLIOpts >>= command >>= processResult -- | Full program options. fullCLIOpts :: ParserInfo CommandOpts fullCLIOpts = info (commandOptsParser <**> helper) ( fullDesc <> progDesc commandDesc <> header strProgramSummary ) -- | Short program description strProgramSummary :: String strProgramSummary = "ogma - an anything-to-Copilot application generator" ogma-cli-1.7.0/src/CLI/0000755000000000000000000000000014767604252012610 5ustar0000000000000000ogma-cli-1.7.0/src/CLI/CommandROSApp.hs0000644000000000000000000001704514767604252015556 0ustar0000000000000000-- Copyright 2022 United States Government as represented by the Administrator -- of the National Aeronautics and Space Administration. All Rights Reserved. -- -- Disclaimers -- -- No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY -- OF ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT -- LIMITED TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO -- SPECIFICATIONS, ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A -- PARTICULAR PURPOSE, OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE -- SUBJECT SOFTWARE WILL BE ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF -- PROVIDED, WILL CONFORM TO THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN -- ANY MANNER, CONSTITUTE AN ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR -- RECIPIENT OF ANY RESULTS, RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR -- ANY OTHER APPLICATIONS RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, -- GOVERNMENT AGENCY DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING -- THIRD-PARTY SOFTWARE, IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES -- IT "AS IS." -- -- Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST -- THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL AS -- ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS IN -- ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH USE, -- INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, RECIPIENT'S -- USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD HARMLESS THE -- UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL AS ANY -- PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. RECIPIENT'S SOLE REMEDY -- FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, UNILATERAL TERMINATION OF THIS -- AGREEMENT. -- -- | CLI interface to the ROSApp subcommand. module CLI.CommandROSApp ( -- * Direct command access command , CommandOpts , ErrorCode -- * CLI , commandDesc , commandOptsParser ) where -- External imports import Options.Applicative ( Parser, help, long, metavar, optional, short, showDefault, strOption, value ) -- External imports: command results import Command.Result ( Result ) -- External imports: actions or commands supported import Command.ROSApp (ErrorCode) import qualified Command.ROSApp -- * Command -- | Options needed to generate the ROS application. data CommandOpts = CommandOpts { rosAppInputFile :: Maybe String , rosAppTarget :: String , rosAppTemplateDir :: Maybe String , rosAppVarNames :: Maybe String , rosAppVarDB :: Maybe String , rosAppHandlers :: Maybe String , rosAppFormat :: String , rosAppPropFormat :: String , rosAppPropVia :: Maybe String , rosAppTemplateVars :: Maybe String } -- | Create (ROS) applications -- that subscribe to obtain necessary data from topics and call Copilot when -- new data arrives. -- -- This is just a wrapper around "Command.ROSApp". command :: CommandOpts -> IO (Result ErrorCode) command c = Command.ROSApp.command options where options = Command.ROSApp.CommandOptions { Command.ROSApp.commandInputFile = rosAppInputFile c , Command.ROSApp.commandTargetDir = rosAppTarget c , Command.ROSApp.commandTemplateDir = rosAppTemplateDir c , Command.ROSApp.commandVariables = rosAppVarNames c , Command.ROSApp.commandVariableDB = rosAppVarDB c , Command.ROSApp.commandHandlers = rosAppHandlers c , Command.ROSApp.commandFormat = rosAppFormat c , Command.ROSApp.commandPropFormat = rosAppPropFormat c , Command.ROSApp.commandPropVia = rosAppPropVia c , Command.ROSApp.commandExtraVars = rosAppTemplateVars c } -- * CLI -- | ROS command description commandDesc :: String commandDesc = "Generate a ROS 2 monitoring package" -- | Subparser for the @ros@ command, used to generate a Robot Operating System -- application connected to Copilot monitors. commandOptsParser :: Parser CommandOpts commandOptsParser = CommandOpts <$> optional ( strOption ( long "input-file" <> metavar "FILENAME" <> help strROSAppFileNameArgDesc ) ) <*> strOption ( long "app-target-dir" <> metavar "DIR" <> showDefault <> value "ros" <> help strROSAppDirArgDesc ) <*> optional ( strOption ( long "app-template-dir" <> metavar "DIR" <> help strROSAppTemplateDirArgDesc ) ) <*> optional ( strOption ( long "variable-file" <> metavar "FILENAME" <> help strROSAppVarListArgDesc ) ) <*> optional ( strOption ( long "variable-db" <> metavar "FILENAME" <> help strROSAppVarDBArgDesc ) ) <*> optional ( strOption ( long "handlers-file" <> metavar "FILENAME" <> help strROSAppHandlerListArgDesc ) ) <*> strOption ( long "input-format" <> short 'f' <> metavar "FORMAT_NAME" <> help strROSAppFormatDesc <> showDefault <> value "fcs" ) <*> strOption ( long "prop-format" <> short 'p' <> metavar "FORMAT_NAME" <> help strROSAppPropFormatDesc <> showDefault <> value "smv" ) <*> optional ( strOption ( long "parse-prop-via" <> metavar "COMMAND" <> help strROSAppPropViaDesc ) ) <*> optional ( strOption ( long "template-vars" <> metavar "FILENAME" <> help strROSAppTemplateVarsArgDesc ) ) -- | Argument target directory to ROS app generation command strROSAppDirArgDesc :: String strROSAppDirArgDesc = "Target directory" -- | Argument template directory to ROS app generation command strROSAppTemplateDirArgDesc :: String strROSAppTemplateDirArgDesc = "Directory holding ROS application source template" -- | Argument input file to ROS app generation command strROSAppFileNameArgDesc :: String strROSAppFileNameArgDesc = "File containing input specification" -- | Argument variable list to ROS app generation command strROSAppVarListArgDesc :: String strROSAppVarListArgDesc = "File containing list of ROS variables to make accessible" -- | Argument variable database to ROS app generation command strROSAppVarDBArgDesc :: String strROSAppVarDBArgDesc = "File containing a DB of known ROS variables" -- | Argument handler list to ROS app generation command strROSAppHandlerListArgDesc :: String strROSAppHandlerListArgDesc = "File containing list of Copilot handlers used in the specification" -- | Format flag description. strROSAppFormatDesc :: String strROSAppFormatDesc = "Format of the input file" -- | Property format flag description. strROSAppPropFormatDesc :: String strROSAppPropFormatDesc = "Format of temporal or boolean properties" -- | External command to pre-process individual properties. strROSAppPropViaDesc :: String strROSAppPropViaDesc = "Command to pre-process individual properties" -- | Additional template variable file flag description. strROSAppTemplateVarsArgDesc :: String strROSAppTemplateVarsArgDesc = "JSON file containing additional variables to expand in template" ogma-cli-1.7.0/src/CLI/CommandStandalone.hs0000644000000000000000000001646614767604252016550 0ustar0000000000000000-- Copyright 2020 United States Government as represented by the Administrator -- of the National Aeronautics and Space Administration. All Rights Reserved. -- -- Disclaimers -- -- No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY -- OF ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT -- LIMITED TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO -- SPECIFICATIONS, ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A -- PARTICULAR PURPOSE, OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE -- SUBJECT SOFTWARE WILL BE ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF -- PROVIDED, WILL CONFORM TO THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN -- ANY MANNER, CONSTITUTE AN ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR -- RECIPIENT OF ANY RESULTS, RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR -- ANY OTHER APPLICATIONS RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, -- GOVERNMENT AGENCY DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING -- THIRD-PARTY SOFTWARE, IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES -- IT "AS IS." -- -- Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST -- THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL AS -- ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS IN -- ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH USE, -- INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, RECIPIENT'S -- USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD HARMLESS THE -- UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL AS ANY -- PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. RECIPIENT'S SOLE REMEDY -- FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, UNILATERAL TERMINATION OF THIS -- AGREEMENT. -- -- | CLI interface to the Standalone subcommand module CLI.CommandStandalone ( -- * Direct command access command , CommandOpts , ErrorCode -- * CLI , commandDesc , commandOptsParser ) where -- External imports import Options.Applicative (Parser, help, long, many, metavar, optional, short, showDefault, strOption, switch, value) -- External imports: command results import Command.Result ( Result(..) ) import Data.Location ( Location(..) ) -- External imports: actions or commands supported import Command.Standalone (ErrorCode) import qualified Command.Standalone -- * Command -- | Options to generate Copilot from specification. data CommandOpts = CommandOpts { standaloneTargetDir :: FilePath , standaloneTemplateDir :: Maybe FilePath , standaloneFileName :: FilePath , standaloneFormat :: String , standalonePropFormat :: String , standaloneTypes :: [String] , standaloneTarget :: String , standalonePropVia :: Maybe String , standaloneTemplateVars :: Maybe String } -- | Transform an input specification into a Copilot specification. command :: CommandOpts -> IO (Result ErrorCode) command c = Command.Standalone.command internalCommandOpts where internalCommandOpts :: Command.Standalone.CommandOptions internalCommandOpts = Command.Standalone.CommandOptions { Command.Standalone.commandInputFile = standaloneFileName c , Command.Standalone.commandTargetDir = standaloneTargetDir c , Command.Standalone.commandTemplateDir = standaloneTemplateDir c , Command.Standalone.commandFormat = standaloneFormat c , Command.Standalone.commandPropFormat = standalonePropFormat c , Command.Standalone.commandTypeMapping = types , Command.Standalone.commandFilename = standaloneTarget c , Command.Standalone.commandPropVia = standalonePropVia c , Command.Standalone.commandExtraVars = standaloneTemplateVars c } types :: [(String, String)] types = map splitTypeMapping (standaloneTypes c) splitTypeMapping :: String -> (String, String) splitTypeMapping s = (h, safeTail t) where (h, t) = span (/= ':') s safeTail xs = if null xs then xs else tail xs -- * CLI -- | Command description for CLI help. commandDesc :: String commandDesc = "Generate a standalone Copilot file from an input specification" -- | Subparser for the @standalone@ command, used to generate a Copilot -- specification from an input specification file. commandOptsParser :: Parser CommandOpts commandOptsParser = CommandOpts <$> strOption ( long "target-dir" <> metavar "DIR" <> showDefault <> value "copilot" <> help strStandaloneTargetDirDesc ) <*> optional ( strOption ( long "template-dir" <> metavar "DIR" <> help strStandaloneTemplateDirArgDesc ) ) <*> strOption ( long "file-name" <> metavar "FILENAME" <> help strStandaloneFilenameDesc ) <*> strOption ( long "input-format" <> short 'f' <> metavar "FORMAT_NAME" <> help strStandaloneFormatDesc <> showDefault <> value "fcs" ) <*> strOption ( long "prop-format" <> short 'p' <> metavar "FORMAT_NAME" <> help strStandalonePropFormatDesc <> showDefault <> value "smv" ) <*> many (strOption ( long "map-type" <> short 'm' <> metavar "TYPE_NAME:TYPE_NAME" <> help strStandaloneMapTypeDesc ) ) <*> strOption ( long "target-file-name" <> metavar "FILENAME" <> help strStandaloneTargetDesc <> showDefault <> value "monitor" ) <*> optional ( strOption ( long "parse-prop-via" <> metavar "COMMAND" <> help strStandalonePropViaDesc ) ) <*> optional ( strOption ( long "template-vars" <> metavar "FILENAME" <> help strStandaloneTemplateVarsArgDesc ) ) -- | Target dir flag description. strStandaloneTargetDirDesc :: String strStandaloneTargetDirDesc = "Target directory" -- | Template dir flag description. strStandaloneTemplateDirArgDesc :: String strStandaloneTemplateDirArgDesc = "Directory holding standalone source template" -- | Filename flag description. strStandaloneFilenameDesc :: String strStandaloneFilenameDesc = "File with properties or requirements" -- | Format flag description. strStandaloneFormatDesc :: String strStandaloneFormatDesc = "Format of the input file" -- | Property format flag description. strStandalonePropFormatDesc :: String strStandalonePropFormatDesc = "Format of temporal or boolean properties" -- | Type mapping flag description. strStandaloneMapTypeDesc :: String strStandaloneMapTypeDesc = "Map a type to another type" -- | Target file name flag description. strStandaloneTargetDesc :: String strStandaloneTargetDesc = "Filename prefix for monitoring files in target language" -- | External command to pre-process individual properties. strStandalonePropViaDesc :: String strStandalonePropViaDesc = "Command to pre-process individual properties" -- | Additional template variable file flag description. strStandaloneTemplateVarsArgDesc :: String strStandaloneTemplateVarsArgDesc = "JSON file containing additional variables to expand in template" ogma-cli-1.7.0/src/CLI/CommandDiagram.hs0000644000000000000000000002144214767604252016012 0ustar0000000000000000-- Copyright 2024 United States Government as represented by the Administrator -- of the National Aeronautics and Space Administration. All Rights Reserved. -- -- Disclaimers -- -- No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY -- OF ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT -- LIMITED TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO -- SPECIFICATIONS, ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A -- PARTICULAR PURPOSE, OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE -- SUBJECT SOFTWARE WILL BE ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF -- PROVIDED, WILL CONFORM TO THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN -- ANY MANNER, CONSTITUTE AN ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR -- RECIPIENT OF ANY RESULTS, RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR -- ANY OTHER APPLICATIONS RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, -- GOVERNMENT AGENCY DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING -- THIRD-PARTY SOFTWARE, IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES -- IT "AS IS." -- -- Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST -- THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL AS -- ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS IN -- ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH USE, -- INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, RECIPIENT'S -- USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD HARMLESS THE -- UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL AS ANY -- PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. RECIPIENT'S SOLE REMEDY -- FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, UNILATERAL TERMINATION OF THIS -- AGREEMENT. -- -- | CLI interface to the diagram subcommand. module CLI.CommandDiagram ( -- * Direct command access command , CommandOpts , ErrorCode -- * CLI , commandDesc , commandOptsParser ) where -- External imports import Options.Applicative (Parser, help, long, metavar, optional, short, showDefault, strOption, value) -- External imports: command results import Command.Result ( Result(..) ) import Data.Location ( Location(..) ) -- External imports: actions or commands supported import Command.Diagram (diagram) import qualified Command.Diagram -- * Command -- | Options to generate Copilot from diagram. data CommandOpts = CommandOpts { diagramTargetDir :: FilePath , diagramTemplateDir :: Maybe FilePath , diagramFileName :: FilePath , diagramFormat :: String , diagramPropFormat :: String , diagramTarget :: String , diagramMode :: String , diagramStateVar :: String , diagramInputVar :: String } -- | Transform an input diagram into a Copilot specification. command :: CommandOpts -> IO (Result ErrorCode) command c | Nothing <- diagramFormatP = return $ Error ecFormatError "The diagram format specified is incorrect" LocationNothing | Nothing <- diagramModeP = return $ Error ecModeError "The mode specified is incorrect" LocationNothing | Nothing <- diagramPropFormatP = return $ Error ecPropFormatError "The format specified for transitions or edge properties is incorrect" LocationNothing | Just mode <- diagramModeP , Just format <- diagramFormatP , Just propFormat <- diagramPropFormatP = do let internalCommandOpts :: Command.Diagram.DiagramOptions internalCommandOpts = Command.Diagram.DiagramOptions { Command.Diagram.diagramTargetDir = diagramTargetDir c , Command.Diagram.diagramTemplateDir = diagramTemplateDir c , Command.Diagram.diagramFormat = format , Command.Diagram.diagramPropFormat = propFormat , Command.Diagram.diagramFilename = diagramTarget c , Command.Diagram.diagramMode = mode , Command.Diagram.diagramStateVar = diagramStateVar c , Command.Diagram.diagramInputVar = diagramInputVar c } diagram (diagramFileName c) internalCommandOpts where diagramFormatP = parseDiagramFormat (diagramFormat c) diagramModeP = parseDiagramMode (diagramMode c) diagramPropFormatP = parseDiagramPropFormat (diagramPropFormat c) parseDiagramFormat :: String -> Maybe Command.Diagram.DiagramFormat parseDiagramFormat "dot" = Just Command.Diagram.Dot parseDiagramFormat "graphviz" = Just Command.Diagram.Dot parseDiagramFormat "mermaid" = Just Command.Diagram.Mermaid parseDiagramFormat _ = Nothing parseDiagramMode :: String -> Maybe Command.Diagram.DiagramMode parseDiagramMode "check" = Just Command.Diagram.CheckState parseDiagramMode "calculate" = Just Command.Diagram.ComputeState parseDiagramMode "safeguard" = Just Command.Diagram.CheckMoves parseDiagramMode _ = Nothing parseDiagramPropFormat :: String -> Maybe Command.Diagram.DiagramPropFormat parseDiagramPropFormat "lustre" = Just Command.Diagram.Lustre parseDiagramPropFormat "cocospec" = parseDiagramPropFormat "lustre" parseDiagramPropFormat "inputs" = Just Command.Diagram.Inputs parseDiagramPropFormat "literal" = Just Command.Diagram.Literal parseDiagramPropFormat "smv" = Just Command.Diagram.SMV parseDiagramPropFormat _ = Nothing -- * CLI -- | Command description for CLI help. commandDesc :: String commandDesc = "Generate a monitor from state machine diagram" -- | Subparser for the @diagram@ command, used to generate a Copilot -- specification from an input diagram file. commandOptsParser :: Parser CommandOpts commandOptsParser = CommandOpts <$> strOption ( long "target-dir" <> metavar "DIR" <> showDefault <> value "copilot" <> help strDiagramTargetDirDesc ) <*> optional ( strOption ( long "template-dir" <> metavar "DIR" <> help strDiagramTemplateDirArgDesc ) ) <*> strOption ( long "file-name" <> metavar "FILENAME" <> help strDiagramFilenameDesc ) <*> strOption ( long "input-format" <> short 'f' <> metavar "FORMAT_NAME" <> help strDiagramFormatDesc <> showDefault <> value "mermaid" ) <*> strOption ( long "prop-format" <> short 'p' <> metavar "FORMAT_NAME" <> help strDiagramPropFormatDesc <> showDefault <> value "inputs" ) <*> strOption ( long "target-file-name" <> metavar "FILENAME" <> help strDiagramTargetDesc <> showDefault <> value "monitor" ) <*> strOption ( long "mode" <> metavar "MODE" <> help strDiagramModeDesc <> showDefault <> value "check" ) <*> strOption ( long "state-var" <> metavar "NAME" <> help strDiagramStateVarDesc <> showDefault <> value "state" ) <*> strOption ( long "input-var" <> metavar "NAME" <> help strDiagramInputVarDesc <> showDefault <> value "input" ) -- | Target dir flag description. strDiagramTargetDirDesc :: String strDiagramTargetDirDesc = "Target directory" -- | Template dir flag description. strDiagramTemplateDirArgDesc :: String strDiagramTemplateDirArgDesc = "Directory holding target source template" -- | Filename flag description. strDiagramFilenameDesc :: String strDiagramFilenameDesc = "File with diagram source" -- | Format flag description. strDiagramFormatDesc :: String strDiagramFormatDesc = "Format of the input file" -- | Property format flag description. strDiagramPropFormatDesc :: String strDiagramPropFormatDesc = "Format of temporal or boolean properties associated to diagram edges" -- | Target file name flag description. strDiagramTargetDesc :: String strDiagramTargetDesc = "Filename prefix for monitoring files in target language" -- | Mode name flag description. strDiagramModeDesc :: String strDiagramModeDesc = "Mode of operation (check, calculate, safeguard)" strDiagramInputVarDesc :: String strDiagramInputVarDesc = "Name of the input variable" strDiagramStateVarDesc :: String strDiagramStateVarDesc = "Name of the state variable" -- * Error codes -- | Encoding of reasons why the command can fail. -- -- The error code used is 1 for user error. type ErrorCode = Int -- | Error: unknown diagram format. ecFormatError :: ErrorCode ecFormatError = 2 -- | Error: unknown operation mode. ecModeError :: ErrorCode ecModeError = 3 -- | Error: unknown property format. ecPropFormatError :: ErrorCode ecPropFormatError = 4 ogma-cli-1.7.0/src/CLI/CommandFPrimeApp.hs0000644000000000000000000001730114767604252016270 0ustar0000000000000000-- Copyright 2022 United States Government as represented by the Administrator -- of the National Aeronautics and Space Administration. All Rights Reserved. -- -- Disclaimers -- -- No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY -- OF ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT -- LIMITED TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO -- SPECIFICATIONS, ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A -- PARTICULAR PURPOSE, OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE -- SUBJECT SOFTWARE WILL BE ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF -- PROVIDED, WILL CONFORM TO THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN -- ANY MANNER, CONSTITUTE AN ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR -- RECIPIENT OF ANY RESULTS, RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR -- ANY OTHER APPLICATIONS RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, -- GOVERNMENT AGENCY DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING -- THIRD-PARTY SOFTWARE, IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES -- IT "AS IS." -- -- Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST -- THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL AS -- ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS IN -- ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH USE, -- INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, RECIPIENT'S -- USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD HARMLESS THE -- UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL AS ANY -- PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. RECIPIENT'S SOLE REMEDY -- FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, UNILATERAL TERMINATION OF THIS -- AGREEMENT. -- -- | CLI interface to the FPrimeApp subcommand. module CLI.CommandFPrimeApp ( -- * Direct command access command , CommandOpts , ErrorCode -- * CLI , commandDesc , commandOptsParser ) where -- External imports import Options.Applicative ( Parser, help, long, metavar, optional, short, showDefault, strOption, value ) -- External imports: command results import Command.Result ( Result ) -- External imports: actions or commands supported import Command.FPrimeApp (ErrorCode) import qualified Command.FPrimeApp -- * Command -- | Options needed to generate the FPrime component. data CommandOpts = CommandOpts { fprimeAppInputFile :: Maybe String , fprimeAppTarget :: String , fprimeAppTemplateDir :: Maybe String , fprimeAppVariables :: Maybe String , fprimeAppVarDB :: Maybe String , fprimeAppHandlers :: Maybe String , fprimeAppFormat :: String , fprimeAppPropFormat :: String , fprimeAppPropVia :: Maybe String , fprimeAppTemplateVars :: Maybe String } -- | Create component that subscribe -- to obtain necessary data from the bus and call Copilot when new data -- arrives. -- -- This is just a wrapper around "Command.fprimeApp". command :: CommandOpts -> IO (Result ErrorCode) command c = Command.FPrimeApp.command options where options = Command.FPrimeApp.CommandOptions { Command.FPrimeApp.commandInputFile = fprimeAppInputFile c , Command.FPrimeApp.commandTargetDir = fprimeAppTarget c , Command.FPrimeApp.commandTemplateDir = fprimeAppTemplateDir c , Command.FPrimeApp.commandVariables = fprimeAppVariables c , Command.FPrimeApp.commandVariableDB = fprimeAppVarDB c , Command.FPrimeApp.commandHandlers = fprimeAppHandlers c , Command.FPrimeApp.commandFormat = fprimeAppFormat c , Command.FPrimeApp.commandPropFormat = fprimeAppPropFormat c , Command.FPrimeApp.commandPropVia = fprimeAppPropVia c , Command.FPrimeApp.commandExtraVars = fprimeAppTemplateVars c } -- * CLI -- | FPrime command description commandDesc :: String commandDesc = "Generate a complete F' monitoring component" -- | Subparser for the @fprime@ command, used to generate an FPrime component -- connected to Copilot monitors. commandOptsParser :: Parser CommandOpts commandOptsParser = CommandOpts <$> optional ( strOption ( long "input-file" <> metavar "FILENAME" <> help strFPrimeAppFileNameArgDesc ) ) <*> strOption ( long "app-target-dir" <> metavar "DIR" <> showDefault <> value "fprime" <> help strFPrimeAppDirArgDesc ) <*> optional ( strOption ( long "app-template-dir" <> metavar "DIR" <> help strFPrimeAppTemplateDirArgDesc ) ) <*> optional ( strOption ( long "variable-file" <> metavar "FILENAME" <> help strFPrimeAppVarListArgDesc ) ) <*> optional ( strOption ( long "variable-db" <> metavar "FILENAME" <> help strFPrimeAppVarDBArgDesc ) ) <*> optional ( strOption ( long "handlers-file" <> metavar "FILENAME" <> help strFPrimeAppHandlerListArgDesc ) ) <*> strOption ( long "input-format" <> short 'f' <> metavar "FORMAT_NAME" <> help strFPrimeAppFormatDesc <> showDefault <> value "fcs" ) <*> strOption ( long "prop-format" <> short 'p' <> metavar "FORMAT_NAME" <> help strFPrimeAppPropFormatDesc <> showDefault <> value "smv" ) <*> optional ( strOption ( long "parse-prop-via" <> metavar "COMMAND" <> help strFPrimeAppPropViaDesc ) ) <*> optional ( strOption ( long "template-vars" <> metavar "FILENAME" <> help strFPrimeAppTemplateVarsArgDesc ) ) -- | Argument target directory to FPrime component generation command strFPrimeAppDirArgDesc :: String strFPrimeAppDirArgDesc = "Target directory" -- | Argument template directory to FPrime component generation command strFPrimeAppTemplateDirArgDesc :: String strFPrimeAppTemplateDirArgDesc = "Directory holding F' component source template" -- | Argument input file to FPrime component generation command strFPrimeAppFileNameArgDesc :: String strFPrimeAppFileNameArgDesc = "File containing input specification" -- | Argument variable list to FPrime component generation command strFPrimeAppVarListArgDesc :: String strFPrimeAppVarListArgDesc = "File containing list of F' variables to make accessible" -- | Argument variable database to FPrime component generation command strFPrimeAppVarDBArgDesc :: String strFPrimeAppVarDBArgDesc = "File containing a DB of known F' variables" -- | Argument handler list to FPrime component generation command strFPrimeAppHandlerListArgDesc :: String strFPrimeAppHandlerListArgDesc = "File containing list of Copilot handlers used in the specification" -- | Format flag description. strFPrimeAppFormatDesc :: String strFPrimeAppFormatDesc = "Format of the input file" -- | Property format flag description. strFPrimeAppPropFormatDesc :: String strFPrimeAppPropFormatDesc = "Format of temporal or boolean properties" -- | External command to pre-process individual properties. strFPrimeAppPropViaDesc :: String strFPrimeAppPropViaDesc = "Command to pre-process individual properties" -- | Additional template variable file flag description. strFPrimeAppTemplateVarsArgDesc :: String strFPrimeAppTemplateVarsArgDesc = "JSON file containing additional variables to expand in template" ogma-cli-1.7.0/src/CLI/CommandTop.hs0000644000000000000000000002414314767604252015211 0ustar0000000000000000-- Copyright 2020 United States Government as represented by the Administrator -- of the National Aeronautics and Space Administration. All Rights Reserved. -- -- Disclaimers -- -- No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY -- OF ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT -- LIMITED TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO -- SPECIFICATIONS, ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A -- PARTICULAR PURPOSE, OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE -- SUBJECT SOFTWARE WILL BE ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF -- PROVIDED, WILL CONFORM TO THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN -- ANY MANNER, CONSTITUTE AN ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR -- RECIPIENT OF ANY RESULTS, RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR -- ANY OTHER APPLICATIONS RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, -- GOVERNMENT AGENCY DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING -- THIRD-PARTY SOFTWARE, IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES -- IT "AS IS." -- -- Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST -- THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL AS -- ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS IN -- ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH USE, -- INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, RECIPIENT'S -- USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD HARMLESS THE -- UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL AS ANY -- PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. RECIPIENT'S SOLE REMEDY -- FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, UNILATERAL TERMINATION OF THIS -- AGREEMENT. -- -- | CLI parsing, handling, and execution. -- -- The full module CLI is just a sum of all the subcommands with their -- respective CLI options. -- -- This module defines: -- -- - A 'CommandOpts' type that represents all options to the program, -- the subcommand executed, and any options for that subcommand. -- -- - A 'commandOptsParser' parser for the subcommands and their arguments, -- delegating the argument parsing to each subcommand's own CLI parser. -- -- - A 'command' function that dispatcher processing of the execution to the -- appropriate subcommand. -- -- - An 'ErrorCode' type that represents reasons why the program may have -- failed. -- -- Each of the subcommands is defined using the same standard interface. -- This module is merely a sum of all subcommands: -- -- - The type 'CommandOpts' is the sum of all respective subcommand options -- (whose types all share the same name but have different representations). -- -- - The parser is a sum of all subparsers, each attached to a specific -- command name defined in this module. -- -- - The command function is merely a dispatcher that detects the subcommand -- that must be executed, extracts the input, runs it, and translates the -- subcommands result into a top-level command result. -- -- - The error code is a plain representation that collapses the local -- subcommand error codes into a few possible values. module CLI.CommandTop ( -- * Direct command access CommandOpts , command , ErrorCode -- * CLI , commandDesc , commandOptsParser ) where -- External imports import Options.Applicative ( CommandFields, Mod, Parser, helper, info, progDesc, subparser, (<**>) ) import qualified Options.Applicative as OptParse -- External imports: command results import Command.Result ( Result ) -- Internal imports: subcommands import qualified CLI.CommandCFSApp import qualified CLI.CommandCStructs2Copilot import qualified CLI.CommandCStructs2MsgHandlers import qualified CLI.CommandDiagram import qualified CLI.CommandFPrimeApp import qualified CLI.CommandROSApp import qualified CLI.CommandStandalone -- * Command -- | Commands supported by Ogma and their arguments. -- All subcommands use the same interface, so they all use the type name -- @CommandOpts@ to capture their respective arguments. These types are -- different for each subcommand. data CommandOpts = CommandOptsCFSApp CLI.CommandCFSApp.CommandOpts | CommandOptsCStructs2Copilot CLI.CommandCStructs2Copilot.CommandOpts | CommandOptsCStructs2MsgHandlers CLI.CommandCStructs2MsgHandlers.CommandOpts | CommandOptsDiagram CLI.CommandDiagram.CommandOpts | CommandOptsFPrimeApp CLI.CommandFPrimeApp.CommandOpts | CommandOptsROSApp CLI.CommandROSApp.CommandOpts | CommandOptsStandalone CLI.CommandStandalone.CommandOpts -- * CLI -- | Command description for CLI help. commandDesc :: String commandDesc = "Generate complete or partial Copilot applications from multiple languages" -- | Subparser for multiple subcommands. commandOptsParser :: Parser CommandOpts commandOptsParser = subparser ( subcommandCStructs <> subcommandMsgHandlers <> subcommandCFSApp <> subcommandFPrimeApp <> subcommandROSApp <> subcommandStandalone <> subcommandDiagram ) -- | Modifier for the CStruct to Copilot Struct generation subcommand, linking -- the subcommand options and description to the command @structs@ at top -- level. subcommandCStructs :: Mod CommandFields CommandOpts subcommandCStructs = subcommand "structs" (CommandOptsCStructs2Copilot <$> CLI.CommandCStructs2Copilot.commandOptsParser) CLI.CommandCStructs2Copilot.commandDesc -- | Modifier for the msg handler generation subcommand, linking the subcommand -- options and description to the command @handlers@ at top level. subcommandMsgHandlers :: Mod CommandFields CommandOpts subcommandMsgHandlers = subcommand "handlers" (CommandOptsCStructs2MsgHandlers <$> CLI.CommandCStructs2MsgHandlers.commandOptsParser) CLI.CommandCStructs2MsgHandlers.commandDesc -- | Modifier for the CFS app expansion subcommand, linking the subcommand -- options and description to the command @cfs@ at top level. subcommandCFSApp :: Mod CommandFields CommandOpts subcommandCFSApp = subcommand "cfs" (CommandOptsCFSApp <$> CLI.CommandCFSApp.commandOptsParser) CLI.CommandCFSApp.commandDesc -- | Modifier for the ROS app expansion subcommand, linking the subcommand -- options and description to the command @ros@ at top level. subcommandROSApp :: Mod CommandFields CommandOpts subcommandROSApp = subcommand "ros" (CommandOptsROSApp <$> CLI.CommandROSApp.commandOptsParser) CLI.CommandROSApp.commandDesc -- | Modifier for the FPrime app expansion subcommand, linking the subcommand -- options and description to the command @fprime@ at top level. subcommandFPrimeApp :: Mod CommandFields CommandOpts subcommandFPrimeApp = subcommand "fprime" (CommandOptsFPrimeApp <$> CLI.CommandFPrimeApp.commandOptsParser) CLI.CommandFPrimeApp.commandDesc -- | Modifier for the standalone subcommand, linking the subcommand options and -- description to the command @standalone@ at top level. subcommandStandalone :: Mod CommandFields CommandOpts subcommandStandalone = subcommand "standalone" (CommandOptsStandalone <$> CLI.CommandStandalone.commandOptsParser) CLI.CommandStandalone.commandDesc -- | Modifier for the diagram subcommand, linking the subcommand options and -- description to the command @diagram@ at top level. subcommandDiagram :: Mod CommandFields CommandOpts subcommandDiagram = subcommand "diagram" (CommandOptsDiagram <$> CLI.CommandDiagram.commandOptsParser) CLI.CommandDiagram.commandDesc -- * Command dispatcher -- | Command dispatcher that obtains the parameters from the command line and -- passes them as arguments to the actual function that will process them, -- transforming the local result into a global program result. -- This function is implemented as a combination of three processes or -- functions: one that adapts the input to the inner function (down), the -- actual function implementing the command, and a translation of the local -- result into a global result that can be reported to users (up). In this -- case, the commands are all using the same (and compatible) exit codes, but -- they might not do so. This is captured by the fmap of the function id on -- each processing command. -- -- The function that adapts the inputs simply passes the arguments obtained -- from the command line one by one. Composition with this function uncurries -- the next function to work over the product as defined by the record that -- accompanies each command definition in the type OgmaCLICommand. -- -- Neither this nor the internal commands not know, and need to know, that they -- run in CLI. command :: CommandOpts -> IO (Result ErrorCode) command (CommandOptsCFSApp c) = id <$> CLI.CommandCFSApp.command c command (CommandOptsCStructs2Copilot c) = id <$> CLI.CommandCStructs2Copilot.command c command (CommandOptsCStructs2MsgHandlers c) = id <$> CLI.CommandCStructs2MsgHandlers.command c command (CommandOptsFPrimeApp c) = id <$> CLI.CommandFPrimeApp.command c command (CommandOptsROSApp c) = id <$> CLI.CommandROSApp.command c command (CommandOptsStandalone c) = id <$> CLI.CommandStandalone.command c command (CommandOptsDiagram c) = id <$> CLI.CommandDiagram.command c -- We indicate to HLint that the use of (id <$>) above should not trigger a -- warning. Conceptually, there is a transformation taking place, but no change -- is required because the types used by the internal functions and the -- top-level command to represent results are the same, and the error codes are -- non-overlapping. {-# ANN command "HLint: ignore Functor law" #-} -- * Error codes -- | Encoding of reasons why the command can fail. -- -- The error code used is 1 for user error, 2 for internal bug. type ErrorCode = Int -- * Auxiliary defs -- | Build a subcommand modifier from a command name, option parser and command -- description. subcommand :: String -> Parser CommandOpts -> String -> Mod CommandFields CommandOpts subcommand entry parser desc = OptParse.command entry (info (parser <**> helper) (progDesc desc)) ogma-cli-1.7.0/src/CLI/CommandCStructs2Copilot.hs0000644000000000000000000000655014767604252017637 0ustar0000000000000000-- Copyright 2020 United States Government as represented by the Administrator -- of the National Aeronautics and Space Administration. All Rights Reserved. -- -- Disclaimers -- -- No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY -- OF ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT -- LIMITED TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO -- SPECIFICATIONS, ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A -- PARTICULAR PURPOSE, OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE -- SUBJECT SOFTWARE WILL BE ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF -- PROVIDED, WILL CONFORM TO THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN -- ANY MANNER, CONSTITUTE AN ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR -- RECIPIENT OF ANY RESULTS, RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR -- ANY OTHER APPLICATIONS RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, -- GOVERNMENT AGENCY DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING -- THIRD-PARTY SOFTWARE, IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES -- IT "AS IS." -- -- Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST -- THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL AS -- ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS IN -- ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH USE, -- INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, RECIPIENT'S -- USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD HARMLESS THE -- UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL AS ANY -- PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. RECIPIENT'S SOLE REMEDY -- FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, UNILATERAL TERMINATION OF THIS -- AGREEMENT. -- -- | CLI interface to the CStructs2Copilot subcommand module CLI.CommandCStructs2Copilot ( -- * Direct command access command , CommandOpts , ErrorCode -- * CLI , commandDesc , commandOptsParser ) where -- External imports import Options.Applicative ( Parser, help, long, metavar, strOption ) -- External imports: command results import Command.Result ( Result ) -- External imports: actions or commands supported import Command.CStructs2Copilot ( ErrorCode, cstructs2Copilot ) -- * Command -- | A Copilot correspondence for a C struct can be generated by providing -- the path to the file that declares the struct. newtype CommandOpts = CommandOpts { cstructsFileName :: FilePath } -- | Generate Copilot struct definitions and instances from structs defined in -- a C header file. -- -- This is just an uncurried version of "Command.CStructs2Copilot". command :: CommandOpts -> IO (Result ErrorCode) command c = cstructs2Copilot (cstructsFileName c) -- * CLI -- | Command description for CLI help. commandDesc :: String commandDesc = "Generate Copilot structs from C structs" -- | Subparser for the @structs@ command, used to generate Copilot declarations -- from C structs. commandOptsParser :: Parser CommandOpts commandOptsParser = CommandOpts <$> strOption ( long "header-file-name" <> metavar "FILENAME" <> help strStructsHeaderArgDesc ) -- | Argument C header file to struct conversion command strStructsHeaderArgDesc :: String strStructsHeaderArgDesc = "C header file with struct definitions" ogma-cli-1.7.0/src/CLI/CommandCStructs2MsgHandlers.hs0000644000000000000000000000655514767604252020442 0ustar0000000000000000-- Copyright 2020 United States Government as represented by the Administrator -- of the National Aeronautics and Space Administration. All Rights Reserved. -- -- Disclaimers -- -- No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY -- OF ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT -- LIMITED TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO -- SPECIFICATIONS, ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A -- PARTICULAR PURPOSE, OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE -- SUBJECT SOFTWARE WILL BE ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF -- PROVIDED, WILL CONFORM TO THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN -- ANY MANNER, CONSTITUTE AN ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR -- RECIPIENT OF ANY RESULTS, RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR -- ANY OTHER APPLICATIONS RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, -- GOVERNMENT AGENCY DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING -- THIRD-PARTY SOFTWARE, IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES -- IT "AS IS." -- -- Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST -- THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL AS -- ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS IN -- ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH USE, -- INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, RECIPIENT'S -- USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD HARMLESS THE -- UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL AS ANY -- PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. RECIPIENT'S SOLE REMEDY -- FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, UNILATERAL TERMINATION OF THIS -- AGREEMENT. -- -- | CLI interface to the CStructs2Copilot subcommand module CLI.CommandCStructs2MsgHandlers ( -- * Direct command access command , CommandOpts , ErrorCode -- * CLI , commandDesc , commandOptsParser ) where -- External imports import Options.Applicative ( Parser, help, long, metavar, strOption ) -- External imports: command results import Command.Result ( Result ) -- External imports: actions or commands supported import Command.CStructs2MsgHandlers ( ErrorCode, cstructs2MsgHandlers ) -- * Command -- | Options to generate message handlers from C struct definitions. newtype CommandOpts = CommandOpts { msgHandlersFileName :: FilePath } -- | Generate C methods that process NASA Core Flight System messages dealing -- with the structs defined in a header file. -- -- This is just an uncurried version of "Command.CStructs2MsgHandlers". command :: CommandOpts -> IO (Result ErrorCode) command c = cstructs2MsgHandlers (msgHandlersFileName c) -- * CLI -- | Command description for CLI help. commandDesc :: String commandDesc = "Generate message handlers from C structs" -- | Subparser for the @handlers@ command, used to generate message handers -- from C structs. commandOptsParser :: Parser CommandOpts commandOptsParser = CommandOpts <$> strOption ( long "header-file-name" <> metavar "FILENAME" <> help strMsgHandlersHeaderArgDesc ) -- | Argument C header file to handler generation command strMsgHandlersHeaderArgDesc :: String strMsgHandlersHeaderArgDesc = "C header file with struct definitions" ogma-cli-1.7.0/src/CLI/CommandCFSApp.hs0000644000000000000000000001713114767604252015522 0ustar0000000000000000-- Copyright 2020 United States Government as represented by the Administrator -- of the National Aeronautics and Space Administration. All Rights Reserved. -- -- Disclaimers -- -- No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY -- OF ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT -- LIMITED TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO -- SPECIFICATIONS, ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A -- PARTICULAR PURPOSE, OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE -- SUBJECT SOFTWARE WILL BE ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF -- PROVIDED, WILL CONFORM TO THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN -- ANY MANNER, CONSTITUTE AN ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR -- RECIPIENT OF ANY RESULTS, RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR -- ANY OTHER APPLICATIONS RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, -- GOVERNMENT AGENCY DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING -- THIRD-PARTY SOFTWARE, IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES -- IT "AS IS." -- -- Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST -- THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL AS -- ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS IN -- ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH USE, -- INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, RECIPIENT'S -- USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD HARMLESS THE -- UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL AS ANY -- PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. RECIPIENT'S SOLE REMEDY -- FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, UNILATERAL TERMINATION OF THIS -- AGREEMENT. -- -- | CLI interface to the CFSApp subcommand. module CLI.CommandCFSApp ( -- * Direct command access command , CommandOpts , ErrorCode -- * CLI , commandDesc , commandOptsParser ) where -- External imports import Options.Applicative ( Parser, help, long, metavar, optional, short, showDefault, strOption, value ) -- External imports: command results import Command.Result ( Result ) -- External imports: actions or commands supported import Command.CFSApp ( ErrorCode ) import qualified Command.CFSApp -- * Command -- | Options needed to generate the cFS application. data CommandOpts = CommandOpts { cFSAppInputFile :: Maybe String , cFSAppTarget :: String , cFSAppTemplateDir :: Maybe String , cFSAppVarNames :: Maybe String , cFSAppVarDB :: Maybe String , cFSAppHandlers :: Maybe String , cFSAppFormat :: String , cFSAppPropFormat :: String , cFSAppPropVia :: Maybe String , cFSAppTemplateVars :: Maybe String } -- | Create (cFS) -- applications that subscribe to the communication bus and call Copilot when -- new messages arrive. -- -- This is just an uncurried version of "Command.CFSApp". command :: CommandOpts -> IO (Result ErrorCode) command c = Command.CFSApp.command options where options = Command.CFSApp.CommandOptions { Command.CFSApp.commandInputFile = cFSAppInputFile c , Command.CFSApp.commandTargetDir = cFSAppTarget c , Command.CFSApp.commandTemplateDir = cFSAppTemplateDir c , Command.CFSApp.commandVariables = cFSAppVarNames c , Command.CFSApp.commandVariableDB = cFSAppVarDB c , Command.CFSApp.commandHandlers = cFSAppHandlers c , Command.CFSApp.commandFormat = cFSAppFormat c , Command.CFSApp.commandPropFormat = cFSAppPropFormat c , Command.CFSApp.commandPropVia = cFSAppPropVia c , Command.CFSApp.commandExtraVars = cFSAppTemplateVars c } -- * CLI -- | cFS command description commandDesc :: String commandDesc = "Generate a complete cFS/Copilot application" -- | Subparser for the @cfs@ command, used to generate a NASA Core Flight -- System application connected to Copilot monitors. commandOptsParser :: Parser CommandOpts commandOptsParser = CommandOpts <$> optional ( strOption ( long "input-file" <> metavar "FILENAME" <> help strCFSAppFileNameArgDesc ) ) <*> strOption ( long "app-target-dir" <> metavar "DIR" <> showDefault <> value "copilot-cfs-demo" <> help strCFSAppDirArgDesc ) <*> optional ( strOption ( long "app-template-dir" <> metavar "DIR" <> help strCFSAppTemplateDirArgDesc ) ) <*> optional ( strOption ( long "variable-file" <> metavar "FILENAME" <> help strCFSAppVarListArgDesc ) ) <*> optional ( strOption ( long "variable-db" <> metavar "FILENAME" <> help strCFSAppVarDBArgDesc ) ) <*> optional ( strOption ( long "handlers-file" <> metavar "FILENAME" <> help strCFSAppHandlerListArgDesc ) ) <*> strOption ( long "input-format" <> short 'f' <> metavar "FORMAT_NAME" <> help strCFSAppFormatDesc <> showDefault <> value "fcs" ) <*> strOption ( long "prop-format" <> short 'p' <> metavar "FORMAT_NAME" <> help strCFSAppPropFormatDesc <> showDefault <> value "smv" ) <*> optional ( strOption ( long "parse-prop-via" <> metavar "COMMAND" <> help strCFSAppPropViaDesc ) ) <*> optional ( strOption ( long "template-vars" <> metavar "FILENAME" <> help strCFSAppTemplateVarsArgDesc ) ) -- | Argument target directory to cFS app generation command strCFSAppDirArgDesc :: String strCFSAppDirArgDesc = "Target directory" -- | Argument template directory to cFS app generation command strCFSAppTemplateDirArgDesc :: String strCFSAppTemplateDirArgDesc = "Directory holding cFS application source template" -- | Argument input file to CFS app generation command strCFSAppFileNameArgDesc :: String strCFSAppFileNameArgDesc = "File containing input specification" -- | Argument variable list to cFS app generation command strCFSAppVarListArgDesc :: String strCFSAppVarListArgDesc = "File containing list of cFS/ICAROUS variables to make accessible" -- | Argument variable database to cFS app generation command strCFSAppVarDBArgDesc :: String strCFSAppVarDBArgDesc = "File containing a DB of known cFS/ICAROUS variables" -- | Argument handler list to cFS app generation command strCFSAppHandlerListArgDesc :: String strCFSAppHandlerListArgDesc = "File containing list of Copilot handlers used in the specification" -- | Format flag description. strCFSAppFormatDesc :: String strCFSAppFormatDesc = "Format of the input file" -- | Property format flag description. strCFSAppPropFormatDesc :: String strCFSAppPropFormatDesc = "Format of temporal or boolean properties" -- | External command to pre-process individual properties. strCFSAppPropViaDesc :: String strCFSAppPropViaDesc = "Command to pre-process individual properties" -- | Argument template variables to cFS app generation command strCFSAppTemplateVarsArgDesc :: String strCFSAppTemplateVarsArgDesc = "JSON file containing additional variables to expand in template" ogma-cli-1.7.0/src/CLI/Result.hs0000644000000000000000000000557714767604252014440 0ustar0000000000000000-- Copyright 2020 United States Government as represented by the Administrator -- of the National Aeronautics and Space Administration. All Rights Reserved. -- -- Disclaimers -- -- No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY -- OF ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT -- LIMITED TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO -- SPECIFICATIONS, ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A -- PARTICULAR PURPOSE, OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE -- SUBJECT SOFTWARE WILL BE ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF -- PROVIDED, WILL CONFORM TO THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN -- ANY MANNER, CONSTITUTE AN ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR -- RECIPIENT OF ANY RESULTS, RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR -- ANY OTHER APPLICATIONS RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, -- GOVERNMENT AGENCY DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING -- THIRD-PARTY SOFTWARE, IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES -- IT "AS IS." -- -- Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST -- THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL AS -- ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS IN -- ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH USE, -- INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, RECIPIENT'S -- USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD HARMLESS THE -- UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL AS ANY -- PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. RECIPIENT'S SOLE REMEDY -- FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, UNILATERAL TERMINATION OF THIS -- AGREEMENT. -- -- | Process a result of a command in a way suitable for command-line -- interaction. module CLI.Result where -- External imports import System.Exit ( ExitCode (ExitFailure, ExitSuccess), exitWith ) import System.IO ( hPutStrLn, stderr ) -- External imports: command results import Command.Result ( Result (Error, Success) ) import Data.Location ( Location (..) ) {- HLINT ignore "Use exitSuccess" -} -- | Process a result, report any pending messages, and exit with an error code -- if necessary. processResult :: Result Int -> IO () processResult Success = exitWith ExitSuccess processResult (Error ec msg loc) = do hPutStrLn stderr $ showLocation loc ++ "error: " ++ msg exitWith (ExitFailure ec) where -- | Show locations in a standard way in user messages. showLocation :: Location -> String showLocation LocationNothing = ": " showLocation (LocationFile f) = f ++ ": " showLocation (LocationFileLine f l) = f ++ ":" ++ show l ++ ": " showLocation (LocationFileLC f l c) = f ++ ":" ++ show l ++ ":" ++ show c ++ ": "