Re: patch for scrolling issue - LyXscrollpatch20130302.diff (1/1) - LyXscrollpatch20130421.diff (1/1) - LyXscrollpatch20130427.diff (1/1)
Le 09/05/2013 09:43, pdv a écrit : Yes, I'm available. I've posted another version as you might already have noticed. Unfortunately it seems that we will not have time to look at it seriously :( This stuff is complicated to get right... JMarc
Re: patch for scrolling issue - LyXscrollpatch20130302.diff (1/1) - LyXscrollpatch20130421.diff (1/1) - LyXscrollpatch20130427.diff (1/1) - LyXscrollpatch20130509.diff (1/1)
Le 09/05/2013 09:37, pdv a écrit : I've moved the code to GuiFontMetrics which is indeed much better. Solved also a remaining issue with smallcaps. Very good. Thanks. JMarc
Re: patch for scrolling issue - LyXscrollpatch20130302.diff (1/1) - LyXscrollpatch20130421.diff (1/1) - LyXscrollpatch20130427.diff (1/1)
In article <5186ae01.4080...@lyx.org>, Jean-Marc Lasgouttes wrote: > Le 05/05/13 20:36, pdv a écrit : > >> What exactly takes 17.4s? > > > > I suppose that's the time taken by GuiPainter::text(), but I don't know > > enough of the Instruments app and it's modules to give any more details. > > > > I've now monitored both functions with pmprof: > > ( I scroll through a document of mine starting from the top down to the > > same location with the down arrow key (line per line not page per page) ) > > A related question: will you be somewhat available during the coming > week? I'd like at the developers meeting (from Thursday to Sunday) to > start from your patch and apply it to master branch. We will probably > diverge significantly from what you propose but nevertheless it would be > useful to know whether there are times when you are available. The plan > is probably to set up a branch on git to work on. > > JMarc Yes, I'm available. I've posted another version as you might already have noticed.
Re: patch for scrolling issue - LyXscrollpatch20130302.diff (1/1) - LyXscrollpatch20130421.diff (1/1) - LyXscrollpatch20130427.diff (1/1) - LyXscrollpatch20130509.diff (1/1)
In article <517ee12b.4040...@lyx.org>, Jean-Marc Lasgouttes wrote: > Le 28/04/2013 13:06, pdv a écrit : > > OK, here is a new version. Let me know if you experience anymore > > problems. > > For the time being I've left the clean-up step of the map as it was, > > although I realize it's of limited value; when entering the same word > > multiple times, the partial words get included anyway; > > > > The map itself is still defined in the BufferView class, but as a shared > > static map. The reason for this is that when the user makes changes to > > the screen fonts, the map becomes useless and I think the best option is > > to clear it at that point. > > I've added the case LFUN_SCREEN_FONT_UPDATE: to BufferView::dispatch() > > and added a corresponding request in GuiApplication::dispatch(); > > You should move the code that computes text width to > GuiFontMetrics::width(docstring). This is the right place for storing a > map, that could be static if you want to keep your current solution or > just a member of the GuiFontMetrics object so that you do not have to > play tricks with font attributes. > > Moreover, if your mùap is in GuiFontMetrics it will be reset > automatically by the code in GuiApplication.cpp. > > This will be much easier in my opinion. > > > I noticed then that the map was cleared and rebuild twice ... > > ... because in GuiPreferences::dispatchParams() there is first a call > > dispatch(FuncRequest(LFUN_LYXRC_APPLY, ss.str())) > > later followed by > > dispatch(FuncRequest(LFUN_SCREEN_FONT_UPDATE)) > > but the first dispatch runs GuiReset() which also sends a > > LFUN_SCREEN_FONT_UPDATE. > > Therefore I've commented out the 2nd explicit LFUN_SCREEN_FONT_UPDATE > > request. > > Not sure about that, but things should become clearer once code is at > the right place. > > JMarc I've moved the code to GuiFontMetrics which is indeed much better. Solved also a remaining issue with smallcaps. begin 644 LyXscrollpatch20130509.diff M1G)O;2`W9#)C.3(W,S`W,C&5D('-M86QL8V%P'1-971R:6-S+F@@("`@("`@("`@("`@("`@("`@('P@(#$X("LK+0H@ M'1-971R:6-S+F-P<`II M;F1E>"`T93'1U=&EL M7!E(&-O;G-T('!I="D*(`EI;G0@=VED=&@@/2!M87A? M=VED=&A?("T@F4H*2D*(`D)"7!M+G)O=W,H*2YP=7-H7V)A8VLH4F]W M*"DI.PH@"0E2;W<@)B!R;W<@/2!P;2YR;W=S*"E;'1-971R:6-S.CIR961O4&%R86=R M87!H*'!I=%]T>7!E(&-O;G-T('!I="D*(`DO+R!U;F1E7!E(%1E>'1- M971R:6-S.CIR;W="7!E M('!OF4H*3L**PEI;G0@6]U="@I.PH@"D!`("TX-3,L-R`K.#7!E(%1E>'1- M971R:6-S.CIR;W="'1? M+3YP87)A9W)A<&AS*"D["B`)8F]O;"!C;VYS="!D7!E M*'!I="`K(#$I(#P@<&%R`HK"0DO+R!T:&%T)W,@;F5E9&5D('1O(&%V;VED(&9A;&QI;F<@;V9F M('1H92!R:6=H=`HK"0DO+R!I="!W:6QL(&)E(&-O"`K/2!T:&ES=VED=&@["BT)"6-H=6YK=VED=&@@ M*ST@=&AI5]P;W,@?'P@:2`A/2!B;V1Y7W!OPH@"0D)"0EP;VEN="`](&D["BT)"0D)96QS90HK M"0D)"0ER;W=W:61T:"`]('@@+2!T:&ES=VED=&@["BL)"0D)?2!E;'-E"B`) M"0D)"7!O:6YT(#T@:2`K(#$["BL)"0D)"7)O=W=I9'1H(#T@>#L*(`D)"7T* M(`D)"2\O(&5X:70@;VX@;&%S="!R96=I7!E(%1E>'1- M971R:6-S.CIR;W="2@I*2![ M"B`)"0D)<&]I;G0@/2!I("L@,3L**PD)"0ER;W=W:61T:"`]('@["B`)"0D) M8G)E86L["B`)"0E]"B`)"7T*+0HM"0EI;G-E="`]('!APHM"0D)"2\O(')E9VES=&5R(&)R M96%K<&]I;G0Z"BT)"0D)<&]I;G0@/2!I("L@,3L**PD)"BLC:68@8V%L8W5L M871E7W%T7V-H87)?=VED=&AS"BL)"6EF("@A9FDM/FES4FEG:'14;TQE9G0H M*2`F)B`H(6)O9'E?<&]S('Q\(&D@(3T@8F]D>5]P;W,I*2!["BL)"0DO+R!B M=69F97(@=&AE(&-H87)A8W1E<@HK"0D):68@*"%P87(N9V5T26YS970H:2D@ M)B8@(7!APHK"0D)"6EF("AP87(N9V5T26YS970H:2LQ*2!\?"!P M87(N:7-,:6YE4V5P87)A=&]R*&DK,2DI('L**PD)"0D)+R]X("L]('1E>'17 M:61T:"AD;V-S=')I;F#L**PD)"0E]"BL)"0E] M"BLC96YD:68**PD)"6EN"`\('=I9'1H*0HK"6EF M("AI(#T](&5N9"`F)B!X(#P@=VED=&@I('L*(`D)<&]I;G0@/2!E;F0["BL) M"7)O=W=I9'1H(#T@>#L**PE]"BL*(`H@"2\O(&UA;G5A;"!L86)E;',@8V%N M;F]T(&)E(&)R;VME;B!I;B!,851E6"X@0G5T('=E"B`)+R\@=V%N="!T;R!M M86ME(&]U5]P;W,@)B8@<&]I;G0@/"!B M;V1Y7W!O7!E(%1E>'1- M971R:6-S.CIG971#;VQU;6Y.96%R6"AP:71?='EP92!C;VYS="!P:70L"B`) M:6YT(&-O;G-T('AO(#T@;W)I9VEN7RYX7SL*(`EX("T]('AO.PH@"5!A7!E(%1E>'1-971R:6-S.CIG971# M;VQU;6Y.96%R6"AP:71?='EP92!C;VYS="!P:70L"B`)+R\@:6X@9G)E97-P M86-I;F<@<&%R86=R87!H7!E(%1E>'1-971R:6-S.CIG M971#;VQU;6Y.96%R6"AP:71?='EP92!C;VYS="!P:70L"B`)"71M<'@@*ST@ MPHK"0D)+R\@9FQU"`]('1M<'@["BL)"0DO+W1M<'@@ M*ST@=&5X=%=I9'1H*&1O8W-T49O;G0H<&ET+"!C*3L**PD)?0HK"0D**PD) M:68H:6YS971/5]P;W,@/B`P("8F(&,@/3T@8F]D>5]P;W,@+2`Q*2!["BL)"0D) M1F]N=$UE=')I8W,@8V]N'1? M+3YL86)E;$9O;G0H<&%R*2D["BL)"0D)=&UP>"`K/2!R;W5]P;W,@+2`Q*2D**R\O"0D)"0ET;7!X M("T]('-I;F=L95=I9'1H*'!I="P@8F]D>5]P;W,@+2`Q*3L**PD)"7T@96QS M92!["BL)"0D)=&UP>"`K/2!P;2YS:6YG;&57:61T:"AC+"!F;VYT*3L**PD) M"0EI9B`H<&%R+FES4V5P87)A=&]R*&,I("8F(&,@/CT@8F]D>5]P;W,I"BL) M"0D)"0D)"71M<'@@*ST@PHK"0D)"6QA M"`]('1M<'@["BL)"0D)=&UP>"`K/2!P;2YS:6YG;&57:61T:"AC M+"!F;VYT*3L**PD)"7T@96QS92!["BL)"0D)"`]('1M<'@["BL)"2\O=&UP>"`K/2!T97AT5VED=&@H9&]C#P] M=&UP>"`F)B!V8R$]"DO*'1M<'@@+2!L87-T7W1M<'@I*3L**PD):68@*&1V8SX] M,"`F)B!D=F,@/#T@;&%S=%]N;V,I('L@+R\@"`](&QA#L@ M+R\@8F5G:6YN:6YG(&]F('=O"`^('@@)B8@;F]C/C`I('L@+R]S=&5P(&9U"`K('1E>'17:61T M:"AD;V-S=')I;F"`K('1H949O;G1-971R:6-S*&9O;G0I+G=I M9'1H*&1O8W-T"`F)B!N;V,\;&%S=%]N;V,I('L@+R]S=&5P("AB M86-K*2!T
Re: patch for scrolling issue - LyXscrollpatch20130302.diff (1/1) - LyXscrollpatch20130421.diff (1/1) - LyXscrollpatch20130427.diff (1/1)
Le 05/05/13 20:36, pdv a écrit : What exactly takes 17.4s? I suppose that's the time taken by GuiPainter::text(), but I don't know enough of the Instruments app and it's modules to give any more details. I've now monitored both functions with pmprof: ( I scroll through a document of mine starting from the top down to the same location with the down arrow key (line per line not page per page) ) A related question: will you be somewhat available during the coming week? I'd like at the developers meeting (from Thursday to Sunday) to start from your patch and apply it to master branch. We will probably diverge significantly from what you propose but nevertheless it would be useful to know whether there are times when you are available. The plan is probably to set up a branch on git to work on. JMarc
Re: patch for scrolling issue - LyXscrollpatch20130302.diff (1/1) - LyXscrollpatch20130421.diff (1/1) - LyXscrollpatch20130427.diff (1/1)
In article <518166ab.5070...@lyx.org>, Jean-Marc Lasgouttes wrote: > Le 01/05/2013 20:55, pdv a écrit : > > There are 2 occurences of calculate_qt_char_width, in TextMetrics and in > > RowPainter. > > Yes, I toggled both. > > > and there is at least one change which is not enclosed by these > > conditionals: In TextMetrics I changed rowBreakPoint() to return the > > breakpoint as well as the width, so that the subsequent call to > > rowWidth() is not needed anymore. > > > > I'm still many revisions behind master; > > I'll catch-up and see what I obtain with pmprof. > > It would be surprising that playing catch-up is enough. > > > I've done some timing with Instruments and a testdocument; > > with calculate_qt_char_width=0 GuiPainter::text takes 17.4s > > with calculate_qt_char_width=1 GuiPainter::text takes 4.5s > > What exactly takes 17.4s? I suppose that's the time taken by GuiPainter::text(), but I don't know enough of the Instruments app and it's modules to give any more details. I've now monitored both functions with pmprof: ( I scroll through a document of mine starting from the top down to the same location with the down arrow key (line per line not page per page) ) calculate_qt_char_widths = 0 #pmprof# text: 0.04msec, count=1044047, total=45155.01msec calculate_qt_char_widths = 1 #pmprof# text: 0.05msec, count=427662, total=21348.83msec #pmprof# textmetrics_textwidth: 0.00msec, count=285813, total=563.34msec "text" is from GuiPainter::text() in both cases I inserted the macro at the start of the function. Qualitatively this agrees with the Instruments timings, although the gain in text() is smaller and the time in TextMetrics::textWidth() is larger but still negligible compared to the time in GuiPainter::text(). > > > the time taken by TextMetrics::textMetrics is then 137ms > > > > Was this scrolling problem not an "OS X" issue? > > Yes, but I do not have OS X at hand. It is nevertheless important to > test all platforms. > > JMarc
Re: patch for scrolling issue - LyXscrollpatch20130302.diff (1/1) - LyXscrollpatch20130421.diff (1/1) - LyXscrollpatch20130427.diff (1/1)
Le 01/05/2013 20:55, pdv a écrit : There are 2 occurences of calculate_qt_char_width, in TextMetrics and in RowPainter. Yes, I toggled both. and there is at least one change which is not enclosed by these conditionals: In TextMetrics I changed rowBreakPoint() to return the breakpoint as well as the width, so that the subsequent call to rowWidth() is not needed anymore. I'm still many revisions behind master; I'll catch-up and see what I obtain with pmprof. It would be surprising that playing catch-up is enough. I've done some timing with Instruments and a testdocument; with calculate_qt_char_width=0 GuiPainter::text takes 17.4s with calculate_qt_char_width=1 GuiPainter::text takes 4.5s What exactly takes 17.4s? the time taken by TextMetrics::textMetrics is then 137ms Was this scrolling problem not an "OS X" issue? Yes, but I do not have OS X at hand. It is nevertheless important to test all platforms. JMarc
Re: patch for scrolling issue - LyXscrollpatch20130302.diff (1/1) - LyXscrollpatch20130421.diff (1/1) - LyXscrollpatch20130427.diff (1/1)
In article <517fe428.8070...@lyx.org>, Jean-Marc Lasgouttes wrote: > Le 28/04/2013 13:06, pdv a écrit : > > OK, here is a new version. Let me know if you experience anymore > > problems. > > For the time being I've left the clean-up step of the map as it was, > > although I realize it's of limited value; when entering the same word > > multiple times, the partial words get included anyway; > > For now I only tried performance, and did not notice any problem. With > the attached patch I get the following numbers. > > The profiler only computes the time needed to recomputes the metrics. I > do not know what other parts should be intrumented, probably around > rowpainter. > > Experiment is to load the user's guide, go to top and press PageDown 40 > times. The numbers are in milliseconds, 3 runs for each case. > > My numbers are quite noisy actually, but it seems that the cost of > calculate_qt_char_width is non-negligible. OTOH, I do not understand why > calculate_qt_char_widths=0 does not give the same numbers as master? > Didn't you say that it should be equivalent? There are 2 occurences of calculate_qt_char_width, in TextMetrics and in RowPainter. and there is at least one change which is not enclosed by these conditionals: In TextMetrics I changed rowBreakPoint() to return the breakpoint as well as the width, so that the subsequent call to rowWidth() is not needed anymore. I'm still many revisions behind master; I'll catch-up and see what I obtain with pmprof. I've done some timing with Instruments and a testdocument; with calculate_qt_char_width=0 GuiPainter::text takes 17.4s with calculate_qt_char_width=1 GuiPainter::text takes 4.5s the time taken by TextMetrics::textMetrics is then 137ms Was this scrolling problem not an "OS X" issue? > > JMarc > > > Your patch with #define calculate_qt_char_widths 1 > > #pmprof# metrics: 4.43msec, count=49, total=216.90msec > > #pmprof# metrics: 4.23msec, count=49, total=207.36msec > > #pmprof# metrics: 4.49msec, count=49, total=219.83msec > > > Your patch with #define calculate_qt_char_widths 0 > > #pmprof# metrics: 3.05msec, count=49, total=149.61msec > > #pmprof# metrics: 2.81msec, count=50, total=140.57msec > > #pmprof# metrics: 2.74msec, count=50, total=136.93msec > > > Current master: > > #pmprof# metrics: 3.18msec, count=50, total=158.78msec > > #pmprof# metrics: 3.95msec, count=50, total=197.63msec > > #pmprof# metrics: 3.97msec, count=50, total=198.61msec > > > - > diff --git a/src/BufferView.cpp b/src/BufferView.cpp > index 10b5263..4af1b14 100644 > --- a/src/BufferView.cpp > +++ b/src/BufferView.cpp > @@ -78,6 +78,7 @@ > #include "support/lstrings.h" > #include "support/Package.h" > #include "support/types.h" > +#include "support/pmprof.h" > > #include > #include > @@ -2574,6 +2575,7 @@ bool BufferView::singleParUpdate() > > void BufferView::updateMetrics() > { > + PROFILE_THIS_BLOCK(metrics); > if (height_ == 0 || width_ == 0) > return; >
Re: patch for scrolling issue - LyXscrollpatch20130302.diff (1/1) - LyXscrollpatch20130421.diff (1/1) - LyXscrollpatch20130427.diff (1/1)
Le 28/04/2013 13:06, pdv a écrit : OK, here is a new version. Let me know if you experience anymore problems. For the time being I've left the clean-up step of the map as it was, although I realize it's of limited value; when entering the same word multiple times, the partial words get included anyway; For now I only tried performance, and did not notice any problem. With the attached patch I get the following numbers. The profiler only computes the time needed to recomputes the metrics. I do not know what other parts should be intrumented, probably around rowpainter. Experiment is to load the user's guide, go to top and press PageDown 40 times. The numbers are in milliseconds, 3 runs for each case. My numbers are quite noisy actually, but it seems that the cost of calculate_qt_char_width is non-negligible. OTOH, I do not understand why calculate_qt_char_widths=0 does not give the same numbers as master? Didn't you say that it should be equivalent? JMarc Your patch with #define calculate_qt_char_widths 1 #pmprof# metrics: 4.43msec, count=49, total=216.90msec #pmprof# metrics: 4.23msec, count=49, total=207.36msec #pmprof# metrics: 4.49msec, count=49, total=219.83msec Your patch with #define calculate_qt_char_widths 0 #pmprof# metrics: 3.05msec, count=49, total=149.61msec #pmprof# metrics: 2.81msec, count=50, total=140.57msec #pmprof# metrics: 2.74msec, count=50, total=136.93msec Current master: #pmprof# metrics: 3.18msec, count=50, total=158.78msec #pmprof# metrics: 3.95msec, count=50, total=197.63msec #pmprof# metrics: 3.97msec, count=50, total=198.61msec diff --git a/src/BufferView.cpp b/src/BufferView.cpp index 10b5263..4af1b14 100644 --- a/src/BufferView.cpp +++ b/src/BufferView.cpp @@ -78,6 +78,7 @@ #include "support/lstrings.h" #include "support/Package.h" #include "support/types.h" +#include "support/pmprof.h" #include #include @@ -2574,6 +2575,7 @@ bool BufferView::singleParUpdate() void BufferView::updateMetrics() { + PROFILE_THIS_BLOCK(metrics); if (height_ == 0 || width_ == 0) return;
Re: patch for scrolling issue - LyXscrollpatch20130302.diff (1/1) - LyXscrollpatch20130421.diff (1/1) - LyXscrollpatch20130427.diff (1/1)
Le 28/04/2013 13:06, pdv a écrit : OK, here is a new version. Let me know if you experience anymore problems. For the time being I've left the clean-up step of the map as it was, although I realize it's of limited value; when entering the same word multiple times, the partial words get included anyway; The map itself is still defined in the BufferView class, but as a shared static map. The reason for this is that when the user makes changes to the screen fonts, the map becomes useless and I think the best option is to clear it at that point. I've added the case LFUN_SCREEN_FONT_UPDATE: to BufferView::dispatch() and added a corresponding request in GuiApplication::dispatch(); You should move the code that computes text width to GuiFontMetrics::width(docstring). This is the right place for storing a map, that could be static if you want to keep your current solution or just a member of the GuiFontMetrics object so that you do not have to play tricks with font attributes. Moreover, if your mùap is in GuiFontMetrics it will be reset automatically by the code in GuiApplication.cpp. This will be much easier in my opinion. I noticed then that the map was cleared and rebuild twice ... ... because in GuiPreferences::dispatchParams() there is first a call dispatch(FuncRequest(LFUN_LYXRC_APPLY, ss.str())) later followed by dispatch(FuncRequest(LFUN_SCREEN_FONT_UPDATE)) but the first dispatch runs GuiReset() which also sends a LFUN_SCREEN_FONT_UPDATE. Therefore I've commented out the 2nd explicit LFUN_SCREEN_FONT_UPDATE request. Not sure about that, but things should become clearer once code is at the right place. JMarc
Re: patch for scrolling issue - LyXscrollpatch20130302.diff (1/1) - LyXscrollpatch20130421.diff (1/1) - LyXscrollpatch20130427.diff (1/1)
In article <5178e9fc.6040...@lyx.org>, Jean-Marc Lasgouttes wrote: > 24/04/2013 21:41, pdv: > >> Why do you add 0x61 to the values? > > > > That's just for easy reading when looking at what exactly gets written > > to the map; In this way the codes are a, b, c ... > > That makes sense. > > >> I do not think there is a need to have a map per document. A shared map > >> stored in TextLetrics should be OK (like singleWidth currently). > > > > I was worried that the map might grow out of proportion, e.g. when > > leaving the application open for a long time and since there are more > > words than characters this will be worse than for singleWidth. > > I would start with the simple solution and then worry about a more > complicated one. A shared map will take less total memory. If acces time > is bad, then it may be worth implementing qHash(docstring) (by aping the > QString version) and use a QHash. > > >>> When typing it's unavoidable to generate all partials of a word; these > >>> are removed again from the map so that only the final word remains; > >>> However nothing is done to remedy the reverse: when deleting a word > >>> character by character all partials will end-up in the map; > >> > >> Did you do some measurement to ensure that there is a gain of doing that? > > > > I don't think it makes so much difference in time. It was merely to > > avoid filling the map with useless entries, especially if a single map > > is used. > > My policy in these kind of situation is to implement the simple solution > and do optimization only when some measurement (profiling) proved that > there is a problem to solve. Remember Knuth quote: "Premature > optimization is the root of all evil (or at least most of it) in > programming." > > Do not hesitate to post patches as often as needed. While I do not have > time to look at the hard parts of the patch right now, I think we move > in the right direction. > > JMarc OK, here is a new version. Let me know if you experience anymore problems. For the time being I've left the clean-up step of the map as it was, although I realize it's of limited value; when entering the same word multiple times, the partial words get included anyway; The map itself is still defined in the BufferView class, but as a shared static map. The reason for this is that when the user makes changes to the screen fonts, the map becomes useless and I think the best option is to clear it at that point. I've added the case LFUN_SCREEN_FONT_UPDATE: to BufferView::dispatch() and added a corresponding request in GuiApplication::dispatch(); I noticed then that the map was cleared and rebuild twice ... ... because in GuiPreferences::dispatchParams() there is first a call dispatch(FuncRequest(LFUN_LYXRC_APPLY, ss.str())) later followed by dispatch(FuncRequest(LFUN_SCREEN_FONT_UPDATE)) but the first dispatch runs GuiReset() which also sends a LFUN_SCREEN_FONT_UPDATE. Therefore I've commented out the 2nd explicit LFUN_SCREEN_FONT_UPDATE request. Regards, P. De Visschere begin 644 LyXscrollpatch20130427.diff M9&EF9B`M+6=I="!A+W-R8R]"=69F97)6:65W+F-P<"!B+W-R8R]"=69F97)6 M:65W+F-P<`II;F1E>"`S86$R,#%B+BYD8S,W.6(P(#$P,#8T-`HM+2T@82]S M2!D969I;F5D(&EN;&EN90HK("H)=&AI'17:61T:"AD;V-S=')I;F<@8V]N7AEF4@ M/2`B(#P\('1E>'1?=VED=&A?+G-I>F4H*2`\/"`B+"!K97D@/2`B(#P\(&ME M>2`\/"!E;F1L.PHK?0HK("\O"B`*("\J*B!2971UPH@"0E#=7)S;W(@=&UP8W5R(#t...@8w5r.pid:69F M("TM9VET(&$O7!ER!C;&%S'17 M:61T:"@I"BL)+R\O(&9O2D@>R!R971U2P@:6YT(''1?=VED=&A?6VME>5T@/2!W.R!]"BL)=F]I9"!E'17:61T:"AD M;V-S=')I;F<@8V]N'1-971R:6-S.CIT97AT5VED=&@H*0HK"7-T871I8R!S=&0Z M.FUA<#QD;V-S=')I;F'1-971R:6-S+F-P<`II;F1E>"`X8C!F,V$Y+BXW8S4S9C%E(#$P M,#8T-`HM+2T@82]S2AP:71?='EP92!P:70L('!O7!E('!O'1-971R:6-S M.CIR961O4&%R86=R87!H*'!I=%]T>7!E(&-O;G-T('!I="D*('L*(`E087)A M9W)A<&@@)B!P87(@/2!T97AT7RT^9V5T4&%R*'!I="D["D!`("TT-C$L-R`K M-#8V+#$S($!`(&)O;VP@5&5X=$UE=')I8W,Z.G)E9&]087)A9W)A<&@H<&ET M7W1Y<&4@8V]N%]W:61T:%\@+2!R M:6=H=%]M87)G:6X[("\O("T@;&5F=$UAPH@"0E$:6UE;G-I;VX@9&EM.PHM"0EP;W-?='EP92!E M;F0@/2!R;W="7!E(')O=U]B<"`](')O M=T)R96%K4&]I;G0H=VED=&@L('!I="P@9FERF4H*2D*(`D)"2\O($EF('1H97)E(&ES(&UO'!A;F0@=&AE('1E>'0@=&\*(`D)"2\O('1H92!F=6QL(&%L;&]W M86)L92!W:61T:"X@5&AI"`]/2!P;2YR;W=S*"DN MF4H*2D*(`D)"7!M M+G)O=W,H*2YP=7-H7V)A8VLH4F]W*"DI.PI`0"`M-SDX+#$U("LX,3(L.#8@ M0$`@<')I=F%T93H*('T["B`*('T@+R\@86YO;B!N86UE'0@=VED=&@@=7-I M;F<@=&AE(%%T(&9U;F-T:6]N'17:61T M:"AD;V-S=')I;F<@PHK"6EN="!W:61T:"`](#`["BL):68@*',@/3T@(B(I M"BL)"7)E='5R;B!W:61T:#L**PD**PEI9B`H(6-A8VAE*2!["BL)"5%&;VYT M365T3L**PES=&%T:6,@:6YT(&QA7!E(&9I9%LT73L**PEF:61;,%T@/2!F;VYT+F9A;6EL>2@I("L@,'@P M,#8Q.PHK"69I9%LQ72`](&9O;G0N#`P-C$["BL)9FED M6S)=(#T@9F]N="YR96%L4VAA<&4H*2`K(#!X,#`V,3L**PEF:61;,UT@/2!F M;VYT+G-I>F4H*2`K(#!X,#`V,3L**PED;V-S=')I;F<@:V5Y(#T@9&]CPHK"0E11F]N=$UE=')I8W,@<69M(#T@449O;G1- M971R:6-S*&9R;VYT96YD.CIG971&;VYT*&9O;G0I*3L**PD)45-T'17:61T:"AK97DL('=I9'1H*3L**PD)+R]T97AT7W=I M9'1H7UMK97E=(#T@=VED=&@["BL)"0HK"0DO+R!C;&5A;BUU<"!I9B!T:&ES M(&ES(&$@9W)O=VEN9R!W;W)D"BL