diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000000..6ca9b133c7 --- /dev/null +++ b/.gitattributes @@ -0,0 +1 @@ +*.y4m binary diff --git a/Cargo.toml b/Cargo.toml index b67a31a21b..3a0b5c132c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -108,6 +108,7 @@ features = ["parallel"] signal-hook = { version = "0.1.9", optional = true } [dev-dependencies] +assert_cmd = "0.12" criterion = "0.3" pretty_assertions = "0.6" interpolate_name = "0.2.2" diff --git a/src/bin/rav1e.rs b/src/bin/rav1e.rs index c460dc5c51..8b9cd76622 100644 --- a/src/bin/rav1e.rs +++ b/src/bin/rav1e.rs @@ -95,15 +95,14 @@ impl Source { // Encode and write a frame. // Returns frame information in a `Result`. -// -// `Ok(None)` indicates that the encode is finished. fn process_frame( ctx: &mut Context, output_file: &mut dyn Muxer, source: &mut Source, pass1file: Option<&mut File>, pass2file: Option<&mut File>, buffer: &mut [u8], buf_pos: &mut usize, mut y4m_enc: Option<&mut y4m::Encoder<'_, Box>>, -) -> Result, CliError> { +) -> Result>, CliError> { let y4m_details = source.input.get_video_details(); + let mut frame_summaries = Vec::new(); let mut pass1file = pass1file; let mut pass2file = pass2file; // Submit first pass data to pass 2. @@ -143,60 +142,54 @@ fn process_frame( } } - loop { - let pkt_wrapped = ctx.receive_packet(); - match pkt_wrapped { - Ok(pkt) => { - output_file.write_frame( - pkt.input_frameno as u64, - pkt.data.as_ref(), - pkt.frame_type, - ); - if let (Some(ref mut y4m_enc_uw), Some(ref rec)) = - (y4m_enc.as_mut(), &pkt.rec) - { - write_y4m_frame(y4m_enc_uw, rec, y4m_details); - } - return Ok(Some(pkt.into())); - } - Err(EncoderStatus::NeedMoreData) => { - // Read another frame then try receive_packet again - source.read_frame(ctx, y4m_details); - continue; - } - Err(EncoderStatus::EnoughData) => { - unreachable!(); + let pkt_wrapped = ctx.receive_packet(); + match pkt_wrapped { + Ok(pkt) => { + output_file.write_frame( + pkt.input_frameno as u64, + pkt.data.as_ref(), + pkt.frame_type, + ); + if let (Some(ref mut y4m_enc_uw), Some(ref rec)) = + (y4m_enc.as_mut(), &pkt.rec) + { + write_y4m_frame(y4m_enc_uw, rec, y4m_details); } - Err(EncoderStatus::LimitReached) => { - if let Some(passfile) = pass1file.as_mut() { - if let Some(outbuf) = ctx.twopass_out() { - // The last block of data we get is the summary data that needs to go - // at the start of the pass file. - // Seek to the start so we can write it there. - passfile - .seek(std::io::SeekFrom::Start(0)) - .expect("Unable to seek in two-pass data file."); - passfile - .write_all(outbuf) - .expect("Unable to write to two-pass data file."); - } + frame_summaries.push(pkt.into()); + } + Err(EncoderStatus::NeedMoreData) => { + source.read_frame(ctx, y4m_details); + } + Err(EncoderStatus::EnoughData) => { + unreachable!(); + } + Err(EncoderStatus::LimitReached) => { + if let Some(passfile) = pass1file.as_mut() { + if let Some(outbuf) = ctx.twopass_out() { + // The last block of data we get is the summary data that needs to go + // at the start of the pass file. + // Seek to the start so we can write it there. + passfile + .seek(std::io::SeekFrom::Start(0)) + .expect("Unable to seek in two-pass data file."); + passfile + .write_all(outbuf) + .expect("Unable to write to two-pass data file."); } - // Indicate that we are finished with the encode - return Ok(None); - } - e @ Err(EncoderStatus::Failure) => { - let _ = e.map_err(|e| e.context("Failed to encode video"))?; - } - e @ Err(EncoderStatus::NotReady) => { - let _ = e.map_err(|e| { - e.context("Mismanaged handling of two-pass stats data") - })?; - } - Err(EncoderStatus::Encoded) => { - // Safely skip to the next attempt of receive_packet } + return Ok(None); + } + e @ Err(EncoderStatus::Failure) => { + let _ = e.map_err(|e| e.context("Failed to encode video"))?; } + e @ Err(EncoderStatus::NotReady) => { + let _ = e.map_err(|e| { + e.context("Mismanaged handling of two-pass stats data") + })?; + } + Err(EncoderStatus::Encoded) => {} } + Ok(Some(frame_summaries)) } fn do_encode( @@ -233,13 +226,15 @@ fn do_encode( y4m_enc.as_mut(), )? { if verbose != Verbose::Quiet { - progress.add_frame(frame_info.clone()); - if verbose == Verbose::Verbose { - info!("{} - {}", frame_info, progress); - } else { - // Print a one-line progress indicator that overrides itself with every update - eprint!("\r{} ", progress); - }; + for frame in frame_info { + progress.add_frame(frame.clone()); + if verbose == Verbose::Verbose { + info!("{} - {}", frame, progress); + } else { + // Print a one-line progress indicator that overrides itself with every update + eprint!("\r{} ", progress); + }; + } output.flush().unwrap(); } diff --git a/tests/.gitignore b/tests/.gitignore new file mode 100644 index 0000000000..2b23eb4c95 --- /dev/null +++ b/tests/.gitignore @@ -0,0 +1 @@ +!small_input.y4m diff --git a/tests/binary.rs b/tests/binary.rs new file mode 100644 index 0000000000..2843f7ff1f --- /dev/null +++ b/tests/binary.rs @@ -0,0 +1,93 @@ +#[cfg(feature = "binaries")] +mod binary { + use assert_cmd::Command; + use rand::distributions::Alphanumeric; + use rand::{thread_rng, Rng}; + use std::env::temp_dir; + use std::fs::File; + use std::io::Read; + use std::path::PathBuf; + + fn get_y4m_input() -> Vec { + let mut input = File::open(&format!( + "{}/tests/small_input.y4m", + env!("CARGO_MANIFEST_DIR") + )) + .unwrap(); + let mut data = Vec::new(); + input.read_to_end(&mut data).unwrap(); + data + } + + fn get_tempfile_path(extension: &str) -> PathBuf { + let mut path = temp_dir(); + let filename = + thread_rng().sample_iter(&Alphanumeric).take(12).collect::(); + path.push(format!("{}.{}", filename, extension)); + path + } + + #[test] + fn one_pass_qp_based() { + let mut cmd = Command::cargo_bin("rav1e").unwrap(); + let outfile = get_tempfile_path("ivf"); + + cmd + .arg("--quantizer") + .arg("100") + .arg("-o") + .arg(&outfile) + .arg("-") + .write_stdin(get_y4m_input()) + .assert() + .success(); + } + + #[test] + fn one_pass_bitrate_based() { + let mut cmd = Command::cargo_bin("rav1e").unwrap(); + let outfile = get_tempfile_path("ivf"); + + cmd + .arg("--bitrate") + .arg("1000") + .arg("-o") + .arg(&outfile) + .arg("-") + .write_stdin(get_y4m_input()) + .assert() + .success(); + } + + #[test] + fn two_pass_bitrate_based() { + let outfile = get_tempfile_path("ivf"); + let passfile = get_tempfile_path("pass"); + + let mut cmd1 = Command::cargo_bin("rav1e").unwrap(); + cmd1 + .arg("--bitrate") + .arg("1000") + .arg("-o") + .arg(&outfile) + .arg("--first-pass") + .arg(&passfile) + .arg("-") + .write_stdin(get_y4m_input()) + .assert() + .success(); + + let mut cmd2 = Command::cargo_bin("rav1e").unwrap(); + cmd2 + .arg("--bitrate") + .arg("1000") + .arg("-o") + .arg(&outfile) + .arg("--second-pass") + .arg(&passfile) + .arg("-") + .write_stdin(get_y4m_input()) + .assert() + .success(); + } +} diff --git a/tests/small_input.y4m b/tests/small_input.y4m new file mode 100644 index 0000000000..8ef439ed6f --- /dev/null +++ b/tests/small_input.y4m @@ -0,0 +1,7 @@ +YUV4MPEG2 W64 H64 F25:1 Ip A16:9 C420jpeg XYSCSS=420JPEG +FRAME +3-'0**.--Cz�nnI������������������������������ym��_C?5>;:F++,+?/,,0+'*'50)WDNW_gk���������������������������������WJ9342+//,0?,6B%&$%)-,<):<`IG_H��������������������������������aG==3A5(((&Kj8.5(&.+%5-T2HmHacDr�������������������������������_=;=T?*1+=%*A]<38)RQzKU���������������¿�����������������VL99**-,#9md@,9.L(4d�9&&%01wKO���������������������������������mL@-./?*/(=]U<178H!/J:D)'3,,[YVId�������������������������������h<42507RJ@B>0,(-4*,'+)/9F?��������������������������������lN8=B9,JB82*7\LD[&+7'0%%)(8_k{�������������������������������qD:KL4-/32@?70,+3D&,-()0./)*02g����������������������������������ajkP7.@5+0<)(-0:%,$&%(*:.(&<,Ab�����������������������������������R>C?Y8E7%%%-GH*'&%'()3+&''.Hn����������������������������������lDC]LDL|?(+,(B03%'*+&($$'*&*Ar�����������������������������������`fzlZ��T1@iOD99%'-)&)(&&''1(VzV]����������������������������������x]t�rTDR�]9..#$$%%()''*AF.hSBM|�������������������������������}GPFSWiaiLfvP8.$%$%&'(-&)p?]TfFy��������������������������������R=K4<2ZeA7^[.,%%&%&&&4(4`ABwlj���������������������������������LG:68AFP714A-%'%%%%&%%'./*$O~Ug���������������������������������tRQEbHDK82>6('+&'&%&8M-B2(;DY�XPz�������������¿�����������������q{iL8@UA/B0(A<+(&&$Cg;1(0=AAZNHz�������������¿�������������������o7,Mb<17+(F?)((%)24-*(/-/E]J������������������������������������j0I�~O=?H1=@*),>=-'-2+',:_bl������������������������������������~g���SmmoAPH@H.40#'6*34:O��{�����������������������������������������}[\q`jy9h:*'&&0(/<47\�������������������������������������������~OJdHE\(-)(&%%%+1,Bm��������������������������������������������OM]VSml(0(%3-&&&0+Xp���ܩ��������������������������������������xN<=EZo|'-.&S7+%&DHgX���sx��������������������������������������iH3-8=[k6::3:C#(+.EP>s��Ez��������������������������������������`JHK1+PXAf:./UBP77:7=z�t����ź����������¿������������������������{|61R{s~KP*<>D243U��kEvWk����������������������������������������tGGe���~_�K8.4S��n8Vi36we���������������������������������������^l�~c��`Q�F2/;V�]'S�v76_�������������¿�������������������������y��}��j_4@?0173��8N�O_87�������������������������������������������~}�ygHK;/3:.u~}MFZ/40@FRRSI*ikD14^\������������������������������������������`_TT6>AiA6_X;OWg=-6aRJVx���������������������������������������'*1;WJV��mDR?B=gLHF?����������¿����������������������������1-13\��^7)2Ge0��E66uLIU�����������¿����������������������������&'(*0_VRMEEMW4_^8m1;6L2190Q5kk�jDk�����������¿����������������������������)'0Gu@-/4),.4F.13r�tnr������������¿����������������������������*&(AO7174.&(E=(,:O`9Z�������������������������������������������(,*9?@7=()*-,,.@7Ib)q�������������������������������������������#QE1P[70'&)2.+1=5/9FM�������������������������������������������%1b6.==))*')+/3(,-,9L�ez����������������������������������������,8A<3/C1''&+,'++95%6_vn�����������������������������������������>>;911=-'(',6'&1M,7^_uu�����������������������������������������W>V1?5.+'(''()''UIz�Q5������������������������������������������+0S0X\*/0**'')&0����=*Y�����������������������������������������$)V69k+8?02*)-''PF^�W&]�����������������������������������������0,Y2-RF@/((*.+')JPMIo6J�����������������������������������������X�e*$+@/.&)((,#@�uAF�DSè���������������������������������������^ji?SaM-(&6;(23X��nU�[���z��������������������������������������K=Q5MKUK%-,7;00@��2N���W5h��������������������������������������#>(%$D`**.*'-1*T��H_UlpJQY|�������������������������������������0`4$.]p7(.-021=Ze�szw9�bq\��������������������������������������5i6%@LED'9fKD0*-(2-210-)+)31'LN\\j\q���������������������������������]M=223*-/+2V65=))'%*%+8&B;UNBaN��������������������������������ZC;:5A9('&'G_>*-,$'(%9)L44bM\[SZ������������¿�����������������aC@@D1,&)$-GH//(/(%05$(1MIOnNdoSo�������������������������������NOYPD1.1%(ITI*3.A%%2B35D0Y]q_Q�x�������������¿�����������������WT45*.+*%/okF/8-C(0D�I*(#44qR=���������������������������������xF@,0.@06-9PG;.6E8$*RhD-%.--]cR]W�������������������������������vA72703QTBBB0,'5]8&8K'8++,,(6@P4��������������������������������oR=5K;/;B5F?7;).MK7p8':'.%')(1N\|�������������������������������|I=PR4,.118D6,.**4*>-)0,1,(),2c����������������������������������ougT>/H;,-3(&,2L&3$)&'*40+&<,@n�����������������������������������X>BCQ=NE&&$*?F*/%%%*(53%%*,@P����������������������������������yG>cUHN�N+,;,A48(&')%()%'*&(Cq����������������¿�����������������vm�pb��b8>udG66%',-&(&%%(&++E�fi����������������������������������oZh�qVQH�n<00$%'&%'*''(-E&\[JFn��������������������������������BQDHGbkvKPph@,$$$%%'(*&([MQRi;_��������������������������������Y3JP.&%%%%&'%4++`PAdph���������������������������������[I<:.%%%%%%&'%))/80>�][���������������¿�����������������S\H^R?SB0?8+*4$&%$%+6+8:$.?\a`{����������������������������������zL68RG/<2'=H*(&%$9lB8,*hXG_����������������������������������w<)PoI350+:E+('%%/E9*&3.6;\@m�����������������������������������{|����«��������������������������������������V=4>P_q(.,#DE*'$;A\_z���|��������������������������������������oH7/42Le,,755D##%.C^Hr��Ge��������������������������������������u^Sb;)@a7Z=0.SA>@.>7/]�p���˾��������������������������������������C4GyNoK@*5GD<35:���K~{t�����������������������������������������SSc}��}�CqMA01=m��LJZ;1pi���������������������������������������nd�~[���M�[9-8S�h67|�=.Z{������������������������������������������~t��b7FG0223{�<@�][B2�������������������������������������������~���kP6D33=0j�~LAb@36Uz�����������¿����������������������������X��H4)R^L`l���������������������������������������/=4<>,<}�hAR7FG8UJrWXAbf����������������������������������������(*E6o�~h��@OP834df�\p4^�����������¿����������������������������+7B=9m�WBQF;035D:@ALq@3j����������������������������������������1/+B�s�jOQc7)+L�7*/^YID9_���������ÿ����������������������������5715p��g81:7P3h�Y3.oQCSk����������������������������������������&())-UdbQ=:@y5Wo>\>ceJLh����������������������������������������*''-4ZS9:DLG,84Q<[f}AQ�����������������������������������������*()9bc2,6,-0-@331]�}ykx�����������������������������������������*(&<_B,623''9L-)5GgLJ�������������������������������������������**$4<>:;/+)*.0-2<;p2M�������������������������������������������'6I.E]79,%(11)/?=29AG�Ǖ����������������������������������������$/_;3GH+')((+/3,+-.;B��t����������������������������������������&0EK4(>5*(')+(+,,8()Mruv����������������������������������������)9>.:-A5)'''8)&)L;,F_qm�����������������������������������������\?S962/.'((',)'&;d-/.)''&(''g���O-@�����������������������������������������&(>C-r8-<60/&,(&AZX��%?�����������������������������������������$OV"UE=9+**.-)'>NSKo;<�����������������������������������������Ppb.%-F?3'(((*'(h{I3�c4�����������������������������������������M��T5@J(*&+9(,2:��yS�dc����������������������������������������]LQLEnWZ()-:<.64��FC���|5]��������������������������������������)/5+(-PD'+.%23/1��jVtcpWo���������������������������������bLA527)+,*1dI/40--%*&+8#GFIRJ]`o�����������¿������������������V>;75<;)&&-DP;+'2$$%&2)@4+MN^J`J�������������������������������eGHDK7*&(%.HL--+0*&+2%-*ND:vI]nO[�������������������������������UKTP>0,4%&UYQ-21?%%+;),D9WaggV}q��������������������������������V]21+2,(((fjK1833))0nM40&9@i`2����������������������������������C?+1/=7@5:H;5,0P8(,G�S,%',.YlGqe��������������������������������I;2<01G[>DE42'0XH%%F6;2'./(;PU9j�������������������������������sVB0N=12=2AA5<+*8G/RX'7).&()(,FG{��������������������������������Q?VZ6*/001B9'.+.-+]3%5+0+&',-[}q��������������������������������}�gRC4KF/1-'%+2W,)'-)'*1/-'6/?z�����������������������������������^ACHIATV('&%9?,<$%%()39'%--9C�����������������������������������Q8f]PR�`2+K@A:<4%%''(-+&)&'Ag������������������������������������z�te��h@=sxF61&&(.''&#%('(/@�w����������������������������������dWZ~m[\GqxP71$&(*%'+'(&%;)IeSGb��������������������������������BODB=Ru|RBZqJ*$#$$%&)(&)AW@Mm9L}�������������������������������a>D258?d^74=F+$$%$%%'&.,%Q`BZkg~��������������������������������pKB>BK?F:/8<2$&&%&&&'%+-+CD6toV����������������������������������]cQYY9UL2;<,+=%&%%%&((-:&&3erbr������������������������������������T23OM164&3N&''%%.ZG59&7J=plEQ�����������������������������������C)O|\86552A+*'&&*UK/&3/>6TA[j�����������������������������������PI��`K^bL<>((*'*0/)++&-+;\X�����������������������������������������|emue^k*,*1N,**11*-5sszt�����������������������������������������dBaZNV-WD+.&$10*9>F<83M�k3-`\@QX����������������������������������������).*-1Svn[7.5|PDxTGFKsNPT����������������������������������������/''),BaH?IJS969OHKjd�EBy����������������������������������������5'&1AkI-35,;(:71;B���jj�����������������������������������������'*%6Z`+2/5((/J;)/Ai^Mv������������������������������������������(*%,A@:65.+(+:,*73kI/�������������������������������������������*,6/,<@+''%2-&(;I-2Umru����������������������������������������:EF<8004)()&/,'&3=6r~:h�����������������������������������������GCIP,T5,-(''&')%B�~�g42�����������������������������������������,&6J,iM)38,0&))'4k^��0.�����������������������������������������%"1h)FY0@5,.+-,'1OJUsG2h����������������������������������������6EGD&1GL8)('*+)$?mX2a~2}����������������������������������������Nq�e,*7/**'1))0(�Ł[e|H�����������������������������������������DeR_:okU3&)<<-65a�fHp���LSx�������������������������������������56;>,96X1(0&281&nޏ+h_�[KGh�������������������������������������(+H#$&iU',.'(&/0c��O�BYsT�Y�������������������������������������$Bg1&FTg/'2J:H/h�WgH��R�KF]�������Ŀ����������������������������8TR0Mb?D;�D9:��[ZA:i}������������������������������������zyz5;5=B`I��[*7{k^8+Gx��������������������������������������������������������������~~�����������������������������������������������������������}��~����������������������������}����������������������������������������������������������������}����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������~��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������}~}~|poojkjjjiihgffddbdej{}}}}y|{~~|{vstmjjkkjihgfeeccafx|}~~xx}~|}zvrrqkjjkkjjhgfeedcal{|}wr||~vx~ztslkjjkkjjhhfeedcbo}}|ywy|w|wz}}zvpkkjjkjjihgfedcbpzy}{y{}z{{}|~}tmlkjjkkjjhgfeecceq{|zz|{{~|~}wkkkkjkkjjigfeeccbjurktxt{~~~~~~yppkjjjkjjihfeedccdsuqqrnz~~~~~wvsrjjjjkjjihgfeecbi{{{tzx}~~~}|{vonlkjkkkjjhgfedccdns{v{}z~~~v{|ystlkjjkkkjhgfeecccbpun{yy~}{|}}yqmkkkjkkkjihfeedcccffftpszy~~}|xljkkkkkkkjihgfedcccddjxup}}}~~zqkllkkkkkkjihgfeecccddp}{r}{z{}xukokjkjkkkjihgfedcccddio{uutywzzppspkjjjkkjihhffedccdedepkplsu}upvrynkjjkkjihhffedcccdeefgppxz|zquv{skjjkkkjhggfedcccdeefgtqvuwvuuyzrnlkkkkjihfeeccccdeefg{xxupuxzvsuvljkkkjihgeedcbccdeeg~{tntx|{ywtynjkkkjhhfeedcbccdeeg}}upx{~svyuwnjkkkjihfeeccbccceeg}~xv|{|zxoqrkkkkkjihgeeccbbcceeg~}u{}~{|{rskjkkkkjihffeccbbcceeg~yyy}~}||{ulkkkkkjihffedbbbccdef~y{|~~}~|}tnlkkkkkihfedcbabbcdefxx{|~~~wptrkkklkkihfedcbaabcdef~yxx{}}~xpswkkkkkjihfedcbaabccdfws{x|~~}rrqrkkkkkjihfedcbaabbcdfzvyu|~||oqqmtmklkjigfedcbaaabcdf}y~t}|{zqrqrtokkkjhgfedcbaabccdfsu|wwxxroznsyokkkihfeedcbaaabcceFRAME +,%$+:(*'..{�eso����������������������������������tGA1;8./0+,8;.@2.')/(.++5]�lwVf���������������������������������dJB:2>**)(0eT.*;/0'+(.8%BPEUV\mh�����������¿������������������S8;6456)&'4FC1.&7'&$'*&9/.BHb>^Ky������������������������������iHRJO>*+'%2DT/,/94%'*%1/CG,oMWiUK�������������������������������]KKK:-*4'#YfV2047%'(;)$5?SVea[snk�������������������������������W_3/*51'*'X_N35;8(%'K<8<.=Ubo3����������������������������������D<-008j�I5+/%&*(&($%)('/E������������������������������������}YSOmedbS[pkG1#'(/('*&'&&.-6j`K[��������������������������������FIE>8@sX=AhM'$$%&%&)('(0R9Bo@Ad�������������������������������n@A619?RU346A($$$$$%''++&>m>\cbc���������������������������������NJ@FX=H@26=3&'&%%&%'&*3(CZ6[|\����������������������������������rdaWV6OS65@+*H$%%%%'%%(2+'(gpY|������������������������������������_01OU436',K$%'%$(>C.C'0CAmIM�����������������������������������N*N�mB;;C1=(+'&&'W_4--0C9LJPU�����������������������������������fP��nMnlaAM(*(&%*54+)).,1WTo���������������¿������������������������k`hm_i('*,A4.'/2()-Xeso�����������������������������������������tHU`FE+C6,=,$+4*59>Z�������������������������������������������|MU^TXj'Ki2)&%).)2;4?nͱ����������������������������������������lF?CIaj..4))%&%%./*\u���ַ��������������������������������������dE0-:B\1(.&'2)&%)23je��̳���������������¿����������������������O@C>..T&)/))Z.*%)HRd^���S�����������������������������������������vo03T*04<0A8#++2HC?u�oj������������������������������������������fDEe*H[3-6Y=T0<3AW�qn�������������������������������������������zXq|hknHB*>?B22:s��QIU8Y�����������������������������������������q�����oj�E308f�pF<~n'Dq~�����������������������������������������af��Vd}A10>\�T$~�OK6a����������������������������������������������hZ0D:128<��=KmWL2;�������������������������������������������u��nhDK80381ph�GTC#@B_������������������������������������������3w�m8A6>C?1LENQ[@+IUg�dz���������¿����������������������������4�wdTjtatT:yyV?{f=+3cXnu����������������������������������������)tb[T7AAm?;[E8TLL>;W^GHYn���������������������������������������E+/1>QJ[��eHSD8:Gj{{_OE�����������������������������������������((?G;~�vQv]B?@437YMSiW2R����������������������������������������'-85F?��PLQK2*1T\(-9`[=>@���������������������������������������,6-,f���BHOM/,7�}5/Mg@HR����������¾���������������������������14.17_��_7(5[m3�o?I7zTPM�����������¿���������������������������/'((*1`UNIFPJD6QT;qP�S<[����������������������������������������9*&+1N_;0:1F,39.G4z��qa�����������������������������������������-*&/Gu>-.4*)-;H+,7inZc������������������������������������������%+&(AO8282.'(@4)/5Vb%t������������������������������������������++,(8@@7>(),1*-0H7=N3i�������������¿���������������������������%$JI2P\9-'&(/..311,5MG�y����������������������������������������%%2e:.;>*)*'*+-0(+0*/X�kx����������¿���������������������������$,:C>4.E0'&&,/&).G5)Ee|e�����������¿���������������������������&8=<620<-()',4''/A+Q}MV�����������������������������������������:_8-,((''&*&*yl��A+o����������������������������������������40-T4Pd*/3,,(')',km��G)d����������������������������������������)%'O<2l/:>01,*-'(KCUy[+P����������������������������������������',)U9*NJA/'(*.*'+S`C>�BR����������������������������������������@\�o-$(<-/&+*'.%S��\O�HiВ��������������������������������������:ZohEPfV3'&5B,08J��XX���wIj�������������������������������������+T=M9DHNO%-*/>1+>��/Qk�yM?Z�������������������������������������,#:-$#>h*+.)''-,L��lleAuN|ex������������������������������������(*Z@$+WlD&+:6>5Bubn^p�ClBT�������������������������������������3*i@%5N;Q)=cU=;S�\@,�ȂOV0T}������������������������������������smm:246N�<:<4[Il��2(i�i@-;c|��������������������������������������������������������������~�����������������������������������������������������������~������������������������������}���������������������������������~������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������|~|~}qoojkjjjihhgffedbddj{}}}}w|z~~||vstnjjjkjihgfeedcafx|}~}wy}|~}zwsrqljjkkjjhgfeedcak{|}xq{{~xy}ysslkjjjkjjihfeedcbn}||yxz|v}vy~}zvpkjjkkkjihgfedcbnyx}|z{}|{z}|~}umlkkjkkjjigfeeccdpz{yx|z{~~|}}wkjkkjkkjjigfeeccbhsrkrwq{}~~~~~zookjjkkjjihgfedcccrwtqsoy~~~~xwstjjjjkkjihgfeecbhz{{vzz}~~~~|zwonlkjjkkjjhgfedccclq{v{}z~~~w{}ysumkjjkkkjhgfeecccbmukywx~~|{|}{sokkjjkkkjihgfedccceeesqs{x|~||ymjkkkkkkkjihgfedccccdiyvp||~~~|slkkkkkkkkjihgfeecccddm||v~|{{~xuknljkjkkkjjhgfeecccddglywwuzxz{snrpkjjjkkjihhffedccdeeemkomrt|wovryokjjkkjjhhffedcccdeffgoowy|zquuztljjkkjjhhgfedcccdeefgvpvuxxuux|snljkkkjigfeedcccdeeegzwwxptwyxttvnjkkkjihgfedcbccdeeg|vorw{|yvsyojkkkjihffedbbccceeg|~uow{~ut{txojkkkkihgeeccbccdeeg}~zt{z|ywqptlkkkkjihgeedbbbcceef}~vy}}|{|rsljkkkkjihffedcbbccdef~{yx|~||{zvlkkkkkjihffedcbbccdegyz{}~}}}}vnmkkkkkjhgeedbabbcdefzx{|~~~yrrtkkklkkjhfedcbaabccdf|zxw{}~~yprxlkkkkkihfedcbaabccefzu{x{~}~uqrskkkkkjihfedcbaabbcdfztyv{~||rorlsokkkjigfedcbaaabcdf~y~u{}{|sqqrspklkjigffecbaaabcdftt|wvyxunzoqyqkkkjhffedcbaaabcceFRAME +1$$&K-'(,0[wVhn�����������������������������������LF326..0-,EU,;4)&'1'.',.b�p|Zc���������������������������������aG?=4E,)''/]N2'A1.'.(-5*7OPZ^_mo�������������������������������S6::61/(''7M<*.'>+,'')$7+0H?a>RX\������������������������������nH[QOC*0)$7HZ5+6.S#%%&-26F'XPZ^^C�������������������������������gPDD8**0(!Rr\7161/('6+$,V��������������������������������mJ_kD/2>2*34%),CB,Ag/12*+%())@^i����������������������������������xJAACX4M0%%%.I6"DE'-/-/+&-+@|����������������������������������aDGWGCZw5(340B1+((+&'.4-)-;,Ny����������������������������������vBioi^�~L1OzTB1S,$%&*+;+&&'6G~�������������������������������������z^�jQF]�[6-F(&&(&*(%()'.K������������������������������������{OQHYVlgfKZw\4"&&.*'(%%&((--duR]��������������������������������MAG8:5bW=4UF&$&&)&%*)''(>=2mHAS�������������������������������~BB83:AHJ215?($$$$$%&')('1o=\]^M���������������������������������[PGFc@HK82A2),'%&%%'&'5'7h=Kxhs����������������������������������er_M6CU<1?+(D%&$%%'&%*+12(\|Qv������������������������������������i3.Sb;24.*?#%&%%&,5)B/(6Gd�SO�����������������������������������_-N�zLCHT4=%)'&%%Ji57).E?GZNJ��������������¿�������������������v`���UuotMZ'-(&%%8G4'*1.1LWU�����������������������������������������~QYlZY')(*.32'*1((+?Zgl�����������������������������������������xWMeJE*1-*A<&(4,30:T��{�����������������������������������������LI\PVs'@d9*'$'5&0?39c������������������������������������������wN:6CUZ3/Q4+(&%&,1.Ch�������������������¿����������������������iH3-43N;(('&&'%&'-)Wr���Ҟ��������������������������������������aNMX3+B**1*#L9*&%DEgY���cw����������������������������������������;4G$(+60?;#$(0HUAv��L������������������������������������������|MS`09O712W8G84<7:y~q��ž����������������������������������������dk�DBkF9(;DG552O��jFhHV�~���������������������������������������������nxApH>/0M�n8`w/6rh�����������������������������������������`j���Z�O5.=X�^)T�kC7U��������������������������������������������t��`4LB/154��Zth=etC3,\`n�����������������������������������������'q�XjPUSaE0]b;NQ`;1D`NER[���������������������������������������;9G7@:-@��mAS?@?:fc�T\<|����������������������������������������1-(A5u�}e��@JI622]X_`h3J�����������¿���������������������������()9E<;r�TEMJ8,1<^024Tg@9Av���������¿���������������������������9-.+F|z�bMQ_4)-f�<.:lFCMa����������¿���������������������������44417s��d9,6>h2u�ID-t]MPz����������¿���������������������������1****.Vc`O@DJf2R`6lMug7*'&).')+8>)4Zwi����������������������������������������$':@.;-@5)'('8)&)F/9k`M�����������������������������������������)TBP;65..(()''*($Oi}�T+U����������������������������������������3C/RE5h0./+)(&)'(\���f(>����������������������������������������/)':F*m?.>8//(+(&>IKvz,=����������������������������������������%$Aa"NL?9))(/,)'=[X0wX;����������������������������������������-Ifh5%)@=2'()&+'.��\C`?����������������������������������������3Oy�]4HR.*'*B-+9<��lR����Qg��������¿���������������������������#TUKQL��������¿���������������������������+-,7+&*RD(+-&*-20�ȞG�6sTdxb�������¿���������������������������/':N#$9rT(,10352Ygi�P�Gi�EWk�������¿���������������������������5!U`,)V>W)-Mg:F5��>7[ťPb3>{�������¿���������������������������`XRH&-68�^4F@FTT��C+G�{E73Qn�������¿�����������������������������������������������������~������������������������������������������������������������������������������������������}���������������������������������~������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������}~{~}spojjjjjjihgffedbcdiz}}~}v{x~~}|vrsnjjkkjihgfeedcbex|}~~vz}x~~{xurrmjjjkjjhgfeedcbj{|}~yr{z~zy|ysslkjjjkjjihgeedcbl|||yxz}v~ww}~yvqkjjjkjjihgfedcblxw}|{{}||x}}~}wnlkkjkkjjigfeecccnzzxv|yz~~|}}xlkkjjkkkjigfeeccbfqrkpwnz|~~~~~{omkjjjkjjihffedcccrxvrsrx~~~~zxtukjjjkkjjhgfeedcfxz{wzz}~~~~}ywpolkjjkkkjhgfeecccio{uz}|~~~yz}yrtnkjkkkkjhhfeecccbksiwuw~~}y{}{tplkjjkkkjihgfedcccdddqss}y{~||zojkkkkkkkjihgfeedcccehyxqzz~~~}umkkkkjkkkjjhgfeeccdddkz|y~}{{~ytlnmjjkkkkjjhhfeecccddfiux{v{yy{vnrokjjjkkjjhhffedccdeeejjqnrt{ynurypkjjkkjihhgfedcccdeefgpntx|{pvtyvljjkkkjihgfedcccdeefgwovuxyuuw}tnljkkkjihffedccccdeegzuwxrtvyxutvojkkkjihgfedcbcddeeg~|xpquz|zvsyqjkkkjihgfedcbbcdeeg|}wouz}xs}txqjklkkihgfedcbccceef}~|sy{|zwsoumjkkkkjhfeedbbbccdef~ww}}|z}rsnjkkkkjihgfedcbbccdef~|zx|~|}{zxmkkkkkjihgfedcbbccdef{y{}~}}}}xnmkkkkkjhfeeccaabcdef|x{}}~~~{tqtkkkkkkihgedcbaabccdf{zxw|}~~{pozmkkkkkihfedccaabccdf}wzyz~}~xqssmkkkkkihfedcbaaabcdf{rwwz~}}umslrpkkkkigfedcbaaabcce~z}wx~|}uprrsqkkkkigffeccbaabccfvu|xuzxwmxqoxtkkkjhgfedcbaaabbce \ No newline at end of file