last-svn-commit-63-g3395e22 First draft of the dematerialization wizard.
* demo/shared/icons/Symbols-Delete-icon.png, * demo/shared/icons/accept-icon.png, * demo/shared/icons/close.gif, * demo/shared/icons/crop-icon.png, * demo/shared/icons/image-add-icon.png, * demo/shared/icons/image-edit-icon.png, * demo/shared/icons/image-multi-icon.png, * demo/shared/icons/image-next-icon.png, * demo/shared/icons/image-remove-icon.png, * demo/shared/icons/next-icon.png, * demo/shared/icons/page-down-icon.png, * demo/shared/icons/page-search-icon.png, * demo/shared/icons/rotate_ccw.png, * demo/shared/icons/rotate_cw.png, * demo/shared/icons/search-add-icon.png, * demo/shared/icons/search-remove-icon.png, * demo/shared/shared.qrc, * demo/shared/src/bak/crop_item.cc, * demo/shared/src/bak/crop_item.hh, * demo/shared/src/bak/image_viewer.cc, * demo/shared/src/bak/image_viewer.hh, * demo/shared/src/bak/types.hh, * demo/shared/src/browse_widget.cc, * demo/shared/src/browse_widget.hh, * demo/shared/src/crop_item.cc, * demo/shared/src/crop_item.hh, * demo/shared/src/image_viewer.cc, * demo/shared/src/image_viewer.hh, * demo/shared/src/internal.bak/interactive_scene.cc, * demo/shared/src/internal.bak/interactive_scene.hh, * demo/shared/src/internal.bak/selection_rectangle.cc, * demo/shared/src/internal.bak/selection_rectangle.hh, * demo/shared/src/internal/interactive_scene.cc, * demo/shared/src/internal/interactive_scene.hh, * demo/shared/src/internal/selection_rectangle.cc, * demo/shared/src/internal/selection_rectangle.hh, * demo/shared/src/to_mln_image.hh, * demo/shared/src/types.hh, * demo/shared/ui/browse_widget.ui, * demo/shared/ui/crop_widget.ui, * demo/shared/ui/image_viewer.ui, * demo/shared/ui/interactive_scene.cc, * demo/shared/ui/interactive_scene.hh, * demo/shared/ui/rotate_widget.ui, * demo/wizard/images/dematerialization.png, * demo/wizard/src/crop_page.cc, * demo/wizard/src/crop_page.hh, * demo/wizard/src/crop_widget.cc, * demo/wizard/src/crop_widget.hh, * demo/wizard/src/doc_type.hh, * demo/wizard/src/doc_type_page.cc, * demo/wizard/src/doc_type_page.hh, * demo/wizard/src/doc_type_widget.cc, * demo/wizard/src/doc_type_widget.hh, * demo/wizard/src/load_page.cc, * demo/wizard/src/load_page.hh, * demo/wizard/src/load_widget.cc, * demo/wizard/src/load_widget.hh, * demo/wizard/src/main.cc, * demo/wizard/src/main_window.cc, * demo/wizard/src/main_window.hh, * demo/wizard/src/mln_widgets.cc, * demo/wizard/src/preprocessing_page.cc, * demo/wizard/src/preprocessing_page.hh, * demo/wizard/src/preprocessing_task.hh, * demo/wizard/src/preprocessing_widget.cc, * demo/wizard/src/preprocessing_widget.hh, * demo/wizard/src/process_page.cc, * demo/wizard/src/process_page.hh, * demo/wizard/src/process_widget.cc, * demo/wizard/src/process_widget.hh, * demo/wizard/src/rotate_page.cc, * demo/wizard/src/rotate_page.hh, * demo/wizard/src/rotate_widget.cc, * demo/wizard/src/rotate_widget.hh, * demo/wizard/src/runner.cc, * demo/wizard/src/runner.hh, * demo/wizard/src/test.cc, * demo/wizard/ui/doc_type_widget.ui, * demo/wizard/ui/load_widget.ui, * demo/wizard/ui/main_window.ui, * demo/wizard/ui/preprocessing_widget.ui, * demo/wizard/wizard.pro, * demo/wizard/wizard.qrc: New. --- scribo/ChangeLog | 89 +++++ scribo/demo/shared/icons/Symbols-Delete-icon.png | Bin 0 -> 3704 bytes scribo/demo/shared/icons/accept-icon.png | Bin 0 -> 4858 bytes scribo/demo/shared/icons/close.gif | Bin 0 -> 340 bytes scribo/demo/shared/icons/crop-icon.png | Bin 0 -> 228 bytes scribo/demo/shared/icons/image-add-icon.png | Bin 0 -> 2917 bytes scribo/demo/shared/icons/image-edit-icon.png | Bin 0 -> 2305 bytes scribo/demo/shared/icons/image-multi-icon.png | Bin 0 -> 2033 bytes scribo/demo/shared/icons/image-next-icon.png | Bin 0 -> 3008 bytes scribo/demo/shared/icons/image-remove-icon.png | Bin 0 -> 3127 bytes scribo/demo/shared/icons/next-icon.png | Bin 0 -> 4611 bytes scribo/demo/shared/icons/page-down-icon.png | Bin 0 -> 3450 bytes scribo/demo/shared/icons/page-search-icon.png | Bin 0 -> 3101 bytes scribo/demo/shared/icons/rotate_ccw.png | Bin 0 -> 4200 bytes scribo/demo/shared/icons/rotate_cw.png | Bin 0 -> 4161 bytes scribo/demo/shared/icons/search-add-icon.png | Bin 0 -> 4274 bytes scribo/demo/shared/icons/search-remove-icon.png | Bin 0 -> 4196 bytes scribo/demo/shared/shared.qrc | 20 ++ scribo/demo/shared/src/bak/crop_item.cc | 332 +++++++++++++++++++ scribo/demo/shared/src/bak/crop_item.hh | 100 ++++++ scribo/demo/shared/src/bak/image_viewer.cc | 242 ++++++++++++++ scribo/demo/shared/src/bak/image_viewer.hh | 116 +++++++ scribo/demo/shared/src/bak/types.hh | 50 +++ scribo/demo/shared/src/browse_widget.cc | 72 ++++ scribo/demo/shared/src/browse_widget.hh | 78 +++++ scribo/demo/shared/src/crop_item.cc | 313 ++++++++++++++++++ scribo/demo/shared/src/crop_item.hh | 103 ++++++ scribo/demo/shared/src/image_viewer.cc | 344 ++++++++++++++++++++ scribo/demo/shared/src/image_viewer.hh | 135 ++++++++ .../shared/src/internal.bak/interactive_scene.cc | 286 ++++++++++++++++ .../shared/src/internal.bak/interactive_scene.hh | 108 ++++++ .../shared/src/internal.bak/selection_rectangle.cc | 241 ++++++++++++++ .../shared/src/internal.bak/selection_rectangle.hh | 91 +++++ .../demo/shared/src/internal/interactive_scene.cc | 87 +++++ .../demo/shared/src/internal/interactive_scene.hh | 84 +++++ .../shared/src/internal/selection_rectangle.cc | 241 ++++++++++++++ .../shared/src/internal/selection_rectangle.hh | 91 +++++ scribo/demo/shared/src/to_mln_image.hh | 77 +++++ scribo/demo/shared/src/types.hh | 50 +++ scribo/demo/shared/ui/browse_widget.ui | 106 ++++++ scribo/demo/shared/ui/crop_widget.ui | 34 ++ scribo/demo/shared/ui/image_viewer.ui | 284 ++++++++++++++++ scribo/demo/shared/ui/interactive_scene.cc | 143 ++++++++ scribo/demo/shared/ui/interactive_scene.hh | 87 +++++ scribo/demo/shared/ui/rotate_widget.ui | 34 ++ scribo/demo/wizard/images/dematerialization.png | Bin 0 -> 76309 bytes scribo/demo/wizard/src/crop_page.cc | 48 +++ scribo/demo/wizard/src/crop_page.hh | 60 ++++ scribo/demo/wizard/src/crop_widget.cc | 37 ++ scribo/demo/wizard/src/crop_widget.hh | 62 ++++ scribo/demo/wizard/src/doc_type.hh | 51 +++ scribo/demo/wizard/src/doc_type_page.cc | 48 +++ scribo/demo/wizard/src/doc_type_page.hh | 61 ++++ scribo/demo/wizard/src/doc_type_widget.cc | 38 +++ scribo/demo/wizard/src/doc_type_widget.hh | 64 ++++ scribo/demo/wizard/src/load_page.cc | 70 ++++ scribo/demo/wizard/src/load_page.hh | 67 ++++ scribo/demo/wizard/src/load_widget.cc | 56 ++++ scribo/demo/wizard/src/load_widget.hh | 64 ++++ scribo/demo/wizard/src/main.cc | 15 + scribo/demo/wizard/src/main_window.cc | 129 ++++++++ scribo/demo/wizard/src/main_window.hh | 70 ++++ scribo/demo/wizard/src/mln_widgets.cc | 7 + scribo/demo/wizard/src/preprocessing_page.cc | 61 ++++ scribo/demo/wizard/src/preprocessing_page.hh | 66 ++++ scribo/demo/wizard/src/preprocessing_task.hh | 61 ++++ scribo/demo/wizard/src/preprocessing_widget.cc | 87 +++++ scribo/demo/wizard/src/preprocessing_widget.hh | 65 ++++ scribo/demo/wizard/src/process_page.cc | 73 ++++ scribo/demo/wizard/src/process_page.hh | 64 ++++ scribo/demo/wizard/src/process_widget.cc | 80 +++++ scribo/demo/wizard/src/process_widget.hh | 71 ++++ scribo/demo/wizard/src/rotate_page.cc | 45 +++ scribo/demo/wizard/src/rotate_page.hh | 60 ++++ scribo/demo/wizard/src/rotate_widget.cc | 38 +++ scribo/demo/wizard/src/rotate_widget.hh | 62 ++++ scribo/demo/wizard/src/runner.cc | 279 ++++++++++++++++ scribo/demo/wizard/src/runner.hh | 84 +++++ scribo/demo/wizard/src/test.cc | 16 + scribo/demo/wizard/ui/doc_type_widget.ui | 115 +++++++ scribo/demo/wizard/ui/load_widget.ui | 110 +++++++ scribo/demo/wizard/ui/main_window.ui | 216 ++++++++++++ scribo/demo/wizard/ui/preprocessing_widget.ui | 223 +++++++++++++ scribo/demo/wizard/wizard.pro | 67 ++++ scribo/demo/wizard/wizard.qrc | 5 + 85 files changed, 6933 insertions(+), 0 deletions(-) create mode 100644 scribo/demo/shared/icons/Symbols-Delete-icon.png create mode 100644 scribo/demo/shared/icons/accept-icon.png create mode 100644 scribo/demo/shared/icons/close.gif create mode 100644 scribo/demo/shared/icons/crop-icon.png create mode 100644 scribo/demo/shared/icons/image-add-icon.png create mode 100644 scribo/demo/shared/icons/image-edit-icon.png create mode 100644 scribo/demo/shared/icons/image-multi-icon.png create mode 100644 scribo/demo/shared/icons/image-next-icon.png create mode 100644 scribo/demo/shared/icons/image-remove-icon.png create mode 100644 scribo/demo/shared/icons/next-icon.png create mode 100644 scribo/demo/shared/icons/page-down-icon.png create mode 100644 scribo/demo/shared/icons/page-search-icon.png create mode 100644 scribo/demo/shared/icons/rotate_ccw.png create mode 100644 scribo/demo/shared/icons/rotate_cw.png create mode 100644 scribo/demo/shared/icons/search-add-icon.png create mode 100644 scribo/demo/shared/icons/search-remove-icon.png create mode 100644 scribo/demo/shared/shared.qrc create mode 100644 scribo/demo/shared/src/bak/crop_item.cc create mode 100644 scribo/demo/shared/src/bak/crop_item.hh create mode 100644 scribo/demo/shared/src/bak/image_viewer.cc create mode 100644 scribo/demo/shared/src/bak/image_viewer.hh create mode 100644 scribo/demo/shared/src/bak/types.hh create mode 100644 scribo/demo/shared/src/browse_widget.cc create mode 100644 scribo/demo/shared/src/browse_widget.hh create mode 100644 scribo/demo/shared/src/crop_item.cc create mode 100644 scribo/demo/shared/src/crop_item.hh create mode 100644 scribo/demo/shared/src/image_viewer.cc create mode 100644 scribo/demo/shared/src/image_viewer.hh create mode 100644 scribo/demo/shared/src/internal.bak/interactive_scene.cc create mode 100644 scribo/demo/shared/src/internal.bak/interactive_scene.hh create mode 100644 scribo/demo/shared/src/internal.bak/selection_rectangle.cc create mode 100644 scribo/demo/shared/src/internal.bak/selection_rectangle.hh create mode 100644 scribo/demo/shared/src/internal/interactive_scene.cc create mode 100644 scribo/demo/shared/src/internal/interactive_scene.hh create mode 100644 scribo/demo/shared/src/internal/selection_rectangle.cc create mode 100644 scribo/demo/shared/src/internal/selection_rectangle.hh create mode 100644 scribo/demo/shared/src/to_mln_image.hh create mode 100644 scribo/demo/shared/src/types.hh create mode 100644 scribo/demo/shared/ui/browse_widget.ui create mode 100644 scribo/demo/shared/ui/crop_widget.ui create mode 100644 scribo/demo/shared/ui/image_viewer.ui create mode 100644 scribo/demo/shared/ui/interactive_scene.cc create mode 100644 scribo/demo/shared/ui/interactive_scene.hh create mode 100644 scribo/demo/shared/ui/rotate_widget.ui create mode 100644 scribo/demo/wizard/images/dematerialization.png create mode 100644 scribo/demo/wizard/src/crop_page.cc create mode 100644 scribo/demo/wizard/src/crop_page.hh create mode 100644 scribo/demo/wizard/src/crop_widget.cc create mode 100644 scribo/demo/wizard/src/crop_widget.hh create mode 100644 scribo/demo/wizard/src/doc_type.hh create mode 100644 scribo/demo/wizard/src/doc_type_page.cc create mode 100644 scribo/demo/wizard/src/doc_type_page.hh create mode 100644 scribo/demo/wizard/src/doc_type_widget.cc create mode 100644 scribo/demo/wizard/src/doc_type_widget.hh create mode 100644 scribo/demo/wizard/src/load_page.cc create mode 100644 scribo/demo/wizard/src/load_page.hh create mode 100644 scribo/demo/wizard/src/load_widget.cc create mode 100644 scribo/demo/wizard/src/load_widget.hh create mode 100644 scribo/demo/wizard/src/main.cc create mode 100644 scribo/demo/wizard/src/main_window.cc create mode 100644 scribo/demo/wizard/src/main_window.hh create mode 100644 scribo/demo/wizard/src/mln_widgets.cc create mode 100644 scribo/demo/wizard/src/preprocessing_page.cc create mode 100644 scribo/demo/wizard/src/preprocessing_page.hh create mode 100644 scribo/demo/wizard/src/preprocessing_task.hh create mode 100644 scribo/demo/wizard/src/preprocessing_widget.cc create mode 100644 scribo/demo/wizard/src/preprocessing_widget.hh create mode 100644 scribo/demo/wizard/src/process_page.cc create mode 100644 scribo/demo/wizard/src/process_page.hh create mode 100644 scribo/demo/wizard/src/process_widget.cc create mode 100644 scribo/demo/wizard/src/process_widget.hh create mode 100644 scribo/demo/wizard/src/rotate_page.cc create mode 100644 scribo/demo/wizard/src/rotate_page.hh create mode 100644 scribo/demo/wizard/src/rotate_widget.cc create mode 100644 scribo/demo/wizard/src/rotate_widget.hh create mode 100644 scribo/demo/wizard/src/runner.cc create mode 100644 scribo/demo/wizard/src/runner.hh create mode 100644 scribo/demo/wizard/src/test.cc create mode 100644 scribo/demo/wizard/ui/doc_type_widget.ui create mode 100644 scribo/demo/wizard/ui/load_widget.ui create mode 100644 scribo/demo/wizard/ui/main_window.ui create mode 100644 scribo/demo/wizard/ui/preprocessing_widget.ui create mode 100644 scribo/demo/wizard/wizard.pro create mode 100644 scribo/demo/wizard/wizard.qrc diff --git a/scribo/ChangeLog b/scribo/ChangeLog index 87985ff..49df10a 100644 --- a/scribo/ChangeLog +++ b/scribo/ChangeLog @@ -1,5 +1,94 @@ 2010-03-11 Guillaume Lazzara <z@lrde.epita.fr> + First draft of the dematerialization wizard. + + * demo/shared/icons/Symbols-Delete-icon.png, + * demo/shared/icons/accept-icon.png, + * demo/shared/icons/close.gif, + * demo/shared/icons/crop-icon.png, + * demo/shared/icons/image-add-icon.png, + * demo/shared/icons/image-edit-icon.png, + * demo/shared/icons/image-multi-icon.png, + * demo/shared/icons/image-next-icon.png, + * demo/shared/icons/image-remove-icon.png, + * demo/shared/icons/next-icon.png, + * demo/shared/icons/page-down-icon.png, + * demo/shared/icons/page-search-icon.png, + * demo/shared/icons/rotate_ccw.png, + * demo/shared/icons/rotate_cw.png, + * demo/shared/icons/search-add-icon.png, + * demo/shared/icons/search-remove-icon.png, + * demo/shared/shared.qrc, + * demo/shared/src/bak/crop_item.cc, + * demo/shared/src/bak/crop_item.hh, + * demo/shared/src/bak/image_viewer.cc, + * demo/shared/src/bak/image_viewer.hh, + * demo/shared/src/bak/types.hh, + * demo/shared/src/browse_widget.cc, + * demo/shared/src/browse_widget.hh, + * demo/shared/src/crop_item.cc, + * demo/shared/src/crop_item.hh, + * demo/shared/src/image_viewer.cc, + * demo/shared/src/image_viewer.hh, + * demo/shared/src/internal.bak/interactive_scene.cc, + * demo/shared/src/internal.bak/interactive_scene.hh, + * demo/shared/src/internal.bak/selection_rectangle.cc, + * demo/shared/src/internal.bak/selection_rectangle.hh, + * demo/shared/src/internal/interactive_scene.cc, + * demo/shared/src/internal/interactive_scene.hh, + * demo/shared/src/internal/selection_rectangle.cc, + * demo/shared/src/internal/selection_rectangle.hh, + * demo/shared/src/to_mln_image.hh, + * demo/shared/src/types.hh, + * demo/shared/ui/browse_widget.ui, + * demo/shared/ui/crop_widget.ui, + * demo/shared/ui/image_viewer.ui, + * demo/shared/ui/interactive_scene.cc, + * demo/shared/ui/interactive_scene.hh, + * demo/shared/ui/rotate_widget.ui, + * demo/wizard/images/dematerialization.png, + * demo/wizard/src/crop_page.cc, + * demo/wizard/src/crop_page.hh, + * demo/wizard/src/crop_widget.cc, + * demo/wizard/src/crop_widget.hh, + * demo/wizard/src/doc_type.hh, + * demo/wizard/src/doc_type_page.cc, + * demo/wizard/src/doc_type_page.hh, + * demo/wizard/src/doc_type_widget.cc, + * demo/wizard/src/doc_type_widget.hh, + * demo/wizard/src/load_page.cc, + * demo/wizard/src/load_page.hh, + * demo/wizard/src/load_widget.cc, + * demo/wizard/src/load_widget.hh, + * demo/wizard/src/main.cc, + * demo/wizard/src/main_window.cc, + * demo/wizard/src/main_window.hh, + * demo/wizard/src/mln_widgets.cc, + * demo/wizard/src/preprocessing_page.cc, + * demo/wizard/src/preprocessing_page.hh, + * demo/wizard/src/preprocessing_task.hh, + * demo/wizard/src/preprocessing_widget.cc, + * demo/wizard/src/preprocessing_widget.hh, + * demo/wizard/src/process_page.cc, + * demo/wizard/src/process_page.hh, + * demo/wizard/src/process_widget.cc, + * demo/wizard/src/process_widget.hh, + * demo/wizard/src/rotate_page.cc, + * demo/wizard/src/rotate_page.hh, + * demo/wizard/src/rotate_widget.cc, + * demo/wizard/src/rotate_widget.hh, + * demo/wizard/src/runner.cc, + * demo/wizard/src/runner.hh, + * demo/wizard/src/test.cc, + * demo/wizard/ui/doc_type_widget.ui, + * demo/wizard/ui/load_widget.ui, + * demo/wizard/ui/main_window.ui, + * demo/wizard/ui/preprocessing_widget.ui, + * demo/wizard/wizard.pro, + * demo/wizard/wizard.qrc: New. + +2010-03-11 Guillaume Lazzara <z@lrde.epita.fr> + Update examples. * src/text_in_photo_ppm_fast.cc, diff --git a/scribo/demo/shared/icons/Symbols-Delete-icon.png b/scribo/demo/shared/icons/Symbols-Delete-icon.png new file mode 100644 index 0000000000000000000000000000000000000000..3f374398c89a8bd9aaec5b75c0491aced878158e GIT binary patch literal 3704 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 WXc3Fm>%r#$0000<MNUMnLSTX@gB?=< literal 0 HcmV?d00001 diff --git a/scribo/demo/shared/icons/accept-icon.png b/scribo/demo/shared/icons/accept-icon.png new file mode 100644 index 0000000000000000000000000000000000000000..d929648067dcd98708664950e394aa11dae289bd GIT binary patch literal 4858 zcmV<W5(VvvP)<h;3K|Lk000e1NJLTq001xm001xu1^@s6R|5Hm000ufNkl<Zc-p;M z36xV+n*Q(0d&$dMSt==NUn!QND0T)^Kmqp+MWg{a(jIMT9kI1_#<AT7nLg7_&yiMI z9mk_*rd>gxRkRUMK&L?vlzpo`m0D7jN~lzlm%Qc9e_txaQdKBw_pOu4eaU<G{ont8 z|8`#p`~;(+sllkI$|yN0*KoX{Qc1}pK%-8M<Ls1D&@?Ry97GI)a6(m-le|$lz#I5u z!^<jCKla|_2Mg_Q6qBjsL^Y`_G784I7PGm)B#NTZXas}7Ku~zLIA!<H5CqjUDk};} zC6hEENm4u>Z^7%ga3cQ}UbAmxX{Gdc0Z`jq&nFYod>#xd91h16o6SZ{CKD6-ob%#J z0z!#yeeN;4!NQySzhhQW6a^BA1Vnp!=;@x*dt|DvHd@7XW6DP<e-i-pEsY#1ZWga` z&%533F?PEh1VKRUYH+H%k?!>GCtvsvz}M}EX+xxgBo$4UHFFOW&(Tt64w*D;3|v-N zLuV9DAj91y_$2{cm!6J9AQTE6P8rk(MYDN(RoO`GCj)Sz@svwV$gA8=*D|NeWnzNI z<T(APZU=ew+l{cd?Ii7$rOaB?z;T2LMhMXXFpc9MRW*%dY+w`2WO8mL+&%7QxW0TA zweTWg772BANufyh>zqY+eEf*9;U5j)$jPJSCWG-^U$%FG#cE|j!Mc;1Vbx#XfP=vX zTtOEU940H+jTW#7A_xWnc;*9y>l0T4Mbki5Wr)iXL{o9-Nyc<4;XfGbD}~3W-3jwY zTm`DCLL?l9j?UnINlo59xn@$`4+e0w_V{!wFTR&EY*;>X&ZeFK-2Io8bZgVM>^dq6 zMv`rDg3Iin0>|rXQPeksl;+PMbDEwjs!GCA4|K&NAjv6aA~L6B9K3q<6ST;lM|yjE zp*0W)^eTx3lgCc{>qP@NhQixT*7aVW&&TsT`M7=uEZ_PZv_wNxz+<1)MLlLGLAtP2 z&Io!w0CGlXLeB-mEP%8^XOGZeEKD#;L4nOfUz+;}xwdR3#A7kq+SVFGYuz#w2r`85 z<yNC*M@~*o9tsbCI`#qla_jFQrli1bvOu9D2c6QGzM7o161mW-kap?J`+2V<uI-O@ zKr|T#D{q1|vmb^#M&H0dKub$YYp)WYIeF|rIt{p0oxk42DP&7tUfx6|{Qn;NfG*qo zTV1JMq)VRNOPP;Srghy@&uCi5pj#tt0>TImX-}p)<C)gebLg{%krOb{r75MU8npIy z($089zx4I19;0`Rx>2W7v%h(tBG9?#JN7vM{Ov7VA{u`&FE{UAi^W1VA#E0Z`~;1w zGRd)dV3^Gfgd=@|Q;Il<0ap<4Zakag8U}I(4D<m=&zLI{qT(kC^8w0~z`=^Ki$Ua! z^to@}BnfnI2BtmQO*(o*m^%de&b2GawWTvybfW&&mY2mW>-}ek*mD4!YO1}$Wy#v) za=T5<(N>tT_8#!ZLg2HxnCA6p!*LXtyP9<Eq3}3of^&Up=h9XfU|OvY4zq?v)34b@ zv*3Z6JMmf$J_~#ePw#sbVkrr;Higz`Cj@)LP+;}I7YqIi@+~>csgvk0*G(Kf{<8r9 zQ2RW_`u+I@1=Uyv(5p8tCtCvFf?c%Ga%aBotR_6$j2bqg>Un%e?duj`TGxZ74kGQK z`og5o0`v@p(!x_(=^9BMoAPTg^P+AYX0(H$Q}F1n)wEOUAy_{_T_ixGQk=}m9|xP~ zy+pD6AdL+Thlov>Fs3Y>vHJnkHq<TjdAx61G1jlE+e~lY{4^1G0}OW+(k#J5EKKXD zUM4t?(xMg8063;~Mkh!EfIi<yFRmlVxGoB>`-8*iq>oR1ig?Xl$j~dpx)b3>`t;s4 zq#hl*S5DGX5kHY-72dt-X?kn<l_c2F0qxzvpG~M9|4u)EwqTo>N+dte&o7u7R}*mQ z`k%wWa3d5UZAz_J$MjJ}NCUtm1v-sb1Z5ULw}3w3```8d{i4(UfWr|1?izDH)MQT_ zDuTo2=3TII&kMLX56!V|4BeeD)>R5$-ufCC6b|a^>%J1~;^iYtD%0t|IpDv<Zn5pm z%F5#2KD7xJZ+nJ1jV3a|T?`fjhm--50f2|-uuSueLTTFIOLu6luYAblflM_@;f$g$ zE4UJFDqqyE@$)Uv9`B}CtY1MyE(W<)D~+le`KG%Gt&yT{&VGt4thfdOEiGCk8J#h< za?Jnf7d13AtiiCk+`t>il^^{A_6HBpa$63`x44+2rU4kz&Wn`MDP+(ogzm>28@Rs6 z!{#Wjj(}t$et+`HvlWrMsvick!7?ZSMN?tnU!I`{JNJ<Z*)EVZLNP}Ze=H2Oy&ZJ2 zuZC>B;T5c4qqM2H>7{Ws<L)CJ9qmS}KaS+&3@bl%x}MD5xD2Mcd#FN26A?{lL`@3@ z<a{4(cm_ZhoTK`GCUj=r7hls(oc3MPX8{9epeQ`avlXAC@eBZV;R^@W!?Sx{rdJnw z^_7wOG^G)eP!(({j?vv=2l-;&>riSbps4gZLFB7QTU%?5XcBihva-ZKomdB}_WTYO zln_Wl8FVBBo$pNh0^W}mXsC7l#p&;c^qlFP=s^0sm-O?V>7IQztMGc5o;P<$-tTTd z3fF)52wY#}0GpA=;*TN#0x68Y!^|=mXalTm)ZmG!kHXRsw*r<)QbJBlBmU;*r5=yx z4eX}ip)Y<z_O*WkHx=2b+2|ohA{Jc&frU*jEi6xXq!7<E+(#i!50sjw5?M=uqNb>d z_QT>?=M95X;3$V*jDLcf3?ez7^K68q9y)i!L&PUWpxSN6B&QO+deuNr_+wmHy-MBm z&&^RXCHES5e#T0Qi48isf_I_?+E!tM@-J96&}%o&BNna^uE@`!X2C+bl03A=%?JQ> zofaPJpi(+1=TfqzaU*6{nWV7ulCU>WX{xV$AZKM_29hT~ulZ*vb5`{WeLjGH+_9Q| z-n@<6RFaDcPsOzmfL?;DG|wy%uc%=8ouHouI*3GzF(+)G(P)%l^!zvC_xs<=&CQ+9 z)|>M7G^lY&Fgd3H>B8&cv`ZF@0A~G|0a!F@Ip&5cI37L*Zyo**6h7KVrwoNywkG|d zbPCeun(`$uRE4*#Wk1}u>7U@9(Zj)pwU<H_Cb<4?;}ei;PUtjDq95#T55S?Y3HC4E z1rjzt^^NuGNOM!umc0D@IY~{Tv)0ZeQ?gSqHoF+RDuaGUq#_MUZq$ewiX9cOv}%R! zuuO}mA}7fDV{5QU3HOCm<{M`$U^lwxUE}|in0ebdTF=Zo6A`%l{S{DV?WQB0c49L* zk&XuJ+*Gu99JwE%8C}S#M!)H7CVRUC`11DclqejjtF7HiuvFcR7MR)|5765_nx_L8 z?J3pc`k5lkK%z=6+&ug~D9ak9-#jBkpw|!YAA5nu<*sx{#jiLW0S9wRme6Y7WdmrF zjyi<=YUc~^X~QPCvB;?l&FUqa=%!X4h|}1Kp+W7x2A!H7>S`iihj@7Zh7B~E_maB0 zx~~W(h27Y3O$jDiVbLcy!vvQMBR!=93_i>@2Cl7G31ko|oK8hx!-*HMmT!T+ya2iO za=3B$19;32k!|<Fou57lOUtt{FMv)P86Dq1x?z}A1*_mV=X`_$heM5UpqqzxuG;_} z-isNzeh-U6TXOUAbPC=4!3<KBCBrCpiQbrJw3Sq%<Qf#d%ymh>CePPsG}S}4HU1BT z;wLdm3FNBs<tRwSppJ_@F`e@6J!Fzcfohi(>49-eOJSkc0z9<q{YI9U2O{t2zlKrh zP^gI<@8RLYn|4x8HKZwo7GOQ^ZA_+lA5J4h7741{1(>`9Jpn1IM7!gSq$q0|%p0{D zYjpdd0N6Y($KebAI~419a!KLh{)lw;IgCBO+5H;b-0)|zba+0nZJDIfNoA!0&x`e+ z$6=0fTS_R8p_eU?RAhQE6d)~eBYbevZYoI<X>4p*i<!7%mD}Zdj58SEm)mXysy0Hk z$BXFA`ffsZq6tz;TsNcFHVKwgzl`S18Zsd<fl`_TqQNrg_XoP_;L43F;L)*pSe}Qm z{%=C<4!(P0<SpPf7wfwlF>H1YggU`sD1=w$Y=9WHn(e{1-;zL}WvSckd4ugbtp4UH zaxnNQn$<)dCKrjNx{%kw{(6Ru9NQGSpz3+zFlG-*j|<INf|~cy<Dkkr=nP*ByE6$c zbPYSSn|#D-%*Mw5G(8fIlW{p$!GjZ?q2X{CI$0v?2zJz%Me{D~1H>)O8^~Kn{{R*C z1oc_HBowO$Rg(wQEk64svao6m%`$l|3c%Xh?d0JdPr{w$9hjBrpw;O4a|8O5+foLB z-Y(kEYa~lXuYfCyZ=vmNZRt{?v$NBPb-)o%c6NE7w-KJ*^#IuUR>-vo5Ko1Mq>9Tj z3Kmzt22PU~zR!rt38;B%Da`a9hjQD+?c<6<HnhZKh^an!YWj<qABv!<si{sdVKK)} zXle1U!D@6l^ZtL|^K0x!_fwD1hV>5}v~tWiakjOZ+&20}@R;*1XaTl6{RBGhN42kz zTZ$rj2RBqdFd$!`2S^$R-KiW};Fv%joBDf*#}m}=Z+>a?=&JkDO+>KmQk%uT!(y>; zyIZ%yn@9gZ9fo>hHl*}rh62Fe-DrsgRj<%&bMBA;PK5n%*}8k^($WS@Q0kCM8EmfM zQB)BjrWMg8RS%Nsd2;{*j~0`nGb&0e(+y3iyGu+Z<<EUS-_#_wl>fQ+Q8=AAh6x7a zGWqUJV!K!Zi>luMuQ`9fcdQ^?ym=)Adp5$XoajYShs6#_<shNugVQ_`9+~nSmem3@ zH8y@F+Dw-h<(KsDC__uYztH3Iyv@q$eeK)n+GBsjI<gKM`DlMVGMEK2pE=FL$^6l4 zFnN`p^ZCx!gJjVszk;P@Em$JZL95ZBEWpa?gzCV2R06k+x}Q!OHj}XE(}hj_$jZ@Y zntC?6LP1_msr%6iW7zSl2cCvN&mk=Ik7HLRe=mJyiDfXq>J{u|OZq>XwSEOSxg9Xc z9lI#qvlcC`3RsF%LV=?i?j8RO$g&L0&CQ2RR$)SMe(AZ}Dr~g22d=PN?3*lBt0^o6 z$s32Bh2CU67FxB0<>hpvMTgA9Y;G2Y(c8zoP73T5u=dn;`p}NY$g+wq?C6G!^#d%x z?vzBw<+yU{FqV*IHBW-e<fUDmoyn-wbKUUL5d$~2*a(HYxI`@RqSx!Ymp#Nd7TOCR z*Zwz6$n``~oAoV~j8k98@oc6-GQ0eDaL1NE(s7QxWVj=Fp=5Q=F)QCw8Ws|UBCzr$ z^t$19lhN6ep*I?(t!;sqty$Ll3v-JH-&$m&qpRHoDs1t1vL~`N4+MA69nEi%gxmxP zxe?eyrSAg3<|)kz+uJ!hH#bVow%mmPuwA>P%25%uZV?LM@}fm_T+S@QsDl;5K7*0W zEh#J?dUN-TLpPU;Cd&?|)0xNabGUOS>~39;bxR9`6UWgKa(d6<CmgI?mZ=e(VkOv3 z1u!lDR;c#Q&>se3)@@BH(#*<=k>9<&o*98w|8%oxS?_RU`IvU<Bj3Ot1ksZW&|vH+ zQMCx=^<wk;ml6Xj)AYuXtZ~#}a1tNp6o)C7PR*ZB%AMnx@U$}+3}VlHOGVj;@Be_K zA4Hpfx=Ap<hnC1^&wWoPJK;<Jo3tz5Ku#xHXm_F(4Uu5mi~XVY`vPE&s%Qi>V#Z8f zPF-RF@mNaWvce@;V|jJjV8RN>inO4-tn%U?F`Z2(fj7O2ASSQ}9&FTx_rQ^^ZP1(Q zgws+hvkFK`H!i01Z?B)dc!q50ooN&r+ZIu9qqg(GCFWvz?u9DvY#8pEqMyf}R(5rD z?pHMV_KLE~AO4UpGlJ;YDM?<H<;YsbLagqjYJxWP93*w!yAePeO{u*kCPyHlM6iSF zB{KE|8Wzy(9;~h8Igy%p8?o?Cun10SG+2qllm`{=e}H1gSSoO$zNLOT5|JXO!>@}L z)8hqs#XtTrYi4v~h)t$av(V<xJF~K?jV4onhZUAuX-BM<gs}NRdeJ0;F{B@{_Vp4J zos^=`HsZCEB4vtcj<tfgux(_lLc#UD|L#!e5Mq7MWHN0Z=F9u(9(12QLfxIbBqir# zq+VgS+o#~o^xs9CKbQsLa*sZ@V1tet9&iqeFeo^U_Vn!0KwT}G#dRq7-{z+V1A&A@ zMUf}TDdlHIL6|F=%>|hJL>^mH(zhW1`ooU2mDpTWRia{KNhXt0LXuii$>bKnB)lyM z{MSD3u)oibJq8=-a7LuTD2yC6JTFu#vOEHhU1%8_E9f;<jUuQp27wd!-ATbH9Khpa gIli19{d1fD2Od*Arpnv=egFUf07*qoM6N<$f;XF01^@s6 literal 0 HcmV?d00001 diff --git a/scribo/demo/shared/icons/close.gif b/scribo/demo/shared/icons/close.gif new file mode 100644 index 0000000000000000000000000000000000000000..ffcb2e60d537a5d0eb501d622f58b7039dac1bd1 GIT binary patch literal 340 zcmZ?wbhEHb<Y(Y#xXQqAl1+RIhs0J+@vWSaTR0^*afu%?bv$J1bjaN0UV7pA#O(Xo zrGGzu`uF+EV+N^543ZBSrMGZOKT|Y+rfT)l+W(bZ(3_CdYgNskuiyG|^UjxBcYlBU z^yl-JCk)b07-a4<NIzAwd>fSdHYEMq=H0(<-u->+-tRjP{(SlR`{T#||Ni~||DS;} zpaaql@(Tl7<$?YJ4;`z%6H7K7&as-`{~}pwqSvaR4zUoWMg@h-9*bHPw0lB2gS<?2 zJo@h_XDta@<(Bb|@yB0ot#Z!#I_CCv$qG%Wj&_y_91>d6;?kND6DBat;ZWCLV`7uh lS~!Ps1tSOhN)E1-jI5hBZ`mrieaFsSbN1}r$K=Rh4FFn8eLesH literal 0 HcmV?d00001 diff --git a/scribo/demo/shared/icons/crop-icon.png b/scribo/demo/shared/icons/crop-icon.png new file mode 100644 index 0000000000000000000000000000000000000000..2e6b290da671ae4917167d8b14a6963d61bd1141 GIT binary patch literal 228 zcmeAS@N?(olHy`uVBq!ia0vp^LLkh+1SD^+kpz+qoCO|{#S9GG!XV7ZFl&wkP;i>3 zi(^Q|oT-zSSZQxE_3bso+J|{5)T)4aXzAITBkAJyrH_Sz@TT=-%%u!VGE4wl7-6 zpk!G-e?8lRYp>kntr+6c)8=LR3QoMMDE}<zl-!Lcof@*+4~qXf7!v9tQ`D1~aQU`k zuov4l^9SMC$^B1szXhyqwtQl`eRpB!iT#@UZ#_Qxe5d~LcP&h7SlI>sREOuU-CD6# Y{;u1Ni+Zg;bU^O*boFyt=akR{0PwL_(f|Me literal 0 HcmV?d00001 diff --git a/scribo/demo/shared/icons/image-add-icon.png b/scribo/demo/shared/icons/image-add-icon.png new file mode 100644 index 0000000000000000000000000000000000000000..0e4d29c0f34aef24ccf084b23049662f8da0c2a7 GIT binary patch literal 2917 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 P00000NkvXXu0mjf_m*)P literal 0 HcmV?d00001 diff --git a/scribo/demo/shared/icons/image-edit-icon.png b/scribo/demo/shared/icons/image-edit-icon.png new file mode 100644 index 0000000000000000000000000000000000000000..098cfaba705ab0999687bf80e6b1dc5d8ae34c38 GIT binary patch literal 2305 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 bf4BJ`Chgj%7)mWS00000NkvXXu0mjfL@Hu6 literal 0 HcmV?d00001 diff --git a/scribo/demo/shared/icons/image-multi-icon.png b/scribo/demo/shared/icons/image-multi-icon.png new file mode 100644 index 0000000000000000000000000000000000000000..60fb23f2dbd90464c953f327c6e6d0e443ad5843 GIT binary patch literal 2033 zcmV<N2M+j&P)<h;3K|Lk000e1NJLTq001xm001xu1^@s6R|5Hm000NLNkl<Zc-rNe zX=r0r6vxkf*<SXw$xB{4?TlS?%2Zs(aRG4!#T|D+Ma2&yh`4+ZLC_B>2qJz^7&lyz zae)!kaRC_xbzG_)ZLPDkGij2hS(<&%_1u@FO=i;i^3th_7gEm4TXKKr{O>vEzLLqw z$?vRIs|f$_h(@DtZP~Krp-%53fxw(!5WHfpT&0u(seez|xi)t5@k-ZpWUDv=Iu)V& z_V0grcxdQOMF935!T07w1d@gF`nny*adsXq8@5BY0OD)EEYL)uQuh$X0!SOX`FN#k zI<toyJX|?qr+*^Ah*AIt0=zL1p^0L-_5&1{n2xrak5{^;LwnG!hs%a+^v`_=FsvNF z_s(x9p<+de3c4DbY&={tXoGG6#2r&nnk-ZmN~n2(b|#^XHXU5N$=YQE+=BSwRE(yI z@&QyRBGJN2-#hhMdT=pE68RESM@Iky2yp&@rMorYbPK+n({V_Z<V&c}qQ~&-m$C3O z8OcBnpOG%f&u0A=9h}>5=`IT)fcWvgMVelU!0L4XeMbfz2I@BINX?%VzavZbL^w@S zwUqp~b)e6xg>(AM-PHjGu<JmAW=d7U)zmG;cqM?1HUn`PG?Z(abTdGyN=XJIaWI~h z>~;WX5UrYn5vLxGcj&qUaJjv{-G@`sti5JllEG{u2P#s_mRO@fqvF7#(?F?G1&>h& zCar4K2ea8uN7ImPBTJS+H=z7X8a0@;9C%F}>_>nh#Q+|!cqmbkyspL&FfYdPC1U3_ z(p(m@MPkyb!KhJ5=jxtp@%oWAgFckVVP-2I6#;`rMF$;5$!31=8o4ebfB^nvrDYQA z96M~9Ff@*<sW36>b$^>-*tNw<mCz;tb^@hGHLM9@Hhxe^v`{F-DB=9IpQ~MbbmVGt zXxOP#a=roJLjc*-`ceWsE=Q-%TJsSK1p^X54~sym(&D*x@@O0*06_ry;!k0c%*)F* z0J1t<S+<Q=(_2sMA+d$fTvq@u{D=TD)8$$N+_n|~+sDJ0?<?yLVAZMVEn8eI06qi& z+HU2v8I3jY>aPn>2Uyo()v4fyQ5PV<@*0>+u{7FQ1m4&iA?cz7E>-8+dAYXK5JG47 z)NG4ZO|RYTAklD>gjNG6RWl@-`wf!$8AuiV^knO$WTSU8ef#$)$rL-2kjtP24aZR{ zuO{J40b;pQ#}YDYRrKoPTLF9sfEAZrRmH94AqZuDfN=U}Sjg^$#r%F~*4K^4y#gon zZG#<CF-Ui?hv>n{kM@{azMG0>fb~tRV#`!81AxnM8;Srm3AsIjI2AiYr=y>cnZ?g> z!Uxdn*%fzWHxIr{Hur6#AN&y~^;SWa2eE@C{n$b@N4Q#Ryyzd%42k86vYv%)48={* zas+HW7V)_~*U@P9psb8>>(EOQz|MV(vH=96j`kuzqg6R_T@_gaSS-T~wjZo|ulB4y zGfz+V8A&7@tN~bECf_sPU5%a($O_@@L)&3=!#4P0CJAi*xUrEMz(6X$bPe+?hm&Ou z8(Up&qZaDD)v5ylAeJq*J?FwEl0Ab-sMo9l1PC+$#HYW#hQ{*&SrNEvcsm*0a0Z=@ zmnAo9I3m@MaJC@jXx3&&Q4U%aM;&@Cb2&l)Menbe*&4@(F#@cStY@g@_ea=2jW|t& zb;a!ZUW<xE=Iar#AiyKLucwh*P!_-gqc4yX`?u1Ai3;J!vLxz_*pkh10!QSf=B714 zv5Uq1L~DijnRv`xnx)@s0WdkuzPrD?3FfmwSrU5kr03z(fvtc5Eo5sk*o^(j9OTQ( z*^Nzlz-Ey4Cr~Fs09cr>OUU4~h!^g<hx)VgvLf*AsZWrzHlA`+1XlC3+z2o`SFVzH zz6gafw)iMbwim(r(R2?+z^oz*jR<%IK@8^>X@$yrE1}L&;&%4X83Z850D#$9ln~Yj zYGbm&WS~Y>t_UCqUSB6+j>ltQw>vOn9NRwV$j~<i!(drxNkU$)Pwd27@pzor?e=3D zfz@pGi(+#Glmg5q*~{R60f15oA;5|)IP0l0r66RAA?$PJv1gh?J0RJGN&*XD3Ts0V z@2|ZC<A@eioDMS$54_rrA1CNFE^HfoVAl16Q6qps<H7SfV7qCtA)&n!6HoCxU)$i4 z#-DacXnCdvgYhas5FE3~YE#FWCW*o<gfrtbocRR{+3#4LBeYb>5C#LFd_%)pF*RqP zI<=M9^~12iayC70;Ck$ZB6Et;crX|k_jrV{*<=B8_8vG8{}cl0Z!v4kL4C5vbXawL zaPMg!Kq8U~C;|us=f(w(ckJ0c*O5?qFLd|Mj?V9~@xAoE)7~eGk(9Cs%mw}9UXO3= z@o&z@O?^nx(9#Q=PHhGE*b(6V)8A7L;13)g_X*<IV_#o@x?g_)2Le2}bw~FA4}Wzr z#Pjm{r?ng|eJ?zE=DW(*Ktn=ze0C{`<U*2vU>#qpcnl(a_T0BfQfUMli};+6t{}ne z`UCWuM7r~$*GVRlR0<G40AcL=$Rrk}qLN2+HF%X4PIiu9A)8kwp<pOD?s0p@l(rAu zwh|2+>yfeughHWlx7+>S2k1ryYcZtP>;KCLOixemG8v7d|8xWr$%OweiMSME)`(b= P00000NkvXXu0mjf+x)}l literal 0 HcmV?d00001 diff --git a/scribo/demo/shared/icons/image-next-icon.png b/scribo/demo/shared/icons/image-next-icon.png new file mode 100644 index 0000000000000000000000000000000000000000..e8bc7dd4cdd7c12fd4617556d3df6809b6e86547 GIT binary patch literal 3008 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 C;-oVG literal 0 HcmV?d00001 diff --git a/scribo/demo/shared/icons/image-remove-icon.png b/scribo/demo/shared/icons/image-remove-icon.png new file mode 100644 index 0000000000000000000000000000000000000000..9d2bd94609a92dd12b376193f5649e6f60cb2d86 GIT binary patch literal 3127 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 R?*9M)002ovPDHLkV1jt0`tAS# literal 0 HcmV?d00001 diff --git a/scribo/demo/shared/icons/next-icon.png b/scribo/demo/shared/icons/next-icon.png new file mode 100644 index 0000000000000000000000000000000000000000..2d97d3b48954f5296548a478a8c435e8e5e7d14b GIT binary patch literal 4611 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 literal 0 HcmV?d00001 diff --git a/scribo/demo/shared/icons/page-down-icon.png b/scribo/demo/shared/icons/page-down-icon.png new file mode 100644 index 0000000000000000000000000000000000000000..5418a40dc18174d14e926ea5126ca42b7b64cf39 GIT binary patch literal 3450 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 literal 0 HcmV?d00001 diff --git a/scribo/demo/shared/icons/page-search-icon.png b/scribo/demo/shared/icons/page-search-icon.png new file mode 100644 index 0000000000000000000000000000000000000000..85e17185a6d9b8779ba72a35630ffe25108b029d GIT binary patch literal 3101 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 literal 0 HcmV?d00001 diff --git a/scribo/demo/shared/icons/rotate_ccw.png b/scribo/demo/shared/icons/rotate_ccw.png new file mode 100644 index 0000000000000000000000000000000000000000..7adafeda3708790ee8b58f1b1518c3657452bd3d GIT binary patch literal 4200 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 literal 0 HcmV?d00001 diff --git a/scribo/demo/shared/icons/rotate_cw.png b/scribo/demo/shared/icons/rotate_cw.png new file mode 100644 index 0000000000000000000000000000000000000000..90aee825681ece72e2efbcfb2fc4d3fc8649bf61 GIT binary patch literal 4161 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 LNkvXXu0mjf6?w`C literal 0 HcmV?d00001 diff --git a/scribo/demo/shared/icons/search-add-icon.png b/scribo/demo/shared/icons/search-add-icon.png new file mode 100644 index 0000000000000000000000000000000000000000..06c3db2ab01bc4ab673bd663bb8d9514ad3f04fe GIT binary patch literal 4274 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 UDeDQ54FCWD07*qoM6N<$f_Eh*#Q*>R literal 0 HcmV?d00001 diff --git a/scribo/demo/shared/icons/search-remove-icon.png b/scribo/demo/shared/icons/search-remove-icon.png new file mode 100644 index 0000000000000000000000000000000000000000..e770c676a77569cc23e4f97503d6318175ad221d GIT binary patch literal 4196 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 literal 0 HcmV?d00001 diff --git a/scribo/demo/shared/shared.qrc b/scribo/demo/shared/shared.qrc new file mode 100644 index 0000000..051c986 --- /dev/null +++ b/scribo/demo/shared/shared.qrc @@ -0,0 +1,20 @@ +<RCC> + <qresource prefix="icons" > + <file>icons/close.gif</file> + <file>icons/image-next-icon.png</file> + <file>icons/page-down-icon.png</file> + <file>icons/page-search-icon.png</file> + <file>icons/crop-icon.png</file> + <file>icons/image-remove-icon.png</file> + <file>icons/search-add-icon.png</file> + <file>icons/search-remove-icon.png</file> + <file>icons/Symbols-Delete-icon.png</file> + <file>icons/next-icon.png</file> + <file>icons/accept-icon.png</file> + <file>icons/image-add-icon.png</file> + <file>icons/image-multi-icon.png</file> + <file>icons/image-edit-icon.png</file> + <file>icons/rotate_cw.png</file> + <file>icons/rotate_ccw.png</file> + </qresource> +</RCC> diff --git a/scribo/demo/shared/src/bak/crop_item.cc b/scribo/demo/shared/src/bak/crop_item.cc new file mode 100644 index 0000000..5f22878 --- /dev/null +++ b/scribo/demo/shared/src/bak/crop_item.cc @@ -0,0 +1,332 @@ +// Copyright (C) 2010 EPITA Research and Development Laboratory (LRDE) +// +// This file is part of Olena. +// +// Olena is free software: you can redistribute it and/or modify it under +// the terms of the GNU General Public License as published by the Free +// Software Foundation, version 2 of the License. +// +// Olena is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Olena. If not, see <http://www.gnu.org/licenses/>. +// +// As a special exception, you may use this file as part of a free +// software project without restriction. Specifically, if other files +// instantiate templates or use macros or inline functions from this +// file, or you compile this file and link it with other files to produce +// an executable, this file does not by itself cause the resulting +// executable to be covered by the GNU General Public License. This +// exception does not however invalidate any other reasons why the +// executable file might be covered by the GNU General Public License. + + +#include <shared/src/crop_item.hh> + +namespace scribo +{ + + namespace demo + { + + namespace shared + { + + crop_item::crop_item(QGraphicsItem *parent) + : QGraphicsItem(parent) + { + _mousePress = false; + _cropRect = QRectF(20, 20, 100, 70); + setAcceptHoverEvents(true); + + grabMouse(); + } + + QRectF crop_item::cropRect(void) const + { + return(_cropRect); + } + + + QRectF crop_item::boundingRect(void) const + { + return(parentItem()->boundingRect()); + } + + void crop_item::paint(QPainter *painter, + const QStyleOptionGraphicsItem *option, + QWidget *widget) + { + Q_UNUSED(widget); + + painter->save(); + + QPainterPath cropPath; + cropPath.addRect(_cropRect); + + QPainterPath windowPath; + windowPath.addRect(option->rect); + windowPath = windowPath.subtracted(cropPath); + + // Draw Alpha-Black Background. + painter->fillPath(windowPath, QColor(0x33, 0x33, 0x33, 0xcc)); + + // Draw Crop Rect + painter->setPen(QPen(QColor(0xdd, 0xdd, 0xdd), 1)); + painter->drawPath(cropPath); + + int topRightX = _cropRect.x() + _cropRect.width(); + int bottomY = _cropRect.y() + _cropRect.height(); + + // Draw Grid if mouse is Pressed + if (_mousePress) { + qreal f = 1.0f / CROP_GRID_SIZE; + qreal hsize = _cropRect.height() * f; + qreal wsize = _cropRect.width() * f; + + QPainterPath gridPath; + for (uint i = 1; i < CROP_GRID_SIZE; ++i) { + qreal y = _cropRect.y() + i * hsize; + gridPath.moveTo(_cropRect.x(), y); + gridPath.lineTo(topRightX, y); + + for (uint j = 1; j < CROP_GRID_SIZE; ++j) { + qreal x = _cropRect.x() + j * wsize; + gridPath.moveTo(x, _cropRect.y()); + gridPath.lineTo(x, bottomY); + } + } + + // Draw Grid Path + painter->setPen(QPen(QColor(0x99, 0x99, 0x99, 0x80), 1)); + painter->drawPath(gridPath); + } + + QPainterPath borderPath; +// // Top-Left Corner +// borderPath.moveTo(_cropRect.x(), _cropRect.y()); +// borderPath.lineTo(_cropRect.x() + CROP_BORDER_LINE, _cropRect.y()); +// borderPath.moveTo(_cropRect.x(), _cropRect.y()); +// borderPath.lineTo(_cropRect.x(), _cropRect.y() + CROP_BORDER_LINE); + +// // Top-Right Corner +// borderPath.moveTo(topRightX - CROP_BORDER_LINE, _cropRect.y()); +// borderPath.lineTo(topRightX, _cropRect.y()); +// borderPath.moveTo(topRightX, _cropRect.y()); +// borderPath.lineTo(topRightX, _cropRect.y() + CROP_BORDER_LINE); + +// // Bottom-Left Corner +// borderPath.moveTo(_cropRect.x(), bottomY); +// borderPath.lineTo(_cropRect.x() + CROP_BORDER_LINE, bottomY); +// borderPath.moveTo(_cropRect.x(), bottomY - CROP_BORDER_LINE); +// borderPath.lineTo(_cropRect.x(), bottomY); + +// // Bottom-Left Corner +// borderPath.moveTo(topRightX, bottomY); +// borderPath.lineTo(topRightX - CROP_BORDER_LINE, bottomY); +// borderPath.moveTo(topRightX, bottomY - CROP_BORDER_LINE); +// borderPath.lineTo(topRightX, bottomY); + + // Draw Border Path + painter->setPen(QPen(QColor(0xee, 0xee, 0xee), 3)); + painter->drawPath(borderPath); + + painter->restore(); + } + + + void crop_item::mousePressEvent(QGraphicsSceneMouseEvent *event) + { + QGraphicsItem::mousePressEvent(event); + + _mousePress = true; + _cropResize = CropItemResizeNone; + if (event->buttons() & Qt::LeftButton) + { + int lthreshold = (CROP_BORDER_LINE >> 1); + int rthreshold = CROP_BORDER_LINE; + int size = CROP_BORDER_LINE << 1; + + int rightX = _cropRect.x() + _cropRect.width() - rthreshold; + int leftX = _cropRect.x() - lthreshold; + + int bottomY = _cropRect.y() + _cropRect.height() - rthreshold; + int topY = _cropRect.y() - lthreshold; + + QRectF bottomRightCorner(rightX, bottomY, size, size); + QRectF bottomLeftCorner(leftX, bottomY, size, size); + QRectF topRightCorner(rightX, topY, size, size); + QRectF topLeftCorner(leftX, topY, size, size); + + int sideHeight = _cropRect.height() - 2 * size; + int sideWidth = _cropRect.width() - 2 * size; + QRectF leftSide(leftX, topY + size, size, sideHeight); + QRectF rightSide(rightX, topY + size, size, sideHeight); + QRectF topSide(leftX + size, topY, sideWidth, size); + QRectF bottomSide(leftX + size, bottomY, sideWidth, size); + + if (bottomRightCorner.contains(event->pos())) + _cropResize = CropItemResizeBottomRight; + else if (bottomLeftCorner.contains(event->pos())) + _cropResize = CropItemResizeBottomLeft; + else if (topRightCorner.contains(event->pos())) + _cropResize = CropItemResizeTopRight; + else if (topLeftCorner.contains(event->pos())) + _cropResize = CropItemResizeTopLeft; + else if (leftSide.contains(event->pos())) + _cropResize = CropItemResizeLeft; + else if (rightSide.contains(event->pos())) + _cropResize = CropItemResizeRight; + else if (topSide.contains(event->pos())) + _cropResize = CropItemResizeTop; + else if (bottomSide.contains(event->pos())) + _cropResize = CropItemResizeBottom; + } + + update(); + } + + + void crop_item::mouseReleaseEvent(QGraphicsSceneMouseEvent *event) + { + QGraphicsItem::mouseReleaseEvent(event); + + _cropResize = CropItemResizeNone; + _mousePress = false; + + update(); + } + + + void crop_item::updateCursor(QGraphicsSceneMouseEvent *event) + { + int lthreshold = (CROP_BORDER_LINE >> 1); + int rthreshold = CROP_BORDER_LINE; + int size = CROP_BORDER_LINE << 1; + + int rightX = _cropRect.x() + _cropRect.width() - rthreshold; + int leftX = _cropRect.x() - lthreshold; + + int bottomY = _cropRect.y() + _cropRect.height() - rthreshold; + int topY = _cropRect.y() - lthreshold; + + QRectF bottomRightCorner(rightX, bottomY, size, size); + QRectF bottomLeftCorner(leftX, bottomY, size, size); + QRectF topRightCorner(rightX, topY, size, size); + QRectF topLeftCorner(leftX, topY, size, size); + + int sideHeight = _cropRect.height() - 2 * size; + int sideWidth = _cropRect.width() - 2 * size; + QRectF leftSide(leftX, topY + size, size, sideHeight); + QRectF rightSide(rightX, topY + size, size, sideHeight); + QRectF topSide(leftX + size, topY, sideWidth, size); + QRectF bottomSide(leftX + size, bottomY, sideWidth, size); + + if (bottomRightCorner.contains(event->pos())) + setCursor(Qt::SizeFDiagCursor); + else if (bottomLeftCorner.contains(event->pos())) + setCursor(Qt::SizeBDiagCursor); + else if (topRightCorner.contains(event->pos())) + setCursor(Qt::SizeBDiagCursor); + else if (topLeftCorner.contains(event->pos())) + setCursor(Qt::SizeFDiagCursor); + else if (leftSide.contains(event->pos())) + setCursor(Qt::SizeHorCursor); + else if (rightSide.contains(event->pos())) + setCursor(Qt::SizeHorCursor); + else if (topSide.contains(event->pos())) + setCursor(Qt::SizeVerCursor); + else if (bottomSide.contains(event->pos())) + setCursor(Qt::SizeVerCursor); + } + + + void crop_item::mouseMoveEvent(QGraphicsSceneMouseEvent *event) + { + updateCursor(event); + + QGraphicsItem::mouseMoveEvent(event); + + qreal minSize = 4 + (CROP_BORDER_LINE << 1); + + QPointF delta = event->pos() - event->lastPos(); + switch (_cropResize) + { + case CropItemResizeNone: + if (!_cropRect.contains(event->pos())) + return; + + setCursor(Qt::SizeAllCursor); + + if (!(event->buttons() & Qt::LeftButton)) + return; + + _cropRect.translate(delta); + break; + case CropItemResizeTopLeft: + delta.setY(qMin(_cropRect.height() - minSize, delta.y())); + delta.setX(qMin(_cropRect.width() - minSize, delta.x())); + _cropRect.setHeight(_cropRect.height() - delta.y()); + _cropRect.setWidth(_cropRect.width() - delta.x()); + _cropRect.translate(delta); + setCursor(Qt::SizeFDiagCursor); + break; + case CropItemResizeTopRight: + delta.setY(qMin(_cropRect.height() - minSize, delta.y())); + _cropRect.setWidth(_cropRect.width() + delta.x()); + _cropRect.setHeight(_cropRect.height() - delta.y()); + _cropRect.translate(0, delta.y()); + setCursor(Qt::SizeBDiagCursor); + break; + case CropItemResizeBottomLeft: + delta.setX(qMin(_cropRect.width() - minSize, delta.x())); + _cropRect.setHeight(_cropRect.height() + delta.y()); + _cropRect.setWidth(_cropRect.width() - delta.x()); + _cropRect.translate(delta.x(), 0); + setCursor(Qt::SizeBDiagCursor); + break; + case CropItemResizeBottomRight: + _cropRect.setWidth(_cropRect.width() + delta.x()); + _cropRect.setHeight(_cropRect.height() + delta.y()); + setCursor(Qt::SizeFDiagCursor); + break; + case CropItemResizeLeft: + delta.setX(qMin(_cropRect.width() - minSize, delta.x())); + _cropRect.setWidth(_cropRect.width() - delta.x()); + _cropRect.translate(delta.x(), 0); + setCursor(Qt::SizeHorCursor); + break; + case CropItemResizeRight: + _cropRect.setWidth(_cropRect.width() + delta.x()); + setCursor(Qt::SizeHorCursor); + break; + case CropItemResizeTop: + delta.setY(qMin(_cropRect.height() - minSize, delta.y())); + _cropRect.setHeight(_cropRect.height() - delta.y()); + _cropRect.translate(0, delta.y()); + setCursor(Qt::SizeVerCursor); + break; + case CropItemResizeBottom: + _cropRect.setHeight(_cropRect.height() + delta.y()); + setCursor(Qt::SizeVerCursor); + break; + } + + if (_cropRect.width() < minSize) + _cropRect.setWidth(minSize); + if (_cropRect.height() < minSize) + _cropRect.setHeight(minSize); + + update(); + } + + + } // end of namespace scribo::demo::shared + + } // end of namespace scribo::demo + +} // end of namespace scribo + diff --git a/scribo/demo/shared/src/bak/crop_item.hh b/scribo/demo/shared/src/bak/crop_item.hh new file mode 100644 index 0000000..caf2032 --- /dev/null +++ b/scribo/demo/shared/src/bak/crop_item.hh @@ -0,0 +1,100 @@ +// Copyright (C) 2010 EPITA Research and Development Laboratory (LRDE) +// +// This file is part of Olena. +// +// Olena is free software: you can redistribute it and/or modify it under +// the terms of the GNU General Public License as published by the Free +// Software Foundation, version 2 of the License. +// +// Olena is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Olena. If not, see <http://www.gnu.org/licenses/>. +// +// As a special exception, you may use this file as part of a free +// software project without restriction. Specifically, if other files +// instantiate templates or use macros or inline functions from this +// file, or you compile this file and link it with other files to produce +// an executable, this file does not by itself cause the resulting +// executable to be covered by the GNU General Public License. This +// exception does not however invalidate any other reasons why the +// executable file might be covered by the GNU General Public License. +// +// Based on the code located here: +// http://th30z.netsons.org/2010/01/qt4-image-crop-item/ + +#ifndef SCRIBO_DEMO_SHARED_SRC_CROP_ITEM_HH +# define SCRIBO_DEMO_SHARED_SRC_CROP_ITEM_HH + +#include <QStyleOptionGraphicsItem> +#include <QGraphicsSceneMouseEvent> +#include <QGraphicsScene> +#include <QGraphicsView> +#include <QGraphicsItem> +#include <QApplication> +#include <QPainter> +#include <QtGui> + +#define CROP_BORDER_LINE 10 +#define CROP_GRID_SIZE 3 + +namespace scribo +{ + + namespace demo + { + + namespace shared + { + + class crop_item : public QGraphicsItem + { + public: + crop_item(QGraphicsItem *parent); + QRectF cropRect (void) const; + + public: + QRectF boundingRect (void) const; + void paint (QPainter *painter, + const QStyleOptionGraphicsItem *option, + QWidget *widget = 0); + + protected: + void mousePressEvent (QGraphicsSceneMouseEvent *event); + void mouseReleaseEvent (QGraphicsSceneMouseEvent *event); + void updateCursor(QGraphicsSceneMouseEvent *event); + void mouseMoveEvent(QGraphicsSceneMouseEvent *event); + + private: + enum CropItemResize { + CropItemResizeNone, + + CropItemResizeTopLeft, + CropItemResizeTopRight, + CropItemResizeBottomLeft, + CropItemResizeBottomRight, + + CropItemResizeLeft, + CropItemResizeRight, + CropItemResizeTop, + CropItemResizeBottom + }; + + private: + CropItemResize _cropResize; + QRectF _cropRect; + bool _mousePress; + }; + + + } // end of namespace scribo::demo::shared + + } // end of namespace scribo::demo + +} // end of namespace scribo + + +#endif // ! SCRIBO_DEMO_SHARED_SRC_CROP_ITEM_HH diff --git a/scribo/demo/shared/src/bak/image_viewer.cc b/scribo/demo/shared/src/bak/image_viewer.cc new file mode 100644 index 0000000..89d63d2 --- /dev/null +++ b/scribo/demo/shared/src/bak/image_viewer.cc @@ -0,0 +1,242 @@ +// Copyright (C) 2010 EPITA Research and Development Laboratory +// (LRDE) +// +// This file is part of Olena. +// +// Olena is free software: you can redistribute it and/or modify it under +// the terms of the GNU General Public License as published by the Free +// Software Foundation, version 2 of the License. +// +// Olena is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Olena. If not, see <http://www.gnu.org/licenses/>. +// +// As a special exception, you may use this file as part of a free +// software project without restriction. Specifically, if other files +// instantiate templates or use macros or inline functions from this +// file, or you compile this file and link it with other files to produce +// an executable, this file does not by itself cause the resulting +// executable to be covered by the GNU General Public License. This +// exception does not however invalidate any other reasons why the +// executable file might be covered by the GNU General Public License. + + +# include <shared/src/image_viewer.hh> + +namespace scribo +{ + + namespace demo + { + + namespace shared + { + + image_viewer::image_viewer(QWidget *parent) + : QWidget(parent), item_(0) + { + setupUi(this); + + connect(image_->verticalScrollBar(), SIGNAL(valueChanged(int)), + this, SLOT(move_vertical_sliders(int))); + connect(image_->horizontalScrollBar(), SIGNAL(valueChanged(int)), + this, SLOT(move_horizontal_sliders(int))); + + setup_scene(); + + slider->setMinimum(0); + visible_slider(false); + } + + + + image_viewer::~image_viewer() + { + + } + + unsigned image_viewer::current_slice() const + { + return slider->value(); + } + + internal::interactiveScene * image_viewer::scene() + { + return static_cast<internal::interactiveScene *>(image_->scene()); + } + + const internal::interactiveScene * image_viewer::scene() const + { + return static_cast<const internal::interactiveScene *>(image_->scene()); + } + + // Private members + + void image_viewer::setup_scene() + { + QGraphicsScene *scene = new internal::interactiveScene(); + image_->setScene(scene); + image_->show(); + } + + void image_viewer::draw_image(const mln::image2d<dsp_data_t>& ima) + { + QImage + qima = mln::convert::implementation::to_qimage_qt_rgb32_nocopy(ima); + QPixmap pixmap = QPixmap::fromImage(qima); + + if (item_ != 0) + { + image_->scene()->removeItem(item_); + delete item_; + } + + item_ = image_->scene()->addPixmap(pixmap); + image_->scene()->setSceneRect(item_->boundingRect()); + + if (pixmap.width() > image_->maximumViewportSize().width()) + image_->fitInView(item_->boundingRect(), Qt::KeepAspectRatio); + + zoomLabel->setEnabled(true); + zoomIn->setEnabled(true); + zoomOut->setEnabled(true); + zoomFixed->setEnabled(true); + zoomOriginal->setEnabled(true); + + item_->translate(ima.domain().pmin().col(), ima.domain().pmin().row()); + + image_->setSceneRect(item_->sceneBoundingRect()); + } + + + void image_viewer::resize_image(const QRectF& rect) + { + if (item_ != 0) + image_->fitInView(rect, Qt::KeepAspectRatio); + } + + void image_viewer::resizeEvent(QResizeEvent * event) + { + if (item_ != 0) + resize_image(item_->boundingRect()); + event->ignore(); + } + + + void image_viewer::keyPressEvent(QKeyEvent *event) + { + if (event->text() == QString("+")) + { + on_zoomIn_clicked(); + event->accept(); + } + else if (event->text() == QString("-")) + { + on_zoomOut_clicked(); + event->accept(); + } + else if (event->key() == Qt::Key_Return || event->key() == Qt::Key_Enter) + { + if (event->modifiers() == Qt::ControlModifier) + on_zoomFixed_clicked(); + else + on_zoomOriginal_clicked(); + event->accept(); + } + else + event->ignore(); + } + + + // Private slots + + void image_viewer::visible_slider(bool b) + { + slider->setVisible(b); + label_2->setVisible(b); + frame_nb->setVisible(b); + } + + void image_viewer::move_vertical_sliders(int value) + { + image_->verticalScrollBar()->setValue(value); + } + + + void image_viewer::move_horizontal_sliders(int value) + { + image_->horizontalScrollBar()->setValue(value); + } + + + void image_viewer::on_slider_valueChanged(int sli) + { + frame_nb->setText(QString("%1/%2").arg(sli).arg(slider->maximum())); + emit slider_valueChanged(sli); + } + + void image_viewer::update_image(const mln::image2d<dsp_data_t>& ima) + { + draw_image(ima); + } + + void image_viewer::on_zoomIn_clicked() + { + image_->scale(1.2, 1.2); + } + + void image_viewer::on_zoomOut_clicked() + { + image_->scale(1 / 1.2, 1 / 1.2); + } + + void image_viewer::on_zoomFixed_clicked() + { + if (item_ != 0) + resize_image(item_->boundingRect()); + } + + void image_viewer::on_zoomOriginal_clicked() + { + if (item_ != 0) + resize_image(image_->viewport()->geometry()); + } + + + void image_viewer::clear() + { + visible_slider(false); + if (item_ != 0 && item_->scene() == image_->scene()) + { + image_->scene()->removeItem(item_); + delete item_; + item_ = 0; + } + } + + + // Public slots + + void image_viewer::set_image_layer_count(unsigned nslis) + { + visible_slider(nslis > 1); + + slider->setMaximum(nslis - 1); + + unsigned sli = current_slice(); + if (current_slice() >= nslis) + sli = 0; + + slider->setSliderPosition(sli); + on_slider_valueChanged(sli); + } + + } // end of namespace scribo::demo::shared + + } // end of namespace scribo::demo + +} // end of namespace scribo diff --git a/scribo/demo/shared/src/bak/image_viewer.hh b/scribo/demo/shared/src/bak/image_viewer.hh new file mode 100644 index 0000000..f18ca3b --- /dev/null +++ b/scribo/demo/shared/src/bak/image_viewer.hh @@ -0,0 +1,116 @@ +// Copyright (C) 2010 EPITA Research and Development Laboratory (LRDE) +// +// This file is part of Olena. +// +// Olena is free software: you can redistribute it and/or modify it under +// the terms of the GNU General Public License as published by the Free +// Software Foundation, version 2 of the License. +// +// Olena is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Olena. If not, see <http://www.gnu.org/licenses/>. +// +// As a special exception, you may use this file as part of a free +// software project without restriction. Specifically, if other files +// instantiate templates or use macros or inline functions from this +// file, or you compile this file and link it with other files to produce +// an executable, this file does not by itself cause the resulting +// executable to be covered by the GNU General Public License. This +// exception does not however invalidate any other reasons why the +// executable file might be covered by the GNU General Public License. + +#ifndef SCRIBO_DEMO_SHARED_SRC_IMAGE_VIEWER_HH +# define SCRIBO_DEMO_SHARED_SRC_IMAGE_VIEWER_HH + +# include <QApplication> +# include <QtCore> +# include <QtGui> + +# include <ui_image_viewer.h> + +# include <mln/core/image/image2d.hh> +# include <mln/convert/to_qimage.hh> + +# include <shared/src/types.hh> +# include <shared/src/internal/interactive_scene.hh> + + +namespace scribo +{ + + namespace demo + { + + namespace shared + { + + class image_viewer + : public QWidget, private Ui::ImageViewer + { + Q_OBJECT; + + public: + image_viewer(QWidget *parent = 0); + ~image_viewer(); + + unsigned current_slice() const; + + internal::interactiveScene * scene(); + const internal::interactiveScene * scene() const; + + void clear(); + + private: // members + void setup_scene(); + + void draw_image(const mln::image2d<dsp_data_t>& ima); + + void resize_image(const QRectF& rect); + + void keyPressEvent(QKeyEvent *event); + void resizeEvent(QResizeEvent * event); +// void mouseMoveEvent(QMouseEvent *e); +// void mousePressEvent(QMouseEvent *e); +// void mouseReleasedEvent(QMouseEvent *e); + + private slots: + void visible_slider(bool b); + + void move_vertical_sliders(int value); + void move_horizontal_sliders(int value); + + void on_slider_valueChanged(int sli); + + void on_zoomIn_clicked(); + void on_zoomOut_clicked(); + void on_zoomFixed_clicked(); + void on_zoomOriginal_clicked(); + + + public slots: + void set_image_layer_count(unsigned nslis); + void update_image(const mln::image2d<dsp_data_t>& ima); + + + signals: + void slider_valueChanged(int sli); + + private: // attributes + QGraphicsItem *item_; + bool mouse_moving_; + QPoint p_start_; + }; + + + } // end of namespace scribo::demo::shared + + } // end of namespace scribo::demo + +} // end of namespace scribo + + +#endif // ! SCRIBO_DEMO_SHARED_SRC_IMAGE_VIEWER_HH diff --git a/scribo/demo/shared/src/bak/types.hh b/scribo/demo/shared/src/bak/types.hh new file mode 100644 index 0000000..8edb54a --- /dev/null +++ b/scribo/demo/shared/src/bak/types.hh @@ -0,0 +1,50 @@ +// Copyright (C) 2010 EPITA Research and Development Laboratory (LRDE) +// +// This file is part of Olena. +// +// Olena is free software: you can redistribute it and/or modify it under +// the terms of the GNU General Public License as published by the Free +// Software Foundation, version 2 of the License. +// +// Olena is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Olena. If not, see <http://www.gnu.org/licenses/>. +// +// As a special exception, you may use this file as part of a free +// software project without restriction. Specifically, if other files +// instantiate templates or use macros or inline functions from this +// file, or you compile this file and link it with other files to produce +// an executable, this file does not by itself cause the resulting +// executable to be covered by the GNU General Public License. This +// exception does not however invalidate any other reasons why the +// executable file might be covered by the GNU General Public License. + +#ifndef SCRIBO_DEMO_SHARED_SRC_TYPES_HH +# define SCRIBO_DEMO_SHARED_SRC_TYPES_HH + + +# include <mln/value/qt/rgb32.hh> + +namespace scribo +{ + + namespace demo + { + + namespace shared + { + + typedef mln::value::qt::rgb32 dsp_data_t; + + } // end of namespace scribo::demo::shared + + } // end of namespace scribo::demo + +} // end of namespace scribo + + +#endif // !SCRIBO_DEMO_SHARED_SRC_TYPES_HH diff --git a/scribo/demo/shared/src/browse_widget.cc b/scribo/demo/shared/src/browse_widget.cc new file mode 100644 index 0000000..67e553a --- /dev/null +++ b/scribo/demo/shared/src/browse_widget.cc @@ -0,0 +1,72 @@ +#include <shared/src/browse_widget.hh> + +namespace scribo +{ + + namespace demo + { + + namespace shared + { + + + browse_widget::browse_widget(QWidget *parent) + : QWidget(parent) + { + setupUi(this); + + QStringList filters; + filters << tr("Any (*.*)"); + setDialogFilter(filters); + + setDialogFileMode(QFileDialog::ExistingFile); + setDialogTitle(tr("Choose an existing file")); + setDescription(tr("Choose a file:")); + } + + void browse_widget::setDescription(const QString& desc) + { + description_->setText(desc); + } + + QString browse_widget::path() const + { + return path_->text(); + } + + void browse_widget::reset() + { + path_->clear(); + } + + void browse_widget::setDialogTitle(const QString& title) + { + dialog_.setLabelText(QFileDialog::LookIn, title); + } + + void browse_widget::setDialogFileMode(const QFileDialog::FileMode& filemode) + { + dialog_.setFileMode(filemode); + } + + void browse_widget::setDialogFilter(const QStringList& filters) + { + dialog_.setNameFilters(filters); + } + + + void browse_widget::on_browseBtn__clicked() + { + if (dialog_.exec()) + { + path_->setText(dialog_.selectedFiles().at(0)); + emit path_updated(); + } + } + + + } // end of namespace scribo::demo::shared + + } // end of namespace scribo::demo + +} // end of namespace scribo diff --git a/scribo/demo/shared/src/browse_widget.hh b/scribo/demo/shared/src/browse_widget.hh new file mode 100644 index 0000000..d30213c --- /dev/null +++ b/scribo/demo/shared/src/browse_widget.hh @@ -0,0 +1,78 @@ +// Copyright (C) 2010 EPITA Research and Development Laboratory (LRDE) +// +// This file is part of Olena. +// +// Olena is free software: you can redistribute it and/or modify it under +// the terms of the GNU General Public License as published by the Free +// Software Foundation, version 2 of the License. +// +// Olena is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Olena. If not, see <http://www.gnu.org/licenses/>. +// +// As a special exception, you may use this file as part of a free +// software project without restriction. Specifically, if other files +// instantiate templates or use macros or inline functions from this +// file, or you compile this file and link it with other files to produce +// an executable, this file does not by itself cause the resulting +// executable to be covered by the GNU General Public License. This +// exception does not however invalidate any other reasons why the +// executable file might be covered by the GNU General Public License. + +#ifndef SCRIBO_DEMO_SHARED_SRC_BROWSE_WIDGET_HH +# define SCRIBO_DEMO_SHARED_SRC_BROWSE_WIDGET_HH + +# include <QtGui> +# include <ui_browse_widget.h> + +namespace scribo +{ + + namespace demo + { + + namespace shared + { + + + class browse_widget : public QWidget, protected Ui::BrowseWidget + { + Q_OBJECT; + + Q_PROPERTY(QString path READ path); + + public: + browse_widget(QWidget *parent = 0); + + void setDescription(const QString& desc); + void setDialogTitle(const QString& title); + void setDialogFileMode(const QFileDialog::FileMode& filemode); + void setDialogFilter(const QStringList& filters); + + QString path() const; + + void reset(); + + private slots: + void on_browseBtn__clicked(); + + signals: + void path_updated(); + + private: + QFileDialog dialog_; + }; + + + } // end of namespace scribo::demo::shared + + } // end of namespace scribo::demo + +} // end of namespace scribo + + +#endif // ! SCRIBO_DEMO_SHARED_SRC_BROWSE_WIDGET_HH diff --git a/scribo/demo/shared/src/crop_item.cc b/scribo/demo/shared/src/crop_item.cc new file mode 100644 index 0000000..100ac7d --- /dev/null +++ b/scribo/demo/shared/src/crop_item.cc @@ -0,0 +1,313 @@ +// Copyright (C) 2010 EPITA Research and Development Laboratory (LRDE) +// +// This file is part of Olena. +// +// Olena is free software: you can redistribute it and/or modify it under +// the terms of the GNU General Public License as published by the Free +// Software Foundation, version 2 of the License. +// +// Olena is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Olena. If not, see <http://www.gnu.org/licenses/>. +// +// As a special exception, you may use this file as part of a free +// software project without restriction. Specifically, if other files +// instantiate templates or use macros or inline functions from this +// file, or you compile this file and link it with other files to produce +// an executable, this file does not by itself cause the resulting +// executable to be covered by the GNU General Public License. This +// exception does not however invalidate any other reasons why the +// executable file might be covered by the GNU General Public License. + + +#include <shared/src/crop_item.hh> + +namespace scribo +{ + + namespace demo + { + + namespace shared + { + + crop_item::crop_item(QGraphicsItem *parent) + : QGraphicsItem(parent) + { + mousePress_ = false; + setAcceptHoverEvents(true); + + reset(); + + grabMouse(); + } + + void crop_item::reset() + { + if (parentItem()) + cropRect_ = parentItem()->boundingRect(); + else + cropRect_ = QRectF(20, 20, 100, 70); + } + + const QRectF& crop_item::cropRect() const + { + return cropRect_; + } + + + QRectF crop_item::boundingRect() const + { + return parentItem()->boundingRect(); + } + + void crop_item::paint(QPainter *painter, + const QStyleOptionGraphicsItem *option, + QWidget *widget) + { + Q_UNUSED(widget); + + painter->save(); + + QPainterPath cropPath; + cropPath.addRect(cropRect_); + + QPainterPath windowPath; + windowPath.addRect(option->rect); + windowPath = windowPath.subtracted(cropPath); + + // Draw Alpha-Black Background. + painter->fillPath(windowPath, QColor(0x33, 0x33, 0x33, 0xcc)); + + // Draw Crop Rect + painter->setPen(QPen(QColor(0xdd, 0xdd, 0xdd), 1)); + painter->drawPath(cropPath); + + int topRightX = cropRect_.x() + cropRect_.width(); + int bottomY = cropRect_.y() + cropRect_.height(); + + QPainterPath borderPath; + int corner_width = cropRect_.width() / 6.f; + int corner_height = cropRect_.height() / 6.f; + + // Top-Left Corner + painter->drawRect(QRectF(cropRect_.x(), cropRect_.y(), + corner_width, corner_height)); + + + // Top-Right Corner + painter->drawRect(QRectF(topRightX - corner_width, cropRect_.y(), + corner_width, corner_height)); + + // Bottom-Left Corner + painter->drawRect(QRectF(cropRect_.x(), bottomY - corner_height, + corner_width, corner_height)); + + // Bottom-Left Corner + painter->drawRect(QRectF(topRightX - corner_width, + bottomY - corner_height, + corner_width, corner_height)); + + // Draw Border Path + painter->setPen(QPen(QColor(0xee, 0xee, 0xee), 3)); + painter->drawPath(borderPath); + + painter->restore(); + } + + + void crop_item::mousePressEvent(QGraphicsSceneMouseEvent *event) + { + QGraphicsItem::mousePressEvent(event); + + mousePress_ = true; + cropResize_ = CropItemResizeNone; + if (event->buttons() & Qt::LeftButton) + { + int wsize = cropRect_.width() / 6.f; + int hsize = cropRect_.height() / 6.f; + + int rightX = cropRect_.x() + cropRect_.width() - wsize; + int leftX = cropRect_.x(); + + int bottomY = cropRect_.y() + cropRect_.height() - hsize; + int topY = cropRect_.y(); + + QRectF bottomRightCorner(rightX, bottomY, wsize, hsize); + QRectF bottomLeftCorner(leftX, bottomY, wsize, hsize); + QRectF topRightCorner(rightX, topY, wsize, hsize); + QRectF topLeftCorner(leftX, topY, wsize, hsize); + + int sideHeight = cropRect_.height() - 2 * hsize; + int sideWidth = cropRect_.width() - 2 * wsize; + QRectF leftSide(leftX, topY + hsize, wsize, sideHeight); + QRectF rightSide(rightX, topY + hsize, wsize, sideHeight); + QRectF topSide(leftX + wsize, topY, sideWidth, hsize); + QRectF bottomSide(leftX + wsize, bottomY, sideWidth, hsize); + + if (bottomRightCorner.contains(event->pos())) + cropResize_ = CropItemResizeBottomRight; + else if (bottomLeftCorner.contains(event->pos())) + cropResize_ = CropItemResizeBottomLeft; + else if (topRightCorner.contains(event->pos())) + cropResize_ = CropItemResizeTopRight; + else if (topLeftCorner.contains(event->pos())) + cropResize_ = CropItemResizeTopLeft; + else if (leftSide.contains(event->pos())) + cropResize_ = CropItemResizeLeft; + else if (rightSide.contains(event->pos())) + cropResize_ = CropItemResizeRight; + else if (topSide.contains(event->pos())) + cropResize_ = CropItemResizeTop; + else if (bottomSide.contains(event->pos())) + cropResize_ = CropItemResizeBottom; + } + + update(); + } + + + void crop_item::mouseReleaseEvent(QGraphicsSceneMouseEvent *event) + { + QGraphicsItem::mouseReleaseEvent(event); + + cropResize_ = CropItemResizeNone; + mousePress_ = false; + + update(); + } + + +// void crop_item::updateCursor(QGraphicsSceneMouseEvent *event) +// { +// int lthreshold = (CROP_BORDER_LINE >> 1); +// int rthreshold = CROP_BORDER_LINE; +// int size = CROP_BORDER_LINE << 1; + +// int rightX = cropRect_.x() + cropRect_.width() - rthreshold; +// int leftX = cropRect_.x() - lthreshold; + +// int bottomY = cropRect_.y() + cropRect_.height() - rthreshold; +// int topY = cropRect_.y() - lthreshold; + +// QRectF bottomRightCorner(rightX, bottomY, size, size); +// QRectF bottomLeftCorner(leftX, bottomY, size, size); +// QRectF topRightCorner(rightX, topY, size, size); +// QRectF topLeftCorner(leftX, topY, size, size); + +// int sideHeight = cropRect_.height() - 2 * size; +// int sideWidth = cropRect_.width() - 2 * size; +// QRectF leftSide(leftX, topY + size, size, sideHeight); +// QRectF rightSide(rightX, topY + size, size, sideHeight); +// QRectF topSide(leftX + size, topY, sideWidth, size); +// QRectF bottomSide(leftX + size, bottomY, sideWidth, size); + +// if (bottomRightCorner.contains(event->pos())) +// setCursor(Qt::SizeFDiagCursor); +// else if (bottomLeftCorner.contains(event->pos())) +// setCursor(Qt::SizeBDiagCursor); +// else if (topRightCorner.contains(event->pos())) +// setCursor(Qt::SizeBDiagCursor); +// else if (topLeftCorner.contains(event->pos())) +// setCursor(Qt::SizeFDiagCursor); +// else if (leftSide.contains(event->pos())) +// setCursor(Qt::SizeHorCursor); +// else if (rightSide.contains(event->pos())) +// setCursor(Qt::SizeHorCursor); +// else if (topSide.contains(event->pos())) +// setCursor(Qt::SizeVerCursor); +// else if (bottomSide.contains(event->pos())) +// setCursor(Qt::SizeVerCursor); +// } + + + void crop_item::mouseMoveEvent(QGraphicsSceneMouseEvent *event) + { +// updateCursor(event); + + QGraphicsItem::mouseMoveEvent(event); + + qreal minSize = 4 + (CROP_BORDER_LINE << 1); + + QPointF delta = event->pos() - event->lastPos(); + switch (cropResize_) + { + case CropItemResizeNone: + if (!cropRect_.contains(event->pos())) + return; + + setCursor(Qt::SizeAllCursor); + + if (!(event->buttons() & Qt::LeftButton)) + return; + + cropRect_.translate(delta); + break; + case CropItemResizeTopLeft: + delta.setY(qMin(cropRect_.height() - minSize, delta.y())); + delta.setX(qMin(cropRect_.width() - minSize, delta.x())); + cropRect_.setHeight(cropRect_.height() - delta.y()); + cropRect_.setWidth(cropRect_.width() - delta.x()); + cropRect_.translate(delta); + setCursor(Qt::SizeFDiagCursor); + break; + case CropItemResizeTopRight: + delta.setY(qMin(cropRect_.height() - minSize, delta.y())); + cropRect_.setWidth(cropRect_.width() + delta.x()); + cropRect_.setHeight(cropRect_.height() - delta.y()); + cropRect_.translate(0, delta.y()); + setCursor(Qt::SizeBDiagCursor); + break; + case CropItemResizeBottomLeft: + delta.setX(qMin(cropRect_.width() - minSize, delta.x())); + cropRect_.setHeight(cropRect_.height() + delta.y()); + cropRect_.setWidth(cropRect_.width() - delta.x()); + cropRect_.translate(delta.x(), 0); + setCursor(Qt::SizeBDiagCursor); + break; + case CropItemResizeBottomRight: + cropRect_.setWidth(cropRect_.width() + delta.x()); + cropRect_.setHeight(cropRect_.height() + delta.y()); + setCursor(Qt::SizeFDiagCursor); + break; + case CropItemResizeLeft: + delta.setX(qMin(cropRect_.width() - minSize, delta.x())); + cropRect_.setWidth(cropRect_.width() - delta.x()); + cropRect_.translate(delta.x(), 0); + setCursor(Qt::SizeHorCursor); + break; + case CropItemResizeRight: + cropRect_.setWidth(cropRect_.width() + delta.x()); + setCursor(Qt::SizeHorCursor); + break; + case CropItemResizeTop: + delta.setY(qMin(cropRect_.height() - minSize, delta.y())); + cropRect_.setHeight(cropRect_.height() - delta.y()); + cropRect_.translate(0, delta.y()); + setCursor(Qt::SizeVerCursor); + break; + case CropItemResizeBottom: + cropRect_.setHeight(cropRect_.height() + delta.y()); + setCursor(Qt::SizeVerCursor); + break; + } + + if (cropRect_.width() < minSize) + cropRect_.setWidth(minSize); + if (cropRect_.height() < minSize) + cropRect_.setHeight(minSize); + + update(); + } + + + } // end of namespace scribo::demo::shared + + } // end of namespace scribo::demo + +} // end of namespace scribo + diff --git a/scribo/demo/shared/src/crop_item.hh b/scribo/demo/shared/src/crop_item.hh new file mode 100644 index 0000000..c0b1394 --- /dev/null +++ b/scribo/demo/shared/src/crop_item.hh @@ -0,0 +1,103 @@ +// Copyright (C) 2010 EPITA Research and Development Laboratory (LRDE) +// +// This file is part of Olena. +// +// Olena is free software: you can redistribute it and/or modify it under +// the terms of the GNU General Public License as published by the Free +// Software Foundation, version 2 of the License. +// +// Olena is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Olena. If not, see <http://www.gnu.org/licenses/>. +// +// As a special exception, you may use this file as part of a free +// software project without restriction. Specifically, if other files +// instantiate templates or use macros or inline functions from this +// file, or you compile this file and link it with other files to produce +// an executable, this file does not by itself cause the resulting +// executable to be covered by the GNU General Public License. This +// exception does not however invalidate any other reasons why the +// executable file might be covered by the GNU General Public License. +// +// Based on the code located here: +// http://th30z.netsons.org/2010/01/qt4-image-crop-item/ + +#ifndef SCRIBO_DEMO_SHARED_SRC_CROP_ITEM_HH +# define SCRIBO_DEMO_SHARED_SRC_CROP_ITEM_HH + +#include <QStyleOptionGraphicsItem> +#include <QGraphicsSceneMouseEvent> +#include <QGraphicsScene> +#include <QGraphicsView> +#include <QGraphicsItem> +#include <QApplication> +#include <QPainter> +#include <QtGui> + +#define CROP_BORDER_LINE 10 +#define CROP_GRID_SIZE 3 + +namespace scribo +{ + + namespace demo + { + + namespace shared + { + + class crop_item : public QGraphicsItem + { + public: + crop_item(QGraphicsItem *parent); + const QRectF& cropRect() const; + + QRectF boundingRect() const; + void paint (QPainter *painter, + const QStyleOptionGraphicsItem *option, + QWidget *widget = 0); + + void reset(); + + protected: + void mousePressEvent (QGraphicsSceneMouseEvent *event); + void mouseReleaseEvent (QGraphicsSceneMouseEvent *event); + void mouseMoveEvent(QGraphicsSceneMouseEvent *event); + +// void updateCursor(QGraphicsSceneMouseEvent *event); + + private: + enum CropItemResize + { + CropItemResizeNone, + + CropItemResizeTopLeft, + CropItemResizeTopRight, + CropItemResizeBottomLeft, + CropItemResizeBottomRight, + + CropItemResizeLeft, + CropItemResizeRight, + CropItemResizeTop, + CropItemResizeBottom + }; + + private: + CropItemResize cropResize_; + QRectF cropRect_; + bool mousePress_; + }; + + + } // end of namespace scribo::demo::shared + + } // end of namespace scribo::demo + +} // end of namespace scribo + + +#endif // ! SCRIBO_DEMO_SHARED_SRC_CROP_ITEM_HH diff --git a/scribo/demo/shared/src/image_viewer.cc b/scribo/demo/shared/src/image_viewer.cc new file mode 100644 index 0000000..b61f86b --- /dev/null +++ b/scribo/demo/shared/src/image_viewer.cc @@ -0,0 +1,344 @@ +// Copyright (C) 2010 EPITA Research and Development Laboratory +// (LRDE) +// +// This file is part of Olena. +// +// Olena is free software: you can redistribute it and/or modify it under +// the terms of the GNU General Public License as published by the Free +// Software Foundation, version 2 of the License. +// +// Olena is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Olena. If not, see <http://www.gnu.org/licenses/>. +// +// As a special exception, you may use this file as part of a free +// software project without restriction. Specifically, if other files +// instantiate templates or use macros or inline functions from this +// file, or you compile this file and link it with other files to produce +// an executable, this file does not by itself cause the resulting +// executable to be covered by the GNU General Public License. This +// exception does not however invalidate any other reasons why the +// executable file might be covered by the GNU General Public License. + + +# include <shared/src/image_viewer.hh> +# include <shared/src/crop_item.hh> + +namespace scribo +{ + + namespace demo + { + + namespace shared + { + + image_viewer::image_viewer(QWidget *parent) + : QWidget(parent), image_(0), selection_(0), angle_(0) + { + setupUi(this); + + connect(viewer_->verticalScrollBar(), SIGNAL(valueChanged(int)), + this, SLOT(move_vertical_sliders(int))); + connect(viewer_->horizontalScrollBar(), SIGNAL(valueChanged(int)), + this, SLOT(move_horizontal_sliders(int))); + + setup_scene(); + + slider->setMinimum(0); + visible_slider(false); + + set_selection_enabled(false); + set_rotation_enabled(false); + } + + + + image_viewer::~image_viewer() + { + + } + + unsigned image_viewer::current_slice() const + { + return slider->value(); + } + + internal::interactiveScene * image_viewer::scene() + { + return static_cast<internal::interactiveScene *>(viewer_->scene()); + } + + const internal::interactiveScene * image_viewer::scene() const + { + return static_cast<const internal::interactiveScene *>(viewer_->scene()); + } + + // Private members + + void image_viewer::setup_scene() + { + QGraphicsScene *scene = new internal::interactiveScene(); + viewer_->setScene(scene); + viewer_->show(); + } + + void image_viewer::draw_image(const mln::image2d<dsp_data_t>& ima) + { + QImage + qima = mln::convert::to_qimage_nocopy(ima); + QPixmap pixmap = QPixmap::fromImage(qima); + + draw_image(pixmap, QPoint(ima.domain().pmin().col(), + ima.domain().pmin().row())); + } + + + void image_viewer::draw_image(const QPixmap& pixmap) + { + draw_image(pixmap, QPoint(0, 0)); + } + + + void image_viewer::draw_image(const QPixmap& pixmap, + const QPoint& origin) + { + bool restore_selection = false; + + if (image_ != 0) + { + viewer_->scene()->removeItem(image_); + delete image_; + + if (selection_) + { + selection_ = 0; + restore_selection = true; + } + } + + image_ = viewer_->scene()->addPixmap(pixmap); + viewer_->scene()->setSceneRect(image_->boundingRect()); + + if (pixmap.width() > viewer_->maximumViewportSize().width()) + viewer_->fitInView(image_->boundingRect(), Qt::KeepAspectRatio); + + zoomLabel->setEnabled(true); + zoomIn->setEnabled(true); + zoomOut->setEnabled(true); + zoomFixed->setEnabled(true); + zoomOriginal->setEnabled(true); + + image_->translate(origin.x(), origin.y()); + + viewer_->setSceneRect(image_->sceneBoundingRect()); + + // Restore selection mode if needed + set_selection_enabled(restore_selection); + } + + + void image_viewer::resize_image(const QRectF& rect) + { + if (image_ != 0) + viewer_->fitInView(rect, Qt::KeepAspectRatio); + } + + void image_viewer::resizeEvent(QResizeEvent * event) + { + if (image_ != 0) + resize_image(image_->boundingRect()); + event->ignore(); + } + + void image_viewer::keyPressEvent(QKeyEvent *event) + { + if (event->text() == QString("+")) + { + on_zoomIn_clicked(); + event->accept(); + } + else if (event->text() == QString("-")) + { + on_zoomOut_clicked(); + event->accept(); + } + else if (event->key() == Qt::Key_Return || event->key() == Qt::Key_Enter) + { + if (event->modifiers() == Qt::ControlModifier) + on_zoomFixed_clicked(); + else + on_zoomOriginal_clicked(); + event->accept(); + } + else + event->ignore(); + } + + + // Private slots + + void image_viewer::visible_slider(bool b) + { + slider->setVisible(b); + label_2->setVisible(b); + frame_nb->setVisible(b); + } + + void image_viewer::move_vertical_sliders(int value) + { + viewer_->verticalScrollBar()->setValue(value); + } + + + void image_viewer::move_horizontal_sliders(int value) + { + viewer_->horizontalScrollBar()->setValue(value); + } + + + void image_viewer::on_slider_valueChanged(int sli) + { + frame_nb->setText(QString("%1/%2").arg(sli).arg(slider->maximum())); + emit slider_valueChanged(sli); + } + + void image_viewer::update_image(const mln::image2d<dsp_data_t>& ima) + { + draw_image(ima); + } + + void image_viewer::on_rotate_cw_btn_clicked() + { + angle_ += 90 % 360; + image_->rotate(90); + viewer_->setSceneRect(image_->sceneBoundingRect()); + } + + void image_viewer::on_rotate_ccw_btn_clicked() + { + angle_ -= 90 % 360; + image_->rotate(-90); + viewer_->setSceneRect(image_->sceneBoundingRect()); + } + + void image_viewer::on_zoomIn_clicked() + { + viewer_->scale(1.2, 1.2); + } + + void image_viewer::on_zoomOut_clicked() + { + viewer_->scale(1 / 1.2, 1 / 1.2); + } + + void image_viewer::on_zoomFixed_clicked() + { + if (image_ != 0) + resize_image(image_->boundingRect()); + } + + void image_viewer::on_zoomOriginal_clicked() + { + if (image_ != 0) + resize_image(viewer_->viewport()->geometry()); + } + + void image_viewer::clear() + { + visible_slider(false); + if (image_ != 0 && image_->scene() == viewer_->scene()) + { + viewer_->scene()->removeItem(image_); + delete image_; + image_ = 0; + } + } + + void image_viewer::set_selection_enabled(bool b) + { + if (b) + { + if (selection_ == 0) + selection_ = new crop_item(image_); + } + else + { + delete selection_; + selection_ = 0; + } + } + + + void image_viewer::set_rotation_enabled(bool b) + { + angle_ = 0; + rotate_lbl->setVisible(b); + rotate_cw_btn->setVisible(b); + rotate_ccw_btn->setVisible(b); + vline->setVisible(b); + } + + + bool image_viewer::has_selection() const + { + return selection_; + } + + + const QRectF& image_viewer::selection() const + { + static QRectF invalid_selection; + mln_assertion(has_selection()); + + if (selection_) + return selection_->cropRect(); + + return invalid_selection; + } + + + bool image_viewer::has_rotation() const + { + return rotate_lbl->isVisible(); + } + + + qreal image_viewer::rotation() const + { + mln_assertion(has_rotation()); + + return angle_; + } + + + QPixmap image_viewer::image() const + { + return image_->pixmap(); + } + + // Public slots + + void image_viewer::set_image_layer_count(unsigned nslis) + { + visible_slider(nslis > 1); + + slider->setMaximum(nslis - 1); + + unsigned sli = current_slice(); + if (current_slice() >= nslis) + sli = 0; + + slider->setSliderPosition(sli); + on_slider_valueChanged(sli); + } + + } // end of namespace scribo::demo::shared + + } // end of namespace scribo::demo + +} // end of namespace scribo diff --git a/scribo/demo/shared/src/image_viewer.hh b/scribo/demo/shared/src/image_viewer.hh new file mode 100644 index 0000000..628f5d4 --- /dev/null +++ b/scribo/demo/shared/src/image_viewer.hh @@ -0,0 +1,135 @@ +// Copyright (C) 2010 EPITA Research and Development Laboratory (LRDE) +// +// This file is part of Olena. +// +// Olena is free software: you can redistribute it and/or modify it under +// the terms of the GNU General Public License as published by the Free +// Software Foundation, version 2 of the License. +// +// Olena is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Olena. If not, see <http://www.gnu.org/licenses/>. +// +// As a special exception, you may use this file as part of a free +// software project without restriction. Specifically, if other files +// instantiate templates or use macros or inline functions from this +// file, or you compile this file and link it with other files to produce +// an executable, this file does not by itself cause the resulting +// executable to be covered by the GNU General Public License. This +// exception does not however invalidate any other reasons why the +// executable file might be covered by the GNU General Public License. + +#ifndef SCRIBO_DEMO_SHARED_SRC_IMAGE_VIEWER_HH +# define SCRIBO_DEMO_SHARED_SRC_IMAGE_VIEWER_HH + +# include <QApplication> +# include <QtCore> +# include <QtGui> + +# include <ui_image_viewer.h> + +# include <mln/core/image/image2d.hh> +# include <mln/convert/to_qimage_nocopy.hh> + +# include <shared/src/types.hh> +# include <shared/src/internal/interactive_scene.hh> + + +namespace scribo +{ + + namespace demo + { + + namespace shared + { + + // Forward declaration. + class crop_item; + + class image_viewer + : public QWidget, private Ui::ImageViewer + { + Q_OBJECT; + + public: + image_viewer(QWidget *parent = 0); + ~image_viewer(); + + void draw_image(const mln::image2d<dsp_data_t>& ima); + void draw_image(const QPixmap& pixmap); + void draw_image(const QPixmap& pixmap, const QPoint& origin); + + unsigned current_slice() const; + + internal::interactiveScene * scene(); + const internal::interactiveScene * scene() const; + + void clear(); + + void set_selection_enabled(bool b); + void set_rotation_enabled(bool b); + + + bool has_selection() const; + const QRectF& selection() const; + + bool has_rotation() const; + qreal rotation() const; + + QPixmap image() const; + + private: // members + void setup_scene(); + + void resize_image(const QRectF& rect); + + void keyPressEvent(QKeyEvent *event); + void resizeEvent(QResizeEvent * event); + + private slots: + void visible_slider(bool b); + + void move_vertical_sliders(int value); + void move_horizontal_sliders(int value); + + void on_slider_valueChanged(int sli); + + void on_rotate_cw_btn_clicked(); + void on_rotate_ccw_btn_clicked(); + + void on_zoomIn_clicked(); + void on_zoomOut_clicked(); + void on_zoomFixed_clicked(); + void on_zoomOriginal_clicked(); + + + public slots: + void set_image_layer_count(unsigned nslis); + void update_image(const mln::image2d<dsp_data_t>& ima); + + + signals: + void slider_valueChanged(int sli); + + private: // attributes + QGraphicsPixmapItem* image_; + crop_item* selection_; + bool mouse_moving_; + QPoint p_start_; + qreal angle_; + }; + + + } // end of namespace scribo::demo::shared + + } // end of namespace scribo::demo + +} // end of namespace scribo + + +#endif // ! SCRIBO_DEMO_SHARED_SRC_IMAGE_VIEWER_HH diff --git a/scribo/demo/shared/src/internal.bak/interactive_scene.cc b/scribo/demo/shared/src/internal.bak/interactive_scene.cc new file mode 100644 index 0000000..b839f6b --- /dev/null +++ b/scribo/demo/shared/src/internal.bak/interactive_scene.cc @@ -0,0 +1,286 @@ +// Copyright (C) 2010 EPITA Research and Development Laboratory (LRDE) +// +// This file is part of Olena. +// +// Olena is free software: you can redistribute it and/or modify it under +// the terms of the GNU General Public License as published by the Free +// Software Foundation, version 2 of the License. +// +// Olena is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Olena. If not, see <http://www.gnu.org/licenses/>. +// +// As a special exception, you may use this file as part of a free +// software project without restriction. Specifically, if other files +// instantiate templates or use macros or inline functions from this +// file, or you compile this file and link it with other files to produce +// an executable, this file does not by itself cause the resulting +// executable to be covered by the GNU General Public License. This +// exception does not however invalidate any other reasons why the +// executable file might be covered by the GNU General Public License. + +# include <shared/src/internal/interactive_scene.hh> + +namespace scribo +{ + + namespace demo + { + + namespace shared + { + + namespace internal + { + + + struct test : public QGraphicsItem + { + test() + { + setZValue(0); + setCursor(Qt::OpenHandCursor); + + } + + void mousePressEvent(QGraphicsSceneMouseEvent *event) + { + setCursor(Qt::ClosedHandCursor); + } + + void mouseMoveEvent(QGraphicsSceneMouseEvent *event) + { + setCursor(Qt::OpenHandCursor); + } + + void mouseReleaseEvent(QGraphicsSceneMouseEvent *) + { + setCursor(Qt::OpenHandCursor); + } + + void paint(QPainter *painter, + const QStyleOptionGraphicsItem *option, + QWidget *widget) + { + painter->setPen(Qt::NoPen); + painter->setBrush(Qt::darkGray); + painter->drawEllipse(-12, -12, 30, 30); + painter->setPen(QPen(Qt::black, 1)); + painter->setBrush(QBrush(Qt::red)); + painter->drawEllipse(-15, -15, 30, 30); + + painter->setBrush(QColor(0, 0, 0, 127)); + painter->drawRect(scene()->sceneRect()); + + } + + QRectF boundingRect() const + { + return QRectF(-15.5, -15.5, 34, 34); + } + + }; + + + + interactiveScene::interactiveScene(QObject * parent) + : QGraphicsScene(parent), mode_(Drawing), + mouse_moved_(false), mouse_pressed_(false), + selectionTracking_(false) + { + rect_.setZValue(1); + + QPen pen; + pen.setColor(QColor(Qt::black)); + pen.setStyle(Qt::SolidLine); + pen.setWidth(1); + + rect_.setPen(pen); + + setSceneRect(QRectF(-150, -150, 300, 300)); + + addItem(new test()); + } + + + void interactiveScene::mouseMoveEvent(QGraphicsSceneMouseEvent *e) + { + if (mouse_pressed_) + { + // If selection is enabled. + if (selectionTracking_) + { + switch(mode_) + { + // Moving an existing selection. + case Moving: + { + QPointF p = e->scenePos() - e->lastScenePos(); + rect_.translate(p.x(), p.y()); + e->accept(); + break; + } + + // A new selection must be extended. + case Drawing: + { + rect_.setRect(QRectF(e->buttonDownScenePos(Qt::LeftButton), + e->scenePos())); + e->accept(); + break; + } + + + // Extending an existing selection + case Extending: + { + rect_.update_size(rect_corner_, e->scenePos()); + break; + } + + default: + qDebug() << "interactiveScene::mouseMoveEvent - Invalid mode"; + } + + emit mouse_pressed(e->scenePos()); + mouse_moved_ = true; + } + } + else + super_::mouseMoveEvent(e); + + emit mouse_moved(e->scenePos()); + } + + void interactiveScene::mousePressEvent(QGraphicsSceneMouseEvent *e) + { + mouse_moved_ = false; + mouse_pressed_ = true; + pressed_point_ = e->scenePos(); + + emit mouse_pressed(e->scenePos()); + + // If selection is enabled. + if (selectionTracking_) + { + // About to move an existing rectangle. + QGraphicsItem *item = itemAt(e->scenePos()); + if (item == &rect_) + { + mode_ = Moving; + super_::mousePressEvent(e); + } + else if (item != 0) + { + mode_ = Extending; + rect_corner_ = item; + super_::mousePressEvent(e); + } + // Draw a new rectangle + else + { + mode_ = Drawing; + rect_.resetTransform(); + rect_.setRect(QRectF(e->scenePos(), e->scenePos())); + if (rect_.scene() != this) + addItem(&rect_); + e->accept(); + } + } + } + + void interactiveScene::mouseReleaseEvent(QGraphicsSceneMouseEvent *e) + { + mouse_pressed_ = false; + + switch(mode_) + { + + case Drawing: + { + if (selectionTracking_ && mouse_moved_) + emit new_selection(rect_.boundingRect()); + else + { + // A mouse click is performed outside the selection + // rectangle. + // Clear selection if exists. + if (mode_ != Moving && rect_.scene() == this) + { + rect_.setRect(sceneRect()); + removeItem(&rect_); + emit selection_cleared(); + } + } + break; + } + + case Moving: + { + if (mouse_moved_) + { + QPointF p = e->scenePos() - pressed_point_; + + + // FIXME: the bounding rectangle size is increasing by + // 0.5 pixels for an unknown reason... + rect_.setRect(rect_.boundingRect().translated(p.x(), p.y())); + rect_.resetTransform(); + } + break; + } + + + case Extending: + { + break; + } + + default: + qDebug() << "interactiveScene::mouseReleaseEvent - invalid mode"; + + } + + + if (!mouse_moved_) + emit mouse_click(e->scenePos()); + + emit mouse_released(e->scenePos()); + + e->accept(); + } + + + void interactiveScene::setSelectionTracking(bool b) + { + selectionTracking_ = b; + } + + bool interactiveScene::has_selection() const + { + return rect_.scene() == this; + } + + QRectF interactiveScene::selection() const + { + return rect_.boundingRect(); + } + + void interactiveScene::clear_selection() + { + if (rect_.scene() == this) + removeItem(&rect_); + } + + + } // end of namespace mln::demo::shared::internal + + } // end of namespace mln::demo::shared + + } // end of namespace mln::demo + +} // end of namespace mln diff --git a/scribo/demo/shared/src/internal.bak/interactive_scene.hh b/scribo/demo/shared/src/internal.bak/interactive_scene.hh new file mode 100644 index 0000000..5888152 --- /dev/null +++ b/scribo/demo/shared/src/internal.bak/interactive_scene.hh @@ -0,0 +1,108 @@ +// Copyright (C) 2010 EPITA Research and Development Laboratory (LRDE) +// +// This file is part of Olena. +// +// Olena is free software: you can redistribute it and/or modify it under +// the terms of the GNU General Public License as published by the Free +// Software Foundation, version 2 of the License. +// +// Olena is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Olena. If not, see <http://www.gnu.org/licenses/>. +// +// As a special exception, you may use this file as part of a free +// software project without restriction. Specifically, if other files +// instantiate templates or use macros or inline functions from this +// file, or you compile this file and link it with other files to produce +// an executable, this file does not by itself cause the resulting +// executable to be covered by the GNU General Public License. This +// exception does not however invalidate any other reasons why the +// executable file might be covered by the GNU General Public License. + +#ifndef SCRIBO_DEMO_SHARED_SRC_INTERNAL_INTERACTIVE_SCENE_HH +# define SCRIBO_DEMO_SHARED_SRC_INTERNAL_INTERACTIVE_SCENE_HH + +# include <QtGui/QGraphicsScene> +# include <QtGui/QGraphicsSceneMouseEvent> +# include <QtGui/QGraphicsLineItem> +# include <QtCore/QPoint> +# include <QtCore/QDebug> + +# include <shared/src/internal/selection_rectangle.hh> + +namespace scribo +{ + + namespace demo + { + + namespace shared + { + + namespace internal + { + + enum Mode + { + Moving, + Drawing, + Extending + }; + + class interactiveScene : public QGraphicsScene + { + Q_OBJECT; + + typedef QGraphicsScene super_; + + public: + + interactiveScene(QObject * parent = 0); + + void mouseMoveEvent(QGraphicsSceneMouseEvent *e); + void mousePressEvent(QGraphicsSceneMouseEvent *e); + void mouseReleaseEvent(QGraphicsSceneMouseEvent *e); + + void setSelectionTracking(bool b); + + bool has_selection() const; + QRectF selection() const; + void clear_selection(); + + signals: + void mouse_click(const QPointF& p); + void mouse_moved(const QPointF& p); + void mouse_pressed(const QPointF& p); + void mouse_released(const QPointF& p); + + void new_selection(const QRectF& rect); + void selection_cleared(); + + private: + selection_rectangle rect_; + + QGraphicsItem* rect_corner_; + + QPointF pressed_point_; + + Mode mode_; + + bool mouse_moved_; + bool mouse_pressed_; + bool selectionTracking_; + }; + + + } // end of namespace mln::demo::shared::internal + + } // end of namespace mln::demo::shared + + } // end of namespace mln::demo + +} // end of namespace mln + +#endif // ! SCRIBO_DEMO_SHARED_SRC_INTERNAL_INTERACTIVE_SCENE_HH diff --git a/scribo/demo/shared/src/internal.bak/selection_rectangle.cc b/scribo/demo/shared/src/internal.bak/selection_rectangle.cc new file mode 100644 index 0000000..d3f82b7 --- /dev/null +++ b/scribo/demo/shared/src/internal.bak/selection_rectangle.cc @@ -0,0 +1,241 @@ +// Copyright (C) 2010 EPITA Research and Development Laboratory (LRDE) +// +// This file is part of Olena. +// +// Olena is free software: you can redistribute it and/or modify it under +// the terms of the GNU General Public License as published by the Free +// Software Foundation, version 2 of the License. +// +// Olena is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Olena. If not, see <http://www.gnu.org/licenses/>. +// +// As a special exception, you may use this file as part of a free +// software project without restriction. Specifically, if other files +// instantiate templates or use macros or inline functions from this +// file, or you compile this file and link it with other files to produce +// an executable, this file does not by itself cause the resulting +// executable to be covered by the GNU General Public License. This +// exception does not however invalidate any other reasons why the +// executable file might be covered by the GNU General Public License. + +#include <QtGui> +#include <shared/src/internal/selection_rectangle.hh> + + +namespace scribo +{ + + namespace demo + { + + namespace shared + { + + namespace internal + { + + selection_rectangle::selection_rectangle() + { + QPen pen; + pen.setColor(QColor(Qt::red)); + pen.setStyle(Qt::SolidLine); + pen.setWidth(1); + + + rects_.resize(9); + for (int i = 0; i < rects_.size(); ++i) + { + rects_[i] = new QGraphicsRectItem(this); + rects_[i]->setZValue(1); + rects_[i]->setPen(pen); + rects_[i]->show(); + rects_[i]->setAcceptHoverEvents(true); + } + + rects_[1]->setCursor(Qt::SizeFDiagCursor); + rects_[2]->setCursor(Qt::SizeVerCursor); + rects_[3]->setCursor(Qt::SizeBDiagCursor); + rects_[4]->setCursor(Qt::SizeHorCursor); + rects_[5]->setCursor(Qt::SizeHorCursor); + rects_[6]->setCursor(Qt::SizeBDiagCursor); + rects_[7]->setCursor(Qt::SizeVerCursor); + rects_[8]->setCursor(Qt::SizeFDiagCursor); + +// setHandlesChildEvents(true); + setCursor(Qt::SizeAllCursor); + setAcceptHoverEvents(true); + } + + + selection_rectangle::~selection_rectangle() + { + foreach(QGraphicsRectItem *item, rects_) + delete item; + } + + + void selection_rectangle::paint(QPainter *painter, + const QStyleOptionGraphicsItem *option, + QWidget *widget) + { + /* + -------------- + |1| 2 |3| + |--========--| + | || || | + | || || | + |4|| ||5| + | || || | + | || || | + |--========--| + |6| 7 |8| + -------------- + */ + + qreal border = 15; + qreal corner_width = qMin(qAbs(1/8.f * brect_.width()), border); + qreal corner_height = qMin(qAbs(1/8.f * brect_.height()), border); + + painter->setBrush(QColor(255, 255, 255, 127)); + painter->drawRect(brect_); + + // Rectangle 1 + QRectF rect1(brect_.topLeft().x(), brect_.topLeft().y(), + corner_width, + corner_height); + rects_[1]->setRect(rect1); + + // Rectangle 2 + QRectF rect2(rect1.topRight().x(), rect1.topRight().y(), + brect_.width() - 2 * corner_width, + corner_height); + rects_[2]->setRect(rect2); + + // Rectangle 3 + QRectF rect3(brect_.topRight().x() - corner_width, + brect_.topRight().y(), + corner_width, + corner_height); + rects_[3]->setRect(rect3); + + + + // Rectangle 4 + QRectF rect4(brect_.topLeft().x(), + brect_.topLeft().y() + corner_height, + corner_width, + brect_.height() - corner_height); + rects_[4]->setRect(rect4); + + // Rectangle 5 + QRectF rect5(brect_.topRight().x() - corner_width, + brect_.topRight().y() + corner_height, + corner_width, + brect_.height() - corner_height); + rects_[5]->setRect(rect5); + + + + // Rectangle 6 + QRectF rect6(brect_.bottomLeft().x(), + brect_.bottomLeft().y() - corner_height, + corner_width, + corner_height); + rects_[6]->setRect(rect6); + + // Rectangle 7 + QRectF rect7(rect6.topRight().x(), rect6.topRight().y(), + brect_.width() - 2 * corner_width, + corner_height); + rects_[7]->setRect(rect7); + + // Rectangle 8 + QRectF rect8(rect7.topRight().x(), rect7.topRight().y(), + corner_width, + corner_height); + rects_[8]->setRect(rect8); + + + painter->setPen(pen()); + painter->drawRect(brect_); + } + + + QRectF selection_rectangle::boundingRect() const + { + qreal penWidth = pen().width(); + return QRectF(brect_.x() - penWidth / 2, brect_.y() - penWidth / 2, + brect_.width() + penWidth / 2, + brect_.height() + penWidth / 2); + } + + + void selection_rectangle::setRect(qreal x, qreal y, + qreal width, qreal height) + { + prepareGeometryChange(); + brect_ = QRectF(x, y, width, height).normalized(); + } + + + void selection_rectangle::setRect(const QRectF & rectangle) + { + prepareGeometryChange(); + brect_ = rectangle.normalized(); + } + + + void selection_rectangle::update_size(QGraphicsItem *item, + const QPointF& p) + { + /* + -------------- + |1| 2 |3| + |--========--| + | || || | + | || || | + |4|| ||5| + | || || | + | || || | + |--========--| + |6| 7 |8| + -------------- + */ + QPointF p_ = p; + + prepareGeometryChange(); + if (rects_[1] == item) + brect_.setTopLeft(p_); + else if (rects_[2] == item) + brect_.setTop(p_.y()); + else if (rects_[3] == item) + brect_.setTopRight(p_); + else if (rects_[4] == item) + brect_.setLeft(p_.x()); + else if (rects_[5] == item) + brect_.setRight(p_.x()); + else if (rects_[6] == item) + brect_.setBottomLeft(p_); + else if (rects_[7] == item) + brect_.setBottom(p_.y()); + else if (rects_[8] == item) + brect_.setBottomRight(p_); + else + qDebug() << "selection_rectangle::update_size - invalid item"; + + brect_ = brect_.normalized(); + } + + + } // end of namespace mln::demo::shared::internal + + } // end of namespace mln::demo::shared + + } // end of namespace mln::demo + +} // end of namespace mln diff --git a/scribo/demo/shared/src/internal.bak/selection_rectangle.hh b/scribo/demo/shared/src/internal.bak/selection_rectangle.hh new file mode 100644 index 0000000..b58bad2 --- /dev/null +++ b/scribo/demo/shared/src/internal.bak/selection_rectangle.hh @@ -0,0 +1,91 @@ +// Copyright (C) 2010 EPITA Research and Development Laboratory (LRDE) +// +// This file is part of Olena. +// +// Olena is free software: you can redistribute it and/or modify it under +// the terms of the GNU General Public License as published by the Free +// Software Foundation, version 2 of the License. +// +// Olena is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Olena. If not, see <http://www.gnu.org/licenses/>. +// +// As a special exception, you may use this file as part of a free +// software project without restriction. Specifically, if other files +// instantiate templates or use macros or inline functions from this +// file, or you compile this file and link it with other files to produce +// an executable, this file does not by itself cause the resulting +// executable to be covered by the GNU General Public License. This +// exception does not however invalidate any other reasons why the +// executable file might be covered by the GNU General Public License. + +#ifndef SCRIBO_DEMO_SHARED_SRC_INTERNAL_SELECTION_RECTANGLE_HH +# define SCRIBO_DEMO_SHARED_SRC_INTERNAL_SELECTION_RECTANGLE_HH + +# include <QtCore> +# include <QtGui> + +namespace scribo +{ + + namespace demo + { + + namespace shared + { + + namespace internal + { + + class selection_rectangle : public QAbstractGraphicsShapeItem + { + + public: + selection_rectangle(); + ~selection_rectangle(); + + void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, + QWidget *widget); + + QRectF boundingRect() const; + + void setRect(qreal x, qreal y, qreal width, qreal height); + void setRect(const QRectF & rectangle); + + void update_size(QGraphicsItem *item, const QPointF& p); + + private: // members + + + private: // attributes + /* + -------------- + |1| 2 |3| + |--========--| + | || || | + | || || | + |4|| ||5| + | || || | + | || || | + |--========--| + |6| 7 |8| + -------------- + */ + QVector<QGraphicsRectItem *> rects_; + QRectF brect_; + + }; + + } // end of namespace mln::demo::shared::internal + + } // end of namespace mln::demo::shared + + } // end of namespace mln::demo + +} // end of namespace mln + +#endif // !SCRIBO_DEMO_SHARED_SRC_INTERNAL_SELECTION_RECTANGLE_HH diff --git a/scribo/demo/shared/src/internal/interactive_scene.cc b/scribo/demo/shared/src/internal/interactive_scene.cc new file mode 100644 index 0000000..a56517b --- /dev/null +++ b/scribo/demo/shared/src/internal/interactive_scene.cc @@ -0,0 +1,87 @@ +// Copyright (C) 2010 EPITA Research and Development Laboratory (LRDE) +// +// This file is part of Olena. +// +// Olena is free software: you can redistribute it and/or modify it under +// the terms of the GNU General Public License as published by the Free +// Software Foundation, version 2 of the License. +// +// Olena is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Olena. If not, see <http://www.gnu.org/licenses/>. +// +// As a special exception, you may use this file as part of a free +// software project without restriction. Specifically, if other files +// instantiate templates or use macros or inline functions from this +// file, or you compile this file and link it with other files to produce +// an executable, this file does not by itself cause the resulting +// executable to be covered by the GNU General Public License. This +// exception does not however invalidate any other reasons why the +// executable file might be covered by the GNU General Public License. + +# include <shared/src/internal/interactive_scene.hh> + +namespace scribo +{ + + namespace demo + { + + namespace shared + { + + namespace internal + { + + interactiveScene::interactiveScene(QObject * parent) + : QGraphicsScene(parent), mouse_moved_(false) + { + } + + + void interactiveScene::mouseMoveEvent(QGraphicsSceneMouseEvent *e) + { + super_::mouseMoveEvent(e); + + if (e->buttons() & Qt::LeftButton) + { + emit mouse_pressed(e->scenePos()); + mouse_moved_ = true; + } + + emit mouse_moved(e->scenePos()); + } + + void interactiveScene::mousePressEvent(QGraphicsSceneMouseEvent *e) + { + super_::mousePressEvent(e); + + mouse_moved_ = false; + pressed_point_ = e->scenePos(); + + emit mouse_pressed(e->scenePos()); + } + + void interactiveScene::mouseReleaseEvent(QGraphicsSceneMouseEvent *e) + { + super_::mouseReleaseEvent(e); + + if (!mouse_moved_) + emit mouse_click(e->scenePos()); + + emit mouse_released(e->scenePos()); + + e->accept(); + } + + } // end of namespace mln::demo::shared::internal + + } // end of namespace mln::demo::shared + + } // end of namespace mln::demo + +} // end of namespace mln diff --git a/scribo/demo/shared/src/internal/interactive_scene.hh b/scribo/demo/shared/src/internal/interactive_scene.hh new file mode 100644 index 0000000..ba9e9e4 --- /dev/null +++ b/scribo/demo/shared/src/internal/interactive_scene.hh @@ -0,0 +1,84 @@ +// Copyright (C) 2010 EPITA Research and Development Laboratory (LRDE) +// +// This file is part of Olena. +// +// Olena is free software: you can redistribute it and/or modify it under +// the terms of the GNU General Public License as published by the Free +// Software Foundation, version 2 of the License. +// +// Olena is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Olena. If not, see <http://www.gnu.org/licenses/>. +// +// As a special exception, you may use this file as part of a free +// software project without restriction. Specifically, if other files +// instantiate templates or use macros or inline functions from this +// file, or you compile this file and link it with other files to produce +// an executable, this file does not by itself cause the resulting +// executable to be covered by the GNU General Public License. This +// exception does not however invalidate any other reasons why the +// executable file might be covered by the GNU General Public License. + +#ifndef SCRIBO_DEMO_SHARED_SRC_INTERNAL_INTERACTIVE_SCENE_HH +# define SCRIBO_DEMO_SHARED_SRC_INTERNAL_INTERACTIVE_SCENE_HH + +# include <QtGui/QGraphicsScene> +# include <QtGui/QGraphicsSceneMouseEvent> +# include <QtGui/QGraphicsLineItem> +# include <QtCore/QPoint> +# include <QtCore/QDebug> + +# include <shared/src/internal/selection_rectangle.hh> + +namespace scribo +{ + + namespace demo + { + + namespace shared + { + + namespace internal + { + + class interactiveScene : public QGraphicsScene + { + Q_OBJECT; + + typedef QGraphicsScene super_; + + public: + + interactiveScene(QObject * parent = 0); + + void mouseMoveEvent(QGraphicsSceneMouseEvent *e); + void mousePressEvent(QGraphicsSceneMouseEvent *e); + void mouseReleaseEvent(QGraphicsSceneMouseEvent *e); + + signals: + void mouse_click(const QPointF& p); + void mouse_moved(const QPointF& p); + void mouse_pressed(const QPointF& p); + void mouse_released(const QPointF& p); + + private: + QPointF pressed_point_; + + bool mouse_moved_; + }; + + + } // end of namespace mln::demo::shared::internal + + } // end of namespace mln::demo::shared + + } // end of namespace mln::demo + +} // end of namespace mln + +#endif // ! SCRIBO_DEMO_SHARED_SRC_INTERNAL_INTERACTIVE_SCENE_HH diff --git a/scribo/demo/shared/src/internal/selection_rectangle.cc b/scribo/demo/shared/src/internal/selection_rectangle.cc new file mode 100644 index 0000000..d3f82b7 --- /dev/null +++ b/scribo/demo/shared/src/internal/selection_rectangle.cc @@ -0,0 +1,241 @@ +// Copyright (C) 2010 EPITA Research and Development Laboratory (LRDE) +// +// This file is part of Olena. +// +// Olena is free software: you can redistribute it and/or modify it under +// the terms of the GNU General Public License as published by the Free +// Software Foundation, version 2 of the License. +// +// Olena is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Olena. If not, see <http://www.gnu.org/licenses/>. +// +// As a special exception, you may use this file as part of a free +// software project without restriction. Specifically, if other files +// instantiate templates or use macros or inline functions from this +// file, or you compile this file and link it with other files to produce +// an executable, this file does not by itself cause the resulting +// executable to be covered by the GNU General Public License. This +// exception does not however invalidate any other reasons why the +// executable file might be covered by the GNU General Public License. + +#include <QtGui> +#include <shared/src/internal/selection_rectangle.hh> + + +namespace scribo +{ + + namespace demo + { + + namespace shared + { + + namespace internal + { + + selection_rectangle::selection_rectangle() + { + QPen pen; + pen.setColor(QColor(Qt::red)); + pen.setStyle(Qt::SolidLine); + pen.setWidth(1); + + + rects_.resize(9); + for (int i = 0; i < rects_.size(); ++i) + { + rects_[i] = new QGraphicsRectItem(this); + rects_[i]->setZValue(1); + rects_[i]->setPen(pen); + rects_[i]->show(); + rects_[i]->setAcceptHoverEvents(true); + } + + rects_[1]->setCursor(Qt::SizeFDiagCursor); + rects_[2]->setCursor(Qt::SizeVerCursor); + rects_[3]->setCursor(Qt::SizeBDiagCursor); + rects_[4]->setCursor(Qt::SizeHorCursor); + rects_[5]->setCursor(Qt::SizeHorCursor); + rects_[6]->setCursor(Qt::SizeBDiagCursor); + rects_[7]->setCursor(Qt::SizeVerCursor); + rects_[8]->setCursor(Qt::SizeFDiagCursor); + +// setHandlesChildEvents(true); + setCursor(Qt::SizeAllCursor); + setAcceptHoverEvents(true); + } + + + selection_rectangle::~selection_rectangle() + { + foreach(QGraphicsRectItem *item, rects_) + delete item; + } + + + void selection_rectangle::paint(QPainter *painter, + const QStyleOptionGraphicsItem *option, + QWidget *widget) + { + /* + -------------- + |1| 2 |3| + |--========--| + | || || | + | || || | + |4|| ||5| + | || || | + | || || | + |--========--| + |6| 7 |8| + -------------- + */ + + qreal border = 15; + qreal corner_width = qMin(qAbs(1/8.f * brect_.width()), border); + qreal corner_height = qMin(qAbs(1/8.f * brect_.height()), border); + + painter->setBrush(QColor(255, 255, 255, 127)); + painter->drawRect(brect_); + + // Rectangle 1 + QRectF rect1(brect_.topLeft().x(), brect_.topLeft().y(), + corner_width, + corner_height); + rects_[1]->setRect(rect1); + + // Rectangle 2 + QRectF rect2(rect1.topRight().x(), rect1.topRight().y(), + brect_.width() - 2 * corner_width, + corner_height); + rects_[2]->setRect(rect2); + + // Rectangle 3 + QRectF rect3(brect_.topRight().x() - corner_width, + brect_.topRight().y(), + corner_width, + corner_height); + rects_[3]->setRect(rect3); + + + + // Rectangle 4 + QRectF rect4(brect_.topLeft().x(), + brect_.topLeft().y() + corner_height, + corner_width, + brect_.height() - corner_height); + rects_[4]->setRect(rect4); + + // Rectangle 5 + QRectF rect5(brect_.topRight().x() - corner_width, + brect_.topRight().y() + corner_height, + corner_width, + brect_.height() - corner_height); + rects_[5]->setRect(rect5); + + + + // Rectangle 6 + QRectF rect6(brect_.bottomLeft().x(), + brect_.bottomLeft().y() - corner_height, + corner_width, + corner_height); + rects_[6]->setRect(rect6); + + // Rectangle 7 + QRectF rect7(rect6.topRight().x(), rect6.topRight().y(), + brect_.width() - 2 * corner_width, + corner_height); + rects_[7]->setRect(rect7); + + // Rectangle 8 + QRectF rect8(rect7.topRight().x(), rect7.topRight().y(), + corner_width, + corner_height); + rects_[8]->setRect(rect8); + + + painter->setPen(pen()); + painter->drawRect(brect_); + } + + + QRectF selection_rectangle::boundingRect() const + { + qreal penWidth = pen().width(); + return QRectF(brect_.x() - penWidth / 2, brect_.y() - penWidth / 2, + brect_.width() + penWidth / 2, + brect_.height() + penWidth / 2); + } + + + void selection_rectangle::setRect(qreal x, qreal y, + qreal width, qreal height) + { + prepareGeometryChange(); + brect_ = QRectF(x, y, width, height).normalized(); + } + + + void selection_rectangle::setRect(const QRectF & rectangle) + { + prepareGeometryChange(); + brect_ = rectangle.normalized(); + } + + + void selection_rectangle::update_size(QGraphicsItem *item, + const QPointF& p) + { + /* + -------------- + |1| 2 |3| + |--========--| + | || || | + | || || | + |4|| ||5| + | || || | + | || || | + |--========--| + |6| 7 |8| + -------------- + */ + QPointF p_ = p; + + prepareGeometryChange(); + if (rects_[1] == item) + brect_.setTopLeft(p_); + else if (rects_[2] == item) + brect_.setTop(p_.y()); + else if (rects_[3] == item) + brect_.setTopRight(p_); + else if (rects_[4] == item) + brect_.setLeft(p_.x()); + else if (rects_[5] == item) + brect_.setRight(p_.x()); + else if (rects_[6] == item) + brect_.setBottomLeft(p_); + else if (rects_[7] == item) + brect_.setBottom(p_.y()); + else if (rects_[8] == item) + brect_.setBottomRight(p_); + else + qDebug() << "selection_rectangle::update_size - invalid item"; + + brect_ = brect_.normalized(); + } + + + } // end of namespace mln::demo::shared::internal + + } // end of namespace mln::demo::shared + + } // end of namespace mln::demo + +} // end of namespace mln diff --git a/scribo/demo/shared/src/internal/selection_rectangle.hh b/scribo/demo/shared/src/internal/selection_rectangle.hh new file mode 100644 index 0000000..b58bad2 --- /dev/null +++ b/scribo/demo/shared/src/internal/selection_rectangle.hh @@ -0,0 +1,91 @@ +// Copyright (C) 2010 EPITA Research and Development Laboratory (LRDE) +// +// This file is part of Olena. +// +// Olena is free software: you can redistribute it and/or modify it under +// the terms of the GNU General Public License as published by the Free +// Software Foundation, version 2 of the License. +// +// Olena is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Olena. If not, see <http://www.gnu.org/licenses/>. +// +// As a special exception, you may use this file as part of a free +// software project without restriction. Specifically, if other files +// instantiate templates or use macros or inline functions from this +// file, or you compile this file and link it with other files to produce +// an executable, this file does not by itself cause the resulting +// executable to be covered by the GNU General Public License. This +// exception does not however invalidate any other reasons why the +// executable file might be covered by the GNU General Public License. + +#ifndef SCRIBO_DEMO_SHARED_SRC_INTERNAL_SELECTION_RECTANGLE_HH +# define SCRIBO_DEMO_SHARED_SRC_INTERNAL_SELECTION_RECTANGLE_HH + +# include <QtCore> +# include <QtGui> + +namespace scribo +{ + + namespace demo + { + + namespace shared + { + + namespace internal + { + + class selection_rectangle : public QAbstractGraphicsShapeItem + { + + public: + selection_rectangle(); + ~selection_rectangle(); + + void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, + QWidget *widget); + + QRectF boundingRect() const; + + void setRect(qreal x, qreal y, qreal width, qreal height); + void setRect(const QRectF & rectangle); + + void update_size(QGraphicsItem *item, const QPointF& p); + + private: // members + + + private: // attributes + /* + -------------- + |1| 2 |3| + |--========--| + | || || | + | || || | + |4|| ||5| + | || || | + | || || | + |--========--| + |6| 7 |8| + -------------- + */ + QVector<QGraphicsRectItem *> rects_; + QRectF brect_; + + }; + + } // end of namespace mln::demo::shared::internal + + } // end of namespace mln::demo::shared + + } // end of namespace mln::demo + +} // end of namespace mln + +#endif // !SCRIBO_DEMO_SHARED_SRC_INTERNAL_SELECTION_RECTANGLE_HH diff --git a/scribo/demo/shared/src/to_mln_image.hh b/scribo/demo/shared/src/to_mln_image.hh new file mode 100644 index 0000000..229f975 --- /dev/null +++ b/scribo/demo/shared/src/to_mln_image.hh @@ -0,0 +1,77 @@ +// Copyright (C) 2010 EPITA Research and Development Laboratory (LRDE) +// +// This file is part of Olena. +// +// Olena is free software: you can redistribute it and/or modify it under +// the terms of the GNU General Public License as published by the Free +// Software Foundation, version 2 of the License. +// +// Olena is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Olena. If not, see <http://www.gnu.org/licenses/>. +// +// As a special exception, you may use this file as part of a free +// software project without restriction. Specifically, if other files +// instantiate templates or use macros or inline functions from this +// file, or you compile this file and link it with other files to produce +// an executable, this file does not by itself cause the resulting +// executable to be covered by the GNU General Public License. This +// exception does not however invalidate any other reasons why the +// executable file might be covered by the GNU General Public License. + +#ifndef SCRIBO_DEMO_SHARED_SRC_TO_MLN_IMAGE_HH +# define SCRIBO_DEMO_SHARED_SRC_TO_MLN_IMAGE_HH + +# include <QImage> +# include <QPoint> + +# include <mln/core/image/image2d.hh> +# include <mln/value/qt/rgb32.hh> +# include <mln/make/box2d.hh> + +namespace scribo +{ + + namespace demo + { + + namespace shared + { + using namespace mln; + + image2d<value::qt::rgb32> + to_mln_image(const QImage& ima, const QPoint& origin) + { + trace::entering("scribo::demo::shared"); + + mln_assertion(!ima.isNull()); + + image2d<value::qt::rgb32> + output(make::box2d(origin.y(), + origin.x(), + origin.y() + ima.height() - 1, + origin.x() + ima.width() - 1), 0); + + memcpy(output.buffer(), ima.bits(), ima.numBytes()); + + mln_assertion(output.nrows() == (unsigned) ima.height()); + mln_assertion(output.ncols() == (unsigned) ima.width()); + + trace::exiting("scribo::demo::shared"); + return output; + } + + + + } // end of namespace scribo::demo::shared + + } // end of namespace scribo::demo + +} // end of namespace scribo + + +#endif // ! SCRIBO_DEMO_SHARED_SRC_TO_MLN_IMAGE_HH diff --git a/scribo/demo/shared/src/types.hh b/scribo/demo/shared/src/types.hh new file mode 100644 index 0000000..8edb54a --- /dev/null +++ b/scribo/demo/shared/src/types.hh @@ -0,0 +1,50 @@ +// Copyright (C) 2010 EPITA Research and Development Laboratory (LRDE) +// +// This file is part of Olena. +// +// Olena is free software: you can redistribute it and/or modify it under +// the terms of the GNU General Public License as published by the Free +// Software Foundation, version 2 of the License. +// +// Olena is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Olena. If not, see <http://www.gnu.org/licenses/>. +// +// As a special exception, you may use this file as part of a free +// software project without restriction. Specifically, if other files +// instantiate templates or use macros or inline functions from this +// file, or you compile this file and link it with other files to produce +// an executable, this file does not by itself cause the resulting +// executable to be covered by the GNU General Public License. This +// exception does not however invalidate any other reasons why the +// executable file might be covered by the GNU General Public License. + +#ifndef SCRIBO_DEMO_SHARED_SRC_TYPES_HH +# define SCRIBO_DEMO_SHARED_SRC_TYPES_HH + + +# include <mln/value/qt/rgb32.hh> + +namespace scribo +{ + + namespace demo + { + + namespace shared + { + + typedef mln::value::qt::rgb32 dsp_data_t; + + } // end of namespace scribo::demo::shared + + } // end of namespace scribo::demo + +} // end of namespace scribo + + +#endif // !SCRIBO_DEMO_SHARED_SRC_TYPES_HH diff --git a/scribo/demo/shared/ui/browse_widget.ui b/scribo/demo/shared/ui/browse_widget.ui new file mode 100644 index 0000000..fde675c --- /dev/null +++ b/scribo/demo/shared/ui/browse_widget.ui @@ -0,0 +1,106 @@ +<ui version="4.0" > + <class>BrowseWidget</class> + <widget class="QWidget" name="BrowseWidget" > + <property name="geometry" > + <rect> + <x>0</x> + <y>0</y> + <width>301</width> + <height>104</height> + </rect> + </property> + <property name="windowTitle" > + <string>Form</string> + </property> + <layout class="QVBoxLayout" name="verticalLayout" > + <property name="margin" > + <number>0</number> + </property> + <item> + <layout class="QGridLayout" name="gridLayout_2" > + <property name="sizeConstraint" > + <enum>QLayout::SetMaximumSize</enum> + </property> + <item row="0" column="1" > + <spacer name="verticalSpacer" > + <property name="orientation" > + <enum>Qt::Vertical</enum> + </property> + <property name="sizeHint" stdset="0" > + <size> + <width>20</width> + <height>40</height> + </size> + </property> + </spacer> + </item> + <item row="1" column="0" > + <spacer name="horizontalSpacer" > + <property name="orientation" > + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0" > + <size> + <width>40</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + <item row="1" column="1" > + <layout class="QGridLayout" name="gridLayout" > + <property name="sizeConstraint" > + <enum>QLayout::SetMaximumSize</enum> + </property> + <item row="0" column="0" colspan="2" > + <widget class="QLabel" name="description_" > + <property name="text" > + <string>Description</string> + </property> + </widget> + </item> + <item row="1" column="0" > + <widget class="QLineEdit" name="path_" /> + </item> + <item row="1" column="1" > + <widget class="QPushButton" name="browseBtn_" > + <property name="text" > + <string>&Browse</string> + </property> + </widget> + </item> + </layout> + </item> + <item row="1" column="2" > + <spacer name="horizontalSpacer_2" > + <property name="orientation" > + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0" > + <size> + <width>40</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + <item row="2" column="1" > + <spacer name="verticalSpacer_2" > + <property name="orientation" > + <enum>Qt::Vertical</enum> + </property> + <property name="sizeHint" stdset="0" > + <size> + <width>20</width> + <height>40</height> + </size> + </property> + </spacer> + </item> + </layout> + </item> + </layout> + </widget> + <resources/> + <connections/> +</ui> diff --git a/scribo/demo/shared/ui/crop_widget.ui b/scribo/demo/shared/ui/crop_widget.ui new file mode 100644 index 0000000..6b67b2b --- /dev/null +++ b/scribo/demo/shared/ui/crop_widget.ui @@ -0,0 +1,34 @@ +<ui version="4.0" > + <class>CropWidget</class> + <widget class="QWidget" name="CropWidget" > + <property name="geometry" > + <rect> + <x>0</x> + <y>0</y> + <width>567</width> + <height>481</height> + </rect> + </property> + <property name="windowTitle" > + <string>Form</string> + </property> + <layout class="QVBoxLayout" name="verticalLayout" > + <property name="margin" > + <number>0</number> + </property> + <item> + <widget class="scribo::demo::shared::image_viewer" native="1" name="viewer_" /> + </item> + </layout> + </widget> + <customwidgets> + <customwidget> + <class>scribo::demo::shared::image_viewer</class> + <extends>QWidget</extends> + <header location="global" >shared/src/image_viewer.hh</header> + <container>1</container> + </customwidget> + </customwidgets> + <resources/> + <connections/> +</ui> diff --git a/scribo/demo/shared/ui/image_viewer.ui b/scribo/demo/shared/ui/image_viewer.ui new file mode 100644 index 0000000..d6f80cb --- /dev/null +++ b/scribo/demo/shared/ui/image_viewer.ui @@ -0,0 +1,284 @@ +<ui version="4.0" > + <class>ImageViewer</class> + <widget class="QWidget" name="ImageViewer" > + <property name="geometry" > + <rect> + <x>0</x> + <y>0</y> + <width>464</width> + <height>350</height> + </rect> + </property> + <property name="sizePolicy" > + <sizepolicy vsizetype="Expanding" hsizetype="Expanding" > + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="windowTitle" > + <string>Form</string> + </property> + <layout class="QVBoxLayout" > + <item> + <layout class="QVBoxLayout" > + <item> + <layout class="QHBoxLayout" > + <item> + <spacer> + <property name="orientation" > + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0" > + <size> + <width>40</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + <item> + <widget class="QLabel" name="rotate_lbl" > + <property name="text" > + <string>Rotate:</string> + </property> + </widget> + </item> + <item> + <widget class="QPushButton" name="rotate_cw_btn" > + <property name="toolTip" > + <string>Rotate clock-wise</string> + </property> + <property name="text" > + <string/> + </property> + <property name="icon" > + <iconset resource="../shared.qrc" > + <normaloff>:/icons/icons/rotate_cw.png</normaloff>:/icons/icons/rotate_cw.png</iconset> + </property> + </widget> + </item> + <item> + <widget class="QPushButton" name="rotate_ccw_btn" > + <property name="toolTip" > + <string>Rotate counter-clock-wise</string> + </property> + <property name="text" > + <string/> + </property> + <property name="icon" > + <iconset resource="../shared.qrc" > + <normaloff>:/icons/icons/rotate_ccw.png</normaloff>:/icons/icons/rotate_ccw.png</iconset> + </property> + </widget> + </item> + <item> + <widget class="Line" name="vline" > + <property name="orientation" > + <enum>Qt::Vertical</enum> + </property> + </widget> + </item> + <item> + <widget class="QLabel" name="zoomLabel" > + <property name="enabled" > + <bool>false</bool> + </property> + <property name="text" > + <string>Zoom:</string> + </property> + </widget> + </item> + <item> + <widget class="QPushButton" name="zoomIn" > + <property name="enabled" > + <bool>false</bool> + </property> + <property name="maximumSize" > + <size> + <width>20</width> + <height>20</height> + </size> + </property> + <property name="text" > + <string/> + </property> + <property name="icon" > + <iconset resource="../shared.qrc" > + <normaloff>:/icons/icons/search-add-icon.png</normaloff>:/icons/icons/search-add-icon.png</iconset> + </property> + <property name="shortcut" > + <string>+</string> + </property> + </widget> + </item> + <item> + <widget class="QPushButton" name="zoomOut" > + <property name="enabled" > + <bool>false</bool> + </property> + <property name="maximumSize" > + <size> + <width>20</width> + <height>20</height> + </size> + </property> + <property name="text" > + <string/> + </property> + <property name="icon" > + <iconset resource="../shared.qrc" > + <normaloff>:/icons/icons/search-remove-icon.png</normaloff>:/icons/icons/search-remove-icon.png</iconset> + </property> + <property name="iconSize" > + <size> + <width>16</width> + <height>16</height> + </size> + </property> + <property name="shortcut" > + <string>-</string> + </property> + </widget> + </item> + <item> + <widget class="QPushButton" name="zoomFixed" > + <property name="enabled" > + <bool>false</bool> + </property> + <property name="maximumSize" > + <size> + <width>16777215</width> + <height>20</height> + </size> + </property> + <property name="text" > + <string>&Fit to screen</string> + </property> + <property name="shortcut" > + <string>F</string> + </property> + </widget> + </item> + <item> + <widget class="QPushButton" name="zoomOriginal" > + <property name="enabled" > + <bool>false</bool> + </property> + <property name="maximumSize" > + <size> + <width>16777215</width> + <height>20</height> + </size> + </property> + <property name="text" > + <string>&Original size</string> + </property> + <property name="shortcut" > + <string>O</string> + </property> + </widget> + </item> + <item> + <spacer> + <property name="orientation" > + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0" > + <size> + <width>40</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + </layout> + </item> + <item> + <widget class="QGraphicsView" name="viewer_" > + <property name="mouseTracking" > + <bool>true</bool> + </property> + <property name="acceptDrops" > + <bool>false</bool> + </property> + <property name="interactive" > + <bool>true</bool> + </property> + <property name="renderHints" > + <set>QPainter::Antialiasing</set> + </property> + <property name="dragMode" > + <enum>QGraphicsView::NoDrag</enum> + </property> + </widget> + </item> + <item> + <layout class="QHBoxLayout" > + <item> + <widget class="QSlider" name="slider" > + <property name="focusPolicy" > + <enum>Qt::WheelFocus</enum> + </property> + <property name="orientation" > + <enum>Qt::Horizontal</enum> + </property> + <property name="tickPosition" > + <enum>QSlider::TicksAbove</enum> + </property> + </widget> + </item> + <item> + <widget class="QLabel" name="label_2" > + <property name="sizePolicy" > + <sizepolicy vsizetype="Preferred" hsizetype="Preferred" > + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="minimumSize" > + <size> + <width>0</width> + <height>0</height> + </size> + </property> + <property name="text" > + <string>Current Frame :</string> + </property> + </widget> + </item> + <item> + <widget class="QLabel" name="frame_nb" > + <property name="sizePolicy" > + <sizepolicy vsizetype="Preferred" hsizetype="Maximum" > + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="minimumSize" > + <size> + <width>60</width> + <height>0</height> + </size> + </property> + <property name="font" > + <font> + <weight>75</weight> + <bold>true</bold> + </font> + </property> + <property name="text" > + <string>0</string> + </property> + </widget> + </item> + </layout> + </item> + </layout> + </item> + </layout> + </widget> + <resources> + <include location="../shared.qrc" /> + </resources> + <connections/> +</ui> diff --git a/scribo/demo/shared/ui/interactive_scene.cc b/scribo/demo/shared/ui/interactive_scene.cc new file mode 100644 index 0000000..1ab28a3 --- /dev/null +++ b/scribo/demo/shared/ui/interactive_scene.cc @@ -0,0 +1,143 @@ +// Copyright (C) 2009, 2010 EPITA Research and Development Laboratory +// (LRDE) +// +// This file is part of Olena. +// +// Olena is free software: you can redistribute it and/or modify it under +// the terms of the GNU General Public License as published by the Free +// Software Foundation, version 2 of the License. +// +// Olena is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Olena. If not, see <http://www.gnu.org/licenses/>. +// +// As a special exception, you may use this file as part of a free +// software project without restriction. Specifically, if other files +// instantiate templates or use macros or inline functions from this +// file, or you compile this file and link it with other files to produce +// an executable, this file does not by itself cause the resulting +// executable to be covered by the GNU General Public License. This +// exception does not however invalidate any other reasons why the +// executable file might be covered by the GNU General Public License. + +# include <src/internal/interactive_scene.hh> + +namespace mln +{ + + namespace demo + { + + namespace internal + { + + interactiveScene::interactiveScene(QObject * parent) + : QGraphicsScene(parent), selectionTracking_(false) + { +// line_.setZValue(1); + rect_.setZValue(1); + + QPen pen; + pen.setColor(QColor(Qt::red)); + pen.setStyle(Qt::SolidLine); + pen.setWidth(1); + +// line_.setPen(pen); + rect_.setPen(pen); + } + + + void interactiveScene::mouseMoveEvent(QGraphicsSceneMouseEvent *e) + { + if (selectionTracking_ && mouse_pressed_) + rect_.setRect(QRectF(p_start_, e->scenePos())); +// line_.setLine(QLineF(p_start_, e->scenePos())); + + mouse_moved_ = true; + + if (mouse_pressed_) + emit mouse_pressed(e->scenePos()); + + emit mouse_moved(e->scenePos()); + + e->accept(); + } + + void interactiveScene::mousePressEvent(QGraphicsSceneMouseEvent *e) + { + p_start_ = e->scenePos(); + mouse_moved_ = false; + mouse_pressed_ = true; + + if (selectionTracking_) + { +// line_.setLine(QLineF(e->scenePos(), e->scenePos())); +// addItem(&line_); + rect_.setRect(QRectF(e->scenePos(), e->scenePos())); + if (rect_.scene() != this) + addItem(&rect_); + } + + emit mouse_pressed(e->scenePos()); + + e->accept(); + } + + void interactiveScene::mouseReleaseEvent(QGraphicsSceneMouseEvent *e) + { +// if (selectionTracking_ && line_.scene() == this) +// removeItem(&line_); + + mouse_pressed_ = false; + + if (mouse_moved_ && selectionTracking_) + emit new_selection(rect_.rect()); + else + { + if (rect_.scene() == this) + { + rect_.setRect(sceneRect()); + removeItem(&rect_); + emit selection_cleared(); + } + + emit mouse_click(e->scenePos()); + } + + emit mouse_released(e->scenePos()); + + e->ignore(); + } + + + void interactiveScene::setSelectionTracking(bool b) + { + selectionTracking_ = b; + } + + bool interactiveScene::has_selection() const + { + return rect_.scene() == this; + } + + QRectF interactiveScene::selection() const + { + return rect_.rect(); + } + + void interactiveScene::clear_selection() + { + if (rect_.scene() == this) + removeItem(&rect_); + } + + + } // end of namespace mln::demo::internal + + } // end of namespace mln::demo + +} // end of namespace mln diff --git a/scribo/demo/shared/ui/interactive_scene.hh b/scribo/demo/shared/ui/interactive_scene.hh new file mode 100644 index 0000000..b5d5595 --- /dev/null +++ b/scribo/demo/shared/ui/interactive_scene.hh @@ -0,0 +1,87 @@ +// Copyright (C) 2009 EPITA Research and Development Laboratory (LRDE) +// +// This file is part of Olena. +// +// Olena is free software: you can redistribute it and/or modify it under +// the terms of the GNU General Public License as published by the Free +// Software Foundation, version 2 of the License. +// +// Olena is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Olena. If not, see <http://www.gnu.org/licenses/>. +// +// As a special exception, you may use this file as part of a free +// software project without restriction. Specifically, if other files +// instantiate templates or use macros or inline functions from this +// file, or you compile this file and link it with other files to produce +// an executable, this file does not by itself cause the resulting +// executable to be covered by the GNU General Public License. This +// exception does not however invalidate any other reasons why the +// executable file might be covered by the GNU General Public License. + +#ifndef MLN_DEMO_SRC_INTERNAL_INTERACTIVE_SCENE_HH +# define MLN_DEMO_SRC_INTERNAL_INTERACTIVE_SCENE_HH + +# include <QtGui/QGraphicsScene> +# include <QtGui/QGraphicsSceneMouseEvent> +# include <QtGui/QGraphicsLineItem> +# include <QtCore/QPoint> +# include <QtCore/QDebug> + +namespace mln +{ + + namespace demo + { + + namespace internal + { + + class interactiveScene : public QGraphicsScene + { + Q_OBJECT + + public: + + interactiveScene(QObject * parent = 0); + + void mouseMoveEvent(QGraphicsSceneMouseEvent *e); + void mousePressEvent(QGraphicsSceneMouseEvent *e); + void mouseReleaseEvent(QGraphicsSceneMouseEvent *e); + + void setSelectionTracking(bool b); + + bool has_selection() const; + QRectF selection() const; + void clear_selection(); + + signals: + void mouse_click(const QPointF& p); + void mouse_moved(const QPointF& p); + void mouse_pressed(const QPointF& p); + void mouse_released(const QPointF& p); + + void new_selection(const QRectF& rect); + void selection_cleared(); + + private: + QGraphicsRectItem rect_; + bool mouse_moved_; + bool mouse_pressed_; + QPointF p_start_; + + bool selectionTracking_; + }; + + + } // end of namespace mln::demo::internal + + } // end of namespace mln::demo + +} // end of namespace mln + +#endif // ! MLN_DEMO_SRC_INTERNAL_INTERACTIVE_SCENE_HH diff --git a/scribo/demo/shared/ui/rotate_widget.ui b/scribo/demo/shared/ui/rotate_widget.ui new file mode 100644 index 0000000..112e713 --- /dev/null +++ b/scribo/demo/shared/ui/rotate_widget.ui @@ -0,0 +1,34 @@ +<ui version="4.0" > + <class>RotateWidget</class> + <widget class="QWidget" name="RotateWidget" > + <property name="geometry" > + <rect> + <x>0</x> + <y>0</y> + <width>567</width> + <height>481</height> + </rect> + </property> + <property name="windowTitle" > + <string>Form</string> + </property> + <layout class="QVBoxLayout" name="verticalLayout" > + <property name="margin" > + <number>0</number> + </property> + <item> + <widget class="scribo::demo::shared::image_viewer" native="1" name="viewer_" /> + </item> + </layout> + </widget> + <customwidgets> + <customwidget> + <class>scribo::demo::shared::image_viewer</class> + <extends>QWidget</extends> + <header location="global" >shared/src/image_viewer.hh</header> + <container>1</container> + </customwidget> + </customwidgets> + <resources/> + <connections/> +</ui> diff --git a/scribo/demo/wizard/images/dematerialization.png b/scribo/demo/wizard/images/dematerialization.png new file mode 100644 index 0000000000000000000000000000000000000000..bcae3c439f77122e055fb3b14b8fd98325092393 GIT binary patch literal 76309 zcmXt92QZs|+>hDNl*Fh|MPe%@c2F~BX^q7CQ?t>kQG3rCF=}sWwN@xaQJdN;w5Y10 ztr0a_v&4AwzIShOx#vkPce&?&zvuJ)ti%~U(7r*>K@R``Zs_WujLFAz0D!_0NJ&1+ zWcwFSK2UfWYpVll37o&lZ)olBYoh>H|NAWNtRR0EK=)k7!V3Uk==<Ln#gKcYBl*K? z-ns^w*S=AL8Q|C5O?lq~06YL)lp5OqTSn(d8lP?&|6l^{Zu1#a(A`W6jJ1@;^x~5r zk+*8)e{uie|EC%b<e>z{?&jfZY7&Qm%dSQkiyZcAMkaD{C&O+~n#Y#@Ir;ebKl?eS zi0hZ)S6f$D>{1Yh27rAa41<I5_*@tq0xQMiMH-5h6e;1xx=8Jpzq4&FkAD-p-TnMH z(sU?I_y|8P54z7!mP1ZL76_fym|4(R)A;x}0H8_%Fq{}?z9k9Hw=l(w5mI>eT2551 z4vFI3=bss0#fd-xj?wdH6Dk)6SML-Qy$GoeL@Q%h>HeCdEw-2zaOlquu-A~L0yvmx zX-vr3C|@2fUj~O9A&JxgEPx>R!f!d4G^BEoJs%urMFpY2i|~SZA}GUQaC_5qrQq}5 zHg(Du7sqGxH;m~;KEL-ex<7yUll!V&&RwOzx`PP;heyh9yVZrAuDOSWe&{kll)@YC zJO9{hoO8dL4!a=EJBwju6ty&{A`<~8Cvs**%58W&niVo8kedsW-$O-JDv1KZ@gkHG z6sq(0rKsNRn*pFPcF>rN&+qR5!;@00+gxwxpxO2HC#HG;05AYD=m!W#Ird=7;W!*l zKheJY%Sp)ci7-DvXn{7S_?@{ZHbFD>?f&vU4_vbL@+X5&29s+4KCdP~DC|>C4EPLs zEmcVm(~9gH*bEL{?K@_Ma6t2f;2bbG{7G{G9}Sg^lp-)C@-bEA=Fxn>A|V2*&!QE8 zzZazSYltLjmW<FIX~N~Odsx7zQ#fNT`YskT?>s}?3z&aXN<XfT!dse_1gk#o0KoHp z+lhVHBH7_WKuF;nJdg>o@7Y>7NhGws2&8~Oj1ucRa;1}TxfYF2jr38DzWvU+12J~M zixgwZ_nuT*)XoMAvIbOuVf1cy@WM~e$41;Xz8zs$>Uc-shvhxN5mi(l{4xE;!aU^& z(kw1hTmw#NBqcHJ8RyZ6A$84V7)Zhuh~efGH{R|WEHpp9m*5XEGBLAG6{CXl@bXZy zQh5<Dn6-iz1#v)C1LJ1S_KT?<6DTkoY(X(5!!kws2AYs?x^16iF<=;>Z`5E={&^fN zQ^rR>9_;ITyg6Ha6gV-C5ARYZI;5391%E}#as1a0eU0<qV~qdLlnnzL6onI7;kw0^ zS)b9qj3?tDfN=j)#;>Gi*I4LRMZhr9X}Yb}L{D=&(Gaq|!3c@dL4b-am+n7cHCaCC zli(@M$+N&<L{xoD=ENEw3S$VlK=vo2@jSM}s3grd+{caOZSAePu-%g&064Xv(Tf0z z_`bQV&)RW<T`%w=WL9jnxdm%A_Aw!f6;)K~wm1MCC%7C3&wk<lt?J3{(DTPF3#|>D zF%MCmOyj!I$zk@fY!8eLteP6-+?T~}Cb)Gk?wz#9l44_HUFV9dtxPc(^p24SrlKwo z&s2<$(JXP5rWJuvV=xo`j&y+Vj(jn;wRxNlB;F_Yja_iq;RR3!r8Dpm#vvI_(GSH) zMP~kI9OXi9TRn>}Y{Fm=QsH^*#kUs&jMyJbj3CNkgC*bp3%Cn0(%heQQTD?)$kX46 z$hFWD9?bC~h+ws^+a14Khyeqwt>=<@T3FX=kZ!UkFzSgB3Yb2_&nGR1!&jX7KUOA8 zG~kkaD8Q<3y;aSmA^*UXUwhY{#`tXT@6AD6s(B9(aywpU{^ZkbI7N6wrV1dcl0F=Z zdV}<_W>eoFDHE;SP^j<^wOgmbNl7$`anG%UUme$2sWYT$(@qz%BGn`TQWF{*#(G$+ zKsYa)D*V)b&DwhP)(kWvby!2>?(REvRE9lwTS%f2CIU=BAyl24>NRU0vc82E%F5*_ zc4oMkiiO39&eI3N9T7B*JHEFZ4r^;~)xn!qY8RH57rhs(37^2<`7Q<PR$^nbj~N-o z0bmU*Ey_qjhROvycDfI`J;bN09d4P`)KTx$KzS|0xUhG;Co#OgW{(72kpN*ww*jiN zxF^jy(-d0|TBHNo9b#3wU^5W9U-enUg7(_`NRG%H4!9+RK_!2Jp?qN~O0~-BJ0LfH zPC`l@s8RGQ#Y@>L53Dl|7ztXIz5#jp>}^b?$Wx#-5Vq=wwMFy!GttEI{?HSyAKBSC znyo8}G3;ksoNK<pV0hr@LB|4)UrT?nR4Jn1^g5eXBeocTqqmwxMl}>8iM&tnkHsoj zRVYIQu@=Uhp#Jfk+}zn>K;>!hBS7WI1}YAhn-Hu-8T*S845gd>Vfzx2nu7L(BtTbI zViUgq!z$ZwrOa$BdL_|EZ4V~HQiLN1r-+=hs2)R#Pl-J}fKO&kEA**<pPK=SkrgEm zg<1QO69JXBw$!MxwFbNhaRkQ4s{3uHrG3#28UvM5@TEC2sAGm*eB1h=`TR^1`NQ86 z6BhtA_vkO{{;9~_v=jcJyofE}u7Vx5QfplE{wQGr+t`pzYwo+H!|=dWQ8IV_$smIn z-^UuuW>;zNH8TJppx)9HBLjDpmUtW)=>;%iJh9kq*itZP&0#i?;lol&+2&1P2iSQb z5en22G_zp!fcN&+M?9Eet9OqOf~btoDKU@ub-%zdyGQ`CzHoBxWHol!YIkIu-k25x z&@cfwU<DX$)75UldQ4Izb=%<a&T32aJbCmw=^2_)owqOrt$6%^JwlHwvRa8lU+qEa zn@^LudF;YGX%rC=Re2Wm1{R+syphC_DOhS=$;wfn_0*53VH_~xb~}%y3kY(@{wDiz zd&cYdh?kdjN*M=7!A-uI*Wl7rqV#X!Pd82mUPzR_EYgO1F4dXd0q~fZJpKrdDfswd zdmB9UQqq3N|2L2JLmBsA{A<izN_F1yIR`uOEBe=fdQ0WYo`mIK;EoZBGnH5TwRE+R zBZ6WkQe+-EH0#opQ#V?69jE;QtgiOi1QZC8ff$tyi{{Y5OYm<v9cBtd6LJ&d?EtIm z2d(a#kcm9itkPuQllT~#i%3e`aEd*FeHP5POAP^AuMrQBr!RakGL+~$b26+_MxJO& ze`&bm`kKow^mbz|SZx@#R#S|0vZdq^jJ++AjS#YX&w`0|I?HC&20o!p5uEViZ_C-< zNxjlWsmD6v@y0#kFE`GgX4E*RrSaO5VW-h#%xX65--=4j7bi0tWp~;9#Xc$k?(f;J zrusU(77HEXnp*#;9G)Wv9j<TjSdtomriSxKU~CY;GI=m%&LQdTI-jtlRKQ$pIA&mb zeN0A*=>;DC4hgUYjM9&9$9WQjQPRATza)+I2pC-{1hYcw^UwgKjc5*1SBr}BXgD!P zLtjHj7^&^iU6*wo&<u^XmU<?WAc$4fkeDG&SgW%0fgvULkspWxfBn^p%m?azf1!9& z;NQCvcJKJL;Ida~*f=g`g{>4`dQzCX97bAPU|hxxXN%kH?zzX><%pXR<|utZBZUq> zh-dfIy;9)ja9uvuLq{Gwu%A{sf5K|*`g=7L6&1f2yQ0)=TFf0^U`}qQgH5J1rI2NP z{J76OXR$OXBTAkaPEXvuoG0<6>P>7ARti3e|K6GsShdTsHywa5P(2%jT2!|0RpdVJ zvs2DA&V}*xGUU>VL$%`1b)xzos|rRO)L;TUo|1x#yS>hNYwwj;7k;TDq#8f46D!KU z76jrATe+mT4?20mWX}W{L-M94{ebciDZ_A_C5m6)m>9i7oazDA7$q9<Jl~$Uci4<$ z`R)1%bSO#HDDc@uXwdKvM;jRn8bD7FU)P6@Lmy2P&eoaC!n%?*3^Cd+BDjshts$0& z1y9ER3O+R4_}i_VT>6MwUNA`ILWXF?cleKp)mrr=(1h#9O@Y%WGWFNJPW?lDq%`s_ z;{b?qB@lU;^pv;xd5~0AZwVcB0_=)<{*mkwQucJ!_jO9)a5ybqfL1Ste*ME;1wZ>f z^^JD7Y%jQ~G#O&6qiz86E!xfNh81Z%Q8i4lJP2JqwC5XO&uY2EhQC=7VoY~wi%vbl z!QWs~<6rtkVQ3|Ox=-mowG^E9GoJ#$)|8&@4IcFXrKts~3e4m7FRTyhN}cv9%OKC8 z6ytGvd3!#%jojE#z_j#p$J?Oo5xFVmXaVnGJ|0R++i>au`}iuH2~|_+bL0@1l%q}{ z-@K<8%yXhh4V~G6@wv=<&NQGt9(c-|3=mGoV91&9_jC3fOYH5176-GxP5q-I>#v?H z#QhBhH8XJE@tBli+d_MtI$|*Vakf|=>l4^3m#^+`qV)K@T|_(y8X$xq4T?ufQ{AL; zD{KBS&E(`P8>{FuI1hk^T8olsWj*WDDfYxml*f(`0Hrlx-_($N_%ZbB?#Tl5+NX@y z=$E`$cnnML>45XoVVr3ByhNGwwxaI*n;FU*P_^(vVrtQg-^^h7i|1#jarJ?2Rb5z5 z8{EAV7DG_KD#eWv@Iay!&1#ytsUeS}xNQi?#-z?+D<o}80e{DcBB~r`IEtWN1-K{| zJv9A^`WOB@@DY36{Q)$z1eTG~T`V?LV64P984lntCoQy-+84ki<Nhx-Ng)LKuE3La z?nj*g*P}K*pfwy4t>-LmnnY`4nqwBDE+5|X3+zN6D$ux_&=3dKf@)ts9(gqWroeWF z>O5Vz1oNd0@Bo!@-k{H^EhE0WE0nqlqMMJSuLLMy>!K27EfoKIzoYb+1~6a@^WO(L z=z+wlBcI+(wc=D0MnW^~^DF(Lu-K1Jgok2d+jo5PjlsH0a|pe)YR<Ae@zC?1j0Z<Z zaAP%(wggKm%Ss7fv4gH!#MR%h^P&n?<Wh&{PlvaGU3NqNNoH9WI{x~pd0lpdlrZQk zQpNUEsL0WGNUP}y6>Oy!tG}SKc;LZs=KpL2ga(WtWBZeyHd%Fq9DFmIb?%fc4h1I6 zo*m`4jIE7=hdgDViHa}FA|v||g7#XfV;`fUyt`W`kb@;u_NX-QCy$-20ehLE$qDJ0 z(Dv3a{|^hUd-fZ>hOF6R2Nx26k8ACIbxU17K0CoQF-deYVDAlIjh1XMx&ca=N}>FP zzTEiV`x_30zlS}Q#b*rMyUO$UulrcJhB2r;Tza?=cHT4|%qdd{UC?DnYWYKxt*<qV zEsh1J1kVCyd@jV@m&+x#ecNkqO_5IRF-=m`H>aH@6YNa^J2~q34nK+i#wRDm+b^&i zK|+3yO5zuntYG^tvKr+(z6ZZohN>sIO*qH(8^Vpp>4q_l&ADR1ixNSY$G$-7O2PQu zTp9py@$X=P(#`?TZ|aJI%KN8ZJ*?}8LlIUcWq<hqVQx|nzvC_D-2=HizxE2<Yl$@x zLPnqatIqIKyus5_1D59WWnk~>vbGu<uhZ_A^27|+IB5P!{mth<^H(*<NCtzk_uO&$ zL|C_;TZ2LK9B8K{yjxmqE+@$Xy|P+%?RikpZBlPg?WSxA&txeF>1?r`ac`+Jf0C%W z^nS)tOD<KjK}VKGoyLTD@74+D{KL|V?^Cz;zK`7eHjSV9%V=}{w$4rk9$MQzE%vH% zyB-safCO&K+~192Tn;M+rcyHXq`+|*>IlGN45rM(0Q9ox%`YPgfA2PtyjgvglBaq2 zy!wOr$U&iPFht*z-bOiu+82c?PkL3gF6#W_4mXJ)hCdif7;rA5PlLD9YjJ%pv9!ly z2aI!ov#SEU0Zf72xJDb%zAm6Nm(&{J)swz@xqE-}Oh&ytJq3qpo;o`AHrlRy7070M z=oj>6O*<<+E`_28H8h2L29+@;lT3hxSn_v3|LbL1NUji1*;GIJ?HuvvQHpWf*v+#L z7=)E8#_thYECDW=`CU9NA}V72V64U6jEybn4#bGYNj2O-y$ILgfc0`{W<#0i?S2In zW{h@aoss<R`w7O?via?5GL7<T`~jF&XsYlmPM-td_qsco8$B#3<S;Z?g?B<|kQX6| zQT8UMBt=@)M~H^guSF>3@P^fm)S1M@8zC?Ex=&@xq`gC+v|>+1h+u>++%vvhmt`Vo zk`PzP)O~fiu-8R$Yc|K_IH`yP#>Ky%iN7a#o2NEHL&B5!<*vVhpy#}o%1M)T!9Tyr zR}+6}J92VD;cz@qH8yN*$i51eL~<O8VR>l1?ZNuzA1Mw9)*oa0k>Pze-rP9B)_Am3 zq|}17X5T7JkoH;xm6VW9I>ROdJV0Nt!R9UDQFrJaVNm-^ozJ4HP&$eX+(ho<VT<|G za#ts|Z1?3bssCyKmHyrkO+H%Lv1?BzdK`gx=h9Urjy8wGf1GdcCHIBCXz>IY3SQ$< zf9{sZ@o-;q@`C?1|9FzU0O`hEedQFZq?dotoGNs8<CIFxOWdh)fdEP<Grxg9&wl_2 zrDVOJ@fZys1=o89icFT7#3{gAK4uGp+a>TvR$Z2Nv&YuX4=QYAPy94m<Q%mU5fp&A zOs3**zqZehNQ`Xm%i>?|Kr~jH-_ltZT_bYht0*LS8obc;yq*HZK%gk{&)(HqnCDVO z!7IPC##|3r3Fqi*oFmSmKFdNgC9y}J#)VG`@2Ea3+%}ro_I#mvMWj*zdu#gX@HjTb zi&hoRWoCua1iozjV-l~?P{o2vL<mv|QS;wkG1mH(UR-*fnJWkmD*fAEd#+3=fq-ST z(ZL~#_Obo1Z$whP^5D~B=BZM%U=fnGz~s0vAt>KD@CXdKwd{>B{AuEtLkb4^tsE zTFh&gu6F&pNqyWZ!K9GIao}*h_Uiuo*zYg%u+#caGKq`Fb}jQvpCUwu+?M^e7ZbLX z_Bvsi3gR$WF*cP2z>-SA!g3??Q)cXAtfUb2w1eege?Z>*)}AcgdM(X>!O;dmAH_>c zqd%?PN(`)BH(w}=b8}H`BcgiXiWQkDf4c$NnX#!=?3xrApjNjpm`<x#VWf#Y)avdo z`S)Pd%QH?yqLY)8RR9GK6{W1uFO6&H8ellcR*TxlT0DEpB51+qmET=mTENNkFvVxj z_AXGhl2kHH!IgnHaH_-2)RJY!3*|u=KSY-&oPlkpG<Py*KA^~0R!UP6yti2(#RcVj zA`tyv(_E)8=9-pZX7@s6*>uA<qp@BOp#1I@Ge{|SOV~5)QHp}rL&3YJ{c44d%0*Wv zt=wXz>mu%HY7C&O(V#sF+b*j&8J>iV5BO($A+oFxG_{F;o+_;b1rLCiy0p!0a&mHS zZ%+dVqn;h#UJPwdmoq+7PjdejppwTHIa+VIDa&|r(xP&4Bpy9r4HU)6=TBf0PS*yi z-Mg-8U5Pqx=;I9m2qj&SEbHKLohmX;wekrT4S;O!S3j_-hY&b-z9ca0^HDud?0B#* zIX!!dEBjjj`XgGFbgdlnU_M#5(c1d7+*Aq@mo`$*8$)G7wAf$Fs6>NuDy?g?whkt+ z>0VltCMyG5%QlZ5p}VwHWo(I{;*3%Q)=!)c^oz5^hh)!m?qSj8<@2y<pLXaq6jgeG z12m>&t1Gw_u1<NF=||9g5Mx_Rtr~?>G69^$-fz?uMxL0WE9q&D`pa#@y&-3C{M z`4z8BEAgwp<od&B5xzC;L-+28W1Sz|&6Z(vX3Y>4WP(#MF}*0!8wryPN`Ab+m1`=` zGzg}+pGFI;@_q$wa7+;1^<A(J{Sb1rvLNTaiI=68hOgT@qp9`TjZ8kYcU_VmhFzTh z-fN$DMV3d!?5`EzBAq&Lk-tCfyh1`;oeu`SBkL^Qey6aHD~PXuPc(|S-SmAb>gR*k zNyOhRae#jvJ3q_d%VyC(zFK^qo;$n{><%qR2vh$gKl66SP*fbGMzrd^+0##emFDG% z^!^*;l`Hk1V`7*W+H$yp8jaW|=t1Ev*~{Ib2hDhA4kVk9$oM#_9O+G3$gi%pQCV6F zPP!=U)muQdiW~9+wD<;nzc9f1C$L4oJew@vPJ*kBXJG;Il2H#8p$sm+hBlKqlt+)A zTE{?s140s%`lgM0+}~_*y>6?hAEJw0F^4>4*)^wpK>ta*DG6RHy(C_L(pBt-viA*t zV{d_;)l-d(?J3=!j!J59<U>&!X#lW8NjBDx8oV^P3vetYw$KQw$`W?iZu{j}1=-%- zZy{|}Pr3F=0vyFw%|ueckyTX!H~M~TYApnYg`ND}Q<=mz;@#r11|+_f(EROR{u)s) zWf#u`N-qglo=ht2p+;p?gxkko*yz`En7@`!QtKX!3w%(Dv<p(AQ%a&|D?4Zg_+TdZ z#d}x7(X%rTcn(c0)qk7q+ltt3=atK-6v?>$CwDz*cmHT>?%?!eP*H>Y5Q-WP$n*Np zdAa{Qj8_=XNBx{o?`1I&MC{O>Do9_onl+%{f)8Rk=XddKT_1u6^v9EOQ*Y~62TZ9^ z+rqJqQB{36(64x>j9PnH^gA7>S6-*}@HTE#f;~#v`BQ|(*Bneg$3=GO$SKTsu#xvc zZj^d9G@lz?VwG(nc=Jz5kS{0&%;{AULuFF``1zClAZbQaztz{t@bGQoShV7QHqtvC zIW&`2$ZW49;p3;|T^RVG+dyL&iN9H+rZG<YmB6;Q)cs0s$CpGVPPZHqLu8HAjdin* z#_Ebpt7l1!%jFpbUc**jEz5fD#c=aD=QdEna|UzxV%pp^iqwG{{`KY={6g>XPYrTI z0`PIg7o1wk707!PPq}$h*@Vjl<KD38dJ2ZV7a9%g(9rNW7rzK{H6dGmz$PQ#RjWmU z05&|A37S_r@^0Z#*ky27Sdl#^8%`BBB}XJ?FNctRF1V}I+-$sXBOOetgq<B$B?}Me zCs9B;!u<U|w6_Oc{rpdgImm^bqj9i2t>L5)%1``yV_|WfjMFXin-LU55tU~|*M-`- zt;R7kebp#ufl@4GIAxYt<LNTCEBNh{KNBtIob)5Ucjvwd-(J_=3g`Gik=*${Ah{nX z`j$mv-$r}aLKoCoV8bGYMn7K&$?gy5gskWA(HLq@O`TkXRtrbQvBMRGIzO%2bdvt8 zU$pp0QF$H=oSm1pcXl2vRpd<Qi?!@@aND;m#Mo656CAo+=<vD7L9|&CxUGw{zeTJT z?_OG5B-^E683kN33~c?VEA;ATzTe)G%z-9mu1wql#q#r+)e_MvhfQ%bG{0AtHMvlm zL-6a-v%%x5hdyf?7jq;w##R_Dpk*({kX9to*-4l|W6r1D0Cev`#M=Y>{BX;`(f&C` z%7)#6g%@Shf>{K&8^?tgXi}p|U3;XEdp1H)N+=6DkpTk!P=)%u9(r&(J!GSD(Gc?C zzAyx8EKE%m6sv=b&Yvu5CQU3}>{OGz^sX?oJoJ4P87bZ$2a%hru@7+1CQbN;3~VM_ zb^;`xZ)@9#3bY%ms6umRDtRZ4g@}fpSjS?rk1H}7D;uq;P#!<1G))mog@5|=^YgCS zn)jxZnab@3bBk6XUG1H_q>$g%cT7ZCtY$@*!cO`&&zVA2p6#isFULhtva0B<mg<bt zL2<>;dFPGn7MOX8OCy|R(<d$#>$t;C_fMxoNhu#~vHU(3`_G@C=L$c>BZ(}br@zHR zfJ-Di9zXcdwR)Ox+kHW|dCeSBr0p;GpZ~{kq4Vr8vs|vHX4>;9>8_XG#6Ow=&4zY^ z@St1a>dh{0%~mo7QVNb#M(l0mB|E};scb8Hi<Z;BaSrcLR#6E$!WX`kG?$eK=gS+| zmp_dFeVX-&<3wZlRAgiVg+Qwd`TrMDT>h(HCPNvoV`@Qq-B(0ugx>ZwBO?hkpJ9l< z|G)E7FR5pf;`gMo3AVI>^(jGC)e2S9%GY=Wb#qrhV_r8qJ2MItH;=@=ImE_%&vwo| zmZ7SCU7owYajK^_3#i|)S!1vmX{)ui&aA1#twJ?`eN$@^Z&*aHb8!Bmw!HhrK<dt0 zC|tz8c0XaD)Rp+ST0bgR%>W~pKQTKYBbh1T@y4KB2&tFkXJ*!7X48D)hd6v}kvl(! z87&?hW_We7)ILhZTlsv2Z`<9i`}@*Tf2cgj+BSOmW0rQSt+4e{_)1Zok&hs60B2f} z`c*~UYwGxWP6HRs>7;Mhx?+;mfx`T$`eR3wpVXnHD3nynMQFa)-E^#8{UGy;O5R6x zrU`9L85X^~sS!@Zc_fh&L80*L>k-Nk-njM=<0A>MKMsY)NDcwT_PBTLTW(yK@*}k! z!uP6k4C-sm>fTv+$S}g<f#ERVQ`-9+BysMr`5ig9)<#EN&TYwTj&xpCW@$A^tm(UY zHQG%5+Y7;_h@5`a^1@FL`MiJ3zQYJe@<^LY8i;<`GNrtuxf;)b3kL#I>23q^OZi49 zW0G=>Wd3`=&<iWp8>qFHlQp8ugh<)0c3zWVe$0nW9>y2b$5U^IkCdOosETh2!{IHK zVg*in9S&Zq7s~4eYG_TM(T%~F0Gk%q_JRpI$c!G7ktU>Ot4%rzOo?mg^Jrjd^xFOP ztCZzb>n)|eus3;KvTa)ONi3yg=+2H1ww{}qV@sG_OAb4aJ+gPpyFAMdyEq)1BrRqE z8&En5he3RD-konX)gp!J<)FkM7@!oE2GRTSvB!u-7EL?xwA+ASwyi`NJyreDMfPBL zQ38Cgc|qxcxaVWqQ3uv_)iVE*n-nz9g;?BA?2BTQDLTBpo2F5d2b>eVddb6MV%P(w zgY?I$Uw3>%=5F*!D9~vDbc9O|e5}*`%8-pY4oxoM`4i>(A_(T$U_jk>pGEnY8)%AG zf_q;j88lkvU1akO2#_3UEI^W4=k$F4*O1C3(X4LCUw!0hr*hbbc3ngc9XUMX85Q<f zunv8-&_+|LF@yfnlXTsh#tP?XC^6;M9^(Ijw6J`+L?9D!;@Fy}?0@|mxPmv{wwK(b z&HwKLT#w8Z76O3#<f~)eDb>GBjn5TMPDgJ`@KfENf9=g7lm_7`g|LU0{{3)6y1|K| zv1NN${;K(v(!4FPQ;<qqR9GOhb}PnC=pY#sey4~pJ8~zuRVa}OaNEKJi~r(dJz7$n zTp+~*4$uIRF5FtGot|mIo)ZG7?+YJUv&G(hW6l-XIVM8?BWr9dVa~~k&G~Ee2KyJH zQ*~@(*Mht3$#~*$an{-8`uh6*!~))VH~{YS@Wmdb;usVGL3~ob`c1mr+{Evl*mMP- z>R!IJsLd<Soy_hgT@JPEsq~9ZGEc1}!Y2e@ipR<+1RD16j@wVB7tokJ^vW-k*J)sj zn58pSz*i@#c-MmT9KKKs)5cZlAHXRwM>iM|#nrD)h}qc~Yvz|42{V$V15kU8!72`E zfqAX`ADmLm#ZE-rr_W?&5aL6AG|jsVS_IJhEbg9!+$#$C_vh#KFQ!qUxAf4&5#k#W ztyT1n?Ih2dywURQR*fF%!G!pS^h~kwak;t=)I6zQreM6jeZO%c=a+Qn*sWDryd&rH zxp|~u|GtXsz~|>mB?sC97`lO}ABKepr9(F%1K_L{ZEonxZ)e=p;wEK&phh4IB-Re+ zF^tTkE4{-UM1NK3{B7ReL)B`a+6lYl9wdAqX3%kBn`6N51kNe4nej0QANZLte0=%y z_-u1`7YmKquhc{WTta-0Ct8-pO`jdh)Kf)=e)X}QJL!aFq=m49S48H}N1n2Eo!5o) zvBla<&xD<_Mog1GMOq{w4mCK><PVdCtJk2?beN;yPhWgq@+M#ChDDCbZxQ*<l=&jL zg||$YI2nD9<og1wBytV6%Obc3c(zdZqUp#xWY}flRUJ7_c5k<G7^vQvRq*eI;HG zK#^EE#TA|F+ipNWME#7b*P@;s@U&36k;fVutX~2W3X)bFM>;*<J=$v73ASi4_}wbt z>9bh)%DQHbh?(ur5In2Fu__Em-#^e4M2t4kK`Pg47k2#e<v~oe$>GK2>^N-W{4WWv zgU3^KPtK$VB`9u{lxukESfQ4w-z5H#qU2N6Fq9BGxcS#ZbV+)mN@zSG_ix=pMh+V^ zhLs{KPyK2CT`zh~DJGr7u3CU?z2)pq$N0{zv1u#{4HSNC_)3Qf0-tLZlWROW>zGkj zGw`A`ny}CN8E!uaX)fZB>?|*1%qwGwzc^D<8E&{vQrl6EfRb*l9+?x^B7~XvRt2 zyKmeqO1)06rYiY5VA5cE#%HI~Y419FK<WF$Y{jSXL)wzHcN%fSU~hft{9<KKy##kf z2JpjG2a)h#*TjzpY_~h|#}LS&Jk42q&KXZaDsZ@6a-uqTF0fO%e~bYg*Mn?Xa90<V zc6p4|ZFSB|X;^jKCJ+b()uZ1^OCs^>rCuu^)WV^!tDO&*z&L0)SbpuR>D`!ji*94@ z4KbRkzIT1@p&QpcTOZXWurgs9>nR5u%2;}b0R>*d4D;`OJNBAk$1rNC5oFTzBh9?# zLTp2vkR+_skwS`c8l+41Pvxcyyw>JHUP%Brexl}gn_KttM4lEZ#_rEj%K=T+HUOrW z98bI2DQ=<|-znT6WK5fklo4~-)pPq9u9VD^e4F-7?`r}Q>r04>d#WeQ`t0|8fDW~D zpF~F1HMk%>Yih6jM74`XZnk0l{lFX${}cgBMqMHhY`|Bs<JP{sa~4{cr(JlHxsms{ zalWDUmQ4#P!`L_#%0KvZubp$6x!2pxo|{#<6~}dy_BCodK~Bq7Dh@FK1NEh>*a4=2 z<uy+^q^1$n{%PI<>QWvX>OkC&PA7rX)q9G2E99(ccXKS8+`bshA%&`dsHD;l8VBq< zl@%4cl~h#xe5lH&D;1Q-#qRi+5ex1mP=vN$xBWKb(Zvs^O!p!L?G;c_3V1FtKSlpn zCw?<QbD?>AP&q1ti3!vPjs-iYDxmxyn<js?ulL5h7&bYs+dA%>Dl=4Qe{1MUFX+-_ zIfwag?yZ{L52+`T>FSaR9sm<ng+I@0z--*Y&CL3WAgx^g`{Om_5)ML3*TcD=pNay% z>FeX0w93$V`{8=PO)VfZvEUPUM*6XY%!EdEopRWc8@F3+E%&Z_EX*>Zosj#nZ{o<w ztTXW7EOz<o=l<+1?<GE-)~dTIchPEh|9FlbYW8?qCHUbgZRg)(@mp<f{~bT@)DwQW z${D@p`TGNh#se+vC_9}*Y>qL<!c2k}t^ImUn|Vz~T?I-6(GL|%(1Djqu32JwspFg) z*%kK4bQMWdGKo(GsRQ|W6v1VgxKigdPEScb2#i=UMGr{?N7(k;${SqczV;e{FNH+H zq3>PWE#KmR!0WHqX|OLMypmEI`qRJ<g_o>CE>DR?WCAh8C@|tlYdDk{AyP^4Bu%_K z^qX7D*wK8fdl%`?;z?fFpWocK8g?9&uXo6guRY80nrT({jzbPWP2$T>r-bwgB*|wU z#=dZSz9uWj<r;G*ei2~y@ZVtNliK52(-BIrgXr;UC2|x!q1r)ge#Pzo1MKje8lL8v z_;i?w;w3wU{{4IXHHV#$R3%fLcdIjhQ@!uJ`GM1Xv%JSgGx2m=&yI;gb8dVcv&i9@ ztLma^spQBW=lWPnFi)gjflo~z=El8STi5L(ce3bqACP3oK9SO^9=~0=9dEh0=SG^K zO<~(=oZU}MeZOi`3@lBTO!#-FiL{*bM+c?%4UM^e$_^Nv*@gf1u{Oi3b=G~zi?Ms4 zy9HhOi%OJisKMjQ3t`41tvR}J<Hs5{n}-8#ECWR?J1(-k-dGxas>o73PW2?=8+Q1L zYJ52ClYM<<zQxbxj;~0+@4ssBH0vx*CP0!i5TN-}uXjU&HMa%~dH4R>lYrF%DG2UO zb+x$4)%n5B1ZG2V0)ie-)Mrltij>B%WAq!mR-JD6?;bBqa)%j>@mlOi)csS@@kEZa zDs2{UQF!mQx&>n}N%eaqNitZw$+c$~W8x?yg`Ci{7opthIK%^1%^r`2&w)OV$~*HS z90>OO^|{6p>QWA|k9R+Cj1vze?W%bodtYa8LQ%>@sJcApz0y~|Ju{+HS@{!O^sdJ{ z38i~bsr&Puvv5b@=+|6gG@b`*da0YEY?7}a#wGBiLjNfGq{`LIw%YdAv-8urWY}TZ zzsFc%P+qiN>YVMy2?2Th$iQS9HqZ6l$0x-1bn_Qka6Y?#`TLYQVL3<g#J(b-y5P<T zudh<R*thvaT#S4Mode7X@|(o<K2bvkLqRjec~+Y!rbR77h2?XkQV;X>P`0VfxqunC zA!sF-A(AG#<{ZW0boEvL5uc%0XolY4(`Hbk9kT_@(=b_e051{W?Ap3-PfwdTwB3q$ zWlo@hKt7_IRmxHtv#K7&1Ium6RWAq|Ml%+dXd7M$j4HcgIs<RE#T1ZglQoJ=QdkV6 zDiKl~I0P9_W__%gzb!6`6|WW0Op)|DndAJ-x|a%zCi8u}o_sRb7clTdg$qoVT+^Q6 z<<q!#Sn_gLmEGtQbSi=;B>=DfRrq7*vi1o5)XZ!bW8*yM)Fkl$k5`@0&mYx|FABT( zcknQ5(anuc>;}XzHsupi^{PVUqJlg0++<d|G-eenQ$^0`x|Y-9^8)Nyal#_(W;>g| zj3d61$_vZ*G7mJq<iwEcYXl49UxBL|5RcKkw3;tOq|@)Vqrg`twnB|t_3uMUAspav zZP#02ew}_?<Vs#t^Q&qLCW_g;t}8A`2T_vOO(}%Be&!f}84pk4jAb#}KgynLkt=HP zn{&*aNCT!O*cW$Lz3L7***)pL(jZhVtDGOsUHOJw&=`pFN3G63)>XM$v$5$^c-Y5T zIf|4s$TxNle#_KLJ!U8*fRZ%CR4F}+M-H{Ox03}oK5sHxAf~ubKITV~7IRx$ty4n4 zqU@sEEibNUi1YyXEM(;tQG(%u?20TLFOo}o>zuh&_&lqpH{a&Z+c(+orOZnu=*<4x zw^xNAMxvFkQx9^5%#O3+H#_$<sAbgPyt?z_eEj}3o|&!GvPF|*3?@pMj5Af7F~B1s z=D({Xv<y)bh_Pae@HpIzs1w9Qwe}lU>93kA=heL!O8&<N{4fjuk}R<@32#!@LPd$$ zn{s?66qP@)AFFcSS8Y~@9cu&!nw<_@EQWS-e|*$PDP)&Rg7VXt95K}B8;B_-{uKfl z8&h*>aA<&O(ihi%5{oVagM!A!-IqEnYQ8kilM!akb0?nb=GL<8LF3Ut-{MYa_d|r@ z-gTzae}7+lT_%V9n;saTDRz_dJCSQy^kq}G)q*p?2BCm}R%dKufQR7HX%4OKCOEJB z=|VFe&+?v6JY%?LsVi_++922SEk5%gFFiMED*H{ISCW<_HIHPm^`j0Eggg_Glf4Rb za!>ksc7!v(Qg#=&-XcCcGBT<c6x?Jky4mJYt7r6w?zUaQEgQr3Iw3(_51<BH>|cE< zdl7A-s?K}!I@4-wGgyNtGBhRq@+1@(4TZ(<(dKzK&c7wJA(4D46VAeouaf6cPiP&5 z2Ma!u=L%xG<yJ~ZYrC3R>VfOR<y_dglgM9AK=DfX(>b>6t)nu(8;%sJ67W)%*!K2? z*oj5At3Ri6Hp-#rq@5if{k|E!yfi?Y898*jx?m(`vtbqhIjXXaPkBy9Y=x!L3zoaX z_QvSM`c$dME3;;eRkp`O&m`l_dI2NgdD2{+O}0h0U~3HXzGLf#1W04<B*Z<yTdaqA zHLqDrLo)33!G+;Qv)%II;-Z^uzP-`?FID3LRg>b6x`P%7*)*@o>Tb&4dd|esA#n3o zD=WAALoG?JTR;2dL>_dya-?@GDD_KAM7TebsGl11ZCr2x^khO#as1-u6He7fo1Td7 z-=8vb@cK7fFZTb2g?*4pKk~dZM_kj<1<$uDU{C*Ck{I{8bDOSHNb?x|T~d=B$@1b< z&(@GO+IQ5U7G)o;5_S-*&(rh7X*?*|bKo?NCzxb`C^P+p@3i9&hq9)%I!=%R6n(}! z{gSJ!t}a_2p$>XgoD3Sns%wcft_#ik6Mr+#J)%0fjBM|#XhXSn-Rru~1H*zG(!fR$ zs+d&3=>mD`Uk;JA(0wUKq8Ecno&zV^*?~K$jsuG&=H$kuuTlwS0ai0&uIDxOLmf6u zpnTD3NMhUQ-~?I0PdwT81lGi0W@{!1Hl2Ze+a^pS>o|Nl{u>8R^*XtZVYlI#1Q;C` zkvK$@Tgfz@+W*e?)n844!4>&9Ubn13-Sof5eP3QyjLP^NtSm??#s4KE7JR}lu2jow zIPQ$B_d_M&loV0Y_h7$-dsbXR(h+I*kxEF}-apSnqwb_~OBqm?2;QkoGub$4pXjq* z_JN<OLb#oRW*VE_uoh~A$ci}JD2|X}Y-%K-DddymnSmx)Y$JZ5F%fAbVeJy($kMzw z&{!^M=1Q+90f97)aJ%P(I9$+bS;pzz4b$p`xw<pAxoFs996~^XBDUC4rb$rTxLotP z)O}eKxY@-txtqT==bm5gQ9CM}^<@moTg_yIk;!zovR*S!!ZPzvHL}Efbb<jUUD9Gg zy8}KfxN*l!-6m-K0Tx??wELeNhfGVGG>)&Z17r0uRj(<{N4)$N-SiJ}LQEXI2$<N- z>d%hS1a*G<JA$7efZ`G^!Xt?h<WU+t2OKDc0Pynpx+*^V)*4>Vj;sLI?sIW_u~|w= z=n&?fF2ueTaX?zDqreP1b3++6>CLtJUciu+Wf(LZla!u{4D+}gon^hpbO$^Dz>#lk z1x1x^f6UyC^lLo(U9JmhgWC>5j?sKs=^VDRge5XLyzFaHy(<8DSEG(Hv3AW{vWySo zPgpN_5%1KP`xN_bXE#FC-~fB@+|TdeUF*W0U#T#wwVFCn{88uSv7d@))|Th)>h$0z zhtgSI2OeS#9xX6wE-Z`Qu0D0?-JZt)RFjg2PI;7d|9iutFZoiCW@NR|D-kn2)0j0v zYU67BgR`C+kmrj-5=-rb*TIx%3<hH`o!B>90YR5}2F(~6R~C~lln;X@O7S4`bLrCh zx|>^=+*S!fj<DSgN?7l}>DEB-(Zz|%`T0rr`RU|UbJ&Mn46ZeC7(F!XD6(2@mR%S2 z@8=MCHkQ=>hd{rBN~UMKSWrSr)Cu*qx3CXaQP(|Qp=JYA9?(y1r+Cr}{5@VjILc0D zN*7ELNYcK9F@=$9P+zLO0QhIiKGw4{xZ$pGh!E0>38HEnSzxcSeP6bgT-l<lzuxzM zF@bf9YrdDPI()N@T#|;UQDe$HLE0#pc~@>vPGh~y6L=NQT9&%>=oFcH$AQI*U@)!2 zQ2T3PVd1w<YqRTd2nsc{n{u?CAq8j9u$eoO=KT^><i!;C((kb`p|9_DaY=l525$Q6 z#AaYCx#E5xKluu$ubMh)WHZ*-T)V}GSPS-AJnjpHD!gRpB<6&FU)yR?x%@{i%XGQt zu{T`vw8c9!n+$~OwWDXp$y!;Kjp)}hx4^>x%$UM{t8a1Q=+A`Q*l7(Ya@m#ZnB=M_ zOe}o`QnjRwGrf^UWiQVXouC&WdM{?pmQf09f-%t&z1F;%LqA8GO98><W7jv!m6|Cs z?oJC%tXD?Yl~D@!XOw2F-~pgYd42Duy8nn<>WoEaX)D8OSsHmBhp&VO$qn#+0s1W5 zO)jEdk@o?97~2?!SO-@e{K>IMxo=9HtGC7sfDZi(GyLr5cXHxt687(y)WW@V(!MjX zb5z$I+R@qRlY|``aQ5+S?vhtjtlP@M;W}}@?ffUcj*G!5N#H!ZXIG)P>A?WmazhS{ zew~{jv{hGEU!7c?cK7XtU0q&~Lc2*@Hsqv=RJM1#0zsniv_JBEFBkVhl~lS#Yy2BQ zQ3NDW(0Adh=|e;3xAxdRiKwrPC3gbaOYe-k)tfg>bV%p*m8h5xR-MF}np5#eHrj32 zs~tqQ$40k=H=YL9o1-ynTb7y-BQM&KkmYRe-SjGNtzw1S*%p|>-0`mrJkUbll+^;i zcI&t&WBwbFFDJaatUlmr0djQL;h*i+-&2ZCe#zorufcZ}c3)wSe=aOjY=m~7G*uWK zcj5(%W`<WGspJx;5d5=?>@|R~i_-z#bw+}pqG86T>lkpjHB?mR-qjIAPKoic?fDZI zolm%$;)R@iFbC_4vD{%-6-TF!)wDc+biwR|>yzeVspwb%UZZP<i%|8o4m?K*4&3gm zO#WL2#C5z%1@?l)=<fBjm=twr@(WRVBh)RARx3jG9UHT8P7|!ah&|kTE?W9c#``yR zqrdY3XiUNY{wc@tZq8+}`o8FjwC0;F1;}p=(POI{!vSb~b@N79KEq*tIb~wVZ)5pB z;40m_@om$Yf%&rB0ePGdm<M6U?rOIJN{-Wd(z8)eXPk)Zu&Na&*ergxx>0hc;sA#` zLC<19ealy8?ih?2CfeCnXE-J$EplVq<?qivIaft(J|b|00-qa?TXz}K@9bOUR0Wn4 zU^vyN2QS%#UhI#xR+T*uRjBBV%8{|qCHY*0N`{PshWY==thTw{|85O@N_YwGj#`Li zALjqHZojpD5HKstd+?2AWUBIcbw%@UV}|o9XwbBPVv?i5WHxSiym6KxoSLpd&3AdX zP|=Ss-BEHnEJatvL^e#ld`~hxSK6;u>vh-S#0^DyOa)<t|Ks9OuT&$$1J<gNPqsWj zPV^en&!3lFlUogGcF=u^=Z>6f>*g{(O;2`BvbbM<`6FRW#Z)G09yOpN^WOR{Elifv zS>_Hr+<f+^Z=MIvY_v=ag|gIGO0$_|KP*&QsClS;nC-lL@}$9PCSfhI=ggN|o#)od zW3{NwK(9bD*`q2ojwilI+P%0Y_)cRhBa8?qyIhkf$k%N7Vr_J2Y?Lw^mQ1T&a!bzE z%SPV}+>iB}37+8u>am}7iIw3pj54WDo|PAo)$61e^CIc%<z~XF&{r8M078tuRj296 z&4g&Pie75fp+81V_SkTJeN7t3?J^yS2Ys4+o?<*{*TF;RfW_ds-Q203!GlZ+N?r*l z*iH`$1;2lKlY9ju*7^6l7u-y&^L3Y-JJmqjNDQzX-(@CSy*4f0efjG&q3zKdbQ~o- zKQ2#_nb)Hq?)&7GJ%fNHUl8`)9dHPj035n9KcCBOwp+GRDD;o#p%&&sWAJ%*oWkUA ze?6YV=5s8p;s-_PW>x9Zy<FkRB|ld(BOi=r7_w&9oIR*i(Rh;i+2<8S98i+k6C!xt ziw&`ylS!+{iQ~NYgn^KsW@LaG$Xs?VV?qD9_ZSsYjF3Q7MjrSA1VD_H6md7Tgs`Tx ziNE)MOR4tvkn4-LVoLT%=0-e(R<_g>yqbOl5?$qdxAty#$mzw}tke%c)RUe>tP31# z8V{v3&JoLkQByK8k7+FX<|W*u8z1PsDvo$(;Vw^`%^y_2p|aG5E-F9!>=d*9_Ts6W zo-jnp3otxhqlt2Sq9{z2QHtLd3Ax33^EGvXg=_f_bKz)2umGo|gjk=%YRQ3|d*V-e zh;V_;BYjymI`570SpdqGrxl!v4_~<pnHUMC!08xqN^N7WOB>2ywbftL{aaa5O=Z{i z5!T}4TTO7Xu~xeHb&=l^Mk3jSos$?P9p6$8(1g=_b}dZ*Udx^=3i~_2wl$rO$M?${ zK38l?_7UKhX@8*#N^t;4gGV$yZQ2O?67NYk!x(**M0N?5V&|qF5w#!4lbe8va~BDs zPV!?%>p4ZNi7kDZ4hA!b@H^d1IGFeyx4e{Lyv&G6ti9E2RjdO*&x*|IPaWmje|3?? z8q;u%qwfRNASQZGR^NjlcKwpx)Xf*(uNFG9tcIj@eu5)%jPYABLe%ky@;}eiH>hS` z7*H5KYQ%AK(M|OL!E|A)!jTGTJfAeqBWdgfq=L@Qs|NxP*4S)pY{JNKN#D+dAm(L# z;NRu*1@Z_A4BWi+If@iMq<X3yW6iIDrGzolFsCaC66q;p{r?VRbEf6rWDRG*-0--3 zP@&Iqbze=0I(zk>!>)xHIP#ecU?Zg(4tM@V>Fh4n>^ccUR=%|m9U6w+>Qr$SuumQK zrVdTl1KG7KM6y8CWO!d~(prgsv6Gz7vGCU!&x^j>{qaE{XMgbUcmPO4B~IZUy07N2 z&9cs{dbW``=}E}D4)MU#_M+#6%UU1hNL}M9Uw-*QRR9GxVq}8GxV3lA@9lNG6DS3j zy8DoeaLNI8;w5UJnM8^n($A%jrqp%TodM;(DfPt}cyCY7G<BJ15=Hph=awA;qu1ip zka?!Deg;#tPQ6Eh?;64f7&Tn}i_N4L8i6z5kFxl)9Cx#!5|48>e(>M{WkqYiO)g_^ zuE!o+9*?*)Js)tm=SC|G#bngG_lAF#e))nsMX2ms<9E+b3gs!EIX$+_h!TfHidrlP z<#jJLm!a<mcD$f*I>bJ)++HuCjUkm`MFM;HFZF8KMzTqA*ierS2IghT{qEpFH-&;k z&^Zc)v~ah5;m(HkrpPnFIeJG%=)4XG_d2bwPnCBsVgzYKdCp$tw@WmRtREhZFMmTU z{G02ENM2v(Jo4q{&%Z6D?egub2j4KM`qPbQDr1m9j5CS_9-Vhq!l^lZ;rlH*9$=u> zNeeL6b0c*sruDr0U>E(o)x2(Q3rrbt+CIz)ND-XdQ;QhIRU!h%ig-_dOoo~4-d|?m z!Pj65ccN%e_ZbCB`3Hq;al?pXq=u0S<2W9|Bly=S=Zh1~ftDAcZ0lGvCKnUqjDx*# zZn6xhnAjTl^K7OkcKc9!<l0Gj@rz01HiQ%Oiv5!S+4mHAstQM$&e%t478v-lnD3`J zc-o>~AiF0uZQ!48ge((xe6M38D47_`pte3n73h28!+}C;-E(+2lT@nU#Pz@9UfgRR zX|<jRl#!{wUyF4Zv18e|zd+<!PS)0JATz$7(={!7zVntn7Iv%0pTPsxYlnSgEv~ME z>J>=lzV|IIm$z@-bsc<lxUs{zh?oYi9^^d^46*b5q=A3d;>R?UvkAUK{}*T@$vv~4 z^rsIPsmk?f_wp4)jKG;nmEu5grxZYG(Ab~KlGND0Owx`O{QDaI%(7W2ayD3bP4lT^ zQeq`}?^Pu4se}f1FD}L7g(@j%Z>Hj(J_@~BT$>goYl-nTc4;?nT*2|Pu4jH0dUBvH zi=0Syk<a!`9bq5AV3^YQ`+MGkoJ;RsXa1Rs^ih7+pX=~zuX7gYXsV@sdia6$c5*F3 zz))V~D^`8OfttgZ83Wk2&Z7M5>CvE!?EJ3M-r3sK-nwp1p#^+z{<iZsQO-T7K_l|@ zNf6hv8RoSuiefmLA(2+V($glUS0p=bbjpWpi!3g>{=Nnm!S?jSGQZ1>4VZ~{S=7oR zOtmTl_o%fo&-E2(i`JPVx?Pnw9Rwu!sOarJiPBLG=~WcoH+=4WD-kDTvS%uilgB|h z^gMYF#Rt5Wd^J2~iunkJYN8%LioZQ0s}}lc@pE`jl;ifJ1%!t~ElTz0RGh*?FNW#& z*y5>GM&EFrh*W$*VWCZ-4QTnI_kHl0_r=e?*!+ins{X!#(ZdKWRy6=C%`FVXONVVp zB4gVpBj?e*pum<3!<gWfMbCIiASGJn>Q5hIetKhh)n?n$()X?q(%JE`Nsyo1;k{TP zdzMJ{$dBuX-?LNf@iY$l%HoFr29uQ@(nXh^8hXLEyS;sJZx4{k+uoJpz}etJARx<g zL+JoN4Vfius#;M6d%4|X%69{-;6AD^0uIaG8#(@Y=5|af1m>mue;0sZsm^Gf*z^-D z#Q}(zA7{HM!=r(2G?$6sDL?zQ|5VtL1z%1J@6#yeS57p`zobJj<vp^pS`0n&4hdO7 zR5*U|d1ZNZHaiKhoFiAQ_a0sS4^8L&4OjcM@iDqb7`;TBQG)25XknBHqKy{4N0jKj zx6wPJ_cmG(1ks{Lk07E&bb{!e_k4eN*P1_I)>-G=_qF%FuFpOh9j~~wrnXQ4LZFCM zkG?v`2_BvT$*P<(7{9<wz~40oKiRO~M2vWydy+%M$g#>`n>j8@4%UQZxv3Gdr*~sl zQ^_AbS<;tw3_EX51`>(ozq%B}yANCw9%`jGTzJMYV>z+Y=kfh$i8|Rnp-vv50V3ug zBNHH%msj?vfw++{AG%SEY&v1_J(q!i<dA}TQ|G|MP)<b_Kj}$$(o(pMY|!nZX`M5W z#&%r1I9LgI17cT@XX%INofkZuZP$0-L|XjAqh%u3w)hSkb0~iJ0VfL7`EcsTbMGx} zqw!Je+wQDHc{bZ=aY(S{RWt30xzIPwkV`w=t2O-Hf85tk?q*#yFU4PNXinYP7ONd& z{5%UKEvc#`!G(j8xfBK(Rge_gx%@;0iNYTmS$D1w?4cx(dJ(`#|HiXpd3pSqHttMS z6*~RkLJ`rdOxXKo&VW^SwCg~YrRELgsE4Vml?fN6aRJSUwO-x3f5SS$7@*`D!^6WC zX%;Y;TSYQsGv^$?Vn?!O*l6i7klOa<y=`L~;q$V8wuX6=SM67zkN4i1VG`>mc4Hh8 zpQZ2;+4@&`=gIio_XY{t^PgfQkyFsU+IO<SgR@|$st{`S>flU<F%^%Ls)E>yne&d# z4*T>Ygk{=pEP`4mjb+Zb8|5GV6O0dza)I&}PnEWh6AVw9_}`yg23_q{*Z+b()sRWU zoQRL|75}@c5r^z4OcQYLB#x#_64@h@Gjf`1P@zjnprN!oG#F3<b4r)g(#giK!lh%d z#lH9`k(^wi@M!}DN&lFieOs$owuBGDu$h2lE10x03*APg`%)!28m1Phq2s#Cd|E#c zjv_4%Tp@3UeUxtVzEGI=I2gLDzjY#JqtjPYXr%d2NL`Gyo50D|N=I+~JwZEVw01}d zAUuR+>;n-218#hiMkdP7U@09YuG2;+**J`vs?76ZbDLEIch|g#lBLfjJww;DYEHDi z)IY9hf;KQBBKiV2BrQG-wuMXm($oH^<d(*$rYoLw$bQ8c54K9q0*6FXa@gqWs~%w! z+vooZ?!oyp`wNSbE-2Mbmro9sP*qnTeIGid8+$n<y$e&uNHAe{-=-PlX|;toNo{ zvg5P=%>Whfa#&Dm>3sCu$pY{Ynh1I7TOTy*2lou$R%d!m{C@^pYxd0qBcg`e-=js# zLj|7`)vm)guKi0CUq0i<#)U-=UDRGDJ}TyJyL6KbN%WL6n%i7S4sHdY6lFSTSTf9M zefddoV#kc<+YwPnI0hE6{rWpZl;76A(d##kXgmkihP3bJ2IO`5k{#{sOSyRun=+3T zIXO9jtC-K=8C(WfSp@;dn|iz^xu%ki8Skw~o4Bwe8q)yhRwz4Pta2es3T6Y1fLlgg z+V_=%o38P`9yqn7tQMB6z3zUReF14DXYiFMqvW0Xw3)@nBn-|{$ZglNVx0)dpBiam z5yOVQtv?wWlJ2bTKaw7o{B)1PhlC`d;7wVHG1A0bf=&GKy~(VgV1AuItuuc}K}({N z1ca@Ec#4{!;@2e@#HL8z8{7k-Nk>-NVOX&_zf15>EMb1Us^#FQL`Om_3~$6Pt5@%V z(js=*>2hm42WTiQJ5`{o74FY=XDamGWDk7fgW<xt&||%XFeT0O;&3d2<PtQ$f-p0k z0t&-?IABDolCbR!l#-8(yr<m|f(^?M;A>JhpM(-Sa$qNk<IJby{Aqt>{GyWb_fAX- z8r^8#aYRYcTTgzdq`y3*I>l$8Qo$45?JC%`D&29Z<ovHMB+^+Ow>J;;AjA~RPkr6z zjZ|T9$t!rRPNYCsAmwjwqpMmK{QAn$UaqEk0641+CVa*wh5xx!&`<(nzV%DS2W8X& z>LV#QY-H+i`R#uoyNxqEY~?BwN0I$=31Kycn*EOU=s<(7%N4|}t*spada7<2PIk;u zn~m2Go1@g0dBrq`QG^5>v*+mKC7BpQ@w-MM?F3b0u@`&L3io^^g4FAldz|yVZY)t3 ztarYZ<i0FFEn)EtY|Sh6-+z-nRgi}<7pI|}x}O!3Q}**UVv_3&Gz3TSH=Safkw}yG z1a{-5E<4R%wjBuwV31H>&$O7-@7rrO(w>Lxx0~?cfidN-CLd2G0eNzDwX3Uwg9$nA zAAY<Kx;3rux;vQ+dKhvJymZy%#uetyqyA3*@A4@{e@Xpt34cH$3uzX^=HEL*ri-AF z)vHR6BhCC}yuLesn2XRqEd&P}YTTi7<#V%=ht(3U1s|#4?A?c-C*G#`{AGqLN9|q9 zULDH`n6O4@G$DC)YSZbtuatzd28gNuxOwd>z{*HXA>l6TM_}nZm$%m%xj#4<KR>T9 z-`Pj2Beb}q=q{o-PKZmy$RW{RtS!v=#$QcsW_`G;mr_=ikl<y&Z0e*CxN&lMaM3dN zmgK@n2$sUs(0*ioAY*Z#`*i7G>?sno^~0r1+&m5$E%kCI5F8<Ell0n#Na^QAmecKy zgl6Q+Qb274baVoiAtYWTj8=O9nxAJ{J2|1f`~gW<9Hulz4g%(A6%e@%rgBc2coYbh zlTk$I-0B4wlsh{+)jZA}rd6w$@7~{!MEysu#vR*t+Na+veSxpEx*`AN+PT#=VP%?m zVng2KrjO~oukQilXszkDRWaXLttea$Z;W}>B5;6Fjmn=qTa%Y^IZ)=T%+YTgT$oE* zycIB7?V;L?OF||Hjtc%wAE028D`jbe%M*<p-Or*?9id1P_mWrKvS~2lp;V5O?LMBR za~!ajh^{!6PTvwd8VG<;epTLijGr1@CvU<<j;`+1(NDx5HJIa8514OkyUU3!3EZm* z3C8kY2gST1Nla~mk(TS8Xi8kxpFiHzJ=@xJ^$83Nyxxeh6bgPgBtlNq=LcRcU*@FF z3|Lr$<arbX$U=i-DIAj=Z0NM`pqVgxkX-*EZCRRY>*Mhdqh3zx_?8d?KQ7Sm+s%~^ z&AC~*uMxKDtIwBEd1CDc29ukTPkB-IA$_+l-mqL-aQ8(Q!xOIU?)%>fd)p!)Ij*P% zawX}IRsFqXzJr*>P1ozY>r;SWL>l7kRPQY9n6qioEPfCfqK!jDj$#_?GU7QdHQ*Xx zC+<t#Ha+N=_<=@$lTTDGR)kkM#e~vw%~zM33?^+If91*)YlodqW)*E<km#tW@DoeL zLwJw9_y^h13MzyvaA77a;wG$|i)Y$`7L$VvGY0om#5vVU_0!WRKWP_6f@$09kvO3j z4xG!EBE*qn>*jAZr@W$NIm_+C9rik3$x%5bK4ly47IV&J0H?gZIOs;|A}F*GqT{I* zle#%%z|2)Vi6&Vm?aPyho=?66!9{4jXWKy!r!o)gG7pOY&Z)C<3@U5S9&G5!Z_EXR zC*N2oM=904BE8n9WAuIAz*o{L4)1UBpj+51_V30D@iF3wW{8VPXc`H043eNVki3zQ zCYZ|>t>_Dw5Nv0(ueOQ&(>Ea|HJl`V$3ygfc|=2|mZu8=_Ej#7A2M>44X$5AN(fYw z$XD)}vrkUccU^Dg*qR0+=7lj=0^1#rJb`1a*vy6>3-d#w?_vwT4lz|o$?Us_b4ho= zbF!Wz>g<}))YO!knmRKx({8BoyYEFQ8e5gZ=;`B!f)|p`^sE$8gv>9{!`m``X$XJv z;9EX!uh3#fDR~eGY`Jgb;f~6|=+#e>B7Be(&|3+T7KBZ)C}7ZaRBB1$j5Z{0ur^_k z6o!VHvxBP)Bp+`Eyt*GtCh_-m@=Q(q@2=L?hZ5liaB5Z1>BHgH*3F^Q;*Zhxx@VXv z47wJ?^T!7lTTWhXZa`6Se!lu}QUGc*0FsX9GIz(5ZwjQ1dGuDqpB{<MXujls++GX4 z<Fh?vS8=!ymLlYnmJ?(w|0B(Hmylqs^y{;d&09M*m0+c#1@q>UESk+;i$fDxL3y3i zFNa~g!x|x|U>ztZf@(GJ^6x_CO1z2C^YkSzABl2MD4IezeCg=0Meygvbm_;E&-xnN z@~x{YPR>qv4h;r^Q30a<SN{$(^<*4Hat7=XIzOfyI|AG8hx#;jN`9UHyB3zSWqNZx z_Zy07{oP_+$X2xCp6_}>aFkc^ZT!B=mjWV?s^y$w&+Wpukaq{>RXb3>OC%Ea{fTC; zaNQtZpdUP(JZU&7h8)HQ7bI5JIVw_n8^I~}GdEuf$i=k%O4E`<_Ww9|&B1!vnb!L* z-!2L4;X#oEJ|@IQ?WdI_W%o7zIdpn%ElaAi?BontAheh*P1B+%PkvWOO>Uk<8qJv3 z!uXDtI4$6c{m;qTkKGT6{#RL1lSA7bTkDqhN{WU}GCPm;w(gJJD54TIq9<nSj^)#` zeji4M?qRukdEA+=^%kQb(}0Cx+cePU^x<H{w`qB$l7cUp%b|VMF~Gu4KR`++ak4rb z862HqPTfvj?a>TN@VaeDYg};HVx>YUR-`T;X+=pP`<SPbw-gwd{iJEjeSgr&7}Y0S z>`w9mF^FFQ!6j7;J3K$JlRoU62ZE>rKBY^9bRBlT$g1&BtX$`m1L16xa6Dy(kv!qg zb(qNZrLlCqEgMZjwb}2Xt6CRxT&}?%sI?cp0vO~8w@BsTS}KQzxj)~Pql?=Xm!B9v z7Z0;vyr2suUr*b55}XxcM~wqg;ppACpfg}(u1hC^Wj}$Fq~TdI4I8{9F_spSPO(2j zMMl^zPOLe;aL}OlFc}-;WA~1!Wnhh%B5zxp_nS}*I?KyBxF4FN;s0ZM??jCAs2V9a z{la#W9~M4ZZR^pLVgdb7n)KQk28?V>eP0I4GFjPtf70Xc+HO#jVe|~cvgNm_sIp2l zxK*AA%BQ*80l`c;X!WC@xu|WH;>uS3TR(h#eQnbOwaE;h1L}4}2%(sw5;t?Q?;mE1 zBga{Y%0vb$q(pf_Y71Fu>}MM@Zf}54!x#+%X(Baa(Dn#npo*@0?`0fqRj`@BifutX z16MSgU`L5OMSQVQw>*w4Em4(I7CRgoa9mjLq5$vh{0yEvGV&zFc;hwP4WfS2w^#Mw z1Fb$yvQ3%l-4Q#?0uC*tq0X|$gT~J>S%KWtv@)aWjur!D(ku!I388$?qD)>S!<+d~ zXr>hXSD&b9*b{yeu@3+YjQLnR)hBqum<{@65N1Klsp%}PL<e6XK`WJ9h$hQxN=pK` zeah{{eTS&CX{Xa7J?U9M#}N)lO#Fr4&A{pC=rcqo9=xdhzHU_fcBAH~Ln8tb8meX( z<8n+JqMMo&NO!>r=8P&__(ACIV8@t$pP0=oZQ&2t%YRq8eT@FjY_NbAMX`I#CdK`% z7Xx!0^eO`AlHD&K<l^%w9{1Y?-`05<WJQP_rb0o59Agdyh;u`p?WLB3$|U@v4Z`pq zEDkB3lYZiL9wJRF1zDI`%AePXGp9!I+Ttx|#R))$?C)PPnsnb>A5_oZdT#%hzirj& zcX{J1^KiciD7b^sBg*@|lRvM}awC5v$8wDeBnGi3FJCD>%Tv|maVLuONsU&X8l3A7 zY4r4!Ay3#(P$G|wdb+2%de~%7r{r?gr~a2qN{+rD=QqpXD>-eA@fhNpn_NLb=41}= z)RZkTb{k_li2x}qOIDLf$-c7vuiZ{NAUwCB)f#5If)LUnn>L`%isPr{?=?3D9iDgT z9nz+0$ttL!A!US%Id7az?(g=t|7XGBbEhxnpGgvg38`7y$WJ(%c5{|NA^?9<!Q=!l z20}>C&G;EJXLjDn-AA7QRG^^o*|d+p&XkO#%gUQ;r9Mh_a6J86o$z2C)%$tO6p|D} z{s`RTE+yllJ{n$<@w3AZ)Zq6v#RJB&x64jDHvl#$0p$w_C08LX!58c*y{ctt;56j0 z1D#K`z09ZksldA{m+n<efkA4muc++JP$b_!Z+Nj;jQR!zVha`f-WG}Vngr~@`Lp5; z<7#KX{o(Rr&SK(Wg(6s1jRW;^{vevYoHO$RIJ<@eCIs%*5`!dUI<VBk2*(=IdTIV9 zJYj$a@OhdZW%gz{y~}T`8e^XK3=HXCM5lJ)4C&CHnN%n5zdKw7kc%#-IN72$(_4|T zYc7*^CfwWTNNK&g$gqzjte=efO@Tx@v>1<%48%WhdU^_Yf7cjG(iI0%+5SHC^4oBQ zbr-e)&Dn4;jhJ670NThyVF$b6{0R?5aipD^{Lu<MIbOdl2)qJ@%z;2E@Y@tKEjBp^ zYqee+XEA{_brQ2c$j%#?2LOktJ37AWD|qIEUizB+5}$$a?8w%;k_?ne{QSG+%1l^t zgxb(!$;}j7()3S7`LhUue<WOoeV!@ZZk9a6f&!L@xH7s(<;6o5Tcx9j9$2Vqakc{8 zqa@;cY899ri+!f{w38(>u)BMIaRS3wWW`3IJhpmt*Nrb0oD8Lf;wWNG;#`;s^F4uX z1Om;u`+tWAIeOh+f^KP5@s=511wM0K4a4h4WtVExr|tRfL;-0=W23GY;@$sJ8HYXy znR_X11<>81A{@l9m4E<fXhJfZ*b~wr3vBPkO?6u}nY^F(^ue!^it%O^an{pw#NCM7 z1w^vq0=9E92jeV2AWEa*`P(eEq-Zg2z)D|jW%Fk8Hw>&GR<0uoFE#X!btS>!3sH|q zg=S|!FAwStJjHF9;D4x#shN{zzRMvEu-Wbl^j?8j2Ec;Z8%tz{1V7W)E@nJhSI+}t zv7kD3FxWspA#-_bMJD`%-+k5U0TXG26&j2k?X}op8u)O%(8O!m%r`U}Ey=Zgc=YF9 zjXvnChTH4r`O>8EkQ!csWPaj~Bm+Gjql3+5YWZZjChp4QP%sUIyl7t{5i3oAi_&B9 z@W(gb=_RM3vHIzZ&(ha>*Z&bCjed-%1wmPhf4>yt`GuVX`FOMl`DtxeMov)UP zc?^fV8IR$o1@EC0L>0O}ta^?Y?_G4{mK`lF9*lQC>_2vNwAJk^3RN4#H7s7fYw*9m zXAHdT$OL!=0gLw)kH8mjwdO3!=&YzHo6+S606sH$3%Y$C&PC}`VsdVN4CX`AtCX_A z=K;=IXf#2%W5?o=r}!lUK{R=L-D|{bbHMLlWPoQyTl`8-)l?$?nDkGB2alg@xrrN= zXd4+rO#Hs>_vK+B?g<1svvp6u<TF0LY~>C^rFD32o`sDX`caHaTUyFQ^+g!=<+r zqqiH4!Y<kf+*#C$gvfD((cr|;Is~|Wqtiy@6oou~IQk;T!eOWqos9pn>U&`8!J?Cw zUuqPO4h1fj`Lkc;3a8_(yr%xQ%OeY{Ly%eB{nS}|H@|?lzlhjDBwFlc|0CV(>+S>h zKa!my>kiPETg9X-<lOS}LG9O9TeI(N<A5fwk+JdYxNBR84l5>|%3AdM7e_uyWRFoC zRZ6zK$3wVcVGY+_!NFNUO-(d+E4Ya$HpTuz^x}aU&~#g_OCz;BtGA#g__Vyq$U{|~ z{${m;xGdRWTP>I5(Jo-s)3{^NadfJUqeHdx0#M)AE~nT_V@5lFS2L4vtrU{;Wu2X6 z0=_)_J6<0$Z!O_G`~|k53$<FvHS#~c8`#^(wLrj=s|PIF>~uNGoHmO1NvV>TokZ6@ zvxooQVBwv&i&;(OLa4+gjWWsewk<6?t$w+&rj8VKHkm#D8a!8F8+5nMILVtYG|CEl z3TDr?L_q>JuOwS;T8((ut3CNVT#NgbdZZ;?D-&MT(ha^cLA`z2^?PMy#k1qyv%>@7 zSs)1coPF?T@4H`rlq3lp3)c{Wj&AMhs9OXunu`Z~gn`@rOxtm}6Y9K3ykrs-p1Y(M z19=AF>)b^{Hbq@d!AO&u?bNmFma@i34y5=(L)EuIYHI-egyy21Z#=k5!dPc$!=~ zCA^G$qtJ}0JfV+S1Mvbr#`wb-CXj^9G7HOoO`}2sf2|4yOjCk{ZHosc{-@&-m(AQs zB!`!yH00)qv=KzD)y!$wci-YR=L5P0e+4Te0<0$jx>t`b51goRU>|5RqLS0Cjd<n^ zO0Ok<FCG7cv+xl$jMX?_-rfU#<8(<>LxsbW0FxT3ii(QZ0f9lW!4*~P-6aJbzOBMC z+)p`+`@ko5d+F>Z!<8A2>~9xP0DK_lXVuOoBBN>|Ur~fHP--oP5>#X`mMjd%-nd(o zeT<s)Qk;w=LCS)*_LvQ-z?T&@pU?HD2uf`USpLSNIZcc^w#`#GXV`^NO+RE>{a5DC za0jN>f_z`cR$$CsVNE*Y$rLj@-PKgjS=wIF>8MLx0w%L?_-GqMx0)=W=v_ugDvYVJ z+L(BpPWp<P|BLZ_%K=6z0A>>h*r;^4^=K7OP^CLBJ8VnxU!}48Gc(|U1gL7p4C>fw zv;X3nKX*ldFxpU|c2>+=X{1p}x4M#lR0#=N7IT2%)A$Wbsn`p4Vj@Qnh-0?Q9b<%8 z-+2C9e!Bt=;h>o<bRre>Tjj|d+RPU8y;pX2aS#<({dYnCV3s1>N}A|f8pU~&tSXBP zC~$UiiY$7+IQNdqW{~bb{n?tXhnpOLoMlq~1g~cpnG`&@LGeN?#rt^I$5~l6Sll)t z1XUpEBd||8e6HFPE~J3IeeP78)pOG&oNB&9$bto?cIKw85qU;Mr3alOFIFl+;qwhj z@Q99XqBVEb;4d)<<vv_ARt|}*X4-3&?-5Mr5Qpmu9eDzfu#VNE*D_<JB}tq^k^F8P z1AnFED2YAGU4FT{^F8`YczaJVIFE#B9w;{+SB8d#g|t$trDvlp!n=-SOu8R8XNeaN z98GTkKfRRwf4bG<qku2$&EsLW^g?d@%WpGVuc&RHtXZvw*s=<69R<P=6^_1@w}r=l z{&4nlmP$ktgjHBfVze@kPTXeL%pF{oYu)s=Rhsk@7c;diI83NdDs2h4%7Qh<eRd=g zYw6mZHpU@y<F0PLuCA`Sv%-A*f<wQ>6A7ZehHBoh!xE+_N%)v?EVetox;EI@Y_NMW zJ%t8!o_!SX-=WGqjQPFRt%WC*U?e-r_3`tzK9s&n6w$9U&J}Dw(2xnV@;U&$dL+{& z%!OS_h#668z&<<Kb(Jkg_Wc_KFP$vs4@((s<~k&4>c`3X(3>{G`T6-_2c#iZuu4IJ z|2b;~jvVQkhB~k36FMvJ?qG;HlK=?F1T(I5$4?J=kI`WmK=i7gFqcC{ddN{zplI3G zD~`@bhfWwh|6M9WsY*1W^at8KdHXa3LP*_I#FY7yeSXRHs~4ZM=E?IxXmId6IDCD5 zyNsM%GpL_42{jdG;cLag__W$*sUgzawj?Ck$}|>*i3Lv5T>uH9uVW?^Fj;#556ab( zlYoHTFtQlY`5V-=3ub?_+?<ThG61zT-?@Q$%`>h9+_+0^B+$qgnzNt#&U#?OL}O<y zJQ`PW2X)f5re2n6$GZiY9J7U?wJV#fi)HPgE>P~l{qtAorwRF@Yp+9!Q6XaCb28l9 zgxb2!ey!u;N{Yo0xxE+^EyRcKH470({B8WZ!`nLNMW^ixF9edq27{x0`OwL$!=|l@ zDqcIG0&a|&p(rQKLo{0*+%km3ae*@N%sv~{(?4Y!lwQ-;!P5B16-If?^Bv2sysgwd zNiB~wIP~58fy|en`}yvN*+?)bCv|pYVc=%ttV8DRU9&ho2cf|j7tV>ofaZlsKjzL( zhXR3U>wIf#0pO@NeY}|uT6UDt+Ms53`|B6dl`9=^a?r{<IWd8(++U<-HiwL-!g22c z%xyFvBX$yGi_v&5%TS4LGxy_dbG*TvFm;Aunkq4l@~p@f(dqj@8DX|!<Sz}T{>?3` zriFeqnC*DXNFfoiaNz0X<z+Ldn%|96{9)=421}JoEug)79_15Hs_^T;^FecLETqT^ zhcqNLRnU3d8x?}9a;qY;Sp!YZ$z)?b9NyNHr&i%lPKm19Z?8M`6ag6p-FXKDkmU^A zoPjyGMV}!J=bOD{uf;-9&k@^2)YRcYk4KN0X<+7!T<uQ6WEBqiML8o`itfPU6X3}_ z+?^Cpiky`h@VKqsq)3kw7_DK38=>gdW?O2T90&T;IY570+pKKh(h#52Y1AubZR42m zoi-Qa)@7&Ww3<R$9IP@~WKPrRtPNQ;me5Q|a8_&_6?PU142$&+&(F)t7gbwF_mC_) z3BAX3p))K-ZUXMi|0P(CE>-O!%RU#919^A6-lXWC5Ukute)CJfT=YD_cFzYE5)Q>W z3iid=G515vghM<#j1S#nJn)LpoTk)n6K-RlS8iP}l1FAbC@{0rUiwn7W1}dZ2ZM?t zEk>JWHn;jgmmLWfCx+qzP!bH1hF}_K{49Y$lUKD=($7_88=M%x>)K$Xja;XR_!(Us zUb)Br(F_NN95QWX*U@$0Ix!qq2qV?zQtkO<#G`GDfxUtJOY3C)^w^9!Du*UG(nM?y z>>3!zAWtF3$q8kX%T|0Jp8wH-5*%xV`_3<qMvSP>j1v@|OF1g6Nqs7YR67-_H$MvZ z8LLem%LUV?Pwk{*tI>=w3pXoIh-ZTFY^k>Cv}>LV{|B|=;AlK@Y=S$a<&dC~i?Ca# zp-rL!7_a(4@@|dSQ8JG?tDSd1OdO+dz?Gx9iV{0-(GJJc*-QRBE%<)9ZeN0&oLl|M zvcIWGa0m-V=Bf<0-sz0ISRXZtB1ztmBn(q>7^J3gWZ$#MXn!}s%ac9(eOow28)xPJ zy#Nmr2Gd1^eE<mYEs2ZuQ*FL)<kZzRZAQK$+acDMw!EJiMH82QNnR14v{X2@aszaL z<Gn`rdE%w4l?9KkP0J|DO6So;BE{A{p|Os24d|xj=&hVtd4odccfdEOG>30CBgBry z=4P?O^#LRZzbNgMopzSjm@Q(IjYHcsNZjrXi1Gq_v)x_sA^Ty0v>J5b;Kr5v2~`AA za&dI@W*Jbqev8fbT$ffhM8_v1GdiN=VATu8f9kFDW<gWTBqvknj*BZxOJ~LvK0W;@ zg7EM(%Ifj!Yo8|l4}?TSF>nj()^0$cEgtBqywrx52jl6))amY{(R=L|vbh52xoGyW z@6NDqeZNC68L0T0H>xzW8fKbeZQ3M2;Do=z3T}eI^zJNoLIUlRMr*<0(5rO-PVcq| zHgA~5(3(Hr-Q8VSFi=h=RH)%?OXwBc%QY053){Fi#reo2?pA}MNs=uz<TB~HyKm*~ zmJxp;)$RZN^1hg0yzxXSB};8!=`3&+8&@z{3$C(w2)y?bG=p8wMPn%<yaQdPg`T)^ zSttm?%17LUMTEg*IK=2&?TEv-{z!h-7=%i6YV2$<iVO&R4IXc-UY2|c9=X3r>To}1 zDYb9VcbB)Jd1nC67YMa<C$mr)QFWc@n*!XZ=kl4w&*X4q-2%xpH2R9af|V2Q!us?J zro~=eI{wKbMB%z5iwA>Aa78!-$m^aKT$iN*S3wyVVc&zL`K*deJy$MYcpf8(u!yk{ zYHTF!cYS|k+I1J`=1RFg2-2Fh;$RvWBd37Vd?ptryZXYKt!2O1J0=})1BdhL8ZUzX zEO!N*{7usy;3rQ{;$)ZTke$-wleYhF!F8d3xb8?PfxI~l97&Es$;ZfRCgev&Vd>sD zwJs9%@y!Ti71M5-WQ<zR2=S@Auk|PjH+~%dn3hs(JAGCl9bmsGGAKqUU$Y0zOxhdY z`Y}%|c*<f^a?3Nqp2Ext<ByAZi^-Iryw$A8G0=ep9L|Bio|@kT1f4IZ+BBc7HKHSv zTqo@8*_0#0*?z116aOw64(YnRmjPM~=QpJWb#FwrfvLP&r;x?bpErBUw@F%20X;<| zR&d;$Oi!3k!h|Mbmd;}KN36bZ|E|Wl$i&RMK~$1$>x6#`B=j3{iw`S72a%rjsv!wR z5|N~VL(?C1wQ>#$Zh2|}mshXe%rp(?w9_5?+a-qzCJ?tx%p%~A2}b%Po^5R@c61I- z=|m&NfWHDv(FV}a1X(h$(9&e13#TUve+-gNWH-&jbUI{Vlq7i_jk3@Xdee}vg6po! zMcP0T45I-{41ZH{clw6^xc+!16Kl@lglSo*p*qUfg3m@n=u>7_Votg{g`W^^@3Ygg zSnHLwY{OvrHwp}zwOHVyf?{F9tv+AgR4u3qF?4t_;0vX$1}x=jeFIgG?@~>6OG`;T zfkKohfRz*{HSF`$l>c$CB8KHL`q?5<Q^_u|GE*!gn#h)#2C}j+5V5PTZLht(LvYK$ zJ@#(x`t=s+TjSm-3+glmswLxQR)4>j^0rge3{gw1eUox4_wkRnaL^sqLC7kTj}68O z1SUbD?}N?4hljC-?ZJf@>{)oE0@z!4;pNK5f}xK;1g)J_8F<9(v3toWfV*g0^i3?} zr~N{>{(-MSy-0&S;fOr_ogs<Dm-*{IX7(1rSZ*!3-H7tCv|<9fA(3uBW_diVI7oAx zg8%9z47^@v*`QKx1PsOcA>!dNS05xPEzcIdjlr{DqwO1H`QUUnFWGD7a@q|B_1g+` zF+k1a&v>=*FoOO0y>e2O^Un#8iquR~Q->W+T&MuvGo~b)2D@ywL804TRrmZ{Cb}^K zqMx`pkR+Hn6O)y|0GC3k_gky{?kT$hD_Qo!-%;#XnA7i+r&<8L-r3c~6F?k{Gv~3K zWbNbICcW@Eg*GG@Y3mawg>2B!Nz*8^X*McwkV}uObC*9Fn)VO42b>K}qtB?eqqBMm z)r|52TRX;m@Su3KuuK8SsB1&}=g%k;0RoJUx>)`j4z@v+p*X|i*IUoHO=IC!eDpWc zwY07DE_e^{=&YgTHl7$%^AdA0oiTSLU$23Y?m`QY+q|?Cqs3z56KJq$Q}IyX2Q{h_ zNtQ&jd42qf(SR~HQv|J<QCH+*^J$x@a0oQv^3&(ON_bb~W|i0t%l|GshgUbrQH<U{ zAGtYWnSByfnEFNgM??XxkO8gKRKCc@knrRe78u@3g^xgT){r{`F&hWrZ0g!y=?;1X zc64+dX{$hgz#?_rsV7W~zFb}8%#PS3aFZnibo{qgw(L}bRI_#aPEJn0T4tA+(K73Z znVR|c7SB!+u|pXLAmb1?JVrfIh?ILqh=;E!1jSexH~86v|C9&^M3R@+mdOc@IMxyr z2L;o;7oZm;%p!K@c}dQWl`lk~fG8zo^}`nab@=x|OzbN*kx-i@N$MzYA6PW(bPRl4 zq)Jc0MZN>VuDaEbP-g$~4@CLQY$Pr$qM@teh2pSIE7@2&vGO`bfG>wO@Lf^li0L=( z@Vng_e<O2$cA6-Y{=JM7{GlK=3o&{=ZyIz8WX&tKGslv}Y&Zay=F^`-Z)il>$aooB z77r?;|LcWwgwNVH8`Teb_I_G{kqTf`zNsKgwq&xx7G#k%>*wFWl|=weEnN<5B)AA& zXaKnCU9}3dIC0E+=*H5fxXUdOJJn@bWRI$<m{CZqawbFfQjiAf{)c7852>o~kbrFA z7w!H{?EH^?j1OPzbj?n-W+$D2SR0_In<vW*d9<6c;3Q<vVOj`8;f54AN5u{6LsTdw zl3zqko0lrrel{i6>K#Vqemjsz&68>KJxSAQ!o%or0+s|BcRUaHFT{1ig3~xMO{-JC zR@5ZOE5MZZD<5HrJtr1yFVg(%HfGcO=Ru2c$5E6>nN=MBhxr4H4{a+t<D?`MN6$p@ zj8v313>_@Wdq$X#?;1Wv&%vp=sKb^HoV;2W>-LfCgGsp9zmw4CBL+45kmsdLZQkdW zIORx;X#M73Ke?fW0NS;^9y}|k;)Nq+ToRo1^756lNQ?NBS#S4Xdi)%6j%I_&x-NF> z&)z3@-8V;CtN)V}@w_|*ns~o1)l@-Km-K>E*er?`L6TpB$~mhD0y<0!a*d>XJUu<m zA1Vr%6yY_Qu`T;S{^ysx-9CYyE}lNF55OzDco3DdFADUAh&)J1N|W}=(<$Tf{jX>D z&i>x*;e+gUkAA(7*#n0Krxla`3`paEr?0qn*MQSZMj<E_4jiL;^|_p;Vruj+Gs4!o zY8;R<xOf_cFX>t@DLSNgQWFZ|z#;EgB)0Jk2pAtzL%b&`)rVJ_Xf}^Qura}*v9b!X z6j=zP1EIRC!or6&ykT-l99)gW50F50$wr%w=`|>@mIz}3B*qsNjvNTqc5^j3>cBuE z#uJ&FY<?7lDMzVixM)|SRX%aeKb!3Kb@B6iv9x?#%u)73O#v=*e>Hy(jJhxSmX{w6 z_Vt{D9-?WQ^#t{~<{f1~dXHNL56hPTNMvu9jL^ZRs_I!%kwl1*s!}WrjK8sjxpzzK zyx3A(O>U`!$y}6#wxN;V<cJWo+%zG!kdSvLGPe|PTv22XBkcQkxZH7YL6&vVDWHYm zg<S7bt=5QcBRZK9Y!uzOtS(w9pN(Lxv2!wZN=7xjP%>R8QnnF-#4?CyY`xuaOQl{H zt6&1!yzJg%jhA8YZ_pE$J^hupLMk*C%{>BKde2OOVSXks@NHccRde(5!Yw3Uj}om1 zysxK0ciWFM%wHVYJrE)0Xf3>#^)hR&04nMn_-ZTABldu|PIe$zjKxY+CYU6Yrig+g zfWg!8_Tu0zedL%`aFGh3zVNwkr)TXSdEV<U+7sk#qLxdzLcc4&y<5~REk&z@8_!b+ zTd)=bistEYls_>Q`=sru{B!{fDONK0H5YLXA-FXtvAa<Hx*nIucL6=;^DX1e5}){E z8uYJIGON4s7&`kmp0v~oX@T0?+8Y7x>xZq23*bI^4@k2YLRG+MbZFU0PqmB}s^d66 zgjV+eTt?7R=dSzZg@H0!%K1!ztZcM^OWd@q8G2#N%a!jaeY;qr%*a)@7LQ{0?99E* z$S-b<PF+|u_|CIkaVrTc{?bz)(*rbRW>b-qy3{IetNk}t$Ri>!rou&bQdtpMT$jl& z=b9Fu9bDx5%raaLt6c0?@sKLd&~jxAf7AP&0E0qJ+f#!d^B6C5gQHQogKv(d7l^X( z^c!Q|;f3(47LhVH8K}jgo}TdO%F~dGu}VvIU){^xx%j!AWLwyC{rr!5sDs!4L#2 zxKe1`f<0TyQP%KmV`K&}Q@jD<UHJMNvY<ctj#h*<cxYv10&9Vz?1F;e&uGpj>(xts z-GC9C51xSx)o}g<8xqrl0H53f8@S6SJv?)fxJ6rU`_z-;Wj{n`M~CIsCp*^+ARRdi z<V544V3JCSoDfS@C=y^!L!oUxu5moMRkTsW58hu2!abr4uMK`kR(LR|tYGvQpPlAx z|5k$8cVG~+I0%|PxXFGkMU|OFMv`k|n`zy|j#dDUw;))kp3K9C%UucEmxSW4=P#hH z2;N`P%w@2_=<dMlWdIWXa5B=A#0is2C_8&FyfXMoZ(U&UZc5>#kS9*I4vjXcYfmgl z`p{tF=X7NrQ&!JzBHw=9CxyTA=Gf7~bB#1)>rY=E`81Rg(0LN#FY2k(?CpDQAvoD! z)*+wK9~5-PTx4!uXQXtssg}xfVluZ}gd`-hHgaPjwHV1_F9z($=}Fy`$LJ8ic|-~G z`Sa_nHgd$Qr+nv~JhfOXjyivmitZnMVPF$m$LQ$j<E_j?RM7SI<G<a5{ocMpzKr5X zwv?(W9$w!1e4v~-0fcZTs4#7?<mPAm6PK^0#p$Xh*(4;P$}4~`rNC*W)2Cx~1=|99 zx19(Aj1F^rX|xWw{pARuW0@xq6LHF5q`hKlUsx8&%d+mp<v{O8_1e$Xz4T|ns?bt2 zjivGOUmP)ed<6T)HxEhggeZccD5WTv#lOg}MzrIGhLbO)2-WC2Z^(&Ozg}+wdrVGw zC+bK*mFRD+t<=om$&Av;@3O>fqaLaXO))?ix0rwAR}|X*Ve#=H$ou$Uv>@<ix1#&; z-^`>;FzF8uyNvB;+oR{eLAP7LQ<o3W6og|Xl`FsVS-o*^@79{QPD-I31j+J^94sH+ zFM2r#`lMeP8`a<3gS_Z@b>9?7=G4vxM*Ayd8LJDf_b?s<b@)I9O&6reTxJ6Rid-H6 z8>O70LBMVst9Kbs6W%qLP*8~4T&d;N9~j|YNlW~}ljoy&%nPwZjpCAEgh1rb)y02o zJ!F4Fw$@@tL+*)hS!SARPig=3(c|WYL)w>;gPhl?{(SQj{0d3E{2PlTdkznW$UadD z6TxCp#s4w26H5hD?CUZ>O(yERa<|DFbbJ>_#cSeyt@i^CC#+V$RBmGz&_I%hc9?xq zj&o_yH%!iTBVm<OJURd9xcGxhR(KGP!YvL+O9AwM20!0_hmsspR(>}SGhZu9yrTUJ zGl=EgmAS1}WKlKx=jyVnN--^}`bVy*k#H=c(mqG|>#5+un-LP-iTWTyd_t{F`_*@> zXSZuIm*EQwABA7z=4tTDfK%tm6G%Z@L(jt9l^?QjhfaYRFlTQZdAU7xPuvr3Ze8(h zW8O4M(=XmW4`*#zBy!pV)HKP~)T%F4i|~r)Vz&xM(SgR02172z+g7xd=JP&2LTOb| zOQPZF;JpFYHly1YqOtY&jaOkW-cI{hpYB5{LKN{{Mp`fhn!2sN=O{wU;bli4)hE=e z6_{b{7I;eP$?`Sp(-=U^s6a6yOIobndFD&O7OHjOSP`xm4)wl`wax#`d)zfw{Z)q@ zQ(so{is)YY7zLM%r3h`Wq9Q3H91HK?*kujeeG-p^ZN1DjBh5+Ygrw;_n}rb|=|U@t zilOC@EtPu)D*>rwa!d@n3Hil<o3mX2)I4=*&{n5S@aoBY&bY5z_8v~wkDTFQsKTm; z;&;l&AcszaRO5LMw$G7Lxo$(bf*33yKsUssspyQdwi(T?p<S!KEgK`2efKXD0uPZ7 z*vq{4+TT2z8702)WR^HaagSmmNFB3b3Sc^rg$fI)_|lgdaoeL#U75db#5_fFVPHZg z=M}-f!v6bjSBD(*5%@nhzA^mzx=c+*R&75~f@tQ8i!@%wir18Ma&Sr%ZMiAYM9klK zlzpy4`YBBD6~vdn+iO<@H+6}2njCuZuTiAWp_eVbdPH|R^{*_~9J<%HJ?E4)Z2k1D zw`e~~*Ch3L6T>l)p3}})c+SwwqGi?snyu6PuLYk(2n-RhCM~QHk(^uPeP3&xiu+9& z>pAXtl7;d7>A=@S#s1&9?=9?$FQQ7;25qLFmX=<#Y$~PC=+6kX%xZ*s#13SjQ{&yE zEw!yV)7bb|1kB@JYn-px-q)CPua;hY6Y$o%=_<ybUU3V9$;Bzc=b2Jk?5sqpr7UOi z2696bu-@Vsecy9$k-+f5XO{VrZfe}}LD4GW)5<yviSdiZ<*)o%BCZ7NbqdR0X%Nw* zvBlJ9qjxcB6R*+2Irkg)?=^nRJ=@vz*IIy-V7#wECN*S->u3KQql|4D8Q5Il0DTk` zSx`W*GQFj=Q%ei)x1vK6U|}G^Xh;eXPMBnKbd_}%NR~1iAF9s=i)k>JsL0Huns|yh z?%K|og44tgz3q5W$F(m3$<l*Vs~6?9Eo&Hf*o7-Q{1RDmudogH*UQ_t{Q6!8ruCKZ zrTf6_yzCcK67=Zb-|0Ry7^NN?*2|}*uRV(QO~VWqoe=LGXLLYt2#s)=a&ch@H3s#k z00(YH*9a%~nx1sVN{|aV2G*!U-qDjAKiu0W=cQL3Pne+Lqt@x0l^I2zunewJtGHc& z<izTxNiN>$;rRZcnhQ45Z>O4E{aF4Eh(}*CXmP$a6)hr)HK`Y+jsJ3asxXUh(PeSb z%!AuylRuTs7?$FrFxgTqAaM6n>R;WAgTfaJqxpjoA8%vn&c$=Gk<rJ-?;QQ<jFS5A z7p4eEOZ;o(J7X%9vqHz<Na~zO2m!Fe^CcqHOO?=reuR&Sv*m?u%#xNvmV!V|OF(K0 z(xr|_4ew>}aCTU=o|94c#YAhDCU0ibXzV($&n~gRgoiTc?c3owDg}q{5?7hLob$!c z<!bjiGw(99?pN(zJ4CBle-R!-AcWQA;U&|^1sIJ8kDtIj8fUBBG9a_fHT-?1;r!ZX zk13X*#Jf|UXx-F)>RPvJaSkxe1biwX^+&)jd+V0xT-`0R3*7g$SLTf?9_|M1+Bg$V zs(8bAP@y@)Q9RJ-HC>!AyuZ8}T`U_n{mE3i+Qc1=PtD3+bh%=v&aa|nEl~GCfuAn% zvflV{u(i*<i`}mT9qnjqp=yFZ>gd$ve-z-=aD6{vz&D7ri-#t$@H5%r^}^WKtQwI} zqE^6n>*b~)Jh-up)-${Jm!BKOYsmn~sbm<Kac~ZLXTH&z5wb&_FoIrhE3j-Op>%(f zH-!p8nNm+h6dbb$3(a*c#RdvfQdkfWgiWk!ga^L}G+gqlZ1@sgecCKDh_=Ombnqj$ z)K(^&HUNFX(AZw~*A#S9Mk_<3t*b%b1`T5S8#7#9!O6gOacW8oaUAAdC3q+;qN>4L zy6o5$oRm2aZhi@EC#t6$tnW|eum;Nc2hU<)WmZ|-C2ZK_5iFe0auEk=U1bNpxn^3m zBDSPwi40HwpzU)7S1x;o?c8i1f0+jf!6&G`!uaQ{8_N^zMhId;*_82Ws~XMU3Mc1Y z#wlW0sC@GM)y8rC>!i)ziy(<99K<x}-57}v8fK!g{bDYMhcJ#%geT+SX{$7I&F6ec z*v|?Z^Oc><Dscl`;Su608%#|J0_<QCad(Hm?QgBUz!CxV_0JwNO$%Q$SP|OB>v&@2 zwt`4TP)lCzxjm(2=`F$^{f(Iuk#X;!cyGPo`aIiNvlg|^I(g5Hrf1L%UHUrb1fsp= zb$YI52R}OAhU~Bp^Ljy1QPxK%C$0-z@sp_*pr&so^eq?P{Ob-T<1m<5A}IqVhVtAf z5+XTBNNC@W{7lm#P^0V~$;=!`5THDdN$@x%o6|(yb)Jrl+9zC_+NibhY}UL^s`-XB zMt|mebwHcrlsiXZy3D53k&zsYuAP`1)g7Xi`yr8vulrexr!C7s(~_v0mU48!y&+e1 zd*-@^NUdh?Rhrs%faYI%qvfR);AdY9f5oq8v2#<L8Bg!#m!?-Pl=YaRw=0~Qb#ky1 z`Fq)7bo71T?mMW@e`+iM2{fi(d9YB9K3i43aRmyYaawpZ^HGpI(B1EduhKhvdP-z4 zALYqw7G+@do2>wSxVR-(_&VP4(#A1!?1eY98;d5!U%ZZdw`<HdWNPn>ZTCZQo&7B$ z^939$B#ktce{Qf{GuU=AvEq_ZRueT{$nN_x1XSx~-Ccox^%CLNX=37Gq8)}S%M}BA z``eS(ZcbibS6Gl&p3lR0)2~6UGb9V1#9hBj>49t-3DB?TamuPOx5S&aVK#n^1-f3= z?w?D|Vvib<{LVVlm_4VrmKE<J5}Upm#0*m-g!j*dQ|mrGx5_J_=)bIP!59C%jd@An z`(r$CzG5+N#2(kWb}?!r?|EZssS35_UL}JM+^h!MewEuMpF6|nw<vXdtLNp;KhAI# zP6DwPQelmZ*f(Jzq#4#lrAaJh5X-dLnCa0!OSBHJSbi4Kt@yFz<rSa+rJk3UHzC7Z zpdk?Vys!FD<)jGTg%!$Vp^p&0e9K!~T=`Ty#cjf1BDq%Z&o0hReVlCv*+MhjwPfvt zfq$9NAv<;+tJfu8JMO<266L3pK?BA`&9V=^|D^@xjRyw6uVZU7m)gL5gCD;Teq~;F zt6@kSy6t$edNa33^{j%p>*i$Rx~kFTJ}^j(={>rgts1%Wr2g4$-H@?}N5Yf+@B5ls z#@O#G>)xMURY$G&PI=FpbIT4VQL#0B^V)yW<htz2uPyVE={+Yq0Xr!fN#lrULY!sT zT%*eT&sVm%El$X$2@S(by93&kLzdd37oAqGVKv%3CNw17f3BjCD;<YFYvmh1gC|bR z*z1`vw~7?@eCIrEDM)CvRU?P>*?JF?E8_0Nb1XDUtLN)hKOg_f6J7l{XR69eHM;5T zHcHV&)PO0A9QM8>Q0gxc9o*=8pH4N!Pcbo6&eLh__V421A#nG<mO;M)os*KI4^8KE zC7@7<Jf0fG9*!_SNSo;6-j~)1+o5p6z)E|gapWS$_j)AT_T*7;&biX(eDyi*SFYKA z&%izdH3w&D?Oe?ht#%C;jXSRPUdGp}ULTdc{F^fLcw}80GA)TgNMOI_+dlyh0uv1` zAPsM&F@CtE7;j=knuv%<<a+#?cM}0d7F?(dtI|eT!QVjK%No~;OLQ}In&y2HkGe^2 zK3&to<6!S>*mFH1IYJNP^v<u;2^>f^s~8TpR}(a#+8jgdq{^!OO^1try_rEbLywzh z1IPX%)#zWD19o4`Yhq#IsjmrF7689Uj3dNpoe*Rf*DJm#<gxfo`DDdIR7kM+q{~M= zX=0&He4oI~#>Tcuk5d4uy?w;S8Iz<l{DF+Ng{=zy>bhgo^v5)_;8gozs#R@s1a3ch zD*vEF=5wn9tId<hpuka*Q()f2VXY#trBDgcT481uv8p|_)_Msm<?^F_^3*tW>5!Zq z$Pxk{ZD4_+4;YT`^7BaM>P|3K%lG2U4wwtsI`huF3Z4?r>~iXDr8Rkt;Ld3ebh)`Z zeAaz;*Yu`<QHHgcZMb)B{AvAa;P%_qm2OuxgnZ37L9M~imlqLZJR!A{bEhpHIc7Bn zm$%pA!fL6k6{p)ZnGb4l^?VE+kAL%zeaG(!bf(RP_E$^q6+mc1@&O6HoK=SRwa+Th znpT~^$Vs*jEDUUU1Yzx8!|YV>qm!ZutF=rj5#gae%VO2<4N>A%?*FOK<c+|Mo$teV zyHKiZY|i!WAuEQjBTI(o9ikw~3x0`64W*Mg(n#OkS}1;o6m{U)Y#958&AsNZ>ZtzU zjW1<C!;SLlt35qCJ-xcypJwy_ae}1F_uqs)KJp)v-65DidK9%2kxx91Vzp;Bf}b~k zx-hTrClmB?lxhOYX7J0i36-Mz9T2C_hsXL0QyhmkSkJNp)_++oJ!yD}pq|$68>Y|V zSK1X>9H@L=lu;MR(qm(Q*)uRuHez|@kGI#(6BS@N_V>h<kJ|mf(e}@4IKT38_`>F= z>^FY-mJVDwFN1yzOS*MysbKYhu#~YT+Ngi&b?g_P&>DCh&E0o(81fgSH-Da_VLK8d zYx}<cYwGaHaD`;Ose6Qr-qRtJi3<@h5UFXhJV^{kAChu1ZQmzKK906_Fz1786t%zk z`oqa{AeL~Jz6@#%raCTxj&<u{_j~uu_b=>~BmJ~hfHl@l*4h!}qC1zqQcbO$*4&uN z3#W7Zw6M^JLY6StLJr&Layi%jSGb39L8rI0xC|@e9olDRjPg{WXYHdY(ao!YBq%wE zW0Vvbl4g>izo?}khnJ!ohbun@E#u1Nfq7_ek90a_V&IV|H%*P~B~)8&FY5_;2hEb# z#HNn@{kfH8FZvK)J&}k^(txL^XpOL|^p`K!h=y0^`N7A`Aa5<>UXkv#tG_yF5bmGT zhoztdipC{ceSgLvGdP@?A%%ljuTV$~8VG0|{mE&2wjULtNCEF}FaF8#aGjjbXZZhK zfbN?jlH~GtHksP1&ztJuaSaK*J_V`q{EBWTQ*$2$BYb_uvy5_SAXvu=Z?YoB0T$ZF zd0fa*o;9IIGc8$n4Yq{o9DoKdE*YX@KOwVLY^7Cl-~4<jorotOw~C=R_seLYMk&W> zQyMpV;;oay-B*h7Mn^rfS&t2jQlv7#;9z>u!E?H(@K=&OXyEq@b)OkpMWUg^-`zE! zcWg?<+G8t<CaXt1+{#*=+?4?z`Z*nDr?`a`LNfI9DO)%n9nq<PFwAfp#MGU_n^UX$ z7y8X^{A*iA1QqS5%}>U(uxZ%whaX-OT2Y4Y(ABan!LyO;zHJ3A13aPIv15i}^ynN+ z<@uFbMj&DHwhK)+)&9Mt`e;5?iN_OJ+3ao<@_Q`zz^U<a-(D`(*kk43KTp;itIZEu z)1L!pG?Pj2Mo61_!~5s9LPh=qS+%&c)s|un$31@p8HgLbO!46AD0yO&6+FJY?8`68 zKUmBjxt{D+mjI1Gs#+TexRHU$HX|dEKY!Lx`@6c{{au)$F4;!lc}5f}^_$cKZ&BMU zPYf88jRh_Hg0c8gj6S1VI!(Wq#^3km&q8ViG#tRPGSJa&G^$`_@_W9msr_W9Vr@{j z?zdcW@NXmmYyMrFfME8-XIbR`(R7t<QFd*2K)SoTOS+M6q@_W+Q$V`AyBkSqX^|MZ z85#s(xRI6^y5qf`4=;ZJj_cT*d+l|u$cwW|gl~{+7&-e<_2KeV;v4$Ac=JSB*Sg%> z$~acofw5iSwhVryfa7Eoo+mkop`ZyA+m3{5rNo1%JEMK5T=t!8Xf0V?F2BkfLT|Zt zJY&m8$1OcLGP33&GJ8Wzo}qm?8Xsz-2*QiX#K`|ZDK0K9KMcry>v@prTGuQ|w;N#3 z>rO&uTN@jCRaG^qq;QN(rZeG1p3xY%Omq;WC~Fy|q6z=xVCZGSL2DCL;H!}2>(#3- zhB6e8x~{rzb$Q%;d7BIa;<}nv>FK6e=#=J;3A^+O9gJl`=g{am?x#!yt>a&m7Eh*m zImit_Qzoe_>qtfJrluS{Eo()sD|#mbD|vYP!e-_bqn>UQO{BMo*=|lb$K<oNEhHor zq?+w=tHXwd&BCJqH=*YqKAe2zTlD+-DTt6ELY3$}&6ijKCX{9-e)%JuagxT`_%#|C zbiF-13jKJ;Z?5^d9>j&LIdth|OmU!=`h5uL*$rp0_}XtMQrlH6DOL<Lhn6v`!*^=V zFg~gMWTRB<OK2{$%7Y%6mC*xb8AnKWt_Jw|FQ+PV(q1t5?S5V#F#b^{3I(4cgM*LT z{|qI$3z<)~!t|x`Hr#B|Fb_<a9uIc&-z2f){CiEoW=2k}X{h<G3at6suIiV1j<5Z$ zfm^ts%Xi1XXG%W;e5JX*S<$&`K*z2L=PE5sFv8m6vl8%H;ygG!UKX$>^bak=+_A3b z3V`N7bF5q68rq>*b!mirLSBhvS((4%$A@CDkAHQ<o=jCG!%yT40T^-nOKy^EJr5+8 z=KZ*HYToIi(n%#nf`ianH;Hg}q3t&+=sMe!hmTXhF9VM3kLD4vFTvnb<+#*&l8nA& z)kZ$F?l2eV(6|u0WM~$OwpcbxAeS*0iG$|{HXIsy)PZ0620n|%h4#x{Us3v-j4lQz z58GT~!HplleQh1CX8`nWBz9V950VKG^Y1NYPw1Fzsaic&tNvt=hrOiBevX^Z7X8Kl zvh1Ad)BU~>_yO?uKa@eYwy0g43FP7GI)j%pnwxEi_>UaJyyExK3{WZQva%8sBL>cH zI|K&;sO5hDB=0np{P2MS14-+O-2ubUz);<WgirrRL-uX_!dk<hucr?B<$`L-&3INE zPx4Rgh*|_BCVGwSRRxmuVju1NYFzz)K(QMC#QG%J3I$A=LnlKJ&GyH2A6DR`j-N}< z2#->~S_L@-ks?~!>sL!#E%Hn0__{T?<&P4k#pc_11?x!$J>DN4vW|wbrdrryrKdX@ zX2+M3wYNVll8}LR&}XMXtWC?kqB14}(Vv3=mo@nLatbiH78SW@*z)Er@r+imzY{2s zkww@*1B{_Gjj+$&-{=}co3Y>yImHg-tqMJ{r2hR{K}d`yMTiQ0A8x_FLT1%MY0RE6 zU`v>xjDyD#Ve7<`nTc8H9L*sbNr?kj<n_QKeC+Xw;F!s?a5}!MRbnxYr;I@pPFI^J z_md0%=swnrNw>F)lM^~_c}4MsUs!9SlZnMCY1|hG;_$CVt*^l%Hmc>pu-ylTO*yk` ztVYvgY{kvGd48VKGC7cx<1dH;!X>J~*iH8xr$U@sdF^ZoWlg*d-ywF@;*mM`xjfg{ zMAjEgTidFQzh9;7AuB!b|9%Bpt+?(z_Q{WO@VY)vPHL}M!&Vwa2ge>oV?Sp-eJ<*e z$nhO15q{@JdAUaT+whyfTdV4({TO^*P_$Q~!^?5rv5?!z8SJ6OUPuOo?^FL1?^ez< z@`N}LfP6q)&8idr!-VsIb=hl^+HK>fpXUcEKE7Bs3k*wDF@&7lR5+tyL7OB<4~I%D z>GE`Hq@(Wp+J_Sl(Y#%2!6G$vjalTKi_!gC-w$U94o1PaD7ckNEq}Yc`_MIy8745M zmc7J9Bn3t>Vq~YB3u}(a`bG7vrD)jW4s=zKPR^`y;zc)Th$Se4vom}eZ{+ky30ijX zDl+q#>Q_2j<oZZtr%}vJrERWCR%2#2m-mV!L4-JqusctJNlUs^Q0z%<{^64B<)`}N zz4;90og{a#evj{kC7`d9FiY;}0HQ)4UxL-QW9#!djA0z5-^~?C|3Qa2lf9a>W7gHG z0VDlcqRswVVE)#kGox*ymdqF+8?L8~_KN@7sFf!oHtb!pp|&lH!W#K@fc<LDn`hwE z+0o$&gb#E9KD5V~hK2@REOjRbWl|}9r6bWiM(R?|2JZu|m=*of&}4!2`R~8X7eD(l zt$Q<0uwPG|@m?)DQJ;>EM&FrA#q4M?Pv@F7axy6;zO)o_t8#H2EGoAb8q3P@Z~Xq? zAMEke;4}BdI~g=cvSYr-y?Tl}w@wr*gT#absvQ|LI#&Jo6DO^ec($OH$_>-<(_ZUu zel?Lp?C7EP7rb*QdwUNCu5$Cl&c?!@!MwyQ2GA1!A)%otc)=P2^QqUr%lGy90l487 zt2LN2Ca_;8Bwx0%Lw>fmSJvW{R}G{1Daz;+dFtvK9_TFZLeY6f41CR2+beW@u|d&Y z5caR5yS;gh-*`vs>$#iR8!|k-J|F0EGqLm}C8oo(5JK^^Fxmy2)zXe>5D?VTFD=D+ z%O_wSN*BQD)v_9#H*2CN$Tu1*r*oJMr@Q>nLV+RJ>D|&_i{jlx61H!=MY)yTSpMFy zs%}Xv*_8A5=nhY*YV{QfJ+7Oxv$LyfiUPUeW?2^WlQqaTv4*mEPh%YBi$ZI~P8pmV zGJiCY(7Kq>a=zL~#Zd>0ifLOu)aGL%UhOO%HeGqmA%$KyUAa$_c6IcRHZA$J`_uWv z_hOC43N&Khza67=qb!Lqe<j@im`^O#$n7z8f0@>VqybFdy?|AIwU1`whO0o@LX@ce zzWluX++8*^u^pZ)5LvuTAsJ%vnTG`PseIe<N5P&!XqOcSUg_{TuiHlgLV1W=EN?;C zp^d}*RKf%^bqEHY7A2fx`kG~PD;V6~u1gTrib#eelUk84(hmRIRkpnjkA2uLNHZ1p z56<8VvY9GG12}q?iFVc1#9Wa6A6y*m>2@-CD(Gxv(pmcd@+r$!NSPab?hK8@+>(ZW zR}jeBgFN8%Y^Qmf*J!%vH}@yUyDW=_e?Yx<lNoc+A7*279UegDlPxC;Zp7iOs4`jv zuI*6*Md~Rj#l3gX0NSOYS1AHpi(q$mzn7JUqTYyST0`f?cf5KK&=FzIP<FQCPxgtH zHZv6m-aHCQ%Fk<CS@-GcUCqtSy}d3CGi~p~5u}vERrVu~MLGTqEH-TH)p~!gt!+Gx z!KOAfHOYj&1BK-do>H5L3kx5zX~+&I#=AV(<hCkVNHB^B`^XvF7SGs1pOTW2Fp|G+ zH@{1~#O~0&Fbdg>8{Z}KC^}!WIlQs?FVKM&p%u?Y2+*v9$!H^0ap_X)Gn(+S6a4C8 z)^!pduAi@$cnPBtP))S>)z*Kn1NR-;d*>2H#n$W&Hd{$EIR-sjhQK3fw7R{0oIy*T zshzhEtdyA1K&xnBNiR)Dfw7p7>&9<Dj0=_R<YHxGD@+LRJ+fX~e(~cgPcRa}0R~)m zVK&4n{z~4<k0&mnHgM+j)Y;9=O;3%1u4NcPhTuXrSCJ3ca?3|UV=?~a@*<rUGSZ=P zRtonD`#>-Q_5f|w-P7jqZ<;md!Fm@uDXmuc1E~R;O3ms_oyb+exz>XQ8~#l3qa{*p z-6ev8EEP+vxl@qCa#O5QV$z)iHfF4SGmuO{T~b`E{hf&o&AEX%9crFgNo%BOt~ORj z==I5DRo)-9G;|+YSC=oNG@G2vFg#*8&p%_&Z@Cjaw0(Q~Ki)?5Q5#)a+Hzs}%%k)D z>dif+!J>PaEDA9(F>RzN*c=`<z5MbbI_k9Ah#50<Tg~AI>+P&4O?7j)MD)S2A<~^F zDMVEli7YNIzV#P}y&zKu{s4k2+S|QO*V{4j_7hHT{Er#`J}wC<8@Y*^<!O6e7bcrh zY9D_$@8P3Gm|jG*9AaYcs#CJhuQjr+92;>KEm0R78=AN>{O%;Z<KMS+3_CdiJ}hys zL@0~5<3?9mRDIb}(8sh?2CqBO$_l5T3v1q9ADF3%as~!c#DF<YS)!1jppX!9#K7Ly zVn*yMc)z7o{)S1XGm;rf!=@o-PnhoN&BVlnN7n}B?SAXjLm8QyGbU2R_Ltv~_o$|v zhx^o>OeMwYtEKF@S2-oK2PJ`*6HhSk8#DkG^{db8Nf1<6Sjc^~y}b=Uuo=KB^yJp} zV7tf<tbrp2N}brn6r2T7jO@g{@N}H|PJa}m*Splc&*)P7$yCgQ3he&m7M$g0TOY20 zA$)hX8Q}ih(>BVBG(b|WKTfQH0L=lVTV{J{DVMUM;)M4MMlm8e<<0T)?2@EsXzJ<$ zMmFfvy!}`Anrb^@H6`R2A*3PT3mo0VC|Aa5X-_9Bkh0^Bc;%(%klVx_`!mvch={n= zjud`vHo(a%Dx&;Ev~wZM{B8M%sQ}Z6$-E)%nUZI}-00F2qa04!j@_)p>-~=8vqs1l zZ|{!wc0v_!u0}v_u~3fz2UYOJLqd7=Y)VS-OUd&h03`oxY+%s(9z+`Fw6z@Y34Ms< zFn+|VfVe5ITo~xz&TKJwD&zL+czrJzHAK(Xb_QY65y_`jlY8M8h>o(@81@N^awfFU zpsMYdg!KWPlT=9x0Gw`gni}=n`Mvv~wCk+-ZdjdhUzsWlKHTOK8V^F{rYHM)2&gMc zB*mf`qD53x*rsrvhPK-anr_C(<qhE#ba+TSd@U4oYx9lpxS7*pX&@~E1fSx0I1Bu( zdPb(N9(YH8FHIfHCik?L5B$`>o@FA=SabFf1~GM1H69O`gFwlcGEPRuW2v)SU${}& zMh$6p5Ol1){VvWEo<gn;Le_+sjO^s0Kd(m3`Fld%5^TM-a0+t&U0s0#VAbH~>kQcI z4(#nvQBriH*GOO2p3JEM<|osiOF_QMZg(Zpk)*a$`0g(beO2W2%2T3+it7i!M@1rw zR<(n$8;#M;T~}x{ptF>#u3>7T&Z#7))!OFPTkq}d4Un5gO5`@ngxq`?N(K(7k)k$E zlAY;o4q;!Eq_sN@ZvLBk;z~{tQs`~!dt^ghN^gXnxVXTu6oy1~3SKZn87BDE2#w`U z5OH}SG+_XV%z_X9qkZFw9u}lBxk6^?<dQMdUaKHi#%8L1+hhjzI$qg_2!bkd^>}1O zM~GynlXJW>2KFmxP!b-Vn?f%2LvDyeuy`;hp&o+z$|XVm#P9J2Jb2g>d3GttZGta$ zClp`I`Yw{(uHUrQ*ryhVrDbpX+4CN4cp7rL{8Csg>f%a^GL1MT{y;?)oElUTZ1b~; z6In_TxQIuuAOa*)iFB7IYpsue2eBvRKN~y2eRo^{Iu!xHS^6h)VRHU-FFvBezJc-h zl7YW6^W*msON&AQ$g)>aX_SoX#;@gRW<b3+e0v3O2~<>oY8H3{;DqyZZTvUACg{h< zGGD76Hl6&>I?c8<@6N_BJ7cl6+Xp5A1hd%LAzP}jVk%l$Oc&hJ&5Oh|Fq5fdX3nVT z64aooIXix=9A1h9d?l}YX0IdEuLo~S(>X|~or1C`Q)>&^BT&fM-gVh3>|<;r3$dCw z1(pw16IQ1WlU>GywYIMYg4!Yp=y;uIk=uBVguWC<Yw}|bDUo@{%2;ksb3_<6oJ{>E z6cI{W+EQ1McisN9a$1!=t)EtJMvhqdy;L~y|HTPhB`cJtc|!d4-yg6>IS;MvleoNq zu9n_c67Y7E)hbW6a6E}4xaI?YqB?}DSUh0AklnW;URO7UDQT?W>FG&cYgaFGd~Utv zGp7NA&9Nx=XeiL9`Q3+;N!}aMHL+XfP)lIhw3<Mh=>IZdovuxmECh_xJVTkb7m0UO zB&hu69cokm0>1NL`ir-5Rx$9*RJUS7-^83wXN0gQFFYg)OiZavx&|Sxr>?;44s^d; zBu;?|mD|2ewx9O)HoQcPV}P)!B`7dsjKvBjCn1?DzrV{#p>WiGZ)DN+5;O}x6lIRj zlie&V>7;3}zg!7bA%CA_;pC!sVQ@T2sKqEhCnq;@<_f;9F@@CCqRt!(nQ=Y!CMxly z+sL9MDwQVYYROHFiezZV^OSz?ToEbIuC<cd1IjL~k!@zb1>OHw$D}i4u_Xl~2H$hT zB?@)OMUL-Yt{Xb#l5p>@3stJmi;KB?GF_IJ!KZ~WRWUrI_uT2~o}Qgqs(!!!yL&y6 z!MydG!fb8p4|I(Jb4-<k)q0VQ4&K_5C}~tv<!|9<o#m0e-T87w$+rhUMtc6=dR85v zZ(@~8%hf5HEc(;*cHa3m14vo27uU?*_B38$TMxYtE$d7wrFP6*#nj^69o^v8-d>*{ zVr>zr@Uccty_F9h1Br4~CpolAy2x^Pa|G>;b<sNz$iDU32mfpP4^*(zQ<lXRQ{GlX zmw3^N9@LyNrA7YH$E;p`$9x6GvlCapAyxAKnV^|Adi<^?v)FeoNG4bqY#9_XvtikJ zQF0BgnD11Wx(>pBlgXIsOtH+9@D<Di-?o-)f<r>=Ja^3P0)#2h&Ij7-A}l_Nu%ct9 z=ON3Wq0rP;gvv>i*}vzBgKI5M4<)h6uZrh!L<26ir*g^1p~0>{Lay0;6j(7+zX0aM z$;oN%m{`8qWcm`HPj0*-zCSaaTRViCe>C<x?d!kS2=MEKSrXDvF&A%JcPserWY;f5 z`2NfX{B+h0Gc`4p(E#*zZ?M<x2(#zQv(2lkiKDMZ%W$~B68PjVaK#Cad9}(7DRH2! zkm@LFY06t&LWGUgt8y|DCITd1jyAhXTwGnxfbLMPsEOU@g00}=Kfu~UY|HOY{o-|= zAz?*PfQ^u(L+wbboni`=xDf|YT3no^3TXha{FvHH#~35&6{v%}%VVvqps6(y!sOEu z+dvy7IWF>nl2{eS(a}bZc--Dk3{8_sNJszzUQ|G-BIa{;0)yEFa#iN$v(Wf8e-dNT zSO&4ht2h#XCQwS*h6#`(Oce+;)Ya?TV`5@#45`FL^0|oR!2pWNisR#15^)Bx;;M8T z&-I0SwVLRK_vinO-~yv~39N5v;AJld3R6%~OG=7MKHY5H-@pP7#6(7Hi4)mlVyJ^J zrz+qly(m2>fg<Srt1cgU*^>rO$S^_cxkWslOsp2p#mUKu8}#XqhGg&E^+fBhM(RL6 zz)nsL5U~D#U)~<CG$bB<J#J+)w$r6ZtQh88wJ;_^S;D8|m@+0>?KE_U$vLNhfm0Pa zVE&`E)hhAAh8EAtz9njB9bS>WJk8QMA4ldtXDW(MNIx4q^Q{F7qHr)Sptq3SXXn0L z`2PJB$iTqB?QNA(+e&%3O){CZCv!5WUuiVA>>5<YGlGKBuZl(>zm`|VQnl!3m_0S( z?C*Xt_=N5$SfFaxx^@dayFEKwS<x$|^Ru(sj75Q?L!sj)h2wYr{mZ{u6|HsZD5oTZ zhXPAOL*wZsIPn7LoJS5N7it7wLBw`0atQ>Z>2-_Lt0kXd!B0bG!P>V-LT<gcKGcD} zf!EINA|k)HULc*|J)ch26h{;qheRIaKv}(pVVjo;=91^Lkb7~fAe8Nu2IDmmX6*Au zO4GG<iml$KqmmbJh-Iu1Sw<&kB~5;85>KXf?Y~K5p^{mkkYz_xceHCmnCoAaB-x$f z5YRj(LleQu$aForzlO)se9$vMB`YQ8l!vOh<hN6Z4!91K@)D!@MZiCSOBq;?O|OlM z93(&iKEc!V0~H6c0QV?KZY)9mQpM6^?idqyDO)Pf3XX%Ipv}jV_=SMj`FG<$1DTk< zu5M$sLV426%nU%W0|%4Cv&0?K&QN9wMJCBP7t>LjG4S#52xy?*nYUl!pZO|UM>MtO zELt#gw$XJ}PW^Hiu=QlBC2XaNf{GinlQgk8>wW9()_40jF`>LdKeN$<VbE%O)3L;l z$=lo-)yy-wx3^ba0)2Xz4FO^T6&nw4{2}YTo0}t+-odwjpP!#SJc4)59Zhu1f?oSc zEcas3GM}vbPdHbOZxVUFxmI0008Q2rv=t-_q*fSnufR`M#Os&e{PX@pO5a=3f8a-U zEX9$g$?_(eW3UPzuRBm{YwJd3E?oTY$GwT=?)Fx&bCj8xSs8@;)JsMCok{ICdl1vV zFEY5e42bb;(Z*eZ5emAjj1zoZ%B(!GocoJ_(y6Fn=EP`fdL^ek>0*DsiapR9A)J74 zm}GX;|00%+-AUe>cZCzssI|5Nt8(ABmplA^V3g<FcnDMU0aMBi{Gw<0NKkHP#ev@c z@Rg_Fv#B~DOv^zq5C*sN^!+U4AWHbvh#6s%P^$bXlb_;-&|Kp42NC~UyO777Co}Q- zV_^Nmm-sM3Y&LD1V;B(~OVm1bkV56+<`(sfDGMbXXBkISaHYj-v?WiyT37e8iF$H! zGQcDHet?(<y3+Fcm({|v3VzF~R$>*9mU;IZ>k>1~s?}plAkXa={QHRZ4-{CBFHnH` zmUw%nqB}c1Rb$FH`kJrE+-sVaE-IV7hKI*y53h#6eup?;e|(%Y15!~`W<yKH&7RsD z85y}cnC0`DrXht*wwN4^bMh7!h}XTR4fBqS#*k*z+(|GCe4aOZ9x?k6c+VaAqqlh; zcIV;Q(%lWn%a4n$3|;6dHH9GOLR)@MH-DOD4i<5on3Q<>E=I{APe)&Wndqf6tYF3h zhm)zI7T3D<d%om-`P=hRZ};NE$>j17J2JA^pFcwuZ-5z$yj;39_YSSZVIbpbV&WnW z4u^p|a=KwQ8Lv*kNhATgsOa<bzGsxqYP-ze%)~2Wu>exeOK8OR@Cp*R$geiP<hv|a zb$u=tXwz^pTRk~zIf&6gx$4zzm#u-1*EO{OW^@JGn<Dd7V5oARw3YG7<7wF7NST<1 z5-TR#YFlY|LPK>DaJ1{PwYd(mgw}z#HNfd?Q71N1QJI2+#ho;`h+3n~4X%wEZL@bR zwB?llLl5xldcLefUTvht8ZGZ7kwqEPNFnmly$%F#DdHftKpa)s9OgWU6a2XkGkAc9 zR^w-p4Kg=Xh`N<?{Z5O%fu$0Bor4KVT;WwEx>lp9m<i|cNRR)^N)ZWA`d*;Q1b!%Z zI}LdQzqy$OKRjq`Jr!t3bOm?-c=VXkq}Q_0Lf3LK{=v^j!%`Lcv=*2bLtiRd!l}7r z)Sau^*?8^a?ah1d(n}9?*7NN#=bQ#uCYEI~a_6O?XiDjT5I}kE%_g_e@92t(izR}d zg`YHS7-g(fLo|sh`QC#`KA}`t#;T5nfzmKM_J1(hzc(|!f}@lByB4?|FGDNte+|$; zRjg*+-r|v8?yhEi?zE{yJI;G}qWE|ehQ<-9zK-VRF0`PkDYaJlT_0X>0T<5(wJK8% zh=tV;)?N&L7$tY>bMHQAV35{Ta?liRHqT8-E~WrN>HYmhIRY%^xfcQj|E#b3pFSo9 zZwcnKH#--8uJ{jamEk@^@?`?{I`%ehT_-wi+X@6?cu4djsQH}rylMoWzZ3{HLc4-q z%wG51HeODq-mc#6!JH7TyC!E61#Q)y{Iv3LMxtod5>a8{dt&enms!Y5`xrLW^JO_U zkY#L+JhU0{viTyuHML~GXe-w~3Xh^P#fpT0@K0}mf}D|X{J1kRwtO20hpUR1I`Dh| za9M-5z&$;MTvfHAR4I3Nci321lMBE_K?f&;XYDa+ds7S)p%T!_&X%UL*2pPMIwsyF zCjsd%A;7rd3vlKq`wX$OF$4~%X}9<LMPaE=7DYBHHPI`uXcwrzb}XG2#zDq}?*}MZ zQr*bq?yhxLZcZ=M{CB`<J2?PEV?%2rK?p1TJxB-BFHd*O8CStgg@tB1i+g7fZx0eH z0}dkNi10jRLX@8NE3)jV{fouwPO}ht1&4gDB=>`Z1IT&Os_W}5_;njQ_?#2Ju*fWR za&*+br;Dd)=XG0m==(!hoSYJBlE6w?voZlU&84wh?@dD|*l_kBg<3*bTs#OMq4y!T zr++$QhG@yVB?O}Mys5t-s_`uL0CU%V<X~n{ZZtPV^7UtJEx-giHeXxH@1CC<o$Zpq z<?_dQ74q+!O3E&s-WI@<YR`EiCP@+E807Wd>EZ+20JXS(6Rsum|7!s<eL~Kly-z2* zT?{=pzt*<4xZ(qoh9ha0pzDP@Mze~_v5u6)M#1OXT>qGEk;?Z1c?xC}hNQK!yNU#q z*rY(&d8t<AD}P(iN<!S-BucOo`r<@4)_%RNCt;txUOrp_g?K$bTY5!K@-j=+*BM;G zi;FdqHPpEd(CHq5!!qR9eE+ib_QL)YFiK)e7fsT3kWh3wnAIEdB>9p8zUl^>MU5Iv zp~mWHFJ$83TCL<WAKp3Z>M9k=oc4mf4sOL@J&VUTL|%J6v$erI3aI({QqdTAG&H10 zN})WFsg_OG7;JcqjLQ9j8Okh74a5mRfH2T%Hemi`Z!)VorGz7A3R)ThxMw3G-dPFj z)abX+lrxy!XNRW^gSht&V%Iq833a4&W*8ZKHCm&rYaSPfV}XSh>s0#h)6-MRlT%!& z-ui|eQwMejWdsKoWWvzg`c42HWunS_*HAY*F<Aq99zg6$HrbJe2F#bZrYzuY3Tfg! z+w83kWp!8*|4?B8!Rpnby|0fhpE6enk&*QqKZ~Cys!<m4$^Fco0sDJg+DX1nnFT*i z93@<d`9S^OV3Ox6y)U<ake~j5U))}okA)g75N1g%bBn7r^>xL!);B#?$fR+WnTB%_ zVs)Dx@=rb&+(-}(6C;*Z$gx&d)nLHaakna6Mwc<k$Sd39g#IJ(X!L-R!Oeoo*c>s+ z84(@wGZ}0e))Ii5<BFI^g>vB!EKn>A`t;2A>Aq#lP7W}@8X!dNCeFwjA<?s>>sV<r z$ab+grj**K_lKt9abLY~fyu5F1G>A1Ou=7!5140Nd%UlZ!LKPkot^LDNxnvNGigX6 zNXu!htuvHK_320El6(o^f3%bklaz!dMFRx$D)?gGW-;+8!s#i-0cea)!9@iMZVA}A zXH5%J62cr7LN~KIU2lE7*#;NaoV!enbkRi*3qU_G;__0GlO>*GQbM=S_qX>fao<s# zB=ud)7`s75?g0dX)f)z49ak`nww>=h;RwFo-byi<1<^8uu52gf=3Qoo;K?P{va<4g zQK%rT#6n|rleSKs!~5otMUGc$XT<8ksDz7xDo2WnnkO$1#tV<<?*?eauBNMr(^@!6 ziawOg9K`>JL5zigC$~(XDX%@Q^;uVW0>{W(i5olJDCAI1C0?o!(WlfQ|EiVmAb#8Y z`Q-lScGQ=f0-(oXC(bF4QJwu02DWN&!1I71L=Xk^4USH#^2hhHpi9<x09uI-AI)b( zWE4asT@)2`HkwIpkdfBHm8H)Jl9{|;EFaSde%MxAms3mE*0#c*2S6ckPJ_1tuuw}) zbym6?8ZM!mv&PJd$}5>bs`I9znYbz|>B`)+;|){Iz=GJKPelH8_g0XP@JTn520boE z!NS9W-$!Q@lnR#kGL}N2VJ^j^V+o{V|I!sBt3tN2?~LBgB&h_x?Suo?-6fN<Q*->x z%wr+XV{er;*)I!1%i*X}Wj=r|hX68$B*XZANXXMVR&3IEY)B|E5e-iOac=l~MJSqX z7E!_)5Sk2U&3!U+aD|Lbg){#}7+6fKz_S<(WtV;mIKFRsfRhRT)hPLRxKqxonApR! zali5hW+ML6JMen<{?I-kz{+!o7%>%b2M3d3lK1f_fs6V>;Ip;QTR(AcFT1{Nt9;@` z`>Lr}kAD_P&Xg3ALOFcsS%~}dg(7v*Q^d@`VUb%;JI|ppg5pnbuh;SUs6vRrk9KDg zEqZ&rq?QmsPPaUikbo|`#yWLA$tm9PYhJp(y=;N(Tf2^`41v^<pva1v#9x(`){Oqv zl`tjduA*KeOl=u~Q5?E&u8E`2bpRGO_4T~%uFc=RLbnG7AS)<@G)!aB6T)L`N0kur zwuR`jT?$J%MEU*`HE9&oC`?Y<Pgdh3o<Jqqy#1Hgzt{H<T3Ufy#?|mz{gzH=c1DJX znlq^;I=h)|rW_%U(Aj!c#(B#Q{!xH=e2KZ6TDS{{f*%HjN+IC#*D#dUI=sFPnI(2~ z0FP*1h(zG?p)=_?KtX`}y1T`w{OheYl@JnZ0j6FX`D}huBjjOsLd(!O^!(vyVny=l z6*5{SZ>h6`fySTo!-fHfxlUN!`kBFb?5#JEIQj$4F&yE0C_HMaae=7o@@=e=G*0dW zS;U$HDIu;VpGiU<?l(L$l_*<A9nhS2mj+I$+5N)l^NQr#Ov%g1%R?ZPE2!OM_!pD} zLm|TAh!%;)0)_(8F~V2oEkyK)jZKRKkxFTzBBr8b8Az4Ow3+}xL~2a<QA@)}YZ(Ha zuFy%-K{?PuM;P8GnHh=USQ#ZlYp#-`;E><s7?{l{7?1yZ+l^daLXMlj-o7(@OG(1Z zMhxFkKw?kVYY`KBC;y-WF)3TjWd}Kn9#&RMT+uHr+#K+ge5FSE0tTJH6D?x<=nAkK z4kb*q@t>WWhXgFa0)+nEaK|y(l=Y+^7RrXtf_vVeTd&uDeEJ+d<b5AZH}v_bK5ye> z<P+ESH+kS!6KT_*1fS~ESO)YXPzBEWPq!%3*9N7x=TTK_8yv5zZ+juHcW<{_y1F+H zb|o*HPt<|_u(LmIy<P1*+Hjc4+VJjZtc~^R+A3w{skv+1+_H&Mq0t7Ysfjc-@HMyo zz04ZL_bosDU(Tnv`g||`jsO?}Xa>FW@%iY+Lr(AxNPEGd0WoPJAt-3VOEGaK{M~%p z50HE~n)Md)@$dC;gP9x7BK5v5vp?zI`s7M|8d{OjmSVKk5*8Kx<-PNG_9G<VVjl?j zmC>CDG|k?-VMiX4ZZg$#ZeG0#GX7AoB>6C52KIdo<Shbs-6^2doDilD78NwPq#%>i zAK-up_>XmJX;f{2%<~xy#Pe%Q%X$l?c(h1Rtttpj3CK)QN=(;|XK#@E3W*kNBtYRF zQIH4a#WsXxr7-*`Gl*tbYv_!EGY;nfmDXY*kL*>ntYAIvy_&x5x1Yj7V5@Sw+Zkgq z`b{J=bDin%JjRxlSzct`9D)dNai#erTJ!MV_P1*-RYW&P%)0z_Qv>JO1EzjC#M;~W zOp(gK$&Js2I;^dsq@%RTGsU5NGja+7`<(8pC2~X8g~cTS27Hm>qb<et<c5-wY}tGo zoa{~6!xQ)^MiILN1GWLr3tZi1D_Jn?j?T`phylo`dB0S;OsZU)f!^Esw&LR2^WzQq zw6`!tFf3pzL5-W}*4u|0j)%q^19y!es0m?g)-3QmAq6SoLh=#fGj8o>Z#(6j%Ntn9 z-uwKlpGS{bo370)Pg6&DGTmnj(w@uZm(#p)?(tl)He(kY9wo7>?_43Zt<pra`%S|$ zxM%1kVi?XO6LfWZEDp0QFC8pZmN`ZOnf>{rI8&a1Ba@nm8!|1n4@#9fSiXe4okajU z==kxLnlK<$=>g!KAp6-q{Rl{K3}F=<f2=Wi@!lCBq$AKuC(<}{<brP++_>`n@BW*F zoI!zIDS%;vj`wGROX}arhSIPO*P{~3Y;0__t>}K^f&3Z_*=guRvVrZl*L4?=1F&od zqm`b~+;09HU>mJ@wFZG8CZM3njjP%&dYCkngF*$zia^skclB~_D8^>Kz!dU!Ji8@? zGWZ=>=`aQ}a_tyQr%Tj0{v&|Tu&`89Ca9;?Ra1LM=Vu!YO6TXAS56g3a^zQ9SW98n zip<nbH(#T5?0~e%r!nkyZ$(zw6yx%ePTC7}OqF%H$<D2WNLbunOjL^~XerQyXC|kl zNIspk4)|JqpvtlF^Yas-x_)|jwV%^yH;_e0y$E7p2(Q8lHOG<Jq_I5ek%mX_wSYyW zNN`uCl<MM7K|wfoSdH;Ay2!|>H87hsH@ab_=_-Ibu`@0oC=%)ec0a&Y>GOMoy~ix^ z1n!frU$wZO!7<?bi!m;Bbsr(`+N#&X9gXoHTnWM8jXzs}fQ=i27BnnOMx5hi#AySq zNLYIo3f?JE<0QV5eEN_>VxFs(eWj{wrL7AqYPU{oc249WVyUA@gJ)1y8@Kc>os<(q zPi9R8g{Q*Tq^dxJnRR5W31#>ZpdQ;jwB~Y4av;N7acp;vavKKC2x~P#BVx65v94rZ z>r{@`_Ko#GIs<s82@-1r+=t$`b1_8?s;!snMaj2CNf9x>`72jXtDW<ISqm+law66r z7YH=*!wdwWUo1X5s9F3rzQicr2H?ci{YdKr!2MqAyrr}Vp{Kv^ZX8;H9&FIYOxF7q zLqA}P3;hZkl?p{L1}UfEy}ua3Mf)h7;4x0^ZGf9>&hqRQBSCSSLSezqve;oA$Il8B zv>}lJHadL&;Fo=W*%>Q6h#yS+z&WI_!0?8wl%nx_3h~Wl@8pMr;-Fho;AQ97zJBC+ zK-J{da|P{A@-OqEp*z*<G@`_kMIbvq{@>yUA0OX|{J0zW37DaU`GqH5zdn^)Wem|* zf>cr98R;6Z&Nh0tj;?FzhddL|9UL1?0{#K&-6TEn*cTF16(0DJO;@B)0v(Fgf0&g+ zz^^;5TF=kC!o_QHjp|Xrv7nW7lZhv6?tED>_5Ne1g+a3*suTQcWWevg@s?1752Y0( zL^Kz->X4@z<oF_YQ{xor`0f6c_?tov_n<v{uC;?i9u@o>cTPl)S4!Huc{=b5(0Ix& zs7%%#Q5iMDFh$m&M~hKE!#3jU(N;@>Hiv;{*1*E0MvBtEOToK>RzdKamY(8-LUgg) zce_iyyufCSxg?O6Ph1H6Lx(KBuvCYWhRq<x`;WN6R`63p2@H0Em7<ZT_i@Gc)ceUi z<ZZn&0sQc<Nkhl0pSzbTm)9yl9d>qxts5N^U01DMLRp)PnS`a!KGL@8+<q*L!cf|O ze4*S`X1=tqcij5tE<0PJ)2R2LBt$}p=1QLomlgW}-_R-Pg0;+E502f;GDgLrp^SxX zBud*PR%V6)VjyfGj8_*$KyQtv?4TDf42n5<vtu@0_(MrdBF;1zz2U~HVX4MxFGE-S zj~qez``6SzF?i?%(zyJxxJvz4Cmdo=e?4b8RW%6U37uTTPDi2Y^~(6a4T-8z!emH( z=+(pF`6d{RpyUap`54bhwf2Ra4fBeLi3_aNuexsh)T$H0B0p6}LrWF?%2#exffRBb z@?1duvdhdg)3LG=A!TEDyI<gzoe(8?uLzbjLUn<!&`gveV3XhES5D_wZUNM?Sy@>Z zH8t(aH$q#FN4vZCe6uDW1DG&qh=Q+qPrvCo^*$_i0-^~(EpVT-te67m2sjneZd||o zjYZs*`%OA!6n0sK-RkzApMa9ZJ(YUj3PiM-)bqbtiVU2L{V<x8tH$2l@zuE>e<S5k zsJ^;eQWj3NgPwiS10uHiekRy0d;&L`<7R)bT9EFKZ$rYZkBE>%+Y^4Qe!IVO-P#Je z_Pv3;1W<>ZZ#NisRz=tCWLZkh;V{y`s2E1k7?{@|O_R98C=8VFISUO;a;cs!QiAyf zMO`pT#DXA(M_=(j+S{?Pf2qd~`0cQQ{fiQvjGUaDnp%hxoxX@^Q>w<cp@UyyB94Wq zGLN8b#hs$qK*H<z)e5=G?`h>W_$7+iOjXU(*4xq5_9sdyCUYzS>w=3@?Vd;Zd~R{^ znRog(%cD)7t>wSHSjniF!q}F)o)811jMUVFS_9vI9k{qiapAUj3mBIMeL{KjDm)pn z2JhS~YJ!f(9`JG&tS)EX0gBy+E_xZxpIbRsl=rzA{oO%>aZ09}LvEF=@&94^xrBQ% zGploH1fEW57(aD8rF5d?mK0kb<SG?13Zn#$!NvD3AmV0JGwglAu2PK1DGvTOvkE;F zBrDIjTKv>X9r(C?-1K%+laa8>RT57qC45q`6>xe}WOVv(adx;uP>*^m;A=>rho!sw z#q(OL>|WVNEezHr>xK!u=4^Dt;@sl=qP)%yJ|2-5doL#|t8)Gd#h5zfRU%nkj4*;- zb7xy~lka+ZR2@b|pQft!4-OjIMcZpUAsWHA%akcg35WKPq#S*Q|5n9>Vo?p)E&DHM zHXb~RQRs+d9xQOVOjS9)?0Oi3r3;d1X>OIl2Lt=s;nVeotaOzAWBes|GCbqJ(<TxB zO*l5HH9jvlGOfyx1i=B`i4n!#!F!Uyp<dXtDnzV>$P!Ur6|IIemsbk+zsNY5QK*H- z(MgTR_itZ$Vign>IL-QuNLd>i-B<*#cJQ@IxBT9Quw6H}>*bvgsTy_AwR$>Ruj+uU zWXK-7S#cc=w>dJAyPOdphrjs7PxmWmZ@|<PU((Ry^fg7O|0#DoT|?$nq<{#ryC7Ot zayWAL&1sTafo%+O`@Wo&rH3kVeWZc#sy;6kNA~bhpfCvDT~CQdBFdeH$dVBQlC(8a zf`2<sYjA_SKOT1*uZ7TzMTg)HAI73acaE%(X7?eL4lB1X!gp0lKEGEr)2Afrnpr<; zfCwVeu$IPRi7rG_<r`*k(oG-Zg9(&RvF)=C;L?W~(=hk(07v{Ea>Z9wS;MPYa_= zJJSTvLui1XB9`WhVz7xdN;q`XSN;LMk5iayy^D*pL|~h!m}H3W@1CG5J!z9}LpOnc z)#^pU0Ui#PBn`4chPM*()_k<~l4BR=uf0R-ulXI7+76EX-xlpvHBut~^N6IO2i4PR z5|rkxrARznzrH+WThXEIl#23JSv4#yvCyEfO#M7aLS#WUjYZK^_v2#nz_P{+_$#60 zE;;a}EQ|WTNiPu;8s;yWeu9J9Sy2WD9M4LjUXVE4N*#bDry)`qFscsnwPAwe^Gj5r z$b@&m3p225h*)6T<-akag`nZGvzs6Av(rkk<F>Honrqv`v*S(4{S`6IqkbkeL66Yb z5&KEUL~l#hpwkDy!QQ9&B=x%=I+Q+;CC7F>b`o-OaeM0&p*!a4eT!v#6QkVX$F)Ch zqguXumk(~iFHSic@1t4c5ovkq+q|$W=HWxp-u2uMwzjWqk4zEk>rvHjfU~>;W<NiB z=hmD_sL*q>>crY|%@b4(vZv^yM-86eUymD9>NGf0Q?yv)IZ-;bkUHDOTWBUngyOKE zjWd77+I>g-fl!){9WN^&Iu<6Q6~f}pUDZf%z{k`l@kMbE*T~6W48A{(?@KbJ5=DKg zCxbbPEWCWaCyO-uJ>4|ESeCZA!I3BHbL{~oi<>PR5=ruKny~OOMLnTBiPZZpmJ$3> zy&zIIx}3X}w686E)f%smt=Enj|HV)AQy;IyjE(PL&~DFT@6G}#Uni^9&ypMtuBR}Y zO-^O+?dh7Pp69<u58prvA4h+TR+%bpki^Q<4r;O*<>slRSImF!%)iklaBXPt`R5|c z5^Y~0rI3!ha_9Z_$Smp9E^2gqso8AW<N`Z$kS}{mCd4`ZoKr|o>lO{VNRZ#v|4|}+ zulcXsQbKj6@LkU9E-wC_IS>+LQe2Awby!W)o=o=|6{epKO`Xb_@|!W-6Q_G}VuKI+ z64KDS(zeP8d>u+Z<bG@sF;R~$d;^pkD<+9|7K1x28Gii?AdbJP3VYh6<^LU<1yw>F zsl5G>|2XkkW%<`(PVhVP{HGvx)NV3!z0h{IREZA0opB4?nQBVJR;)sA$VBQv`EfhZ z{0@KJtFxo!@>L9`&c&6$=&^9>?bIH$qC+LUD#dCbt&_OwgY|kD&~&;=X7)0<`Z3F~ zTsP!JQ8JwEpMj@i5nn~zXIJ@3rDn1HmX(~M(f+<e68drS|Jd9$etsOd!NsQLq?D?U zEJQ)z=0wxM>9=Kb7x9Yp=vflW+N*NxdhhYZzYAmLvbv-Wa-Dxkh<gq!dNUUFc**_{ ze1FsshPZh#yL=b=E-W*=HC8~qB=@yC<h;b?RN!rQ_Vu~R^y%AzMY91AF*q|6fkWXa zASCX6^KY*y<WwJ0WXKY!B&LbW&!X0#C!L(l&i##Gz(^v<vY7xmCIFe<3jd=Wr(FE! z?BKwionws>G=9}=hndak6KaarlZLzDn!LOy;2*w1)TBju7H=u!W$W3~iZ_RE@kzqv zZ#^M$Nop*7o8`zbg6-rnyd7<F9w9y-LF|MEIQ&24BPEcwAMF6f+s}aQY?iriNC=QY z4e$ekl9O$C3Vf{@{nM}1D^!t77y3yNl82)MiCnrD7ov+(y<KXoVL7^F!oXno@Lj)p z?x$|)5Am4+{<8j?R5VdaUZPAGzQMerK4+5?mGbhu;u7hM?>mkb{+?8#SA(xFufSIY zTN1q=6iCNQ31r`)p|lYlw`q&g!1))+u~J40hwK-kP>DlT`Gj}`CBWPvzF)q)0bgCe zX<9u8{aY=g;Ka$>W7F$R0Ck|p-oHiif+sPtZp#37iXrKP<fGx0xQIg*9GUD`TyE5` z?cwI@EVtn%4bw2cZ3`B<g)vpVpD8?|@FKTG+##VHG%|ntvAE4+LPMVex0N3}DONEl z4A6bEzm<Q8yHLL!L&)4t&I|Q-PZ{`DVWMQbGtsouS1}eMz^BiSNZZ!Uv{FG@M1&Tp z5B7M`@ADOJ75?B{;lQiIN{EJtM~ql&tPz7|fkSsp+s>q8R7dgWmVKwyx*)eX-ZZyp z{m&++?x>!={_#zIb4~LRxf_^$AYrGRkmWU`?`jh;b`_0Oej+y(OY$G2JFXMk*|B;% zg1s=4)ziRRvNW&Q<b_VOc$kjM{b$}5^}T%TH**I6&*_o4em~ddx45a<NV;$o{D)vR z!ylgCgj@(x5h?ibN$7r@7<Ze;!dM;y(h#62zqafnSGlfZj6G_H(|AX;?m9}SK9(3` zvZzh_x%}Jt;WHc7MD*L|&V+ME2B9DxcMK9Gdg%3OL=-EJ&pshkE3cj;j7N`kAuL?J zl1wx~osY51gLa(v=<A{ktqR|9YqxeYPUIm&?I!O|`7+Cr7DZw*mZa}F4JQ#r7x@15 z*ccfgU`%{_emw%BBy`0QmG+K~Pb`FHen;roFepunS-@Vxzmk{jkkzR|`a>l~q8ZnG z;ltRG<J^zQHmPPoX&;`11&3x;Cx?bq*WZ*My|-22>rnDhAOmQ_NW<T3@4bi>RgKaj z3=Wh~@$s#tjK1}ylU&Ugz){*nd}a70{+}|{mGR$aYN~;X)E(~+@6>of(_L}r|J}Tb zV!Vsa;#ZDlZ;lx@z;U$qwa2yS7yQ_uOy6MmebaeFOOp*@vk^B<hIYCqiTf_ABZ}Z% zVqTXaTA5GC>+90+@Crnat93?iEKHZA!Oc}NuqXK6F6rO@_U(k?YV^c@uLtV9m)GYk z1b;az^aeS(Ae>T3^td0JJ*T`a{$9GijQiBe$H&!o|E$?%fFU3PDkI2k_kp*@P#q|h zq7ilyKUg<n?ow^_#L_Aipr1-)@}QG0jR^hq`6I}|W(1W+bF_kH*xj1%0-XikDY1EF z6_kHN<IfvA@vfSClv*_wACJZIsD$Z0oQj4Cxv7BB)Tq7$5!-rNIa1DC^-ceWPkoGV zGbukiC9x{@`c^(dP8iAb4=l)9Dk_^bTp>F#x}FIaPeoiTZw$pZZS!dOCq+$srEQ<! zC*vmYMTU1Zps^L@<?%9bgHceBl?!!Z0hPuvF=NLuY6m9eS|9x>ZH%hH=O?h2vn^68 z-G7pAO|K%XEs;r^5kgS^gBc&_sqJkqwuJv%c}mFTD7la8W`02tb&Xzm=-*Ulro#j` z-`L2M%x@e29qCV-#%9M6q*k)x%YVDYL#HD^fPO%Mr$r)Q9m!m!eTXX!Op5LGMyGTc z@AusI9gN$tYrw{(=<W(kR~^G>O73>S{t$&6CfGC~ew`s%1s{Tb&!Dh(lzUGxA*r$3 zgckNiVkPqVilVaqh5J1`7Mczv)g~0`e{OE$0}J&cP>jkkd&NWD`sr>J;^X7y)4l5Q zr(R4%;`w<|zwaf<t<WeRjU=C-21gx-C}DFtvzGpoXTrtY7XtaG05JfX+&LmI?v$Sl zDj|k3IT0r0e4Ujg{SP#cK!nV)|4bhzsg}qP2HGsfgeN4HIi8#0rSrf^H8`#(Z15tn zKd7_Oq+Y_Io7ihc38K7zePMr4^WLB%1tna<>8HY6i{JY>aaSVK=Hxxf%NKtH9GIT^ z7py$28fDU)5$cKp5nI^4_IeLOr^!@kAv60=3{)f^h&o3^`Uk&r1#hoi9Y7lE>tF8P z{)Y5*Uz$5xK4xG;0f#O|?67rG#EWC)`7`?L%RiyM=f8Zjs#!6z(FXREgJ|A&0S>m^ zy#%7ap=&kE<Oh%<v7r48r7mtUK1l(?c$9Q_cv!AA4-PqVXrZT~((mTMH4y{kLvGHp zRav?@5b_)wO?Z2m0NkNBJ`d6G7pzjNn*aX0mBF&z@zh`E`MrbsCMAsQb{Vj-I=v<E zuEZS|Lwn6?gcj)m3v_E074bE3AoOaHvkRZp#Ed)}LE_)OH=s9|?R;522~mwNLjN6= zAJIH{GA#d`^S0Yg{r1)A*c{wp{AcY;uR2b4NnhZ0T~pxpUJfAlwXGpRM3l~tMN{$# zs4`fvpx6j`zOQzBIr*_>WblEMU{VxgN0^G58oT|hjmG+&FpT0%@|*7)?WKq)yF5ht z!*XQLe*D$a%y4|WHK|2xaTHwzQM@@Hz6wqZO86Y<)ZY^K+sLR_w#QOdg>lLM6!$vp z&}AO*J=%(>qQAnUU{+KxO7ciJ-VnMEKa79-&kL8kUsLL3C|_|VIM#a{9e=QtdE@Q< zAkIY(uP7SIF49e}Fr9`V)0;{~14OgkxxqkjEAV0PYS!fN>-<?&r`wj63MMvYQj&f( zb2L0=gOq~OcN`q2Lz=mwWL=fhWvulgpa4&&QK!SZL*ClX?qD+S6W^!hba-;M@BLMI zsYn*Jy^a5`1-MI^c^pg3OD0xOq{@&(nq%~UTOb(Z#;U|ormM_F32R<Bio4WfGnYTf zjZAj_5%yvEnL^tu(~Nu1T}(qlT)MgBE5#k&wReOfE2@NDSs+E!(Q5c^9qMGwP@fqh zwR>RgrS<37*#U=$cdH>7tR>0g4y2APMrStKbHiw-!^vZlBfnQ2AEt5yhENlw$LG+{ z4h@0S$fZ2|hEM{C$iqo1d2xs-8!<#@_N&pU)YZm`DsA{=KOH9@(-AJAl7YJ`oLqW| zBsa?7;5#>b_P+*<kqq)HQ78-kzdCMx9o+j!q72c8Y~o{EIJ=fuLtxEz{x{TGlR@8* z`R{`dC$_b?RA7bl+7aC7?C|nzJ_@JhX2QYPls=OGVrH0uO2nOvE1`kc&K8`3G|l8F zD)bO6KY@vNC;VW0<zzOBiP`$<=hDRvxib1nDcUuLiAdkCENw&%vn&fEp!B#?Lkon$ zfLd#&MI8Ou@ZOhE<dQ&sLBXm)?W-TC`&r0$>Rb?P{b*6O8U=!}c;0ICs3o$QzNtJ| z4o)QPE<PI4kZ45(AD*o5Rm2}j-<Pozstw72+pjge*ZUf;{ubV@-roDud3>u}W+FU7 z^{Dj*HwBwDiqaCDk&4+u56O?7OmuxmieKc|4rUW}*A*{^;Vx&N|MRHmv;G;&c)`#r zop4}(@K_oumfXqx{SDtt9E8Q|8=j*0NFnx*diZ(H;tMSS-5$N7tuyUhZyR}}MY^{D zveBnfTB4c>G_CPOe!dC=kXk)@{N1`Ty)v1@?ck!>PoFz?3L<Z(fEs1ngDRqG=2{-V zzg1y7p@t4pD0ny|3^?yd4D@POKei>uihMd0-q>=GfUZA*U$4c0k{*_r#}^HlNuU44 zWGk1exJkfUhS>29l|GYq{zP6>%{=W-jBhgQN44Mon=SnPN~yuYX{Su%rq{n}N>|n< zxN<0EqdZyvIUCX4y1{^1ct!L)fEC`ttOzY(%gq80@lxsQo23mkVVu&qc1Zo*cO$7+ zvVRAh>U*dt*m(T0TmjDsfx28{I4%<j?{Lz*;8WXCbfht4lI0?m;t&f<=HXE<!xY?f z_ju#V4i}9(JMXYN1bu#;s_U?EadLVujvgL<sR+VFxAYb8oYnZ&^R^R5vyyf#8i(6I zU|mY*k3_v;>etp4G<Tvt`<`<~y{Sp!=i8wcYrIqUQ-i5?p@-z-T6am%{dR)J=htrV z&G7+o)#p|bao(jPQTPD=LHFLB4`(8x(R&&H2Pr|;z7V?IgadZo6IBt1%5zwVxX)wv zXdNI%2pni3kPrhTzDySyU_%3~d;)=m@;oR%?sBwklq*ypv*mqqXK^g&b>!6z`lny| zO%Fjo?B+?04+i<~&-Ij#bq(bxU)3BC9B$pZ<(%8t*kBIBFtk~=yts67dAV4O@&PBw zr=jyIiC{qtu@FZLhzep7N-ei~jx~RFXItxdV`H;YDz_W;dc6h(R-`ln#!wVB_I7(o zC&_vr-MmpA3g&<BcPoW*yOn`i_{l_{^3>2zrOL4dBcf6%@|k+hOBaE$N_oZ;2B(O` zS7nX|Pr8U#autxv??LiUgY;L&2_WpDQRmBTIoh6MZ^W_W;y2ufvj;mlC`blvjVJcE z50D=HU+(Dj{paCWb%Ffe)jfmV!^2NL`Lqxg!a~s`W`BRz!Ct$5acOq85P^H}W?gyy zW&ptU=dxY?XiG0KQ7LS+)AjwsfB8TBajL@$*PfZ4m|1<WnsnQn>&?UZZlifnEfk6p zDGo-*s#%&04-c<Ce)t#PKY04`rRudStdwTTU4x{br4zY+^RJJa9DTNKYQe-1#Y%{* zK*WY&n3Dzbvx0t)S6Sz{pCS&{)OlQp2m~uf9X<j)F5rLVAi?1$58Sbe?P!q)>+b(B z5N!Q?9wfh5jMDL5$MG{a009JGBRH%#S65ewXklT&TD!iw7Ah_miq-Ov7O332Ti^u! z<*<IdpCSI~CRRb%O%avD&+b3?>HF_H4#KD~J3D{w+!;9AsO?=ib?W8ko}HN(s}v(a z*6p@0UAlDk?Ac0X*gE{=XK$};Y=;#VMNlAp^qre8vZok<;opgPzIqU;AY#_a5+_!m zl?t>Fgq(;Iad1||l2|xP;yj&~;i#W<<n%Nm_hfpKFIiq#fC$q6_Oif^kaPWzV|h=a z5qQ#x8H4X%%)A6L0D~w80Q))3li!0dq*a8Con5U%Av!!ftT&r!*2|J^HI7SBL_i^g zVmL#jG#mm2<MEMPOc3Nea{!$LAK!oU=YRSAVs(_muvV+zyLa#5qr2T+^YWRqfA4pG z<Havr(hB!(Z~p0bzxT77w=$P)u5W4L!qCXWN1Ge9#$IP`Xb_Pwi1U4P>L}O@U=g+i zujd#>aF!xPnM1d0qCgWs;z-DIy!_RicLQ>{rM|Pfr_c|c=zbfhk8d57-M)VU{ygSJ zls^gnDj5`ZpL^La1ALCGSuqGRef*5*iGOnZ&$^Z3=O2BnwJr`-x3;&t-7Yb8+nwo& z(P}9sz<a%Ts~u}WJ}f{S9C_Dy1_ZqxpzysPytZ@LsEm$H&&-XCjGR7wveww17>U36 z)h|DN?%Z$yE4XxNW^CafwEyUjjl<>h7oNLv?e@Lf>+7qZ+<$oD)QMBWvG(^fz~u3L zk-Ymr>T@?XQ!m5H<4t4C;?jZwv__;5l{8t1^F@pGKuMp%a@4Mc2=&W2Cr6<bo(=#< zqP(rK54F-iryf^h%9SAVJoDJSJP=?X1Vf)HA3u?Fj3bk872}sj)PDEs_}}WoPI~*^ zy`-0&IX?%{-EKE&w-)E-rpCs~F_6JAoDmYy%43ue=Y$*>#LnxeK~OB?;lsw`jg5Aa zF3eP|wHs^enq9S0oT!X`;o0kplUf8lgPs9MQj<J*uzqr4d3C3D<M!>jrMbOktJZFr z;TYs{720F(H8&sk09L;+7r+3o|LomQKmBxWZjRu}h4{kRGuJL%7#}J5DL*C=fP{%4 zP!MnBAd;8;`7iPLb02MUEaHVO#R05H$mOrJ5OI0K)<3*>0w4GrzWN!*6LF6S#>(;e zild+j`drKYbC;jCiffJL&`|aC$x|zj){-PCl?$UI)$!qK+A+nF_8L3loB_0AIKbH; z%3&(SNV*`6!v->Irf28c!ci1;x-HvEceYoDC(2)Z{<(6fkV0!HLBJ>%X{c1J)oR71 ziyPey>m)7@RmUcKMxqEv9R!MfelGxmKzUqI1?csR_ufs@j3e%LQSYR;A8p)xux8Ul zE4=>3PydVG|A)^%btNK1ng(m@oA3%M$9|cQ_s*H16|&TbwGgWUr5V;5kj_k|l(II9 zigBlxd0F`*PvXIr(a|4{LfaEQNqt17FWcI8ckVOWjzz=4O)+><^F5=SL#N;U;Nycv zvs@TDJZuz;#d4)IRw++Tj8%$-$p5eY8PUrBUs^+mGjVW2terpz*5QMXKKZLR-|A$R zSf4s|a%XF2^U=dNQor-9SFfL2o-0FT$P7fB5{AY4qsJ$fmnWxY-hStUW|G{zbKhzH z!nI5NaRZO?t3h(56niwZ-vrF7;N4pH-~Wg2b$ZFf#6(mm1td>BdmTCeDIx2GEcq&f z`<TZ7vwPypIhUkXtc`;Z!bFl~DOfvktQClq3Y-(I*+Cf29*c&39~(d&VUnLi>;^E~ z|KG3A^&pS#xvhhP%s6XpZEyeX+G-R>=g*(Ndg)@dREWb|4~&?(4=Z?bD#M95rN{v) zKrh9udv`W>cbnGvgR4RNJ6m7-(u=2NW=0CI4q56P8?D0t=q332%dh<O{To)Rmw)9~ zuBE-qBsS^Q_YX+MJ=4Jtxei=~NRgk~^ZYW;{IY^aYnz!<VWDa{NK+fKv{MHiQ2+(S za0+=G<Uu&1eo1$9Z#W&W2t=_1(#-0B4LDSxCFh4mnBfGh180o2k~`3Y`+Ylrp#UdG zX~l8e`Ilrg|IxI?Cl~$qNrSX=@LGN0%9Zl)aDk)4!^5Ser6lQ|II%P}IT30EeXtdP zBPSpcGS&t<C+9K93P|Cw-CNt;y?p(tJCD{6+le!_G*rRJ@WnG{E1}jYEQ2)#fo6aW zl)>4h)BnpK{o8Iz*PnYa-QOK8O%x$RaghYaEz*4|*tZ4qqOjx~GAl%699TzBKlkEc zvyqxi5jX1x8{0cU7;6m{C}HkXbX^~oB=_Wrqk&Sm5|NC=DXjx76m|g8oMm7JJ469Q zNC$y+!t%uG_xJEWcB+n%LjS+E?U!{NKVLrn==HzuCTX|bQKU=da;wu`U0oe26%@nI z0ei43$MF<Ivv>xwurp$uWP-<=Td%$G=Di0G_iKl6bm{y>FD4ZRG&-ar20N?SiHI>4 z4ut^w+k4$sH%ZOf*7m(ej~=hC21<{QjWNI^$G!)F9?T2{PrY>zFlQD?mX@o-bMwp7 zGYh9qpB<l^o?lp;oSgJaNn#+zdudQEPXXa4A8kN@LL73SGS-H)4RymH(=ZwxMn{1I zxBv!dr${V1-OTlApZzg1SkI7xeD3Qw)8YvZ1${1c{2LD?<%17LXr};rV{3D2YO1%} zn3$MowA&Xio<DW^#Q1nc<=tL^0z*0HH4nX$1K8%nQbg<+_g7b|V`Fh;q=K+f@080G zlck!?>9eN-0vYRU0u_iASW=`w*x1-`4wcGqp-?z`_H03^`I*_Vk%FSUeLS#2lL2bL zG|0}Gm>5aN95z~U9M=w8VH8$|N1mUVT$&!KRzn6n9Z=_h37fnR1bg(jJL;oT^-iLq z$SDY+o#4jp)xuCE6Zy0M@SXYj`RiA&j1N~zp(<!9MbM=X7N1*u$P)?SFZMc)2h6{z zVE@Id@$+|H{~zjRyPH{=oSaTN-JQn1b;+w=eZ|iL=2`MFK2L55X?=Oe{-d{h_~6E; z!;_QCr%&x{?r(4Itv-4@J~2`m84lt|hlp8`i<DBSvre(GsI_eBq%u6LS(T!K1f2D{ z4<0|7h;ZW4q_Y+vMV?8O3+(tR)jD72ic%zuR<{%Bpi-&S8=Z-XiQ(blsqx|Qk%F%~ zl|R17d+fe_<UASVs8uZjIO4Dn5#gYRomyw7*8I+EZy4bA{gs1O>x;$8Tq{YWdAPN{ zG(8zCOb*BSCBpqCeV$1A`{kD%9qG4}K6hPxu55d<;3N5E!PF6mptEN4V6T?x#_4ls zPmGsM)(b>R0ki;s5hrk(`#Giq7{<YmY1mAX)NLKMKK%4%N|8x3A__wtMDg^*<iy0u zxyh0k&qi@%tccTLoH1Ix_RafuIgEC8cB*6J<&jdQ96!2y@8aC3@T3SF<#3^M4#K2K zL@bay`-%wZ3}_|UVY^wc*Uw+PaN@*?t&P>UfBMEZzVuA-<fsP3InNmI_CRp?oI^iI z3gCpufh~~*c5B&BfBw<khifB~vqnc_<CFH`>d5Hi^!$?3@x%4)w|@AOE9cI3y5~<U zOpjGm1QZ2cW()*!eS-%2C9ozRp&=f_KgNIXir2?VLg_zhf&uX&AH49$2LZabx~1XL z;h?A8-tOLHxja)Dbse}kzu1`AIZFZ!hGoUbGJ`-TnNdndq3RuA``|E3<<4iHW#SxV zV-pigOG~HchDr{F08Wsqz&bk;hX6XpZXfP^cIS4>>Y3RE#o5~G-P^ZszWDU>6EoAs zLb39y97;%&&bytOdP%n!24bz&VJkx#;iHwc)vfJ%qcxUg-6Tnqq}!;Sm>#Pz3IYfm zI2Ggyw<JVj9Y+DWJ*yO~OSFnesZ5YqJld)M@Bi+*QF$a@J#au_s4Qv9v5F9^Jb1LV zwz;}?aCq?Xhbxb+UOw};zVW5`GD;3eT@bT%#u^g@LE<t2=hR}~AoLU%fi;Gioftr6 z*2Hn-90Hciqykt$5XK^8tW%n0(3l-GfdzhHM8sL>w9!T>8Xg}To*eJ?+RO8E<uDow z2aQB=loKqK0}+fvpjp_{&>Rupx_8eCz52~pr>CbINymy?SXzvupcH7fP8<^<GZGh7 z(lJ?<MAgz~cW-ZQZ<QzJtw|*_2RoZv>yKw%eYILC5rIfqW%-Drn12O9pcu{(1lD2u zP;TCT@aEg^SB5917M5<@xDmsgKYg;Oxfp<~5S#@=u_F+mS;UdnXeZE0IhY^{TfLr9 zs%zDUHy__$+bIr>S`}pAO0~SXzPi7^IaH`L5BEN~b+_H@&de?<tyMX6#Y(MbtC6Y@ zf<ZGqpSAaQ2tN_`1lre;&VZl;r2>^Y$$Cj*lXAI8qylha4Uy8C-Ld{dPN9PH9De89 z^elR)GMs3DX<}kxcWv$Bg$uK@vC8Lw{R~=uEqcZvIVi=}=0>-n!us0g#MCsA8XKFK zEC!`=CCd^K8)`1ZUPA$KNNG<ra~PNQn`yU~jgF4)9USh(+b0$l8V8N%u09nSSMr@U z<%gK_o%3PcIq&jr{5X05^y=yU-a(~OX|-C12epZ@k<p>y3(GSzGu2+t7K6NnJ}4+W ztI6YsI#9jTD(EndEb#uPD?fhY=MNrlcGK+KrLz)5y-uTh&_1)Yu&}gT+uz=JwBkf% zQD=VnL}_R!%d)rLdZ+lz)w!8cmce8$40IS%Y7MjUytt#iBZw1YB@C57^^EQGQc+r% z<6_K+1!#7<g+jp?r!|vMnkI1+`E~c#F$;s7BQm56ghce%^mI5p)Cz=|1LmP(!DdJd zqR2;92ptijm|(4-Z?b2tG*a5w+Gf_L&zxP~*i>;4hT+{iw<5dv%*m0W1{~5<G*e<T zT?mCy+wb)<`pPR``9J^NpY3jKzx&qPVNqW=b!Ks5a&iR9475=`e>pSAj}8f-G{9<P zWQ25i_u%lLwl_IiEykfD8z_{OGMVxEZN55|ehc3^2?BC}3d2^fhd6$;mwj;aUMgyI za%vPjF){JUt^2Ew?|$w1OTYE)Z&s_}XE#^JhKE1>?C#CmE3f?O*Lz|<{P5%5)s>Mz zEe=0F96>TT0h1!-Kt%o7ryLJ+{SyOZR*033l?B=<G9V&|g^mhDh@;RK^2IRnji3I> z>GLKiM-&`6_4oeCAC63nyGU7QXU4`}diwfADX7G74q%t_g8IxQ_RI}9M_{FTy>xB2 z_7^{S``)8<lNrrwYj^wI_uifu9lLt=)S0=_ViYKX2r_F5h0qC_DIRPc{@XwM?)cQK zNo|&xLLnX=Di05pp1XK{vQpICpDOlkYk~NgD~2XG5n^RQU0`*mb<pZ|dfDXUbhp!< znizfMrKe8K581BML<)`w9{vyl_tS$QP{ty&Hc;Ggyj4&B)&Kq7rs1iXh3d#?paUVc zpc9L8UwQG`^7Qa%i0P^73s+B0&7E0U-DoCBFG*%+XEs+KPmGRCO-_st#|2H+I^&F1 zfzPa{kFR)!U+xwI%A6C$j?i;}1{h389YT#xnm7J!W=Nc3rd(8^zxv`OCBT3Z()D)t z&ZGNt=T4Zkw|sVKe7F#6^x6m_j}p3^*d^?H98BmtxkITSh~lxa@yhW2&dy$|)e@3Y zp~#TQ@sY{V0y2||gkiwoG&7{NRru+9AAEZIu2qFnsnm>G%)GO+H$Og7E<|wv*gRAA z7p?0j(Eju*r2w`-uZPF0>*DD2=`$Of+gC1MoShiCd-Hbn(&^LV%BAqS(Z1v9?L7z8 zu)slV1{H+7(@g*DFMs@{ul;JFJS5hYN~N1OZ<AI}UA}&Hd3GX#0YbnSlmfN5INP*R zDwVdkcE0_s-<%#Fa$2_?iVUqe6G~xqKR@KWfX*knthHJPiZ~-|)sou}9>$fiBsH@$ zQzJtZ`f&|LKqMUKfrQ1AB_IJx^8TfM^Ji~oZ0FCNSYBE<xwKdep%rZZj$}D%6X(0{ zpcsDSB?x$IY^YEu6bgkCOD9H0M{nKzwAE}Yl7+eHkl@5PM<Nn3x4P}9QYMW%57%aw zPIr3g?)G-MROxg&qoc#a!^1<R$fO8#p9}Y7DdU_tCJi=#1M2Pc!%uHCQkh-glc$#3 z^+vl<f9m{+$x)SB!~tN*^Kb@02jy-m5-<tSO--HkXZP2+I8+#_Lg{*aXL4+cNTx?B zbK~U#Bk&K6u|=(xXNER5*LFI|((DP_Go?~hvF;k_7}x+2!4YN7F)M&_79%`a$+8Fq zoH?5b8RmmV>!<I2m_XgScYkqy;rXYpO%D%UKD$VOvl)pQisK_P^-&oo>S&$>T7|*V z@`<0n`;Nx->QmR^5WN<LA~wzpx=w?3FbLLI9rzhjSPM8jdbql>vLcCHn4QUzv{EWx zzj{q8bP`*Qf-DnfY}fQEm2yK+>tcLnu{1e<@%;JMzW<kxA3iEo%OZAadaO_k!U$e^ z^oYk#IoWYA#hqrZ$6RZ6Zr;A#HtOcRmA~`bzrC^cP}$_l$!TjUahQ)TdYjv$20B4N z)@Div&KOqlgSFO=-}?FGE7wn+I+L|)`}_NWjta%_@|lIxGu5#e#u}|8)<G{p(y@(3 z?b5a94mJ*M-?*7In^RNO7hb%2V(z>mBt1zf3!~6IaWR9u{RN5hT@InlVZYvZxV~AP zoU<IZGPkn2_1-&gk5qo+;?j7m18d+1iG7vl`Xm7#^9Joeo}Hfw!(eQrI$9Ybn~A|t z3DypZe?FQ$5jck^QpVXdO+y9|9z0lm^ypC`iUL;EYW2D2o~s@1D@|dDAW+sAMZW(; z0vJNaAO$^G-T3h1kC#rKpir}>cCRrxHO2vKzk}tRqdtw!_1jk@=w=3rS>gW5LmkG` zv$Hyke(-}I{P4B!r=8~b@K8DIgF{-eR{l-<Tho6IV@yC4YNToU;f>o)7p`7=s#+<R zi}B9Z)`N%lpL^>13s;wiBanj<$2JXtf`aLGo6Y9l-rmOA`cSFVtT$|CI=#d{*TslT zn(;9xZ18<V@bUxbjJc%~<I{5=-@3b3@9foEyY<GoOIM1Oss#*SZ5C+d`V&B4f+C;t zIM`I2Q%K42qlXW=oyO9_{L|MjFV9s1g2@11HBn#3%kkh4^is>raU9i}9TCjW&sT;@ zXHK1d>7^H!78ja_wRW?$zrQbnh|%qKt+hd*%cW8;0|5`$>tR&*wQs(9@$w}BcazRx z>)@HEuT9U42O*4D&&*Nqvv+-VB|{Oi%qgXb(deMr?OuQCnc4Zp#f9a^YikU*Ff%bZ zTJ#Y;=A$|PBZdJHfMU65;4&+z#iRAD%U7-!3(=2X`~J$kd-X=G(`uC>H56fpQD78w z7^|SyYl*?+WcfFK<2QmJICt*cNOg2%czASld~<WN(?K@@fRUk+^69v9a7W0qpZPUb zeDLU``1q60dYN5XK3yFdJ*YP}wswLjDwhM_q%B9qPOn2m!ufQk<WVTs-7#=r=qzb( zZLVr<C{2{)VTzd@tPB*>kCCFZR!SpvGE^?YV5m%2uUy_b?3JQus8qO9uZhUs-rn9` zYoS~Y<0uY-W~av#O3Vj6{P|yeZ*{j}pyEjF*AA?>g^8(HV`8)#0>+zA5Qv~4jyNA0 z0u)1ptrJVsGp5#THQO$(j=ucLwG+$pQzbexI~pr5ZiRL)4Z|>>RR;lH1~6yOwv%2I z7Tc}f%7fMGvuB&N8cbHHmQOA(g<&{7QH=nXbyA9$BxH$#m=xF|h@(oSa=203SY3PZ z>Fd)Ile#P;C6Ga{Cpsn(_XL@@4;)*FBSk=Jk!G-tmQI{n->bLM?BvOl2ixnR)`3Fg zt-XkXAUF<q(x6EMXH90DEkq>^$$IUK+-Nb<5rJ)AMKovY93yDvcHNw2(#v|4Vj;28 zX^SRotUZo_QlWV3)-Ax5OO;BsYys9mvzr8QOpL=G-v0SrBkl`dc;WHt=F0A7u@rsr zi!Z(W?6oV)^JAqrx59gZ4<Js+lUt3+Dc@G8(@RIj#vkpjPE|*CcX#WJL*2<1t6@M0 z2?{91VQP<2dIoSJp=XjXDzqK_@QwGH&1TYVZ?CV`4-dlN%-q~uA*AV%NIR<`q`W|Z zSV5<Q!wjF?xN(1dpE|g7>C%}qXPiq4g<{Vk)QFfI!6X@nxpkpNKKkhAHAAI47NJ7D z-v0Q;XAidzHV>O|u_ReCJ28A_d6{f}rR4+M{UC7+n|3UYAW>9EvQ&rcvNVyTi?qjr zLWIEjK2v_q`d6awPv&`A6h)0rH{wt$t{)!kZmx|Ligf_ajEsz=Y3c#pB(=;Wj7A6V z-+1sR-}%n?{E4ToU4ca$1y?Vh+uz$5E*0lT3q?X|U7&d2Voew%7v%2^XPgSzTI}v0 zunMN8XG=qsUfL6pq}!exABza$jB%v(F<L4Mi6|&T5I_?EYGnAq&pwFbc<b?lt*xzI z(s{hGHByNdC&z~(C?~7}5FC)Ewh+a{&;g!#_F1EEg;@|7>Gs;4ZY{1%Sc{aA_0m!? zEX0u!J3xPOc@-uS>Sb^Y0#+V9eDCK!FOE$=_uO-}T77HvK~ay54i!rQiU2!NAm>DR zHPM{O={3$NACR}Aq4gjBxBqNsXNx$SnVe7pvM|PF*16F0?~h8WJ_-&MG67a=4OK4T zr5B!m|C5`YR+EV4W@bt8oqKn0-n@U}rBgbLn2=aljneS=#mm=9qvM}_dgH_Qe_pOs zYx}jN-5M*Gf((@c+J>xgtd1dmIZG@5K@@T7U>wrS-nn-_EKiHj?(SY3glCpcFE7j* z5ty_X7Q1PtbkJu=gO2#F2vxY=>Z}|F2Z?<7<(HhXlBFNt+Q|e-lFdzwM1XTH1Hr*K z7X(oTSjL_Edpr9FjaD<Z(KDB>YDs&w-ou9v&C5?S5EVlL+O1|>EaKR}hi6foklPvn z03ZNKL_t(~gg;QIrD%70)6=s-WyG7bTt0uU8j@sLj35APmV(28j-bnY=e&-g2n5}3 zJ07a&7oJ&mSauc_1*9-(rikNMcN_++rand00>~T~Y@G|kz$HeE{>qnM_>=Gc)z<0; zGZ&B+%VlwLZ{=bA`pHTR0woTQH{0vmy9*~y9@HDVo169hy*qbSZr%9!xBk}GhKt2& zgvRb+ada4pGXF-I`gD<e3D^M&Lg;q8s~hX9>uXWPSrx53SQ#q^qgR&W2ocCK0f@uE zSDZ?Y>O!CA3E4`ySlcn%_3U78e`aFzg%_V6pPg+BHJiJm<pPTXYyZ&$%@8=CYw`LU zZ`|H*%+AhlKiqO6K@jMGt0QHl(J(05tP%y~a@oTAR$@Q7B(K4%71|D+#Ep%OUA%a4 zr`buny^H71uYB^s_3M|XM*{{-VnZ+lVm;vweE`Ty&k0yWX%!Uf#;{mKK;Y*Hoe9H$ znR}^wqLRz|O$@Ns?3@b&PC7lMR1l)bI6Xg|bsCYPcD-TJtWYT2zW?BZTMyQ1$w7jh zhP(H8yWYu&)N9}W;pY0<ShdQwcm4dCU;o-G3lm|QpfWt{#B~#+0i6q-G7+&r36vlV z(Mh2cwsvdZ{j2Zq9UN|NY`*dOj}G>CrY1)(o>?OA;K#~}A@nO@_S27EQUl~9agqY- zo7+Rx;iwR&CKHkQ`FRC24{Nbvc6mS2WVsNk0lF5BX?}XD*KYMXox{V!daJp2aIi2n zRUiy$6r-SL)5NAe(lhe0mYlin)A9sSf$u(CyK(#W!t#lk`MKfY;Yy{vxHuOuY$|c2 zSZf$i5R!PUKq%>}z4m1!8oktNt;-H@2>m{>%Dhfn?!lKc<}&Xwl8<FrSPKr~I2MNh zh@AVouYUcr_ui?u>lB20JG-UI_^FFmr84)&fBDYx;)$`*Nn0G>*|?_~9c5*2YqJ#V z(E`12?aX)y&LUGtGysl>Jn0})0E058ecWfVKqAh8dr$|>w&-Fpbfd+fJX~Cy9MJ?A zPzVJwFqv3T=yDDjI9CXBmS98ySY5f3B@M^iOw8V+hlN6+bFg#u%*pYg;etZavvH_& zgd{;6L4amrt7GG1I$pi`UO9}5#o}Reui0#dNm7=4dPm3+t1fH+6*vb+hFKT_D<B6} z0Up=zV5>GVGdHue@ZjP4kAC?5nc=87q(VZhES!SUnE)1nf=N;iz4aSeke9h7X9FGI z??4A~d=~QvZsDV$6iD7y=RWny&kl;QPLvug@ugGCfAEj~!N2_9{`F?95m!pRPHVqb z`{?$)_io&4*`T~#&$8tH?VIiT!Rn(2S*L#W;@Q9b>esHHJ2?^~2a5n$!=%VT`fAZ3 z<z+mGjG$EDmLMz?Po6usy1HH8-ya(totqe$nHn1@Ah2*o#2M107zR$Dj!(h(Axb7R zI*1fMbNyPY-Q7RfZFPE66Jrr!acZJm1OtI)=irAZQe&M~tD9SIzV){2n*F`T_|$T0 z&G6Xh%=lAJUA{P^kfz|!o7?0JW}naXIWIzR3?_}+_g2?;YqJZ}-EQ~N)eAe@Yg1J< zR4y<?vjZ_4S;+-*f{<9T73;UmPa`>2mUwNyrSYUT%rCIse+d=I&&6v6=Qzs{h8QZ* zuYKdCfAjDE^#1B9>0oO;t+$$%IJGi6HyOozf91~2JD*aP5Yjl}bEi*!^Xp%o9En2Y zqHW>?)&+qw;`+c1at=H}0Wo8{ZCtGPYKPO~(_0(0`4bBV`+NKQ`&qB&`mz<&A3_|c zIFK6vY5COX=H|}Y>c-ipp4;2nESJm8cDqoBYg-$|V(f<qyy}w40ESX3HQ3zVKWwy+ zn3=ix(TVAuot?+4_g=boj)=S)gP$RHunJmXp!1%$MjfcxOKlW>@bO2pv$M}V{cK^V z@bSl=I%l4}{!F!?AXX9k6x#Fc#6bBB*$L-<5aJvs#0PCWSXtG-ICc4p0;|7BQF2b8 zNGXDqG$rd`fPeh^|M2biKmPdE-NR0|(MdM8wl6<*jiqz2`*>sZ9-|ipa_!ocFMr|1 zXRlqJ84E)|ELad|_ztQfaq9nN?#*H(%g#H$|98&0OYB?jOJ!DO?X0e?cd99}Nm=A* zXj_s;1~kxM3<HJ%&+7nwF>F2fVV(>>7%*(Wo*8=#cubE-N+M}N+(oh%R`uSsWK~w~ z`xcpz5pm<*bH3w;b0ab`tGcBD3=b2DLU-1Z8FBAD=R4o`|Ns8P0;vyOg2^f?EYN7_ zQcgYEYJL34r`NAt&*y5~fllJBjrHS3BWfX3sdLx%W5b;A&?y_34G9n)KAdZ|Te)oZ z$oIFmw}%G@FU+2ghikJJrX`S=jup}vt2~c@$Rbc^N1Y&(+1%aGb|+sO&15pALVj?t zrj#-UN<jjNVI@xjeEZJ907NcSPxj(p-@98IoBplWUt5@8<RrOs>&Dc0H3Wzaq+=Pt zBX9~P0h^?2*9G9UnInmhpDg_F$3Iig3dEjuB=r9lgGefCIZjgDs&WzsiC6Aix_#%; zy$=`ur+@LkZLRMPS8^h0l>@Q3vbeeQXnbVk?|=R4zxC=%=f?+&o)b<&NJw_7GDAex zu!}`Xi+Hlu0l6(Qp=w$rM1D5+qaXcbVsiHUxr=ji4~GYbh6ie)57m9Vgb)PPvmuIJ zL&LR0rI;8$_m$kZ7v`+BO2`*)-!2uiqZg-#s*>O=OC4qicnM$$i`z|*_r{mL{Fi_J zy-1tci!*`e*UG`=OBafH<q}7n90}6#%Tv9TOxG>RL`~qA@4VZI_0d87JAd}=wT<=M zK;_Q$f0z|efN~{8qRE#%a!=}mQPKjMp(K%%Eyf2=miG@19i9F&1!B)aAd|#;9!V0; zU~er60Z&2$QG|r>+RgJ9|J(oO{@l~23rkTFH=0KkiGT8+{KGr9Z%>Yn4(Fu;+OZXq zNWufGu-a$=k`fLJPd#KtSN3f!Vg`BGIXGHg-&$B)h0G5QotwRU1<Bs<K*d+^ECd8u z$;>2OtTZgibbofIV?hby>KD%4|H&g0Mb&Ect6zO{V6duSa@oLW#E7#BAYnZSm{?n* z6a~4XW^4T1`EPvl-~Yuge)X$&-o7+5o%N6ld?jEFqyuIt#kwO?$&>Aps8U(H0g9Ds zsalaTY}Ah?N5(i5NBg^KA}>=LH(MBY^fU$}0D_c~NJQEsmPm+}#%>#p*j&4QOZ7`> zLC=vxpV{ghGZ|f)sI{ELOhN$&JV*vJ3IX1@J@e}AnRbLyh@++nL+MFa1~H;omqHb3 z%_fbYXOT`m87!=!)DxAm1)RHBNgO8l)vtej_oENbox9}u;oI-s3k2V}GFr@L+}TqI zC!;@sV5EqS-dGvX22YoEfB54c-+J|pN-<25WMgf8c50$hKwcrR0=5Hfl&7povMM|P zo;+RN**zGWy)rX<ab<O5{_zuS;>mN9BLlfmr20S0kisQKIe{Q`nVB#Q7U(c!He0O? zUYNZqjrq=ZzkTcVTZ5HihTvI{ard3*^8lSZNDNC-Miz6+J3stjZfo~wa`K#b*3U|G z)}Yt_>HET3#Ie!Z^jd;afLR9;IS;}h5byzMPzqpU4CiFVAP4wBR-hUxqd8Pc0M;4- z5+ngKAkD_<yvfB!AO#vYYw+$~^mt*>&t`^4M{d9J($wtCrE8alhic_KNe2*jBtQrO z)q_|P!#W0-GZlE)+S-_$oNTp@7Z(@b`qeLrxh(7W_y`09q<oTr?<<l?99uvF?|u4c zd1<wI)D%LFpPMX|i>A{GB{=4ehDcXS3u{Gpr=>2T%Jn@AuyfFS@BI(7=7$gGe*Nov zH?DtSxK^DWuVxi|bR8e=)&rzU3r1r(O-T_r?%?74^4oVmn3|rwc<GAjH`sxm1IRs9 z!dPOQfCf3WOj%>J6vW1YD3CA~#=rvvLl8JdK-L=akXn;{DYRipf?&A^A^{{RMM655 zeouwt;*JFN59`uXnOwFuG+3$>?fQl>dVF+T0lokdq&y8@8W?L+XF}H(<?aJgfFF9z zR^zbKNt(xVa}TS<!uiQDJux~}nIQ=mW{`A}Y*;*q(e$C2^7;Jc`o_l(9#jTucWzye z>-!_MQYa~-ARV_wx(IUxXfV4{z!)PvX|xrRj+*WJbMrGZHwFjBe*Mc|HXDtpv70#$ zDutE^SnK4pt{#q(I2-uxMwCPcvGqb~#{88pe>Gbfxc9;P;@M~Oxu%5fSGq}O&wTWa z%^_hGtV+{~90UL^28q}bTNtY>NlwYxvfC(8RtoFR%`zQDcE5GA4XyR)$k4>t7};cZ zXY=rIn@v08%iai>2v#^l1f6h9EY46mu3ov+=`@!Y7mgbB;eo-Q{`ALh{qk2yCx(Rp zl7ua!P@yFxjO7jf=#z&^c#j{=&CkzggJ5cWyjIDL4^>Qr)E(#Hk?C7)S{qF;;n! z2%2mg2(!i4zxc-a+1XaBwY0R<Xfz5LKOomiwr4!50J4G445gGYhJnzhtz$f1S~)&$ z9Ujz|mzULN6(-Mz41Bhw)|Ij;>!lCaOCk*oa5Ey;f<hO2E}8oO%^tSUc1eUMP&<Z> znj1@t%UjzS>Ba5i!>!dD=k63Tfg?|)*aPDR(2`&PrwC?iMUUi^Xv2x#SX&t$JKt$F z!a{C*WHgt{l`2(Fp_Rag1Syu#jJf5_|M^?r4>DOI+TGr)j*U-^Pc#oUUU}h#@qt27 zxqF2B#wyOz(KDSmCx)=VLF2ekE<b+s^wIq}2s(FeVxUwokruv6b?s^Mg9&cKqjtNK z4U|+~WYDw_A#T0=dYCPKbpPSp+?+aP>Uw6i{47q#-)8peI!y(Ex|pPN|Ahl|x}IdO zmrwnU3Mbxh^0F?Mq>#gJzj%4#;>`T&x|M3->GGOQYN4uR0tMHTO?edBc1b8FLxPi! ztdfE{FI>I4S#O@7nw%ILzkBy?zK}m?92*Q-4+35cFrk^?r|-OPgjXnKH`kVvcFQJu zcV{cZQ9cl*019wmNc1p5LXuEUy5T7aaH|vBAZ%*PJ$}Moq1kNi?d^rxtdzuYdmy8f zalS-pg{3|ry4J{N16XT}fsj67X*Ib&KR-M$yt%o4?b>y9ikeHO(Lc|-cqfe(vZr0> z;si~`JsKo*kF45-mytUf_q2aRsYfCuNx}f8r%<DmA0rv91m}z1__e7vaQo8uS8iUL z7%GJdf>~H0dxSoFB77oO+@z$Y^fHc@vcL1@SN_?5_di^_F#U~hyj-nTzxAze)gC^4 z;p)sx1q~oJ5E38EZ_RIRA9a%E!QoJ;JUTRJ!~D_y&aIcOPYjnlhHwZ?hi0|bk~DyT zh;^(yDFCgtB^coSPab{eyWg{3j#%b$nd#~2tJh`*D<$igz}CH9m!S5HBT|qcw197a z{|BEuUi$i*U(M%p!(&sb-+T@_>rMX5hm4+gQRyT{>V!V%!1V6T>x0iR*%a1=)Y{^v zI>y4J6GiK?TjBcU0(mc8k{HMminUT+xuc&EB9+05v>NY%g1Rrvf~}Pf<Hex!lOxqi z>4W#~tu8MYt2K~Z+1z>OgHLj=UN2<<iKlz!Uw-?~ck0Jq`NlUJ`*nMGu(-I$#$LMc z>f~rSFQGI98zBXx1hiZ6tV1Qz3EtcDgF5ieukY6DM~%*5DPPKj+4nyDV0<WF%*_TV zt~OnnQhO-_fTz%ICYg*U1Zl?pQL?bIdi&K^OSO_xYGHX(eU_#Cvo}9W-MiQJ;jhwV zx_gSYAlbXmsh5wHg6W)Jzz8SpI`yQx*KYs<TL^TyQJq#4W;3y7vZmzu29VGpt3)8~ z_9tC@N|!0q&!FfbN{vr40BR)+4OAaLdX&rMcINBNINCng`|&S-nM4PdF3<S6@=l|b z9U1=08*fVKpFe*-+0AUMEblZ9$45sh0RVX9RtE_fYc)u^IR{{ck^n422%%vUruuQC zR;!h)-)=^OgM*uUJGp$mn9p_3JLw#iAf$_;fB+DN9tb)y){_h|I65{ud5)zimP;e; z(*+0FKKvs+fA{KTytx|VBrLVNNV{52SnF0P_qI9GQ#Y)~GP8m0_j>mJ+s*7HSOP9I ziJ95zOb`+qkC5|xf`RGe0;Q8qdY4nW%-Zg^bF?*B(R~60fx%Y5blOpd@Sp#qKOP^d z<-%ZWWORRj|ESeA($`*=gW{95-Oc^u(Q~s_$i>CQR{Qw4)wIxWy!zr$iCq3_w<T{Z zGdtv!Q&>Sr2xDCD*lX!T3zP<j2S!F_E?i11*G2{>CnsiSrt=x+WfzvxQJm<RivhzR z0T`=1X@U8Lr<qKU4gI*;{_unM_V%}x=wjTv8oks_q&&$M2DX<)ltz6pteZHwh(Lfr znpp`U+`7mHRw%b~8EaMANp}_nOR2O)av${9axWn_MUz0nqBk|MF2n_bgs^}Qsif3^ z41(CQQYta2V8}ATCD)M<DdRL<6BI~F@<6^x^1$uM?0@#hfAsbTA0I^K%`bmtd2@Se z=CaKUEbYZ>+l?TTZMKrF&DEtRkMG}ox03N+zx~2DfA{r~5DM@BV_6Ep<d9E3Tj7rF z5<~=TVF+y5N_F?)le-TeW@N?Bm^-iEDVB28dVX?z*l56Wq$Q}6YE)RHJmka}Pe~1Q z3|g&Y>a>bVP_cM#d;8NzKUXI@P6pFSN%`FQPU`0B+m?E4Rj0&u{7~uQFyNBkx~Bqw z={ehFucYmrx@7OUKUtGqPgk6Hi%uw?)Ww9RKcTSPtCFclUhcVpv@Yi}jo7f2zkO$> zRIU8t-4EI%XJ%%CLMaF{mc_wd{qf^pAMEWF3t8PddhO1Qmu_C48X2r+;RDLTwYX9T zgv&whl|{?|JSlA&+lVL2E05+E3#u_tZN2v8SIec`@y<>y?-f0VS?W4mErU+VC?P>Y z#z_p{PmKNfFMbsaPQ;z|<iKzkc;}|Z(o;dIo#<Dwce}J_aedvn1<?sEv8OL1P#XN_ z7>e!>&~rV}r@vQUM<4xq_-75*eZuvgoDwHBk?k*`=<H#XrKEPdnakvSVCyKpK3y3Z zdGr7I$=l!it3N+~;quF`zGgY$#_nh_m>s!L-`&1^{pQ!c^v2c6f@`oT3FW#94j={5 zJAIzK<rc!i7_<`|hiYeicc?OSyxUoPy7cDP-aJ1xRkfnv!2@8Jl<2DrT_U@*T`Prq zjjgCts#F^WKl<@cFHW7`KWb#NS#`qV`@E{;RQ+PRv{S}eG{MOs8Zh0ki8FY{zY}=p zc|eeUKbaLI@O&@*-};fs1OO7|fubJ+d5Len`P!FWxij~4Aq>P}<488^re42t@ujKP zZe5!_H(GGJ1XycNDq<^6F&PAR(KxBrku4+vkbwe03jZ75_`Pd0H-GT`ziKt2t@W+h zp<0&U@=i~a*!mqXAR^E65+GLy|KuP2@&EemAEBuan$4Dum*y80q_C&nQ#zBEa`rtX zFc?Buu<XWDrCk0l?a!t-ai@Lyyf?JJI_1+3X7AiVXP!u+6P_J`&jf_@zMV@qJ42^+ zf77s~I1tJJmTl3al818W&(tn6uzgT_<=O?Ubv_>k9tr}!GjS8FFMYtUAp!BcBNM}Q zz8w6QtiasT;p6$G+h3e+wxZhL(C+>L$BkEKU&|<v1;;V@z5~kjtv<G!ISC7j8CGC< zb?@GLALR#zy{O$WeBr`{=gbPkXYn;pt!>=9W+x}~{_$*|;IMD+w4eW+oi-gk=dq(+ zIN=Fhv!538oJa7?^rO>>T%3VUlBCnh2+9J`Ne;*W8DKD{rb}wJ77hof2>7ghm@H`@ z+6NO@$uv6)BthcLjhGl1vMkAZ=m6VC$F<>+>o;z;JJI0qkd;b#Ua64L9ScAN{xc8< zPCF88lf(e<1SIgwx89yQf1y+x8Xg;8SXphhTk2Ute-DJ)-;C}?N;uYIFO<DM=C4QT zx7|j|N&D$k+Q8@D6ynsweNwrcvUl`;wyq!=_L*GIXMiK_r3GO&iXvY~&+~*4tlOUQ z3W_W^PU4Ig2EH_K)^EXV{Zwi!U<_Ge5<*H?7iiLl1MjwGg-Va439y^s;qq!GpKnFc zVRXE>wz{^pdHMX!k(!qUELg`e`5}5`THl>7BqcFhD>ZP`Mkg`1UwnC^-cS;`d;wOd z&u2}YdcV@8(L9qFb?PQ(>Zu(anDFn4m*c))#b+YtPUFhmNdEL3_}TeX-_IyC8x>}( zwGOS~Ne^r-YmzeXBup#_QYhaO##mokSc^D@7lH(YVx0)#Iih~=%@MXop&|w)mL<VJ zv<(g#$Cmli4?lSPWN~qMEeL{vav>eO5qrL`pUY~4&`A;mp1V5=SzNwwai`g;RjSp& z>L32$AGY_m6g{WwZ%<-wdh20VM&*;&;n){`!U?m<D6iFyec$iFj=L1yQzWb2``81W zb@44HEH!sfN17j=df9tCL&9@r^g{Gd#MGA!Vb89deOc31$X*^C!DVDw5-NSIX~KyG zIWd-n1-vkgZnHwFz||D}`>V4qxWR}91PKFeAr20XfBusnU%Ya)eRSMB+7~vS7#u0* zG73;c%ti_!>~oumeZ{<mVLX0t|M70?+RLvUA0OxQ#mRw+=--o`ThyJwgA=SIVPTmO zC=Wn3<2!^Xvo*%TSYj(I96|epRMs~qqm<T@=AfK8dz`9N>GL{s|F*bDn;Khszq;H4 z(VbJAm_5@IqU|;}$f=Eca_>`T((b9%1(#c|+b10x$p6WI^!r!FM;n{#TMLgH+iPCj zss%C!_^_<a^Im`(dq7GFwrsQ~AQ+yYg~yLt^?D(bIX-G`Y-~~7W#gV?3!RCUI(-)q zrI8axTj|RvN<7aq+A2le@eN!ou1m(y-8q1@kd$T|rA29P6bIYOn@Zys`W{ea&mI>} zL+O~#NJaa3g!attPf53d&;=)?X$I*sWqV8YsUv)E-odBmlrCk5aDrWrJFNVG1Y#fp zIsgItb^PqT_l}N^hRfBLuU)z@7%Gzh4B^>S-{fv21_YCUrB2k&gc&v_vZOt6f35jn z{<HsH6$XCio4?;~H{W~v=ju6wQ$jcQ?j*{hw-#wYYYm~Cqeps*34TC{PIdgEOK}mY zQlV$8>h|#a(8;cbbOX_DxXmf%H1!#!|LzmuH!~FLU4wD2;4iC#LVR*=L#v;_Nx& z)Q9f}urLXOgx2gS;W5Sw_y=FT69c|RjvyHj9-v_iNpbehv;-iN$-qK@6$Aq_<GI^c zFCD}81#LGPy9f1DDrmd&7xBDgF6xVtNqahi44^GMNo|cpK&q3Iopf*lLCW3D)N8z? zZN2`r&N^M?31iTv(qK5zt92RF!k%4P+_6DE+ikID&x?Iux3WJ{%btFY&tC869Fj%< zzfUKJ@slrfB6xvRLJ*2lNI(!;ZA)1S1quqXH)F8E=#G?L_hDv0*slLd09MB&;44ZD zU~%UQSN393MD_a7AN<iDiBm_VzI*`Yp5*b=SJ*;H60WJrNC2VI4xS)Dz{<Wzfj(7| zAoP6SC(%V|1h^$Wi}F0PQTJujJm-(~YN)?uSZ_fv(i&;4w6+(K`n=AK?Z5PN`m@`g zKPkd22}>e98i{V(Pj_^?2}ahZjDWO8Br(`n%Soa^Ryw~)uQKfW_DN#M1*o%8;Jm`i zx4uv<<>wwf*xK4!U0V~v?TNPUX|u4LYJt*Qf!%JN{);J7m(Wi1-A^CY+lc{=G&c>$ z?%9!PKgAeB_9Qp&q+C4nWSmx5pUGuUMMpjPUib6V9^9*OT&fy<M!$xbEE5b_O;!`w zVUA9&ilcKo<h}cJ7ucSBc8{8UiRvJBpF{`(t&>Kq8Sp&ehY~ghcL+=rlT08q`GS=) zZgN7WIuP9bf91)OW0~$Gi5V)1J2$2e4-ema@4a_^eOEnOtub4dN7@|~os8}X@O{aE zHE3Hr+1UH%|Mz!)`?uaWH#w2bW^;jGF8Jjz2-4_x(#)c3&p5e$BK_56irJJ6+C7L{ zAuPd(GRXF_CJ2hVizzuDXc|>=CN9O@6DO^-F0HQrm2g_1oQyG_xzxQq&y6~slcbZ1 zB%ZxRq^B}O0NPPI69gb2kZ^b+0kAdfnq<mwqM-U#Vj;TWD{QQk1Z^S6_dKmZK*`6< zXmzj<9&E0qgRibL&asZ{ncA%Hp<yA3fldc;ApYY1*1d;Ms!9bUf=oUa(uH&7%M&9t z3(2sagU!>K_M^LLHK(^lvlC^5P$Rail?aK2)(CwFfVq=mNQESL1~3e5tt1P<GL<i@ zu2jNl%lK3cXnR+$_ZFMJRZ#RD1L#cMVd?qZZ|YUc^qdXVeVsvomF|bJsUF5@(Ry+x zz&>03_LlGNX^vBx3<*Ps2+N1&=l4FEd-_!M=)l~!^Y>7u>4wC;mqT$9386gcZ@2LN z+|%8N2L{WlD{DqKrq2yP`n|j?fD)?%s5Ghur=(a?zyR8$AyERtSYcs1vC9I1hPKuy zA=p}CHdX@)1YeTFog1(d*FIky(_dbY=tuJQheDjfantF)^%-4!OV2rI_Cu3;w^6s! zI{5?X8Nhz#$@%2BsQ=!wWLa5+LX4K=fB5F@-8)}U);@FB;PZBR-}9SM;s?+MD@)5F zSN1$_Wo2b=Z@-wmC3sv|7{C*0CCS}4iTf7JK7l3sN?CxQh{!?)A+$y8xJgoW#ePyj zF!#MjECmTETsX8neUd$SxVy`V=zEO<VCQT~bAE0AXt@7TBjDdY8RGw|kJBgVG$I?E zh42aavafo1F{kVxpK<9dp&3P)FyGYZu$`KmT-iN*|NZwuR$s;d03ZNKL_t)ywl?Be zlhwYEB9(S^t4+(jC6jv<EC9AjST_@Cbz<^-*Y`?*h^>-D@ZD4_;Y6|x71%<UG_6yj z8y9asv)g0I_LULc4jY}2Lc}v?GJC4;`|s|ueZ~outO<z|u!Wzh8G7{ZzIEiemri8E zd<SSIytQ|*zP!49*vLySSICd&b0fopg>2R%2-($+riRV_(|oslH3_*yX-GgQff(pm zBm_t@fB`y;yZ{Lg0v!Y4{G8o61{)Y=B?xIMa(8#=tJB0Y)bVErN!^FkKCc0OdLHuc z`a=+LrzHp^S@qwgOn<ww^0?g&G8sQ3Hg@-jZASS?92W|?^V3sfL$#dmVvoTDX{{vU zQzh>SDvo4|W`nRnpkkn<(TFg=ve8arE9Cah&hhc_rHiu{&yV>)HRv9?0X86563!AP zpFeq^lO?+MTnSk2Q}_yt9v}O3#liT^{IC#y=<Z2{{_L1kf<w>mM*vL7WHK#_BZIkx zh5EtX=;Vyy<fwj7trV-pV$KIKjOcEx>1uWA?&n^Z4N~iV0&LWIv)*hPJX+nGUs|#x zk|a59HXB++#tVqY2TDW5uo6N8u(79{U(UjEf0bd+Y<Jz--&J5_)7;y>9+x|caR1Zl zc0vAIa>@SxUM|xf6k9d`__<11+Z&3XnXowRNz7PW-~Z_T{cKPg8ybGR_@vP|%w@w; zF3fq57P<!lU{<o9_s}=~W^0K_`fY>b4(3)@S9coh=Zwm19kdJO($wswcDv02PuKV3 z*1`OOy>fo+($rWnBLnFKu~xJ8Da14D<muYp>1KP;!u-qvcuGfMe*+)2QzI)SJOy-* zfxS5ZGh4Q7ty1dDWpl4e109R4gM*h}dz};YWMMIz$!}?`V5*hCmA%$l4Gx7Q%Wi;4 z<Ou$0xfUB%(u<N#!X~ovAmRHfYi*-)etvOd^RV4+bQ1VsCd^&DG|M_#-P(A#z7$)t zTi?HR?ZQa8U|}STC%lAvEzQ)2Cx`$RLd2c6@B6UqdPtBGY`~6-D|M%%f*`dwxFf9R zri{b}j+pEUfZu>c(ms1?P|r2&5K%7~&vt<o01PM*2oz+HJvTG!v47m`tncreB*|q$ zU-Y!P-FR%0WFbg6YeA13V5Mm4M0r6g;RlPW|LV{FeEJKwjFOvc%e(tK+I04JHiTq9 z%t~dar>BQT$E-CitL`tX8=|kheoI11$Vev{*$tm@N2PSgX**FX2txpI9Q#2K8v|qf zAOHk23lb{KSms10zQe>rq|$4Gl&UX_oPGnJL$ar@oaoxpyDOTdzDb9*)(~lnofh7` z_x|wY`RS3#F!ZBNYkK-zxsVNHPa$HQiQIYQ+*M>SvEbf9rMwte+CKO{zWo=8%6#<b z$?DFYQYx!(d{oc+vJhHpn@dkVSzmdoyub<?92tH3=*jZ>cC9jW^U_#Bq@!JXYNVFd z96=abW)edB84Do;1t4NpLNuc!msQL*NjMwiERg7quM~(NSUOiwmtqV0%_>oP2R8Lt zldV$;k$qc-6nL_@7R9<yEU&Mx&&|y(uC2ay=SH=dQv~a58L&c-?J;njDTA#=B3K$B z+(<eC>TTO*<>m6jm4QrU5W15SNqzx-B!Sy@{6GG~KPcuzoM3yW^Uwd)|GBxnGdM9R zGlj4;Sl?W``{9Gx@v&?U&ZFCBgs^EifdvsoN$dq#CLAY5NGS!h5D7rppyQg~f!{C) zB#iXjDOPn;zl{a}DSrdEJ^TDC*T3hXU)<4s1x<~F?QgyD+g5r%_~B0)jl=QLvDvAq zN}(XT3$kFNKqk#zrxURTTMG^A8$v_l?GK-R`>%g;)HcdSZ~pG<xkBc{yKfgM`g>pd ztx707KzbM$3;yYU@sGdtmp?yZwX<6f@|A2kY8*$2w!R>(;XAr~+5>SiRcj#<ZB&p= zT>0V2BZI@bwSqc{?Q}ZZo9lxE<*9SkRx=(h`hrA~CLCMgG~#3>{l=CoeD=ycJ4x=R z+Bp8W0irl54;Hug4{Jk%K{gXJ4G#?!v!3eWwJej1Rp|{dl&kK9b=e=x(2TY1`o>oM z+=VNZ!J3J6((0JwR&gL04844J>GKGI#?Ja`Y4TDgUw{x#A01pAoz*(FCJ2=aH|;%e zwx?ba%F{p$G&G*B9PBmPu>lMD@X3>dg9A3Yb#(B;)r+sZcvFUc&PUcc^N1`n!73@? z#5RI{<1QRMUmgdC>!#C(f!?(a6dpZ(vb?-nD3reXJ6|gni#t0zJ3Bjp*A;7s6#T}p z&IxByjY%rjVCKX?Diq7Lp^?c87q1T0Mp>J~oxP*o-7idE2n=LmGmMNus4<ksP_ZN| zkByCHvl)`8R*Ol}j5|$<M5a^MGzSuvyA)c)KxDD7arDDqzWdfk50`eEtB29koyKm0 z>bVP%mwW4@ha2_g!dCsD#rqLQDO%G(NeqZjQU-rxb~#I65-f!Lum1E;yJKIbZj8%G zdZA^}L$d-g(Rvf#|MB1C3)M!W-E1`>aQ({VsiDgGft=6j#1+N}ArrRb&dPvg1F(~q zwybO#dbHYTF|{JC{2&vAtBVVjjC}L87cWm%3JMuP&UGOb9Y*-+Tlbm?3~29gx0KIK zjttiFnaP0yCy^xCn;jv|%7nJ6Eyw`79qhL){Cs(EtkH?rxAzxU*Ajzv+!+`e+S#v@ z?;W?>pFVgXJzpw68!8DHt;xEeQ0mTS(n&aV`4ph;sMfuoz0!d`N2Kz3U+?w1=`&YI z+cUTVP&VyUF@cHMk}y_ry69Oc0IQ9*QuziH0~-g2Mo1kc`@8F(EX-wn`IVP%PSz$u zhGMXUwvft?t#C=Lj^5N_OP&JkQL|%m!C(L4!#!=!U%lQ=j-#DUyHP9#;q{qw7so@7 z;qXf)j)Vt;OhTv)4c4`=x?L;hXV1S-5Wa>z>ey<K)oeW>+U;g0<GXP_k*6V!fV+=2 zj@k3G#V}X><kJW9>npPtFO)O6rKN?qT_~1v<&p7`^H<2m9g=q+Ej3!4zkaTw0LV~T zShh(_O1T+1tfZdaPrxb|uz+ROiUH}9B@I?YNs=hfi<8**d;smJlL<5SdDA#|dhDNL z^vf&yhC#g*rKbtvw9Gs4ZCiFa5$;-Yh@eEbLqRx>I({aT39@U;YYR^oo9&j+aWV9K z3)Ovb++Bp7bIEkzDGyLl9EZ95P6G&Y<>8S=^LTdl{G|&sNA<(NlagZ_+nj<i45MY> zk)l=-7czMLi*FPPIm>#mQa;$*|K$FodmrCtA)`1+lEf*cEWn&V5JN%W$;#nh{O~7h z`}@t<bTq7`=3$+ZSn9|&8>{nkKl!WgKY8+G|L|yZa<Ccm)0K@69?sWWXc}0^s1utc zA<uhGWtYB#q>Z+)N-9VRV>;SE$e1m8K0`pLgsrylf`C7F&*}*&P6=H4M}ViqFli@P zb!qT~(@(oI7Q1L0NNJcgNdpv1<%9jhU#$Hqj`gKWm&QkGLqkKAqJ&BN>Vl|ews*8f z?zTcZY&{@KScMrc$mYw%`feSJO08Tf72;027#0N}Nu+`h11Y>1Xm_H+!^3QCpj4_f z8jZD$^+#JPUw`Go;6Oo`7}i*laiRlH05TRhGT7NW5;Ewtn(HeIBh{&VKI=iZ_c#CK z_y3-tZ`6<W_FC=l|Lm6^y?-yKY$!x7lil6jy+5~FzBN(t5Fp#-N_52$luD#}6IWM+ z8_N=&^~iw<EJ*^`SYJA!C`*W_6J-LA?DGl>?w>VLZ&H}vB;wR?m@K+EjzWFja!eo) zvk{Pqu~woLV`*t+aB#T3SwA;DGk)QmC-l_hL_0#+N0+HWqHDQ#E-9tb`Xm$P>x`|v z{ih4dQ<tyS_ZyGyKd99P0caf$)yCX7PYS>icM_8DJlfNEIQQhJ*&3ZGEj?W*l`2!` zr^9o@g+d`=laoU0SjvnP9$;NPxx5v<`{Ae6>fq|q(ov&zINlnpl>hh-{)5S(%G9t& z1{qas1I2;rzy9uDe)QfwkB|>DNA1qr@4a{H>O>51(#d4JM0Y%)db4bHsT*A#iWGt% zwAI=YfCxwcpP)IteTl6v1%S}^>9h3M_UwgA!v)fup16>x+=xe%u-PO_$fyQ^^rI z))x!O0{aKYabj-2cxP(ne5{lC$B%b6H^}I~PZ!@*5qnzpX$fp>qKyF{u)ed`PPmjW zk%lqWT3ad?!;D|8c)~SxEC3e1M=E3s!w|mz;!7`$Pn>(_t#^O)qaV%9%_*g_0g@y! zrjy<%k~AY?(Xe>`;p6q4gHmNM^!$t`A3XSEV`bsu#Nc$zD-rTQ4p0UYgXL1z_sPC= z>vpwV(QG#N_x2hITPW#U2&ICa_1;lhbjn$A)rnhU`~=u*+ed2$cOR{Nv{Zkxc9^(7 zCdpBc&J-r6)M@=9#*^jPiPD%Xi*(IOe~gnn@n;Wkz29SNdmerv(b0G`zi8O2Rcb+Q zYhiJ@6*p!^ZwFFjyK9Ja<{ifua+W$F*s=f=iDL!}ynp{;SQ(jnG{3dE8MQix2X)`~ zy=o?IF=f+|JY8)W8i+I!!x^czwzg`u+Qo|(4-V^(9zWW=F@0$$57QJfRYw~UFtEC- zKYTnter|T4Hng_#WMh5RXfZi*vm8*xgAWM79GjBw4VS`dp|JFH>H6hsV`CGK=APtp z+1-N!8XA(8v;}J&NUvwNOa-oF3Cu<-DFKmah9}xYcke&^;m?27Zgg^<_sZ=TZd^Wp zd3s{9mb2Chl4Q;26`It=O7ukf&PYcm9?!0&CH))fM07zeu}Uz(F)W!GGL`=s;Gk*l zzW?#Qp({qrJ$XF8IPXaws1zzC&&6$ZtCIAuxL$R_F@QiQNn{wyyPbO<eRAW)634qA ze)wUvS{WFqcH-vf$fZhN`0niyWQApBvXX(QgM<3f{Q7pI-7e(|=g-gh8!KDw{V0kA z@=_|J6Je|YB>|3rPv#dB^0T>u7X;OT;q|qZtFssXz2ClFR8VXs5@@ZIA17S$Md!HT zNna>gELBFvCragVkj;^RPN1aqJRf|jcgc>CZdsf_VMGiZwR!#Ecwuv|l&kFT9VT}_ zWE~GzO5?ShQ1XPrl>U{j{Fu5P^Pa=u%xITIw=_Asr>WEJ5=x&rfSr3JDD)z`=2J z|H(XO3L^7lZf@?{)hpwJ<&kPtrFQ{$wU8n`9SRFT2?c=Tgk>Nlw)PvP+R(KdH)U)D z+wHwwKTuQW#>a*;odgB1`-+I9kj#iWFoZClJKo)^)&_EZ_Q8V(d;6O&Ub{3tHlQtg z1ZGwqDT@P(g`Li$#g(ziDJA@<9Z%29nz%Vtt5ibd6+AYi4U~jVgv_wP)Yv(t_Js1= zi57mawYAeaKM|Q+=z%~w=_u*Looy)9gLWGh!bTkml&5g0v9h@%!u%U={_c~<OAtX~ zBN=4##S#IE$RvqS;<IM=w)=<)aOz64{kk-9O8?wN7bxl}6;q<7s}CRm>CAOPXuty7 z^~S{XtQP+DYhTD@vLl1Fsln>l(11+)Pu;+^)Jf9wyGzSPDv@Z`QY@~nm#ejGHrr~~ z2L=X$Y$j?Q9&Bv{aw>4`Vgkr&ok-7P0S&~AX4G-?i1qdLxYHgSDh85#3Cm=pFwD@2 z@VsV%Kl{Ot=ax6V{(INUxrz`tijGD{$FGc63JQ`fSwJah4c|+Q4J5tt;w$qT8<oMK zW-DG?TA?IaURX?KYb?RWD4}|+h;D8wr$~EC<b?p*F|3EV#iiwyja+qPbaL9%jtf$c zjE#laOzQU+r`#uJ7E5c{_Bh)_#<);YblR~SR9ORKpnR}~K-!QKr`-;scU_sgO-mvI zH1K43<>2sGO6mD>aBx5f)c3XriXxDwRPkib;GmdY0-F*?5e%upp^-+TnIy^H-rn-^ z(u4b-_=3XpCbGsDW}`eWVbeB{A)d@{JY87gM7LV4&CSjI{XOEO5CkyrB*oT-VGfES zgNKWIzr6Q>2F=aQ9USaMQRJ$FT0T^4JjXY6nconQWHfvgRLV8w2a!o2s8A@4j*c2f z1revtNYX-{(oI+x10e9Rw%Pgc;|I-F{K@?Xt#)+WjyiFi%jH5J5>NyoM4AGA_Oh`s z>=ArHGDWEfNKZpFI*H7LEsLf>qF@4a2-<^H5(0^i)o04y1gwVEnv@?~>@@H<Z@s(M z=#&SBAAEXWW`f4v&YkIV9*`9foH&XLtUS}=5#;z6%ofdvGuhnma9FSJQ`C8~Fn|91 z)Z|Fz`sIrr!xMlu((@7%vq>N`4E)Wz%isFW_a-l28K0c+{a~;<xUu}S5Cr2xHIA8- z5abzH#fc%czOyfb?8L-`N#b|k`Bkx8vYxs$S{|zv0ux(+gaFByQ;w!k$YrG$1@|95 zJZiO>xmYY#tJOXZME4cBS)J&2Xc2_a28lpoK}yxi1Ae}m&E*?O+fx`GtYuVJs%*Fi z?o5-SU9Z(LX$uW_ia-J)VX#1KfFL+v#0mTW7TDfx4Gd&;gmQq8gmH?7KB?2m9brrg zG(Bo}I1H*qOkceG(&)L7fx-9RzjttOpgXPEsdJ$MrK<s_RSBr~^8vzWR!YFIfz1{~ zb)Xg>Mx7)Xn>n|*^mue^xD=>bJ})$+4=8CY3#q``7-OWEUt8VYKRB<vX5*NOG=2Wu z{?=MXU~(j%ClC<Du@oq%KpTAeXf9tU9v>bJRBKnRUaHipTL*iUa^545(M;shk^Mj> zKpR+F>+H3(wRGHQY;NyVDwRSZcX)WHM|?;DHz?@m>$sz|JO3mx{7hmI1BFU3J#%4o z`>0l~wBruzn1u~|#XYc)Oe2EM>YQvEiP#fvB^ChMK>gS}dNLm~qF5gs*57{X-QWGj z*DudZ?Idv}>kn13LVSio%@_tiQsgoL5$3mnlZBk<aHdnas+{lIN*XK9eDEY)&&x zdnK%Z6O=PCYhzhT?Cc#Z%+LFQx3KgyTgVp6g<7>dQ1A;rl2}{jj?os7LQ3iFwz0mu zfBVIk%H?ttMTK0x6-CyXsj-m)!2`5TGJc>`&`3-xL7`N7<)xQ1UZ7xyh6bjmM@I*% z1LacEGSbT^&m$qZ>jx2xW~-rf9Qeuud?{vU&u5DHrz;DcPQrj@*GOa+YJSRSOaeg& zL8K4^A3s{^7!6=&dsDCpl&BVS`OqT^SltsZoi-VD5o*pFPa=*vVk80)@O1n5U;JO+ z{oc>t`S9r~XUi9FzEVCnJHK`CXnl7t!Nc{vgMOKB+9o*hUJ3w7(lJ2Hc>H9(P_9f& zPHk^)1-_DsLSOkxngpH_F#1`lf+fHT2noXsNF_T4Yinz3Yiph$&50MPAn+!~DuHyV z=tM#&<!f*fYXFClSzKQ)SE~a915vB(dEVRaz7r?W<=Gk5&iW$SQEV)%k~_!kTrOM4 zWhchQrl+TeMuyu_6n9#qgOz+%0;CPM<5)8@v^B932tz*%edw5swmJcEtUFO0`^uB< zwU96blY;HL3V#R-bUJZc^D$$;W&i3&Kdc`e-oAOOS}G@<W~q>wnVu{bWI*sF!7{Y& zJ!*WWA<4$o<FO<wVSv>m{P?ZAPu6ygpUc-qJLJFh{{6$2Uf(&~sz(buM}PhH2S51P zC!a~xI6Q2WO9kKan`|wp(P~akO}ARnxpNcQQ0=tpv*RN}gE<1EARTpN#(Vxhq%8<S zNdgR`SS(+;oGTOx_ugMzd^#UW@8a;6yb#g?N@^V&<-6%hD~X$t7GYRFI%+(6G%+zz zDwU!ne&OoHvEjS|jA1E}34IMjjHfGWopw|#kXI^~%jF=z{DY;V{cT*HCMZs<P$CR` zh8BR7!WgvM&BM0o800ek!Or%lADc`ee{*&!7YYdoDK%Rog-ESACwqV;5oE#`@PJ4s zji`xEw70jnzq7r!w|!x1Xn3HeQpBb0M%6x}z;(Ampcp~}r09_GaA|*OYxmP9i}ffO z$W{hMrw$GdKlu1zF3ha2?yRkD)&>U_pUiLW9XhnR?2*TM%U-Ee(8ji713@w4-uoY{ zuCA`Eue1}rd$7N|xiMTRLBsa|7!`)y_RRBCwo($50UF1;Sjx;!PaPfX7PI*mu3noQ z9S#(79*lvGJ4y);y4^Zbp67Y~{L*s$uyNdMH;$T>Qi)A6Ib3_;$_3vdqaYl<ilG53 zu(G{7KR@5BAKOINDwX4ig|O43Beh%_Cm<x)XbEfC#4)o(rc_ed?9t)z{@y{S)t<Zm z@%F~@aJ8tMk5R%3E70}N3F=pHTEJ~`N6qHdE7xbH&({z3Mn;CB&T%I6M+d6`0jyo7 zjJtA#6LXAp1rHHxYIRHk>}%ZnXz}0t`S;(t`%yEo)0ZyYdHJP_v)TRa%~t(Dk&T*1 z?RI;wempcWSsNZvT{{^$o2J_ZgaunzqP7;w$HV!}$Z*c5t-X!;wea!$<4P_&T+9`6 zfNPQgu#%usbjryN%#ad^CSMVd%_y?b)2H`|>CV;b!$Sko>YV3%%vJ@;m`Eb2Wc^rk zM*+fXw>ywZCmeT@=<qP3+d~=3NJzl+${|o2*lrv(o6*Md#;bQ;u@<|Bd$~gP#i_{w z51q*7Jc5PLT98Z(Y2|MmvtP-I#QWgEua4@6N6q8esmV(hrUn8kNSKa6C_&cirQA|a z3dR=JXyGYg0Oc3&yzpYPW8xum|M4RYZbwnx_d`NfDHAuP@AsW_;qZ!<NC`<S1tAk) z*P_LM%ohv8A3vTi4h>zoa>XOPbboWI61@7K{)7Gf{eQDQx3Ic-W#rX~i7_u}DW|7* zm(3CbEG>gzjSxy?va)3{KfmyF{_&M^`P%IlJ>iwh#apwJ7pDi^3BYh7(s)bic}l5& zn9H2ROo1qcNa9wdRM^`+Y`5e4AK%XfYVgKok%923)o$i89+<Q?vB(}q=yZ}|u{bn1 z;w#0>8DGBf;;pH{V(1(vY(dr&q76J*+j-~S-K?y&n$6|q<zoBjgOyJw1`E1Y4GMWL zBpAT36cSc=O2&lUR%>}ZK4>Pj!I9~y+1aZXqvrmXUVZ82c!?5tN_IGgu&@#~9mRC{ z9xSYtQpG@Iu(`Fnxpi15SA1UyfiHgXwHvcj17#%{Y!e}b!vl&`#mg?)z&JO*1t*9E z5MX7qxwx{~YID@ldVhc6@xyvP%yc?m`QpnnlchFluiX5nzxeg1KlsJnU;g}O)5B%e zciBz}F{Knbfn_8bc|nuavKP17I~(i!N5=<yW3SyP3YgeHL5W@x@#&MeyUF4<gz|jR zwm58><;AtVqiB3$$_Q`cpnkBudGp$(7?dQO2?7gf_^dKpN9}h$U3fINkaUtvHkg_i z7fDnt<*!Z-<^&RBJtC!)`z}7=sD98oJ_?GZ#3YaA9@IZ*WJa?2iJ^QZn?|<*uuM|G zLR;G;T3lb>X;GyzIzBSmXf(2ge5<t&wgzY&w~EEA5?$ZoiSsyJ>MWoW6On|6X1lY! zvzI`^lS@lWH*Q|LFnumeO%p`2=axFv@~~ZZtC1idb1VDb`HR1L`ecKoZ!Igq>q`sa z*x<`IUziy$0gwhG0baa%d46@bTCTkE!WGq5s`3eYivVlL*ib1i!0&zSwOhAt9GT>} zqrdzswSqJQV<eFFk;mbrh)}cS;YOt_=(~0U{`1ATM8i@umO$Uw`N7jh840tQWA9 z%~&793rJ){aNKEHFVki`THW4hw1f<Hw|CzA^}EsWrNix&FWtFuYx1&Wh@KNGG0ZH( zaHv{&_0^XT56s}ecy!p>sqb7Gzi{Qkg~75g39N<Z!9p-wn`neV46N_(Z|%0DmTeuj z7M2#Tymal_%@+dCCq_P-b@`;)YDK|wHOA7D5@@w?+-jC;1MAy6$E{{In?2s&%lWBE z$fo)fL6UmxQtI<Sum$_rkMX0Q{bF@}L$hf#>Ig(xg`?H-7pA9Pec?h*Km$36cH52? z)%D94k2>*iwV)tQl0DM6$P_+9(wDH17Da*FNVWqsVqE?w|2XMjqyP!PFk3C9P+|Ct z9itnEWUVziVm7`X3cPq_<j*qMmDTkz&$r6Idh_;fvt?FrbF$P15abdd26kh+*N$6J zJT^QM`0~-GA8~XPymVb@gg)4UVTCp%q!3a9gO&1~+c%e14h02cLu2_$t~6Mzl}plP zO8VX76d;u!6Am>t59^%{Y0XkfZFy~DV{G&b(y@INpbaTjq|nDb?%^Q-GHfAfeXG8= zUmu&i^wz!io;;nua`F6Nd90R)bo)OWNHS7%shi!5p%jr%Mo?X2KQe{d;Ki%{!}|*n zGbt(;i#IRMzINk!Xo0p4GfDu3kd6$_4G%ADZB35XR96JceP=NN09wOYu$cr~C4~e6 zABPcY1qg<;2&91S`qcWM`=_oSGx^Ggn*<>QZe73rvwQCc#X@y(pjNFM9M>1NSM&K> zqd8A0G=R51-u&e0TBSC?YjvX&(w%B4`||6z?!0g{qd*3Lv3*`6)+|Y6f^hU)?*1q9 zh2i{_D_7d4k&&?4P1pf4#u_1&A!1;Ce}8Fp?aK6x+c&Pn5$esO;i(ZNX|R$BMLKCR z#z-liwS;#MJKRj9VUScSYirur+TdWbad=^JA`b`#fu)p=HSd%;T><im@HinHGv0sn zv@$R%!qWXmi`AjQLNWKo>o47!8lS598Gx)xjPA5sex~RH&Exv_zV|(ke@Btq1n5-X z*#hKAFpwnhJWmoVbevcc#Xu^+S_IM+q6{q{>3I-?bX_o78wrr-8L-5wH?IE8J8ub& z$H#`F<0iadeseebaB)1JOJaQlZ+YiHWs3P?j1;`#000RoNkl<ZwNg7M=EI%MwSq5R ze&K2*gkT7;3r-;`U<@p2lGa#e7{<oVRzAp;%DL9jA;;PalsoRQj)gBQ(9*{E^03+7 z+}^t~jUa%Z!Qk*vs3f=BK42J$X3s-c$I$<Zdh-_&N+umB&mSBd{^?tH%eCs4zxw6& z{?=%<3<fzS206ei>3%;OS;tsmNJDu4!PEcofBBcy%5ZIHSX*fgA08ekLFG)?Y8X!% z&toNpm(M_J!D@WGHZ(eXblgx#!+g*aY`K$+(JYk<z<^CUq@<EIP!zKfB#e$pdawpk z!dRE(Vb3^S-8slp63}ctf)pT)(Q@X}<WMc|=R5&lDL;RlV5`yo@ZKl7qw{0q5p%s> zUz%SC2ru8bhIV~=Y+$rnAZ`7Ch`}aFS-48USkEKDGKtOH)1{}&OCmw1b<}8V-JTg& z<r*}=+Ko3O80C9A9jvZww%eV+&om?WA*QCr@8ADm^3qJshcr;0u+RiDY^0E<ZtS#R z5zUyJ9n>4gg<|>W`1m;LbUK}x>2m|coM+)F5@f-KHNy+~)hp=~n~4bqSX$qvAa~q~ z*FSogtCTXC&?4U5-tw=`RB}=pvL+&D-%d1qrGVf2``>II?#Ms=um7}{PG-9aF9Z@! z4CGcp>7oJvSRt$cD@iA0DdCbCQ_<+jT!h^0{r_$2Oq$y|t|)x^_M0$+;0Vs5tdX=S z$x$pTimceGinC1?S!R)aeoiWXA&X>@sgjh-cEwS$h#Zw{MUzQTBrS^+K+F%o8@g{6 z{Q!cr_dpfuHC}h$d(ZifFbzM+5SlCoh}Yj-uQwa9QYwnO{-7H~rRj1w(Dhc&%48s= z->g6W@?k#fO%_t+V*b|Kn+p?8$}&+GIyst?Kua;u=mWJ*^s?DZ=O_F|cmG8t?a({d zHm6+2As~)m(;)1#^!gBoJ^lN?{LQx0Kfe26Iwb;y-JKm<1#hjb&ZaHfyeh)59z~)~ zWg*RJz?vCK$k?KquU^&tKuAs2?(S~&;8oF+*UrvoBwT`kf@WbE)H;R{Dnm{@QD2FW z#8=h9;@ZW_=hlNDzIp5R^2*}c^8D@ZUtcN;7tlH)TgEEZN|WXGL62S!e*4EiEiaU< zaZCt}*{cmTXvo+lbKx|srSZW6C%fy3Py*wy5o}T;1cQl{Fb!5Aa#FCw%4Ff`-piwQ z@Xb+Mr*lGxOB<V(o!Wb~Unpdzvf1AB#AH5w;mq=d`I+Sj+e!@K%)%UXiMlNewDbr8 zcD5_?<;8bzFFw0p`R7M}@Ad}1-{+Z(Rv^a#lyp*kP%A_yP<KE0@S{)vasU4PrKP3A z+Tp=o<)<IqS()}y5-Q{nF$s2sH4?xjm9$909W_%Y;OCW{KBpU<wo<B8Dt3=vTPkt@ z%Q)D;r!)x3yQ>s4l(b<{V*tM&zCLWmemoe2`Fy_Btmd-WTxw`8wk$@>0w9XOzQX=D zuQbTbWUW*EDjGvyYjMgYOb}X(61!kVh4d{$JdeAr#|k24Y8+c2NA{a%%Bw5oCttmO z{JTHY!?;tcZ?0d-Wxc6Fsa*Ha&Cq=RaF}V{tAEmk|$i$|V45Gz}ibQrM&bL}*lN zkDqOAw7(ZN{mIE`TZV&}H4sQx5Mjiy?HJhly0(2#zjF2b*ZUW$wfa%L>bDz(w6iij zk(WjwWH>DPbQ_PMlIRhk7`;$6Iz6vA8At6XiY!Ux>C!vbues8!oMsbvF|2giM3W|D zdeTB_V0-`Ye~+K`V~Zjbi$&LUtA~f>>{1~E)`$hnHAIjFldVRmHd>R@Gmh<9-<Bbb zAPs!tT&5&F&Zwyk#X=BR9J49DQ+q8y$C5q;&4w$GAxkqh&d&Vmm%sSp*;cjPEv2Xv z$2}3Pt}R|)UtfP?A_jy)M#6S!Oi@2RNn|NS5M!!<pZw^~XTSc<ryqYZn=R#BCzZ|n zVcby25*z`uY^?~Dm#^=C@w8fP*<R|})vLW;J0+u)>6NqvVyH+-sTtB>+gNF`gb*x_ zQ-+d;TfN;)<tFmQl5#TDX5DYM7MEs<S=W&u78=ZBQatlY#3SG&*;=3vJm0ST=f9sX zuU^Vnsk!ou-)$ef+J9?hPBMs~mDW-#hApI#;l=`vm!9_W{r<o@`M48L0wv~Z9yjMF zb48{hT1}k9R&YW%7_KW1;{i<W1;mNSCW?`>5c~S#tbK0wQaeIF1kr*eFJ~RNfCOR< zGXM&M&~qFHB%hKd0?;Z9gi6iiGp^Q^z1`KT<+=HVFCTqgEMzk&@51UtPCzjZYhis5 zkeji*%vNRZ{Q2{)YahI<O=sMVvu6q^ILSp>09q-Al#r5Hje9?JLe)jR)n~F>onE&e zNGTWQ=Qb{$EoO`)O8}(7r@-`y#Fd$~j)?|<AICRt+&FXgvfpT}uCDgO-t1&?Wqvj- zOjw(VKLTq+N{5mfJv?~$XyfYje70bXAtp4KMhRdfF!GKKmrV?zA;b8Q<L|N<S{8<w ztKraJ53emkvJea<n23qBmWrk_q=6_v*+pcd6Kc;U2|&XkWC&3hLXhV=;O{_!3TUOH zv`12)FYx}ITg|_IViLE`oV)no$<t@gpTGaZo12%`)gav2+gD^;Ud~HpbLpIv^4`6B zX`6p=>E>J-HUmOa@^1%e))Gp<<`Y~B(=Lq_CTGh*dr)hHTU%STR&{BvI8!Q-GKE0$ zNls{M5CqNon3yGmsqW_%7Uovh^M%sR_KQ^3+k3w4I`&jPr!_#(T5Bmu5P>WKNjRuB zUTp7PdHZIg*09X(H>8#f&n$5~k}w>e5ruKo!_mY0$uXnRY^0hn7QZ-d{EP`4MLF zqoE@R9cL^HQ9z_U$5N~$Y$gpI2}nm0pqb+Y7{$j@d}4sLBn61j4+PxzZoK>O$#$!8 zBm||4xgh3_-~RK*pZ)9K58BOU%FC>8Uh|3w22rcq>2*6@zj5Qv&C4qV32+pHl*u@P zCbN}9tgS>8c`QtgG(v@~ofk(TbvseN-;cvV)^pRYWy|CljNoa^W-BrVv?TRhN}++H zjwZ)#G#eei7pVwBw^|LCqf*}SD2a0(0dH*y0xFeCr_;+gX;)hR2hX!}EkVr`3;+NC M07*qoM6N<$f;Ivho&W#< literal 0 HcmV?d00001 diff --git a/scribo/demo/wizard/src/crop_page.cc b/scribo/demo/wizard/src/crop_page.cc new file mode 100644 index 0000000..ea3ca71 --- /dev/null +++ b/scribo/demo/wizard/src/crop_page.cc @@ -0,0 +1,48 @@ +#include <src/crop_page.hh> + +namespace scribo +{ + + namespace demo + { + + + crop_page::crop_page(QWidget *parent) + : QWizardPage(parent) + { + widget_ = new crop_widget(this); + + QVBoxLayout *layout = new QVBoxLayout; + layout->addWidget(widget_); + setLayout(layout); + + setTitle("Region of interest"); + setSubTitle("Select a region of interest"); + + } + + + void crop_page::cleanupPage() + { + setField("load.input_dsp", + QPixmap(field("load.file_path").toString())); + + } + + + void crop_page::initializePage() + { + widget_->load_image(field("load.input_dsp").value<QPixmap>()); + } + + + bool crop_page::validatePage() + { + setField("load.input_dsp", widget_->image()); + return true; + } + + + } // end of namespace scribo::demo + +} // end of namespace scribo diff --git a/scribo/demo/wizard/src/crop_page.hh b/scribo/demo/wizard/src/crop_page.hh new file mode 100644 index 0000000..9891a7e --- /dev/null +++ b/scribo/demo/wizard/src/crop_page.hh @@ -0,0 +1,60 @@ +// Copyright (C) 2010 EPITA Research and Development Laboratory (LRDE) +// +// This file is part of Olena. +// +// Olena is free software: you can redistribute it and/or modify it under +// the terms of the GNU General Public License as published by the Free +// Software Foundation, version 2 of the License. +// +// Olena is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Olena. If not, see <http://www.gnu.org/licenses/>. +// +// As a special exception, you may use this file as part of a free +// software project without restriction. Specifically, if other files +// instantiate templates or use macros or inline functions from this +// file, or you compile this file and link it with other files to produce +// an executable, this file does not by itself cause the resulting +// executable to be covered by the GNU General Public License. This +// exception does not however invalidate any other reasons why the +// executable file might be covered by the GNU General Public License. + +#ifndef SCRIBO_DEMO_SHARED_SRC_CROP_PAGE_HH +# define SCRIBO_DEMO_SHARED_SRC_CROP_PAGE_HH + +# include <QtGui> +# include <src/crop_widget.hh> + +namespace scribo +{ + + namespace demo + { + + + class crop_page : public QWizardPage + { + Q_OBJECT; + + public: + crop_page(QWidget *parent = 0); + + virtual void cleanupPage(); + virtual void initializePage(); + virtual bool validatePage(); + + private: + crop_widget *widget_; + }; + + + } // end of namespace scribo::demo + +} // end of namespace scribo + + +#endif // ! SCRIBO_DEMO_SHARED_SRC_CROP_PAGE_HH diff --git a/scribo/demo/wizard/src/crop_widget.cc b/scribo/demo/wizard/src/crop_widget.cc new file mode 100644 index 0000000..37a9e80 --- /dev/null +++ b/scribo/demo/wizard/src/crop_widget.cc @@ -0,0 +1,37 @@ +#include <src/crop_widget.hh> + +namespace scribo +{ + + namespace demo + { + + + crop_widget::crop_widget(QWidget *parent) + : QWidget(parent) + { + setupUi(this); + } + + + void crop_widget::load_image(const QPixmap& pixmap) + { + viewer_->draw_image(pixmap); + viewer_->set_selection_enabled(true); + } + + + const QRectF& crop_widget::crop_area() const + { + return viewer_->selection(); + } + + + QPixmap crop_widget::image() const + { + return viewer_->image().copy(crop_area().toRect()); + } + + } // end of namespace scribo::demo + +} // end of namespace scribo diff --git a/scribo/demo/wizard/src/crop_widget.hh b/scribo/demo/wizard/src/crop_widget.hh new file mode 100644 index 0000000..8d1f80b --- /dev/null +++ b/scribo/demo/wizard/src/crop_widget.hh @@ -0,0 +1,62 @@ +// Copyright (C) 2010 EPITA Research and Development Laboratory (LRDE) +// +// This file is part of Olena. +// +// Olena is free software: you can redistribute it and/or modify it under +// the terms of the GNU General Public License as published by the Free +// Software Foundation, version 2 of the License. +// +// Olena is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Olena. If not, see <http://www.gnu.org/licenses/>. +// +// As a special exception, you may use this file as part of a free +// software project without restriction. Specifically, if other files +// instantiate templates or use macros or inline functions from this +// file, or you compile this file and link it with other files to produce +// an executable, this file does not by itself cause the resulting +// executable to be covered by the GNU General Public License. This +// exception does not however invalidate any other reasons why the +// executable file might be covered by the GNU General Public License. + +#ifndef SCRIBO_DEMO_SHARED_SRC_CROP_WIDGET_HH +# define SCRIBO_DEMO_SHARED_SRC_CROP_WIDGET_HH + +# include <QtGui> +# include <ui_crop_widget.h> + +namespace scribo +{ + + namespace demo + { + + + class crop_widget : public QWidget, private Ui::CropWidget + { + Q_OBJECT; + + Q_PROPERTY(QRectF crop_area READ crop_area); + + public: + crop_widget(QWidget *parent = 0); + + void load_image(const QPixmap& pixmap); + + const QRectF& crop_area() const; + + QPixmap image() const; + + }; + + + } // end of namespace scribo::demo + +} // end of namespace scribo + + +#endif // ! SCRIBO_DEMO_SHARED_SRC_CROP_WIDGET_HH diff --git a/scribo/demo/wizard/src/doc_type.hh b/scribo/demo/wizard/src/doc_type.hh new file mode 100644 index 0000000..320cd19 --- /dev/null +++ b/scribo/demo/wizard/src/doc_type.hh @@ -0,0 +1,51 @@ +// Copyright (C) 2010 EPITA Research and Development Laboratory (LRDE) +// +// This file is part of Olena. +// +// Olena is free software: you can redistribute it and/or modify it under +// the terms of the GNU General Public License as published by the Free +// Software Foundation, version 2 of the License. +// +// Olena is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Olena. If not, see <http://www.gnu.org/licenses/>. +// +// As a special exception, you may use this file as part of a free +// software project without restriction. Specifically, if other files +// instantiate templates or use macros or inline functions from this +// file, or you compile this file and link it with other files to produce +// an executable, this file does not by itself cause the resulting +// executable to be covered by the GNU General Public License. This +// exception does not however invalidate any other reasons why the +// executable file might be covered by the GNU General Public License. + +#ifndef SCRIBO_DEMO_SHARED_SRC_DOC_TYPE_HH +# define SCRIBO_DEMO_SHARED_SRC_DOC_TYPE_HH + + +namespace scribo +{ + + namespace demo + { + + enum Doc_Type + { + Text_Doc, + Picture, + Mixed_Doc, + + Invalid_Doc + }; + + + } // end of namespace scribo::demo + +} // end of namespace scribo + + +#endif // !SCRIBO_DEMO_SHARED_SRC_DOC_TYPE_HH diff --git a/scribo/demo/wizard/src/doc_type_page.cc b/scribo/demo/wizard/src/doc_type_page.cc new file mode 100644 index 0000000..7245569 --- /dev/null +++ b/scribo/demo/wizard/src/doc_type_page.cc @@ -0,0 +1,48 @@ +#include <src/doc_type_page.hh> +#include <src/doc_type_widget.hh> + +namespace scribo +{ + + namespace demo + { + + + doc_type_page::doc_type_page(QWidget *parent) + : QWizardPage(parent) + { + widget_ = new doc_type_widget(this); + + QVBoxLayout *layout = new QVBoxLayout; + layout->addWidget(widget_); + setLayout(layout); + + setSubTitle("Please choose the document type."); + setTitle("Document type"); + + registerField("doc_type.type_mixed_doc", widget_, "type_mixed_doc", SIGNAL(toggled(bool))); + registerField("doc_type.type_picture", widget_, "type_picture", SIGNAL(toggled(bool))); + registerField("doc_type.type_text_doc", widget_, "type_text_doc", SIGNAL(toggled(bool))); + } + + + void doc_type_page::cleanupPage() + { + widget_->reset(); + } + + + void doc_type_page::initializePage() + { + } + + + bool doc_type_page::isComplete() + { + return true; + } + + + } // end of namespace scribo::demo + +} // end of namespace scribo diff --git a/scribo/demo/wizard/src/doc_type_page.hh b/scribo/demo/wizard/src/doc_type_page.hh new file mode 100644 index 0000000..f0d751b --- /dev/null +++ b/scribo/demo/wizard/src/doc_type_page.hh @@ -0,0 +1,61 @@ +// Copyright (C) 2010 EPITA Research and Development Laboratory (LRDE) +// +// This file is part of Olena. +// +// Olena is free software: you can redistribute it and/or modify it under +// the terms of the GNU General Public License as published by the Free +// Software Foundation, version 2 of the License. +// +// Olena is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Olena. If not, see <http://www.gnu.org/licenses/>. +// +// As a special exception, you may use this file as part of a free +// software project without restriction. Specifically, if other files +// instantiate templates or use macros or inline functions from this +// file, or you compile this file and link it with other files to produce +// an executable, this file does not by itself cause the resulting +// executable to be covered by the GNU General Public License. This +// exception does not however invalidate any other reasons why the +// executable file might be covered by the GNU General Public License. + +#ifndef SCRIBO_DEMO_SHARED_SRC_DOC_TYPE_PAGE_HH +# define SCRIBO_DEMO_SHARED_SRC_DOC_TYPE_PAGE_HH + +# include <QtGui> + +namespace scribo +{ + + namespace demo + { + + // Forward declaration. + class doc_type_widget; + + class doc_type_page : public QWizardPage + { + Q_OBJECT; + + public: + doc_type_page(QWidget *parent = 0); + + virtual void cleanupPage(); + virtual void initializePage(); + virtual bool isComplete(); + + private: + doc_type_widget *widget_; + }; + + + } // end of namespace scribo::demo + +} // end of namespace scribo + + +#endif // ! SCRIBO_DEMO_SHARED_SRC_DOC_TYPE_PAGE_HH diff --git a/scribo/demo/wizard/src/doc_type_widget.cc b/scribo/demo/wizard/src/doc_type_widget.cc new file mode 100644 index 0000000..c8453d4 --- /dev/null +++ b/scribo/demo/wizard/src/doc_type_widget.cc @@ -0,0 +1,38 @@ +#include <src/doc_type_widget.hh> + +namespace scribo +{ + + namespace demo + { + + + doc_type_widget::doc_type_widget(QWidget *parent) + : QWidget(parent) + { + setupUi(this); + } + + void doc_type_widget::reset() + { + type_text_doc_->setChecked(true); + } + + bool doc_type_widget::type_mixed_doc() const + { + return type_mixed_doc_->isChecked(); + } + + bool doc_type_widget::type_picture() const + { + return type_picture_->isChecked(); + } + + bool doc_type_widget::type_text_doc() const + { + return type_text_doc_->isChecked(); + } + + } // end of namespace scribo::demo + +} // end of namespace scribo diff --git a/scribo/demo/wizard/src/doc_type_widget.hh b/scribo/demo/wizard/src/doc_type_widget.hh new file mode 100644 index 0000000..ccd5324 --- /dev/null +++ b/scribo/demo/wizard/src/doc_type_widget.hh @@ -0,0 +1,64 @@ +// Copyright (C) 2010 EPITA Research and Development Laboratory (LRDE) +// +// This file is part of Olena. +// +// Olena is free software: you can redistribute it and/or modify it under +// the terms of the GNU General Public License as published by the Free +// Software Foundation, version 2 of the License. +// +// Olena is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Olena. If not, see <http://www.gnu.org/licenses/>. +// +// As a special exception, you may use this file as part of a free +// software project without restriction. Specifically, if other files +// instantiate templates or use macros or inline functions from this +// file, or you compile this file and link it with other files to produce +// an executable, this file does not by itself cause the resulting +// executable to be covered by the GNU General Public License. This +// exception does not however invalidate any other reasons why the +// executable file might be covered by the GNU General Public License. + +#ifndef SCRIBO_DEMO_SHARED_SRC_DOC_TYPE_WIDGET_HH +# define SCRIBO_DEMO_SHARED_SRC_DOC_TYPE_WIDGET_HH + +# include <QtGui> +# include <ui_doc_type_widget.h> + +namespace scribo +{ + + namespace demo + { + + + class doc_type_widget : public QWidget, private Ui::DocTypeWidget + { + Q_OBJECT; + + Q_PROPERTY(bool type_mixed_doc READ type_mixed_doc); + Q_PROPERTY(bool type_picture READ type_picture); + Q_PROPERTY(bool type_text_doc READ type_text_doc); + + public: + doc_type_widget(QWidget *parent = 0); + + void reset(); + + bool type_mixed_doc() const; + bool type_picture() const; + bool type_text_doc() const; + + }; + + + } // end of namespace scribo::demo + +} // end of namespace scribo + + +#endif // ! SCRIBO_DEMO_SHARED_SRC_DOC_TYPE_WIDGET_HH diff --git a/scribo/demo/wizard/src/load_page.cc b/scribo/demo/wizard/src/load_page.cc new file mode 100644 index 0000000..2d9ed43 --- /dev/null +++ b/scribo/demo/wizard/src/load_page.cc @@ -0,0 +1,70 @@ +#include <src/load_page.hh> + +namespace scribo +{ + + namespace demo + { + + + load_page::load_page(QWidget *parent) + : QWizardPage(parent) + { + widget_ = new load_widget(this); + + QStringList filters; + filters << tr("PNG image (*.png)") + << tr("JPEG image (*.jpg *.jpeg *.jpe)") + << tr("PNM image (*.pnm *.pbm *.pgm *.ppm)"); + widget_->setDialogFilter(filters); + + + QVBoxLayout *layout = new QVBoxLayout; + layout->addWidget(widget_); + setLayout(layout); + + setSubTitle("Choose a file to load"); + setTitle("Image loading"); + + registerField("load.file_path*", widget_, + "path", SIGNAL(path_updated())); + + registerField("load.must_crop", widget_, "must_crop"); + registerField("load.must_rotate", widget_, "must_rotate"); + + registerField("load.input_dsp", this, "input_dsp"); + + } + + + void load_page::cleanupPage() + { + widget_->reset(); + } + + + void load_page::initializePage() + { + } + + + bool load_page::validatePage() + { + input_dsp_ = QPixmap(widget_->path()); + return true; + } + + + const QPixmap& load_page::input_dsp() const + { + return input_dsp_; + } + + void load_page::set_input_dsp(const QPixmap& pixmap) + { + input_dsp_ = pixmap; + } + + } // end of namespace scribo::demo + +} // end of namespace scribo diff --git a/scribo/demo/wizard/src/load_page.hh b/scribo/demo/wizard/src/load_page.hh new file mode 100644 index 0000000..f3b5ec8 --- /dev/null +++ b/scribo/demo/wizard/src/load_page.hh @@ -0,0 +1,67 @@ +// Copyright (C) 2010 EPITA Research and Development Laboratory (LRDE) +// +// This file is part of Olena. +// +// Olena is free software: you can redistribute it and/or modify it under +// the terms of the GNU General Public License as published by the Free +// Software Foundation, version 2 of the License. +// +// Olena is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Olena. If not, see <http://www.gnu.org/licenses/>. +// +// As a special exception, you may use this file as part of a free +// software project without restriction. Specifically, if other files +// instantiate templates or use macros or inline functions from this +// file, or you compile this file and link it with other files to produce +// an executable, this file does not by itself cause the resulting +// executable to be covered by the GNU General Public License. This +// exception does not however invalidate any other reasons why the +// executable file might be covered by the GNU General Public License. + +#ifndef SCRIBO_DEMO_SHARED_SRC_LOAD_PAGE_HH +# define SCRIBO_DEMO_SHARED_SRC_LOAD_PAGE_HH + +# include <QtGui> +# include <src/load_widget.hh> + +namespace scribo +{ + + namespace demo + { + + + class load_page : public QWizardPage + { + Q_OBJECT; + + Q_PROPERTY(QPixmap input_dsp READ input_dsp WRITE set_input_dsp); + + public: + load_page(QWidget *parent = 0); + + virtual void cleanupPage(); + virtual void initializePage(); + virtual bool validatePage(); +// virtual bool isComplete(); + + const QPixmap& input_dsp() const; + void set_input_dsp(const QPixmap& pixmap); + + private: + load_widget *widget_; + QPixmap input_dsp_; + }; + + + } // end of namespace scribo::demo + +} // end of namespace scribo + + +#endif // ! SCRIBO_DEMO_SHARED_SRC_LOAD_PAGE_HH diff --git a/scribo/demo/wizard/src/load_widget.cc b/scribo/demo/wizard/src/load_widget.cc new file mode 100644 index 0000000..1f327af --- /dev/null +++ b/scribo/demo/wizard/src/load_widget.cc @@ -0,0 +1,56 @@ +#include <src/load_widget.hh> + +namespace scribo +{ + + namespace demo + { + + + load_widget::load_widget(QWidget *parent) + : browse_widget(parent) + { + QGroupBox *group_box = new QGroupBox(tr("Options"), this); + + QVBoxLayout *layout = new QVBoxLayout(group_box); + layout->setSizeConstraint(QLayout::SetMaximumSize); + must_crop_ = new QCheckBox(tr("Select a region of interest"), + group_box); + must_rotate_ = new QCheckBox(tr("Perform a manual rotation"), + group_box); + + layout->addWidget(must_crop_); + layout->addWidget(must_rotate_); + + + QSpacerItem* + vspacer = new QSpacerItem(20, 40, QSizePolicy::Minimum, + QSizePolicy::Expanding); + + gridLayout_2->addWidget(group_box, 2, 1); + gridLayout_2->addItem(vspacer, 3, 1, 1, 1); + + gridLayout_2->setSizeConstraint(QLayout::SetMaximumSize); + } + + void load_widget::reset() + { + browse_widget::reset(); + must_crop_->setChecked(false); + must_rotate_->setChecked(false); + } + + bool load_widget::must_crop() const + { + return must_crop_->isChecked(); + } + + bool load_widget::must_rotate() const + { + return must_rotate_->isChecked(); + } + + + } // end of namespace scribo::demo + +} // end of namespace scribo diff --git a/scribo/demo/wizard/src/load_widget.hh b/scribo/demo/wizard/src/load_widget.hh new file mode 100644 index 0000000..d7cf4e5 --- /dev/null +++ b/scribo/demo/wizard/src/load_widget.hh @@ -0,0 +1,64 @@ +// Copyright (C) 2010 EPITA Research and Development Laboratory (LRDE) +// +// This file is part of Olena. +// +// Olena is free software: you can redistribute it and/or modify it under +// the terms of the GNU General Public License as published by the Free +// Software Foundation, version 2 of the License. +// +// Olena is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Olena. If not, see <http://www.gnu.org/licenses/>. +// +// As a special exception, you may use this file as part of a free +// software project without restriction. Specifically, if other files +// instantiate templates or use macros or inline functions from this +// file, or you compile this file and link it with other files to produce +// an executable, this file does not by itself cause the resulting +// executable to be covered by the GNU General Public License. This +// exception does not however invalidate any other reasons why the +// executable file might be covered by the GNU General Public License. + +#ifndef SCRIBO_DEMO_SHARED_SRC_LOAD_WIDGET_HH +# define SCRIBO_DEMO_SHARED_SRC_LOAD_WIDGET_HH + +# include <QtGui> +# include <shared/src/browse_widget.hh> + +namespace scribo +{ + + namespace demo + { + + + class load_widget : public shared::browse_widget + { + Q_OBJECT; + + Q_PROPERTY(bool must_crop READ must_crop); + Q_PROPERTY(bool must_rotate READ must_rotate); + + public: + load_widget(QWidget *parent = 0); + void reset(); + + bool must_crop() const; + bool must_rotate() const; + + private: // attributes. + QCheckBox *must_crop_; + QCheckBox *must_rotate_; + }; + + + } // end of namespace scribo::demo + +} // end of namespace scribo + + +#endif // ! SCRIBO_DEMO_SHARED_SRC_LOAD_WIDGET_HH diff --git a/scribo/demo/wizard/src/main.cc b/scribo/demo/wizard/src/main.cc new file mode 100644 index 0000000..12f024a --- /dev/null +++ b/scribo/demo/wizard/src/main.cc @@ -0,0 +1,15 @@ +#include <QtGui> +#include <src/main_window.hh> +#include <src/preprocessing_task.hh> + +int main(int argc, char* argv[]) +{ + QApplication app(argc, argv); + + qRegisterMetaType<preprocessing_task_set_t>("preprocessing_task_set_t"); + + scribo::demo::wizard::main_window win; + win.show(); + + return app.exec(); +} diff --git a/scribo/demo/wizard/src/main_window.cc b/scribo/demo/wizard/src/main_window.cc new file mode 100644 index 0000000..35aa8c7 --- /dev/null +++ b/scribo/demo/wizard/src/main_window.cc @@ -0,0 +1,129 @@ +// Copyright (C) 2010 EPITA Research and Development Laboratory (LRDE) +// +// This file is part of Olena. +// +// Olena is free software: you can redistribute it and/or modify it under +// the terms of the GNU General Public License as published by the Free +// Software Foundation, version 2 of the License. +// +// Olena is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Olena. If not, see <http://www.gnu.org/licenses/>. +// +// As a special exception, you may use this file as part of a free +// software project without restriction. Specifically, if other files +// instantiate templates or use macros or inline functions from this +// file, or you compile this file and link it with other files to produce +// an executable, this file does not by itself cause the resulting +// executable to be covered by the GNU General Public License. This +// exception does not however invalidate any other reasons why the +// executable file might be covered by the GNU General Public License. + +#include <src/main_window.hh> + +#include <src/load_page.hh> +#include <src/doc_type_page.hh> +#include <src/crop_page.hh> +#include <src/preprocessing_page.hh> +#include <src/process_page.hh> +#include <src/rotate_page.hh> + +namespace scribo +{ + + namespace demo + { + + namespace wizard + { + + + main_window::main_window() + { + setOptions(QWizard::NoBackButtonOnStartPage + | QWizard::DisabledBackButtonOnLastPage + | QWizard::NoCancelButton); + + QPixmap bg_pixmap(":/images/images/dematerialization.png"); + setPixmap(QWizard::WatermarkPixmap, bg_pixmap); + setPixmap(QWizard::BackgroundPixmap, bg_pixmap); + + + // Page_Load + load_page* page_load = new load_page(this); + addPage(page_load); + + // Page_Task + doc_type_page* page_doc_type = new doc_type_page(this); + addPage(page_doc_type); + + // Page_Crop + crop_page* page_crop = new crop_page(this); + addPage(page_crop); + + // Page_Crop + rotate_page* page_rotate = new rotate_page(this); + addPage(page_rotate); + + // Page_Preprocessing + preprocessing_page* + page_preprocessing = new preprocessing_page(this); + addPage(page_preprocessing); + + // Page_Processing + addPage(new process_page(this)); + + // Page_Result + addPage(new QWizardPage(this)); + } + + + int main_window::nextId() const + { + switch (currentId()) + { + case Page_Load: + if (field("load.must_crop").toBool()) + return Page_Crop; + else if (field("load.must_rotate").toBool()) + return Page_Rotate; + else + return Page_Task; + + case Page_Crop: + if (field("load.must_rotate").toBool()) + return Page_Rotate; + else + return Page_Task; + + case Page_Rotate: + return Page_Task; + + case Page_Task: + return Page_Preprocessing; + + case Page_Preprocessing: + return Page_Process; + + case Page_Process: + return Page_Result; + + case Page_Result: + return -1; + + default: + qDebug() << "Warning: using default nextId() case."; + return currentId() + 1; + } + } + + + } // end of namespace scribo::demo::wizard + + } // end of namespace scribo::demo + +} // end of namespace scribo diff --git a/scribo/demo/wizard/src/main_window.hh b/scribo/demo/wizard/src/main_window.hh new file mode 100644 index 0000000..af4c113 --- /dev/null +++ b/scribo/demo/wizard/src/main_window.hh @@ -0,0 +1,70 @@ +// Copyright (C) 2010 EPITA Research and Development Laboratory (LRDE) +// +// This file is part of Olena. +// +// Olena is free software: you can redistribute it and/or modify it under +// the terms of the GNU General Public License as published by the Free +// Software Foundation, version 2 of the License. +// +// Olena is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Olena. If not, see <http://www.gnu.org/licenses/>. +// +// As a special exception, you may use this file as part of a free +// software project without restriction. Specifically, if other files +// instantiate templates or use macros or inline functions from this +// file, or you compile this file and link it with other files to produce +// an executable, this file does not by itself cause the resulting +// executable to be covered by the GNU General Public License. This +// exception does not however invalidate any other reasons why the +// executable file might be covered by the GNU General Public License. + +#ifndef SCRIBO_DEMO_WIZARD_SRC_MAIN_WINDOW_HH +# define SCRIBO_DEMO_WIZARD_SRC_MAIN_WINDOW_HH + +# include <QtGui/QWizard> +//# include <ui_main_window.h> + +namespace scribo +{ + + namespace demo + { + + namespace wizard + { + + + class main_window : public QWizard + { + Q_OBJECT; + + public: + main_window(); + + virtual int nextId() const; + + + private: + enum { Page_Load, + Page_Task, + Page_Crop, + Page_Rotate, + Page_Preprocessing, + Page_Process, + Page_Result }; + }; + + + } // end of namespace scribo::demo::wizard + + } // end of namespace scribo::demo + +} // end of namespace scribo + + +#endif // ! SCRIBO_DEMO_WIZARD_SRC_MAIN_WINDOW_HH diff --git a/scribo/demo/wizard/src/mln_widgets.cc b/scribo/demo/wizard/src/mln_widgets.cc new file mode 100644 index 0000000..621cc6f --- /dev/null +++ b/scribo/demo/wizard/src/mln_widgets.cc @@ -0,0 +1,7 @@ +#undef MLN_INCLUDE_ONLY + +// Widgets +#include <shared/src/image_viewer.cc> + +// Misc +#include <src/runner.cc> diff --git a/scribo/demo/wizard/src/preprocessing_page.cc b/scribo/demo/wizard/src/preprocessing_page.cc new file mode 100644 index 0000000..f727581 --- /dev/null +++ b/scribo/demo/wizard/src/preprocessing_page.cc @@ -0,0 +1,61 @@ +#include <src/preprocessing_page.hh> + +namespace scribo +{ + + namespace demo + { + + + preprocessing_page::preprocessing_page(QWidget *parent) + : QWizardPage(parent) + { + widget_ = new preprocessing_widget(this); + + QVBoxLayout *layout = new QVBoxLayout; + layout->addWidget(widget_); + setLayout(layout); + + setTitle("Preprocessing tasks"); + setSubTitle("Choose preprocessing algorithms."); + + registerField("preprocessing.tasks", this, "tasks"); + } + + + void preprocessing_page::cleanupPage() + { + widget_->reset(); + } + + + void preprocessing_page::initializePage() + { + if (field("doc_type.type_text_doc").toBool()) + widget_->setup_text_doc(); + else if (field("doc_type.type_mixed_doc").toBool()) + widget_->setup_mixed_doc(); + else if (field("doc_type.type_picture").toBool()) + widget_->setup_picture(); + else + qDebug() << "preprocessing_page - initializePage - invalid document type"; + } + + + const preprocessing_task_set_t& preprocessing_page::tasks() const + { + return tasks_; + } + + + bool preprocessing_page::validatePage() + { + tasks_ = widget_->tasks(); + return true; + } + + + + } // end of namespace scribo::demo + +} // end of namespace scribo diff --git a/scribo/demo/wizard/src/preprocessing_page.hh b/scribo/demo/wizard/src/preprocessing_page.hh new file mode 100644 index 0000000..1cfbea9 --- /dev/null +++ b/scribo/demo/wizard/src/preprocessing_page.hh @@ -0,0 +1,66 @@ +// Copyright (C) 2010 EPITA Research and Development Laboratory (LRDE) +// +// This file is part of Olena. +// +// Olena is free software: you can redistribute it and/or modify it under +// the terms of the GNU General Public License as published by the Free +// Software Foundation, version 2 of the License. +// +// Olena is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Olena. If not, see <http://www.gnu.org/licenses/>. +// +// As a special exception, you may use this file as part of a free +// software project without restriction. Specifically, if other files +// instantiate templates or use macros or inline functions from this +// file, or you compile this file and link it with other files to produce +// an executable, this file does not by itself cause the resulting +// executable to be covered by the GNU General Public License. This +// exception does not however invalidate any other reasons why the +// executable file might be covered by the GNU General Public License. + +#ifndef SCRIBO_DEMO_SHARED_SRC_PREPROCESSING_PAGE_HH +# define SCRIBO_DEMO_SHARED_SRC_PREPROCESSING_PAGE_HH + +# include <QtGui> +# include <src/preprocessing_widget.hh> +# include <src/preprocessing_task.hh> + +namespace scribo +{ + + namespace demo + { + + + class preprocessing_page : public QWizardPage + { + Q_OBJECT; + + Q_PROPERTY(preprocessing_task_set_t tasks READ tasks); + + public: + preprocessing_page(QWidget *parent = 0); + + virtual void cleanupPage(); + virtual void initializePage(); + virtual bool validatePage(); + + const preprocessing_task_set_t& tasks() const; + + private: + preprocessing_widget *widget_; + preprocessing_task_set_t tasks_; + }; + + + } // end of namespace scribo::demo + +} // end of namespace scribo + + +#endif // ! SCRIBO_DEMO_SHARED_SRC_PREPROCESSING_PAGE_HH diff --git a/scribo/demo/wizard/src/preprocessing_task.hh b/scribo/demo/wizard/src/preprocessing_task.hh new file mode 100644 index 0000000..5c335b7 --- /dev/null +++ b/scribo/demo/wizard/src/preprocessing_task.hh @@ -0,0 +1,61 @@ +// Copyright (C) 2010 EPITA Research and Development Laboratory (LRDE) +// +// This file is part of Olena. +// +// Olena is free software: you can redistribute it and/or modify it under +// the terms of the GNU General Public License as published by the Free +// Software Foundation, version 2 of the License. +// +// Olena is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Olena. If not, see <http://www.gnu.org/licenses/>. +// +// As a special exception, you may use this file as part of a free +// software project without restriction. Specifically, if other files +// instantiate templates or use macros or inline functions from this +// file, or you compile this file and link it with other files to produce +// an executable, this file does not by itself cause the resulting +// executable to be covered by the GNU General Public License. This +// exception does not however invalidate any other reasons why the +// executable file might be covered by the GNU General Public License. + +#ifndef SCRIBO_DEMO_SHARED_SRC_PREPROCESSING_TASK_HH +# define SCRIBO_DEMO_SHARED_SRC_PREPROCESSING_TASK_HH + +# include <QSet> + + +namespace scribo +{ + + namespace demo + { + + enum Preprocessing_Task + { + RemoveBg = 0, + Unskew, + RemoveNoise, + ImproveContrast, + ReduceSize, + + BinarizationSimple, + BinarizationSauvola, + BinarizationSauvolaMs, + + PREPROCESSING_TASK_COUNT // Invalid task. + }; + + + } // end of namespace scribo::demo + +} // end of namespace scribo + +typedef QSet<scribo::demo::Preprocessing_Task> preprocessing_task_set_t; +Q_DECLARE_METATYPE(preprocessing_task_set_t); + +#endif // !SCRIBO_DEMO_SHARED_SRC_PREPROCESSING_TASK_HH diff --git a/scribo/demo/wizard/src/preprocessing_widget.cc b/scribo/demo/wizard/src/preprocessing_widget.cc new file mode 100644 index 0000000..7a2c9fa --- /dev/null +++ b/scribo/demo/wizard/src/preprocessing_widget.cc @@ -0,0 +1,87 @@ +#include <src/preprocessing_widget.hh> + +namespace scribo +{ + + namespace demo + { + + + preprocessing_widget::preprocessing_widget(QWidget *parent) + : QWidget(parent) + { + setupUi(this); + } + + void preprocessing_widget::reset() + { + binarizationCBox->setCurrentIndex(2); // Sauvola ms + clear_checked(); + } + + void preprocessing_widget::setup_picture() + { + qDebug() << "setup picture"; + + removeBg->setChecked(true); + } + + void preprocessing_widget::setup_mixed_doc() + { + qDebug() << "setup mixed doc"; + } + + void preprocessing_widget::setup_text_doc() + { + qDebug() << "setup text doc"; + + removeBg->setChecked(true); + unskew->setChecked(true); + removeNoise->setChecked(true); + improveContrast->setChecked(true); + } + + + void preprocessing_widget::clear_checked() + { + removeBg->setChecked(false); + unskew->setChecked(false); + removeNoise->setChecked(false); + improveContrast->setChecked(false); + reduceSize->setChecked(false); + } + + + preprocessing_task_set_t preprocessing_widget::tasks() const + { + preprocessing_task_set_t tasks; + + if (removeBg->isChecked()) + tasks.insert(RemoveBg); + + if (unskew->isChecked()) + tasks.insert(Unskew); + + if (removeNoise->isChecked()) + tasks.insert(RemoveNoise); + + if (improveContrast->isChecked()) + tasks.insert(ImproveContrast); + + if (reduceSize->isChecked()) + tasks.insert(ReduceSize); + + if (binarizationCBox->currentIndex() == 0) + tasks.insert(BinarizationSimple); + else if (binarizationCBox->currentIndex() == 1) + tasks.insert(BinarizationSauvola); + else if (binarizationCBox->currentIndex() == 2) + tasks.insert(BinarizationSauvolaMs); + + return tasks; + } + + + } // end of namespace scribo::demo + +} // end of namespace scribo diff --git a/scribo/demo/wizard/src/preprocessing_widget.hh b/scribo/demo/wizard/src/preprocessing_widget.hh new file mode 100644 index 0000000..fff268d --- /dev/null +++ b/scribo/demo/wizard/src/preprocessing_widget.hh @@ -0,0 +1,65 @@ +// Copyright (C) 2010 EPITA Research and Development Laboratory (LRDE) +// +// This file is part of Olena. +// +// Olena is free software: you can redistribute it and/or modify it under +// the terms of the GNU General Public License as published by the Free +// Software Foundation, version 2 of the License. +// +// Olena is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Olena. If not, see <http://www.gnu.org/licenses/>. +// +// As a special exception, you may use this file as part of a free +// software project without restriction. Specifically, if other files +// instantiate templates or use macros or inline functions from this +// file, or you compile this file and link it with other files to produce +// an executable, this file does not by itself cause the resulting +// executable to be covered by the GNU General Public License. This +// exception does not however invalidate any other reasons why the +// executable file might be covered by the GNU General Public License. + +#ifndef SCRIBO_DEMO_SHARED_SRC_PREPROCESSING_WIDGET_HH +# define SCRIBO_DEMO_SHARED_SRC_PREPROCESSING_WIDGET_HH + +# include <QtGui> +# include <ui_preprocessing_widget.h> +# include <src/preprocessing_task.hh> + +namespace scribo +{ + + namespace demo + { + + + class preprocessing_widget : public QWidget, + private Ui::PreprocessingWidget + { + Q_OBJECT; + + public: + preprocessing_widget(QWidget *parent = 0); + void reset(); + + void setup_picture(); + void setup_mixed_doc(); + void setup_text_doc(); + + preprocessing_task_set_t tasks() const; + + private: // members + void clear_checked(); + }; + + + } // end of namespace scribo::demo + +} // end of namespace scribo + + +#endif // ! SCRIBO_DEMO_SHARED_SRC_PREPROCESSING_WIDGET_HH diff --git a/scribo/demo/wizard/src/process_page.cc b/scribo/demo/wizard/src/process_page.cc new file mode 100644 index 0000000..bbba0e3 --- /dev/null +++ b/scribo/demo/wizard/src/process_page.cc @@ -0,0 +1,73 @@ +#include <src/process_page.hh> +#include <src/process_widget.hh> +#include <src/preprocessing_task.hh> + + +namespace scribo +{ + + namespace demo + { + + + process_page::process_page(QWidget *parent) + : QWizardPage(parent) + { + widget_ = new process_widget(this); + QVBoxLayout *layout = new QVBoxLayout; + layout->addWidget(widget_); + setLayout(layout); + + setSubTitle("Processing..."); + setTitle("Please wait while computing results."); + + + void progress(unsigned i); + + void progress(unsigned i); + + connect(&runner_, SIGNAL(new_intermediate_result(const QImage&)), + widget_, SLOT(update_pixmap(const QImage&))); + + connect(&runner_, SIGNAL(new_progress_max_value(unsigned)), + widget_, SLOT(set_progress_max_value(unsigned))); + + connect(&runner_, SIGNAL(new_progress_label(const QString&)), + widget_, SLOT(update_progress_label(const QString&))); + + connect(&runner_, SIGNAL(progress(unsigned)), + widget_, SLOT(progress(unsigned))); + } + + + void process_page::cleanupPage() + { + widget_->reset(); + runner_.stop(); + } + + + void process_page::initializePage() + { + runner_.start(field("load.input_dsp").value<QPixmap>().toImage(), + get_doc_type(), + field("preprocessing.tasks").value<preprocessing_task_set_t>()); + } + + + Doc_Type process_page::get_doc_type() + { + if (field("doc_type.type_text_doc").toBool()) + return Text_Doc; + else if (field("doc_type.type_picture").toBool()) + return Picture; + else if (field("doc_type.type_mixed_doc").toBool()) + return Mixed_Doc; + + return Invalid_Doc; + } + + + } // end of namespace scribo::demo + +} // end of namespace scribo diff --git a/scribo/demo/wizard/src/process_page.hh b/scribo/demo/wizard/src/process_page.hh new file mode 100644 index 0000000..6425a53 --- /dev/null +++ b/scribo/demo/wizard/src/process_page.hh @@ -0,0 +1,64 @@ +// Copyright (C) 2010 EPITA Research and Development Laboratory (LRDE) +// +// This file is part of Olena. +// +// Olena is free software: you can redistribute it and/or modify it under +// the terms of the GNU General Public License as published by the Free +// Software Foundation, version 2 of the License. +// +// Olena is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Olena. If not, see <http://www.gnu.org/licenses/>. +// +// As a special exception, you may use this file as part of a free +// software project without restriction. Specifically, if other files +// instantiate templates or use macros or inline functions from this +// file, or you compile this file and link it with other files to produce +// an executable, this file does not by itself cause the resulting +// executable to be covered by the GNU General Public License. This +// exception does not however invalidate any other reasons why the +// executable file might be covered by the GNU General Public License. + +#ifndef SCRIBO_DEMO_SHARED_SRC_PROCESS_PAGE_HH +# define SCRIBO_DEMO_SHARED_SRC_PROCESS_PAGE_HH + +# include <QtGui> +# include <src/process_widget.hh> +# include <src/runner.hh> + +namespace scribo +{ + + namespace demo + { + + + class process_page : public QWizardPage + { + Q_OBJECT; + + public: + process_page(QWidget *parent = 0); + + virtual void cleanupPage(); + virtual void initializePage(); + + private: // members + Doc_Type get_doc_type(); + + private: // attributes + process_widget* widget_; + runner runner_; + }; + + + } // end of namespace scribo::demo + +} // end of namespace scribo + + +#endif // ! SCRIBO_DEMO_SHARED_SRC_PROCESS_PAGE_HH diff --git a/scribo/demo/wizard/src/process_widget.cc b/scribo/demo/wizard/src/process_widget.cc new file mode 100644 index 0000000..c0d652f --- /dev/null +++ b/scribo/demo/wizard/src/process_widget.cc @@ -0,0 +1,80 @@ +#include <src/process_widget.hh> + +namespace scribo +{ + + namespace demo + { + + + process_widget::process_widget(QWidget *parent) + : QWidget(parent) + { + view_ = new QGraphicsView(this); + QVBoxLayout *layout = new QVBoxLayout; + layout->addWidget(view_); + setLayout(layout); + + QVBoxLayout *progress_layout = new QVBoxLayout; + progress_bar_ = new QProgressBar(this); + progress_bar_->setMinimum(0); + progress_label_ = new QLabel("Processing..."); + progress_layout->addWidget(progress_bar_); + progress_layout->addWidget(progress_label_); + + progress_dialog_ = new QWidget(); + progress_dialog_->setLayout(progress_layout); + + view_->setScene(new QGraphicsScene()); + progress_ = view_->scene()->addWidget(progress_dialog_); + progress_->setZValue(1); + + image_ = view_->scene()->addPixmap(QPixmap()); + } + + void process_widget::reset() + { + progress_bar_->show(); + progress_bar_->setValue(0); + progress_bar_->setMaximum(0); + image_->setPixmap(QPixmap()); + } + + void process_widget::set_progress_max_value(unsigned max) + { + progress_bar_->setMaximum(max); + } + + void process_widget::update_pixmap(const QImage& image) + { + image_->setPixmap(QPixmap::fromImage(image)); + } + + void process_widget::progress(unsigned i) + { + progress_bar_->setValue(progress_bar_->value() + i); + + if (progress_bar_->value() == progress_bar_->maximum()) + progress_->hide(); + } + + void process_widget::update_progress_label(const QString& msg) + { + progress_label_->setText(msg); + } + + void process_widget::resizeEvent(QResizeEvent* event) + { + QPoint tmp(view_->geometry().center().x() + - progress_->boundingRect().width() / 2, + view_->geometry().center().y() + - progress_->boundingRect().height() / 2); + + progress_->setPos(view_->mapToScene(tmp)); + + event->ignore(); + } + + } // end of namespace scribo::demo + +} // end of namespace scribo diff --git a/scribo/demo/wizard/src/process_widget.hh b/scribo/demo/wizard/src/process_widget.hh new file mode 100644 index 0000000..8c0ed88 --- /dev/null +++ b/scribo/demo/wizard/src/process_widget.hh @@ -0,0 +1,71 @@ +// Copyright (C) 2010 EPITA Research and Development Laboratory (LRDE) +// +// This file is part of Olena. +// +// Olena is free software: you can redistribute it and/or modify it under +// the terms of the GNU General Public License as published by the Free +// Software Foundation, version 2 of the License. +// +// Olena is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Olena. If not, see <http://www.gnu.org/licenses/>. +// +// As a special exception, you may use this file as part of a free +// software project without restriction. Specifically, if other files +// instantiate templates or use macros or inline functions from this +// file, or you compile this file and link it with other files to produce +// an executable, this file does not by itself cause the resulting +// executable to be covered by the GNU General Public License. This +// exception does not however invalidate any other reasons why the +// executable file might be covered by the GNU General Public License. + +#ifndef SCRIBO_DEMO_SHARED_SRC_PROCESS_WIDGET_HH +# define SCRIBO_DEMO_SHARED_SRC_PROCESS_WIDGET_HH + +# include <QtGui> + +namespace scribo +{ + + namespace demo + { + + + class process_widget : public QWidget + { + Q_OBJECT; + + public: + process_widget(QWidget *parent = 0); + void reset(); + + public slots: + void set_progress_max_value(unsigned max); + void update_pixmap(const QImage& image); + void progress(unsigned i); + void update_progress_label(const QString& msg); + + virtual void resizeEvent(QResizeEvent* event); + + private: + QGraphicsView *view_; + QGraphicsPixmapItem *image_; + + QLabel *progress_label_; + QProgressBar* progress_bar_; + QWidget* progress_dialog_; + + QGraphicsProxyWidget* progress_; + }; + + + } // end of namespace scribo::demo + +} // end of namespace scribo + + +#endif // ! SCRIBO_DEMO_SHARED_SRC_PROCESS_WIDGET_HH diff --git a/scribo/demo/wizard/src/rotate_page.cc b/scribo/demo/wizard/src/rotate_page.cc new file mode 100644 index 0000000..9b17a5d --- /dev/null +++ b/scribo/demo/wizard/src/rotate_page.cc @@ -0,0 +1,45 @@ +#include <src/rotate_page.hh> + +namespace scribo +{ + + namespace demo + { + + + rotate_page::rotate_page(QWidget *parent) + : QWizardPage(parent) + { + widget_ = new rotate_widget(this); + + QVBoxLayout *layout = new QVBoxLayout; + layout->addWidget(widget_); + setLayout(layout); + + setTitle("Rotation."); + setSubTitle("Rotate the input image using the buttons above."); + + } + + + void rotate_page::cleanupPage() + { + } + + + void rotate_page::initializePage() + { + widget_->load_image(field("load.input_dsp").value<QPixmap>()); + } + + + bool rotate_page::isComplete() + { + setField("load.input_dsp", widget_->image()); + return true; + } + + + } // end of namespace scribo::demo + +} // end of namespace scribo diff --git a/scribo/demo/wizard/src/rotate_page.hh b/scribo/demo/wizard/src/rotate_page.hh new file mode 100644 index 0000000..21c2074 --- /dev/null +++ b/scribo/demo/wizard/src/rotate_page.hh @@ -0,0 +1,60 @@ +// Copyright (C) 2010 EPITA Research and Development Laboratory (LRDE) +// +// This file is part of Olena. +// +// Olena is free software: you can redistribute it and/or modify it under +// the terms of the GNU General Public License as published by the Free +// Software Foundation, version 2 of the License. +// +// Olena is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Olena. If not, see <http://www.gnu.org/licenses/>. +// +// As a special exception, you may use this file as part of a free +// software project without restriction. Specifically, if other files +// instantiate templates or use macros or inline functions from this +// file, or you compile this file and link it with other files to produce +// an executable, this file does not by itself cause the resulting +// executable to be covered by the GNU General Public License. This +// exception does not however invalidate any other reasons why the +// executable file might be covered by the GNU General Public License. + +#ifndef SCRIBO_DEMO_SHARED_SRC_ROTATE_PAGE_HH +# define SCRIBO_DEMO_SHARED_SRC_ROTATE_PAGE_HH + +# include <QtGui> +# include <src/rotate_widget.hh> + +namespace scribo +{ + + namespace demo + { + + + class rotate_page : public QWizardPage + { + Q_OBJECT; + + public: + rotate_page(QWidget *parent = 0); + + virtual void cleanupPage(); + virtual void initializePage(); + virtual bool isComplete(); + + private: + rotate_widget *widget_; + }; + + + } // end of namespace scribo::demo + +} // end of namespace scribo + + +#endif // ! SCRIBO_DEMO_SHARED_SRC_ROTATE_PAGE_HH diff --git a/scribo/demo/wizard/src/rotate_widget.cc b/scribo/demo/wizard/src/rotate_widget.cc new file mode 100644 index 0000000..41de670 --- /dev/null +++ b/scribo/demo/wizard/src/rotate_widget.cc @@ -0,0 +1,38 @@ +#include <src/rotate_widget.hh> + +namespace scribo +{ + + namespace demo + { + + + rotate_widget::rotate_widget(QWidget *parent) + : QWidget(parent) + { + setupUi(this); + } + + + void rotate_widget::load_image(const QPixmap& pixmap) + { + viewer_->draw_image(pixmap); + viewer_->set_rotation_enabled(true); + } + + + const QRectF& rotate_widget::rotate_area() const + { + return viewer_->selection(); + } + + + QPixmap rotate_widget::image() const + { + return viewer_->image(); + } + + + } // end of namespace scribo::demo + +} // end of namespace scribo diff --git a/scribo/demo/wizard/src/rotate_widget.hh b/scribo/demo/wizard/src/rotate_widget.hh new file mode 100644 index 0000000..8465f98 --- /dev/null +++ b/scribo/demo/wizard/src/rotate_widget.hh @@ -0,0 +1,62 @@ +// Copyright (C) 2010 EPITA Research and Development Laboratory (LRDE) +// +// This file is part of Olena. +// +// Olena is free software: you can redistribute it and/or modify it under +// the terms of the GNU General Public License as published by the Free +// Software Foundation, version 2 of the License. +// +// Olena is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Olena. If not, see <http://www.gnu.org/licenses/>. +// +// As a special exception, you may use this file as part of a free +// software project without restriction. Specifically, if other files +// instantiate templates or use macros or inline functions from this +// file, or you compile this file and link it with other files to produce +// an executable, this file does not by itself cause the resulting +// executable to be covered by the GNU General Public License. This +// exception does not however invalidate any other reasons why the +// executable file might be covered by the GNU General Public License. + +#ifndef SCRIBO_DEMO_SHARED_SRC_ROTATE_WIDGET_HH +# define SCRIBO_DEMO_SHARED_SRC_ROTATE_WIDGET_HH + +# include <QtGui> +# include <ui_rotate_widget.h> + +namespace scribo +{ + + namespace demo + { + + + class rotate_widget : public QWidget, private Ui::RotateWidget + { + Q_OBJECT; + + Q_PROPERTY(QRectF rotate_area READ rotate_area); + + public: + rotate_widget(QWidget *parent = 0); + + void load_image(const QPixmap& pixmap); + + const QRectF& rotate_area() const; + + QPixmap image() const; + + }; + + + } // end of namespace scribo::demo + +} // end of namespace scribo + + +#endif // ! SCRIBO_DEMO_SHARED_SRC_ROTATE_WIDGET_HH diff --git a/scribo/demo/wizard/src/runner.cc b/scribo/demo/wizard/src/runner.cc new file mode 100644 index 0000000..162f1cb --- /dev/null +++ b/scribo/demo/wizard/src/runner.cc @@ -0,0 +1,279 @@ +#include <src/runner.hh> + +#include <shared/src/to_mln_image.hh> +#include <src/preprocessing_task.hh> +#include <src/doc_type.hh> + +#include <mln/convert/to_qimage.hh> +#include <mln/convert/to_qimage_nocopy.hh> +#include <mln/fun/v2v/rgb_to_int_u.hh> +#include <mln/value/int_u8.hh> +#include <mln/data/convert.hh> +#include <mln/io/pbm/save.hh> + +#include <scribo/preprocessing/split_bg_fg.hh> +#include <scribo/preprocessing/denoise.hh> +#include <scribo/preprocessing/homogeneous_contrast.hh> +#include <scribo/preprocessing/unskew.hh> +#include <scribo/binarization/sauvola.hh> +#include <scribo/binarization/sauvola_ms.hh> +#include <scribo/binarization/simple.hh> + +#include <mln/logical/not.hh> + +namespace scribo +{ + + namespace demo + { + + QString basedir_ = "/home/lazzara/build/scribo/src"; + + runner::runner(QObject *parent) + : QThread(parent) + { + process_.moveToThread(this); + } + + + void runner::start(const QImage& input, + const Doc_Type& doc_type, + const preprocessing_task_set_t& tasks) + { + input_ = input; + doc_type_ = doc_type; + tasks_ = tasks; + + QThread::start(); + } + + + void runner::run() + { + // Notification of the number of tasks. + emit new_progress_max_value(tasks_.size() + 2); + + image2d<value::qt::rgb32> ima = load(); + + preprocess(ima); + + process(); + } + + + image2d<value::qt::rgb32> runner::load() + { + emit new_progress_label("Loading image"); + + // FIXME: specify the right top left corner. + // This is relevant when the image is cropped... + image2d<value::qt::rgb32> + output = shared::to_mln_image(input_, QPoint(0, 0)); + + QImage q_ima = convert::to_qimage_nocopy(output); + q_ima.save("/tmp/tmp.ppm"); + +// io::magick::load(output, filename_.toStdString()); + + emit progress(1); + emit new_intermediate_result(input_); + + return output; + } + + + void runner::preprocess(const image2d<value::qt::rgb32>& ima) + { + + image2d<value::rgb8> tmp_color; + io::ppm::load(tmp_color, "/tmp/tmp.ppm"); + + image2d<bool> out_bool; + + + //================== + // Remove background + //================== + if (tasks_.contains(RemoveBg)) + { + std::cout << "Foreground extraction" << std::endl; + emit new_progress_label("Foreground Extraction"); + + QStringList args; + args << "/tmp/tmp.ppm" << "10000" << "32" + << "/tmp/tmp.ppm" << "/dev/null"; + if (process_.execute(basedir_ + "/preprocessing/split_bg_fg", args)) + { + qDebug() << "Error running split_bg_fg"; + return; + } + + emit progress(1); + emit new_intermediate_result(mln::convert::to_qimage(tmp_color)); + } + + + //============================================= + // Convert to grayscale image (always happens). + //============================================= + emit new_progress_label("Convert to gray-scale image"); + image2d<value::int_u8> + intensity_ima = data::transform(tmp_color, + mln::fun::v2v::rgb_to_int_u<8>()); + emit progress(1); + + + //============================= + // Improve contrast homogeneity + //============================= + if (tasks_.contains(ImproveContrast)) + { + std::cout << "Improve contrast homogeneity" << std::endl; + emit new_progress_label("Improve contrast homogeneity"); + + intensity_ima = preprocessing::homogeneous_contrast(intensity_ima, 75); + + image2d<value::qt::rgb32> + tmp_color32 = data::convert(value::qt::rgb32(), out_bool); + emit new_intermediate_result(convert::to_qimage(tmp_color32)); + emit progress(1); + } + + + //============================== + // Binarization (always happens) + //============================== + emit new_progress_label("Binarization"); + + if (tasks_.contains(BinarizationSauvola)) + { + // FIXME: sauvola should not negate the image. + std::cout << "Binarization Sauvola" << std::endl; + out_bool = logical::not_(binarization::sauvola(intensity_ima)); + } + else if (tasks_.contains(BinarizationSauvolaMs)) + { + // FIXME: sauvola should not negate the image. + std::cout << "Binarization Sauvola_ms" << std::endl; + out_bool = logical::not_(binarization::sauvola_ms(intensity_ima, + 51, 2, 67)); + } + else if (tasks_.contains(BinarizationSimple)) + { + std::cout << "Binarization Simple" << std::endl; + out_bool = scribo::binarization::simple(intensity_ima); + } + else + { + std::cout << "Binary image conversion" << std::endl; + out_bool = data::convert(bool(), intensity_ima); + } + + image2d<value::qt::rgb32> + tmp_color32 = data::convert(value::qt::rgb32(), out_bool); + emit new_intermediate_result(convert::to_qimage(tmp_color32)); + emit progress(1); + + + //======== + // Denoise + //======== + if (tasks_.contains(RemoveNoise)) + { + std::cout << "Remove noise" << std::endl; + emit new_progress_label("Remove noise"); + + out_bool = preprocessing::denoise(out_bool, c8(), 2, 2); + + image2d<value::qt::rgb32> + tmp_color32 = data::convert(value::qt::rgb32(), out_bool); + emit new_intermediate_result(convert::to_qimage(tmp_color32)); + emit progress(1); + } + + + //======= + // Unskew + //======= + if (tasks_.contains(Unskew)) + { + std::cout << "Unskew" << std::endl; + emit new_progress_label("Unskew"); + + out_bool = scribo::preprocessing::unskew(out_bool).first(); + + image2d<value::qt::rgb32> + tmp_color32 = data::convert(value::qt::rgb32(), out_bool); + emit new_intermediate_result(convert::to_qimage(tmp_color32)); + emit progress(1); + } + + + //========================= + // Save preprocessed image. + //========================= + io::pbm::save(out_bool, "/tmp/tmp.pbm"); + } + + + void runner::process() + { + QStringList args; + + + // FIXME: require binaries to ask for a filename for bboxes + // output files. + switch(doc_type_) + { + case Text_Doc: + qDebug() << "Running text_in_article_pbm"; + args << "/tmp/tmp.pbm" << "/tmp/out.ppm"; + if (process_.execute(basedir_ + "/text_in_article_pbm", args)) + { + qDebug() << "Error while running text_in_article_pbm."; + return; + } + break; + + case Picture: + qDebug() << "Running text_in_photo_pbm_fast"; + args << "/tmp/tmp.pbm" << "/tmp/out.ppm" << "1" << "1" << "1"; + if (process_.execute(basedir_ + "/text_in_photo_pbm_fast", args)) + { + qDebug() << "Error while running text_in_photo_pbm_fast."; + return; + } + break; + + case Mixed_Doc: + qDebug() << "Running pbm_text_in_mixed_doc"; + if (process_.execute(basedir_ + "/pbm_text_in_mixed_doc", args)) + { + qDebug() << "Error while running pbm_text_in_mixed_doc."; + return; + } + break; + + default: + case Invalid_Doc: + qDebug() << "runner - Invalid doc type..."; + return; + } + + process_.waitForFinished(-1); + + emit progress(1); + emit new_intermediate_result(QImage("/tmp/out.ppm")); + qDebug() << "Done"; + } + + + void runner::stop() + { + process_.kill(); + terminate(); + } + + } // end of namespace scribo::demo + +} // end of namespace scribo diff --git a/scribo/demo/wizard/src/runner.hh b/scribo/demo/wizard/src/runner.hh new file mode 100644 index 0000000..4dcedc0 --- /dev/null +++ b/scribo/demo/wizard/src/runner.hh @@ -0,0 +1,84 @@ +// Copyright (C) 2010 EPITA Research and Development Laboratory (LRDE) +// +// This file is part of Olena. +// +// Olena is free software: you can redistribute it and/or modify it under +// the terms of the GNU General Public License as published by the Free +// Software Foundation, version 2 of the License. +// +// Olena is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Olena. If not, see <http://www.gnu.org/licenses/>. +// +// As a special exception, you may use this file as part of a free +// software project without restriction. Specifically, if other files +// instantiate templates or use macros or inline functions from this +// file, or you compile this file and link it with other files to produce +// an executable, this file does not by itself cause the resulting +// executable to be covered by the GNU General Public License. This +// exception does not however invalidate any other reasons why the +// executable file might be covered by the GNU General Public License. + +#ifndef SCRIBO_DEMO_SHARED_SRC_RUNNER_HH +# define SCRIBO_DEMO_SHARED_SRC_RUNNER_HH + +# include <QtGui> +# include <QProcess> + +# include <src/preprocessing_task.hh> +# include <src/doc_type.hh> + +# include <mln/core/image/image2d.hh> +# include <mln/value/qt/rgb32.hh> + +namespace scribo +{ + + namespace demo + { + + + class runner : public QThread + { + Q_OBJECT; + + public: + runner(QObject *parent = 0); + + void start(const QImage& input, + const Doc_Type& doc_type, + const preprocessing_task_set_t& tasks); + + void stop(); + + signals: + void new_intermediate_result(const QImage& ima); + void new_progress_max_value(unsigned i); + void new_progress_label(const QString& msg); + void progress(unsigned i); + + private: // members + mln::image2d<mln::value::qt::rgb32> load(); + void preprocess(const mln::image2d<mln::value::qt::rgb32>& ima); + void process(); + virtual void run(); + + private: // attributes + QProcess process_; + Doc_Type doc_type_; + QSet<Preprocessing_Task> tasks_; + QImage input_; + }; + + + + } // end of namespace scribo::demo + +} // end of namespace scribo + + +#endif // ! SCRIBO_DEMO_SHARED_SRC_RUNNER_HH diff --git a/scribo/demo/wizard/src/test.cc b/scribo/demo/wizard/src/test.cc new file mode 100644 index 0000000..3d95db6 --- /dev/null +++ b/scribo/demo/wizard/src/test.cc @@ -0,0 +1,16 @@ +#include <QtGui> +#include <shared/src/image_viewer.hh> +#include <shared/src/crop_item.hh> + +int main(int argc, char* argv[]) +{ + QApplication app(argc, argv); + + scribo::demo::shared::image_viewer win; + win.show(); + win.draw_image(QPixmap("image.jpg"), QPoint(0,0)); + + win.setSelectionEnabled(true); + + return app.exec(); +} diff --git a/scribo/demo/wizard/ui/doc_type_widget.ui b/scribo/demo/wizard/ui/doc_type_widget.ui new file mode 100644 index 0000000..39c8422 --- /dev/null +++ b/scribo/demo/wizard/ui/doc_type_widget.ui @@ -0,0 +1,115 @@ +<ui version="4.0" > + <class>DocTypeWidget</class> + <widget class="QWidget" name="DocTypeWidget" > + <property name="geometry" > + <rect> + <x>0</x> + <y>0</y> + <width>166</width> + <height>140</height> + </rect> + </property> + <property name="windowTitle" > + <string>Form</string> + </property> + <layout class="QVBoxLayout" name="verticalLayout" > + <property name="margin" > + <number>0</number> + </property> + <item> + <layout class="QGridLayout" name="gridLayout" > + <item row="0" column="1" > + <spacer name="verticalSpacer" > + <property name="orientation" > + <enum>Qt::Vertical</enum> + </property> + <property name="sizeHint" stdset="0" > + <size> + <width>20</width> + <height>40</height> + </size> + </property> + </spacer> + </item> + <item row="1" column="0" > + <spacer name="horizontalSpacer_2" > + <property name="orientation" > + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0" > + <size> + <width>40</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + <item row="1" column="1" > + <widget class="QGroupBox" name="groupBox" > + <property name="title" > + <string>Document type</string> + </property> + <layout class="QVBoxLayout" name="verticalLayout_3" > + <item> + <widget class="QRadioButton" name="type_text_doc_" > + <property name="text" > + <string>Text Document </string> + </property> + <property name="checked" > + <bool>true</bool> + </property> + </widget> + </item> + <item> + <widget class="QRadioButton" name="type_picture_" > + <property name="text" > + <string>Picture</string> + </property> + </widget> + </item> + <item> + <widget class="QRadioButton" name="type_mixed_doc_" > + <property name="enabled" > + <bool>false</bool> + </property> + <property name="text" > + <string>Mixed document</string> + </property> + </widget> + </item> + </layout> + </widget> + </item> + <item row="1" column="2" > + <spacer name="horizontalSpacer_3" > + <property name="orientation" > + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0" > + <size> + <width>40</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + <item row="2" column="1" > + <spacer name="verticalSpacer_2" > + <property name="orientation" > + <enum>Qt::Vertical</enum> + </property> + <property name="sizeHint" stdset="0" > + <size> + <width>20</width> + <height>40</height> + </size> + </property> + </spacer> + </item> + </layout> + </item> + </layout> + </widget> + <resources/> + <connections/> +</ui> diff --git a/scribo/demo/wizard/ui/load_widget.ui b/scribo/demo/wizard/ui/load_widget.ui new file mode 100644 index 0000000..db0dbc4 --- /dev/null +++ b/scribo/demo/wizard/ui/load_widget.ui @@ -0,0 +1,110 @@ +<ui version="4.0" > + <class>Form</class> + <widget class="QWidget" name="Form" > + <property name="geometry" > + <rect> + <x>0</x> + <y>0</y> + <width>400</width> + <height>300</height> + </rect> + </property> + <property name="windowTitle" > + <string>Form</string> + </property> + <layout class="QGridLayout" name="gridLayout" > + <item row="0" column="1" > + <spacer name="verticalSpacer" > + <property name="orientation" > + <enum>Qt::Vertical</enum> + </property> + <property name="sizeHint" stdset="0" > + <size> + <width>20</width> + <height>76</height> + </size> + </property> + </spacer> + </item> + <item row="1" column="0" > + <spacer name="horizontalSpacer" > + <property name="orientation" > + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0" > + <size> + <width>83</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + <item row="1" column="1" colspan="2" > + <layout class="QVBoxLayout" name="verticalLayout" > + <item> + <widget class="scribo::demo::shared::browse_widget" native="1" name="widget" /> + </item> + <item> + <widget class="QGroupBox" name="groupBox" > + <property name="title" > + <string>Options</string> + </property> + <layout class="QVBoxLayout" name="verticalLayout_2" > + <item> + <widget class="QCheckBox" name="checkBox" > + <property name="text" > + <string>Select a region of interest</string> + </property> + </widget> + </item> + <item> + <widget class="QCheckBox" name="checkBox_2" > + <property name="text" > + <string>Perform a manual rotation</string> + </property> + </widget> + </item> + </layout> + </widget> + </item> + </layout> + </item> + <item row="1" column="3" > + <spacer name="horizontalSpacer_2" > + <property name="orientation" > + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0" > + <size> + <width>83</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + <item row="2" column="1" > + <spacer name="verticalSpacer_2" > + <property name="orientation" > + <enum>Qt::Vertical</enum> + </property> + <property name="sizeHint" stdset="0" > + <size> + <width>20</width> + <height>76</height> + </size> + </property> + </spacer> + </item> + </layout> + </widget> + <customwidgets> + <customwidget> + <class>scribo::demo::shared::browse_widget</class> + <extends>QWidget</extends> + <header location="global" >shared/src/browse_widget.hh</header> + <container>1</container> + </customwidget> + </customwidgets> + <resources/> + <connections/> +</ui> diff --git a/scribo/demo/wizard/ui/main_window.ui b/scribo/demo/wizard/ui/main_window.ui new file mode 100644 index 0000000..0facd09 --- /dev/null +++ b/scribo/demo/wizard/ui/main_window.ui @@ -0,0 +1,216 @@ +<ui version="4.0" > + <class>MainWindow</class> + <widget class="QMainWindow" name="MainWindow" > + <property name="geometry" > + <rect> + <x>0</x> + <y>0</y> + <width>507</width> + <height>476</height> + </rect> + </property> + <property name="windowTitle" > + <string>MainWindow</string> + </property> + <widget class="QWidget" name="centralwidget" > + <layout class="QVBoxLayout" name="verticalLayout" > + <property name="margin" > + <number>0</number> + </property> + <item> + <widget class="QStackedWidget" name="stackedWidget" > + <property name="currentIndex" > + <number>0</number> + </property> + <widget class="QWidget" name="page_3" > + <layout class="QVBoxLayout" name="verticalLayout_2" > + <item> + <widget class="scribo::demo::shared::wizard_title_widget" native="1" name="title_0" > + <property name="sizePolicy" > + <sizepolicy vsizetype="Preferred" hsizetype="Preferred" > + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + </widget> + </item> + <item> + <widget class="scribo::demo::shared::browse_widget" native="1" name="widget_1" > + <property name="sizePolicy" > + <sizepolicy vsizetype="Expanding" hsizetype="Preferred" > + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + </widget> + </item> + </layout> + </widget> + <widget class="QWidget" name="page" > + <layout class="QVBoxLayout" name="verticalLayout_4" > + <item> + <widget class="scribo::demo::shared::wizard_title_widget" native="1" name="title_2" /> + </item> + <item> + <layout class="QGridLayout" name="gridLayout" > + <item row="0" column="1" > + <spacer name="verticalSpacer" > + <property name="orientation" > + <enum>Qt::Vertical</enum> + </property> + <property name="sizeHint" stdset="0" > + <size> + <width>20</width> + <height>40</height> + </size> + </property> + </spacer> + </item> + <item row="1" column="0" > + <spacer name="horizontalSpacer_2" > + <property name="orientation" > + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0" > + <size> + <width>40</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + <item row="1" column="1" > + <widget class="QGroupBox" name="groupBox" > + <property name="title" > + <string/> + </property> + <layout class="QVBoxLayout" name="verticalLayout_3" > + <item> + <widget class="QRadioButton" name="radioButton_4" > + <property name="text" > + <string>Extract all (Text, tables, images...)</string> + </property> + </widget> + </item> + <item> + <widget class="QRadioButton" name="radioButton" > + <property name="text" > + <string>Find text</string> + </property> + </widget> + </item> + <item> + <widget class="QRadioButton" name="radioButton_2" > + <property name="text" > + <string>Extract tables</string> + </property> + </widget> + </item> + <item> + <widget class="QRadioButton" name="radioButton_3" > + <property name="text" > + <string>Detect text</string> + </property> + </widget> + </item> + </layout> + </widget> + </item> + <item row="1" column="2" > + <spacer name="horizontalSpacer_3" > + <property name="orientation" > + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0" > + <size> + <width>40</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + <item row="2" column="1" > + <spacer name="verticalSpacer_2" > + <property name="orientation" > + <enum>Qt::Vertical</enum> + </property> + <property name="sizeHint" stdset="0" > + <size> + <width>20</width> + <height>40</height> + </size> + </property> + </spacer> + </item> + </layout> + </item> + </layout> + </widget> + <widget class="QWidget" name="page_2" /> + </widget> + </item> + <item> + <layout class="QHBoxLayout" name="horizontalLayout" > + <item> + <spacer name="horizontalSpacer" > + <property name="orientation" > + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0" > + <size> + <width>40</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + <item> + <widget class="QPushButton" name="prevBtn" > + <property name="enabled" > + <bool>false</bool> + </property> + <property name="text" > + <string>&Previous</string> + </property> + </widget> + </item> + <item> + <widget class="QPushButton" name="nextBtn" > + <property name="text" > + <string>&Next</string> + </property> + </widget> + </item> + </layout> + </item> + </layout> + </widget> + <widget class="QMenuBar" name="menubar" > + <property name="geometry" > + <rect> + <x>0</x> + <y>0</y> + <width>507</width> + <height>31</height> + </rect> + </property> + </widget> + <widget class="QStatusBar" name="statusbar" /> + </widget> + <customwidgets> + <customwidget> + <class>scribo::demo::shared::wizard_title_widget</class> + <extends>QWidget</extends> + <header location="global" >shared/src/wizard_title_widget.hh</header> + <container>1</container> + </customwidget> + <customwidget> + <class>scribo::demo::shared::browse_widget</class> + <extends>QWidget</extends> + <header location="global" >shared/src/browse_widget.hh</header> + <container>1</container> + </customwidget> + </customwidgets> + <resources/> + <connections/> +</ui> diff --git a/scribo/demo/wizard/ui/preprocessing_widget.ui b/scribo/demo/wizard/ui/preprocessing_widget.ui new file mode 100644 index 0000000..17225a8 --- /dev/null +++ b/scribo/demo/wizard/ui/preprocessing_widget.ui @@ -0,0 +1,223 @@ +<ui version="4.0" > + <class>PreprocessingWidget</class> + <widget class="QWidget" name="PreprocessingWidget" > + <property name="geometry" > + <rect> + <x>0</x> + <y>0</y> + <width>398</width> + <height>318</height> + </rect> + </property> + <property name="windowTitle" > + <string>Form</string> + </property> + <layout class="QGridLayout" name="gridLayout" > + <item row="0" column="1" > + <spacer name="verticalSpacer_2" > + <property name="orientation" > + <enum>Qt::Vertical</enum> + </property> + <property name="sizeHint" stdset="0" > + <size> + <width>20</width> + <height>1</height> + </size> + </property> + </spacer> + </item> + <item row="1" column="0" > + <spacer name="horizontalSpacer_2" > + <property name="orientation" > + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0" > + <size> + <width>1</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + <item row="1" column="1" > + <layout class="QVBoxLayout" name="verticalLayout_3" > + <item> + <widget class="QGroupBox" name="groupBox" > + <property name="title" > + <string>Preprocessing</string> + </property> + <layout class="QVBoxLayout" name="verticalLayout_2" > + <item> + <widget class="QCheckBox" name="removeBg" > + <property name="text" > + <string>Remove background (slow)</string> + </property> + <property name="checked" > + <bool>false</bool> + </property> + </widget> + </item> + <item> + <widget class="QCheckBox" name="unskew" > + <property name="text" > + <string>Unskew</string> + </property> + <property name="checked" > + <bool>false</bool> + </property> + </widget> + </item> + <item> + <widget class="QCheckBox" name="removeNoise" > + <property name="enabled" > + <bool>false</bool> + </property> + <property name="text" > + <string>Remove noise</string> + </property> + <property name="checked" > + <bool>false</bool> + </property> + </widget> + </item> + <item> + <widget class="QCheckBox" name="improveContrast" > + <property name="enabled" > + <bool>false</bool> + </property> + <property name="text" > + <string>Improve brightness/contrast</string> + </property> + <property name="checked" > + <bool>false</bool> + </property> + </widget> + </item> + <item> + <layout class="QHBoxLayout" name="horizontalLayout_2" > + <item> + <widget class="QCheckBox" name="reduceSize" > + <property name="text" > + <string>Reduce size by</string> + </property> + </widget> + </item> + <item> + <widget class="QSpinBox" name="spinBox" > + <property name="minimum" > + <number>2</number> + </property> + </widget> + </item> + </layout> + </item> + </layout> + </widget> + </item> + <item> + <spacer name="verticalSpacer" > + <property name="orientation" > + <enum>Qt::Vertical</enum> + </property> + <property name="sizeType" > + <enum>QSizePolicy::Fixed</enum> + </property> + <property name="sizeHint" stdset="0" > + <size> + <width>20</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + <item> + <widget class="QGroupBox" name="groupBox_2" > + <property name="title" > + <string>Advanced options</string> + </property> + <layout class="QVBoxLayout" name="verticalLayout" > + <item> + <layout class="QHBoxLayout" name="horizontalLayout" > + <item> + <widget class="QLabel" name="binarizeLbl" > + <property name="text" > + <string>Binarization method:</string> + </property> + </widget> + </item> + <item> + <spacer name="horizontalSpacer" > + <property name="orientation" > + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeType" > + <enum>QSizePolicy::Fixed</enum> + </property> + <property name="sizeHint" stdset="0" > + <size> + <width>40</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + <item> + <widget class="QComboBox" name="binarizationCBox" > + <property name="currentIndex" > + <number>2</number> + </property> + <item> + <property name="text" > + <string>Simple</string> + </property> + </item> + <item> + <property name="text" > + <string>Sauvola</string> + </property> + </item> + <item> + <property name="text" > + <string>Sauvola multi-scale</string> + </property> + </item> + </widget> + </item> + </layout> + </item> + </layout> + </widget> + </item> + </layout> + </item> + <item row="1" column="2" > + <spacer name="horizontalSpacer_3" > + <property name="orientation" > + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0" > + <size> + <width>1</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + <item row="2" column="1" > + <spacer name="verticalSpacer_3" > + <property name="orientation" > + <enum>Qt::Vertical</enum> + </property> + <property name="sizeHint" stdset="0" > + <size> + <width>20</width> + <height>2</height> + </size> + </property> + </spacer> + </item> + </layout> + </widget> + <resources/> + <connections/> +</ui> diff --git a/scribo/demo/wizard/wizard.pro b/scribo/demo/wizard/wizard.pro new file mode 100644 index 0000000..c7ab290 --- /dev/null +++ b/scribo/demo/wizard/wizard.pro @@ -0,0 +1,67 @@ +# -*- c++ -*- +###################################################################### +# Automatically generated by qmake (2.01a) Tue Feb 9 12:02:10 2010 +###################################################################### + +TEMPLATE = app +TARGET = +DEPENDPATH += . src +INCLUDEPATH += . ../ ../shared $(OLN)/milena $(OLN) + +DEFINES += NDEBUG MLN_INCLUDE_ONLY + +# Input +HEADERS += \ + ../shared/src/image_viewer.hh \ + ../shared/src/internal/interactive_scene.hh \ + ../shared/src/crop_item.hh \ + ../shared/src/browse_widget.hh \ + src/load_page.hh \ + src/load_widget.hh \ + src/doc_type_widget.hh \ + src/doc_type_page.hh \ + src/crop_widget.hh \ + src/crop_page.hh \ + src/rotate_widget.hh \ + src/rotate_page.hh \ + src/preprocessing_widget.hh \ + src/preprocessing_page.hh \ + src/process_page.hh \ + src/process_widget.hh \ + src/runner.hh \ + src/preprocessing_task.hh \ + src/doc_type.hh \ + src/main_window.hh + + +SOURCES += \ + ../shared/src/crop_item.cc \ + ../shared/src/internal/interactive_scene.cc \ + ../shared/src/browse_widget.cc \ + src/main.cc \ + src/main_window.cc \ + src/doc_type_widget.cc \ + src/doc_type_page.cc \ + src/load_page.cc \ + src/load_widget.cc \ + src/crop_widget.cc \ + src/crop_page.cc \ + src/rotate_widget.cc \ + src/rotate_page.cc \ + src/preprocessing_widget.cc \ + src/preprocessing_page.cc \ + src/process_page.cc \ + src/process_widget.cc \ + src/mln_widgets.cc + +FORMS += \ + ../shared/ui/browse_widget.ui \ + ../shared/ui/crop_widget.ui \ + ../shared/ui/rotate_widget.ui \ + ../shared/ui/image_viewer.ui \ + ui/preprocessing_widget.ui \ + ui/doc_type_widget.ui \ + ui/main_window.ui + + +RESOURCES += ../shared/shared.qrc wizard.qrc diff --git a/scribo/demo/wizard/wizard.qrc b/scribo/demo/wizard/wizard.qrc new file mode 100644 index 0000000..bd6b146 --- /dev/null +++ b/scribo/demo/wizard/wizard.qrc @@ -0,0 +1,5 @@ +<RCC> + <qresource prefix="images" > + <file>images/dematerialization.png</file> + </qresource> +</RCC> -- 1.5.6.5
participants (1)
-
Guillaume Lazzara