
    {mjt                     l   S r SSKrSSKrSrSrSrSrSrSrSr	1 S	kr
1 S
krS rS rS rS rS rSrSrS r1 Skr0 SS_SS_SS_SS_SS_SS_SS _S!S"_S#S$_S%S&_S'S(_S)S*_S+S,_S-S._S/S0_S1S2_S3S4_S5S6S7S8S9S:S;S<S=S>S?S@SASBSCSD.Er\R,                  " SE5      rSF rSG rSH rSI rSJ rSK rSL rSM r\4SN jr SO r!g)Pu@  Матчинг плановых операций Финтабло с фактическими — ЕДИНЫЙ алгоритм.

Раньше матчеров было два: аккуратный каскад в report.py (для «ещё платить») и грубый
«статья + сумма ±5%» в plan_sync.find_retire, который по этому совпадению УДАЛЯЛ плановую
операцию. Грубый матчер мог погасить планку случайным платежом близкой суммы — обязательство
исчезало из прогноза. Теперь оба зовут этот модуль.

Каскад по контрагентам, каждый рубль факта тратится один раз:
  A. partnerId — если у планки проставлен контрагент (см. plan_sync): его факты в окне гасят
     планку, сумма НЕ критерий; недоплата → «оплачено X из Y». Кандидаты сортируются так,
     чтобы факты ТОЙ ЖЕ статьи шли первыми (у одного человека может быть и ЗП, и взнос).
  A2. ФИО из колонки «Контрагент» таблицы Оли (p['kontr']) — гасим ТОЛЬКО тройкой
     контрагент + СУММА + СТАТЬЯ. Такая планка из остальных шагов исключена (p['person']):
     раз человек известен, догадки по сумме или по единственной планке статьи запрещены —
     ложный матч прячет живой долг, а непогашенная планка просто видна в «просрочено».
  B. фамилия — из description планки берём фамилию/имя и ищем её ТОЛЬКО в ИМЕНИ КОНТРАГЕНТА
     факта (не в свободном тексте — там мусорные совпадения); сумма НЕ критерий.
  C. точная сумма — |факт−план| ≤ max(1% планки, 50 ₽); статья «Неразнесенное списание» —
     ДЖОКЕР (гасит любую статью планки), для прочих статья должна совпасть. Совпадения суммы
     мало: если описания называют разных людей, матч отклоняем (см. _name_conflict).
  C2. уникальная пара по статье — если в статье осталась РОВНО ОДНА непогашенная не-агрегатная
     планка, гасим её фактами той же статьи в окне (сумма не критерий, но санити [50%;150%]).
  D. агрегат — планка во множественном («Администраторы») гасится суммой ещё не использованных
     фактов той же статьи в окне; частичное покрытие → «оплачено X из Y».
Окно дат: факт мог пройти за 14 дней ДО срока планки (оплатили заранее) и не позже сегодня.
    N{Gz?g      I@   g      ?g      ?gffffff?>0      зп   бот   доп   енп   ндс   банк   вода   займ   счет   счёт
   взнос
   займу
   карта
   налог
   новый
   товар   аренда   взносы   кредит   налоги   оплата   платеж   платёж   прочее   прочие   сервис   услуга   услуги   аутсорс   возврат   выплата   договор   перевод   пожарка   процент   сервисы   интернет   комиссия   подписка   подписки   проценты   оборотный   банковское   зачисления   типография   бухгалтерия   водоотведение   хозяйственные>      команда   педагоги   педагогов   сотрудники   администраторыc                     U R                  S5      u  pn[        R                  " [        U5      [        U5      [        U5      5      $ )N.)splitdatetimedateint)sdmoys       /home/rasp/finsync/matching.py	parse_dmyrE   3   s1    wws|HA1HMM#a&#b'3q6$JJ    c                     [         R                  " SS[        U =(       d    S5      R                  5       5      R	                  5       R                  SS5      $ )Nz\s+  u   ёu   е)resubstrstriplowerreplacer@   s    rD   _normrQ   7   s<    66&#s17|1134::<DDT4PPrF   c                 T    [        [        R                  " S[        U 5      5      5      $ )Nu   [а-яa-z]+)setrJ   findallrQ   rP   s    rD   _tokensrU   ;   s    rzz.%(344rF   c                     [         R                  " SU =(       d    S5       H-  n[        U5      n[        U5      S:  d  M  U[        ;  d  M+  Us  $    g)u   Первое значимое слово описания (пропуская префиксы вроде «ЗП»/«Оплата»).   [А-Яа-яЁёA-Za-z]+rI      )rJ   rT   rQ   lenNON_NAMEdesctns      rD   _lead_tokenr_   ?   sB    ZZ2DJB?!Hq6Q;1H,H @ rF   c                     [         R                  " SU =(       d    S5       H0  n[        U5      n[        U5      S:  d  M  US;  d  M'  U[        ;   s  $    g)u   Планка агрегатная, если её первое слово — множественное (администраторы/педагоги/…).rW   rI   rX   >   r   r#   F)rJ   rT   rQ   rY   	AGG_WORDSr[   s      rD   _is_aggregaterb   H   sH    ZZ2DJB?!Hq6Q;1$>>	>! @ rF         c                     [        U 5      [        U5      p2U(       a  U(       a  US[         US[         :X  a  gU[        U5      ;  =(       a    U[        U 5      ;  $ )uH  Ведущие слова описаний называют РАЗНЫХ людей? Чистая функция.

Шаг C матчит по одной лишь сумме, и этого мало: 27.07.2026 планку «Саше Русманову за МК
ЩУКА» погасил факт «Сергею звукорежиссёру за хор в ПГ» — те же 5 000 в статье b2b-ивентов,
но это два человека и два события, и обязательство молча исчезло из прогноза.

Сравниваем по основе, потому что склонение меняет окончание: «Полине»/«Полина» — один
человек, «Саше»/«Сергею» — разные. Если имя одной стороны вообще встречается в тексте
другой — это тот же платёж, конфликта нет. Безымянные описания («Типография», «Счёт №…»)
ведущего слова не дают (см. NON_NAME) и матч не блокируют — поведение как раньше.

НЕ применяется к джокеру «Неразнесенное списание»: там описание — сырой текст из банка,
первое слово в нём случайное («Для зачисления на счет Харитонова…» → «для»), и проверка
рубила бы верные матчи. У джокера статья ничего не значит по определению, вся опора —
сумма и дата; здесь же статья УЖЕ совпала, и описание — единственная добавочная улика.

Блокировать матч безопаснее, чем ошибиться в другую сторону: непогашенная планка уедет
в «просрочено, не вижу оплаты», где её видно, а ложный матч прячет живой долг.
NF)r_   	NAME_STEMrU   )	plan_desc	fact_descabs       rD   _name_conflictrk   U   sO    ( y!;y#9qA:I!JY-7GI&&F1GI4F+FFrF   >      зао   нко   оао   ооо   пао   чопu   сашаu   александрu   шураu
   ксюшаu   ксенияu   воваu   владимирu   юраu   юрийu   сережаu   сергейu   стасu   станиславu
   настяu   анастасияu   оляu
   ольгаu   катяu   екатеринаu   машаu
   марияu   дашаu
   дарьяu   лешаu   алексейu   женяu   евгенийu   димаu   дмитрийu   мишаu   михаилu   пашаu
   павелu   петрu   николайu   анатолийu   татьянаu   светланаu
   софьяu   полинаu
   еленаu
   иринаu   аннаu   надежда   вераu   даниил
   алиса
   марта)u   петяu   коляu   толяu   таняu
   светаu   софаu   поляu   ленаu   ираu   аняu   надяrr   u   данилаrs   rt   u   (?:^|\s)[А-ЯЁA-Z]\.(?:\s|$)c                 ,    [         R                  X 5      $ )u]   Уменьшительное имя → полная форма. Чистая функция.)DIMINUTIVESget)words    rD   _canon_namery      s    ??4&&rF   c                    / n[         R                  " S[        U =(       d    S5      5       HO  n[        U5      n[	        U5      S:  d  M  U[
        ;  d  M+  U[        ;  d  M7  X1;  d  M>  UR                  U5        MQ     U$ )u.  Значимые слова имени ПО ПОРЯДКУ: без «СЗ»/«ИП», правовых форм и канцелярита.

Порядок сохраняем, потому что первое слово — обычно фамилия (см. _same_person).
Чистая функция.
rW   rI   rX   )rJ   rT   rL   rQ   rY   rZ   	ORG_WORDSappend)r@   outr]   r^   s       rD   _person_wordsr~      s`     CZZ2CRLA!Hq6Q;1H,)1CJJqM B JrF   c                    [         R                  [        U =(       d    S5      5      (       d,  [         R                  [        U=(       d    S5      5      (       a  g[        U 5      [        U5      p2[	        U5      S:  d  [	        U5      S:  a  gS nS n[	        U5      S:  =(       a:    [	        U5      S:  =(       a%    U" US   US   5      =(       a    U" US   US   5      nU" US   US   5      (       d  U(       d  g[        U5      SpU HK  n	U HB  n
[        U	5      S[         [        U
5      S[         :X  d  M+  UR                  U
5        US-  n  MI     MM     US:  $ )	u  Колонка «Контрагент» Оли и контрагент факта — один человек? Чистая функция.

Совпасть должна ФАМИЛИЯ (первое слово) и ещё хотя бы одно слово — имя или отчество.
Без фамилии проверка пропускала однофамильцев наоборот: «Кокорев Юрий Сергеевич» и
«Шапошников Юрий Сергеевич» дают два совпадения (имя + отчество), и гонорар одного
гасил обязательство перед другим. Одного имени тоже мало: «Александр» есть и у
Русманова, и у Булгакова. Сравниваем по основе — склонение меняет окончание, а
таблица и Финтабло пишут по-разному («Хохлова Ксения» / «Хохлова Ксения Игоревна»).
rI   F   c                 D   ^ [        U 5      m[        U4S jU 5       5      $ )Nc              3   \   >#    U  H!  nTS [          [        U5      S [          :H  v   M#     g 7fN)rf   ry   ).0ww1s     rD   	<genexpr>,_same_person.<locals>.hit.<locals>.<genexpr>   s'     OA2jy>[^JY%??s   ),)ry   any)rx   wordsr   s     @rD   hit_same_person.<locals>.hit   s    OOOOrF   c                 L    [        U 5      S [         [        U5      S [         :H  $ r   )ry   SURNAME_STEM)xrC   s     rD   
surname_eq _same_person.<locals>.surname_eq   s#    1~m|,A}0MMMrF      r   N)	_ANON_SURNAMEsearchrL   r~   rY   listry   rf   remove)kontrpartner_nameri   rj   r   r   swappedfreehitsr   rC   s              rD   _same_personr      s7    C,--1E1Ec,J\Z\F]1^1^|!<q
1vzSVaZPN !fqj]SVaZ]JqtQqT,B]zRSTURVXYZ[X\G]GqtQqT""g a!$A1~jy)[^JY-GGA		   19rF   c                     U R                  S5      UR                  S5      p2[        U5      =(       a"    [        U5      =(       a    [        X#5      (       + $ )uW  Планка знает своего человека, а факт — другого? Тогда матч по сумме запрещён.

«Оплата Олегу (кахон)» — это Козлов, и платёж Соловьевой на ту же сумму в тот же день
его не гасит: иначе живой долг молча исчезает из прогноза (та же логика, что _name_conflict,
но по надёжному источнику — колонке «Контрагент», а не по первому слову описания).
r   r   )rw   boolr   )pfr   pnames       rD   _kontr_conflictr      s<     55>155#85;I4;I|E/I+IIrF   c                 <    S[        U R                  S5      5      ;   $ )u   Статья-помойка «Неразнесенное списание» — джокер: гасит планку любой статьи.u   неразнесенcat)rQ   rw   )facts    rD   	_is_jokerr      s    !U488E?%;;;rF   c           
      r   U R                  S5      =(       d    SU R                  S5      U R                  S5      U R                  S5      UR                  U R                  S5      S5      [        U R                  S5      =(       d    S5      U R                  S5      U R                  S	5      =(       d    SS
S.	$ )N
externalIdrI   r>   	factMonth
categoryIdvaluer   	partnerIddescriptionF)	extr>   r   catIdr   r   r   r\   matchedrw   float)r]   catss     rD   plan_opr      s     55&,"EE&Mk0BUU<(!%%:Mr1R155>.Q/{+QUU=5I5OR rF   c                 ~   U R                  S5      U R                  S5      UR                  U R                  S5      S5      U R                  S5      [        U R                  S5      =(       d    S5      U R                  S5      U R                  S5      =(       d    SUR                  U R                  S5      S5      S	.$ )
Nr>   r   rI   r   r   r   r   r   )r>   r   r   r   r   r   r\   r   r   )r]   r   partnerss      rD   fact_opr      s    EE&MAEE,,?88AEE,/4155CU155>.Q/{+EE-(.B$LL{);R@B BrF   c                    ^^^^ U  HX  mSTS'   STS'   [        TR                  S5      5      TS'   [        TR                  S5      5      =(       a
    TS   (       + TS'   MZ     U Vs/ s H  n[        U[	        US	   5      S
9PM     nnU4S jmS n[        U S S9nU H  mTS   (       d*  TS   (       d   TS   (       d  TR                  S5      (       d  M9  [        U Vs/ s H9  o3S   S:  d  M  T" TU5      (       d  M  UR                  S5      TS   :X  d  M7  UPM;     snU4S jS9nU" TU5        TS   S:  d  M  STS'   M     U H  mTS   (       d   TS   (       d  TR                  S5      (       d  M/  [        U Vs/ s Hl  o3S   S:  d  M  T" TU5      (       d  M  US   TS   :X  d  M+  [        US	   TS	   -
  5      S::  d  ME  [        TS   UR                  S5      5      (       d  Mj  UPMn     snS S9nU(       d  M  SUS   S'   TS	   TS'   STS'   M     U H  mTS   (       d  TS   (       d
  TS   (       a  M#  [        TR                  S5      5      n[        U5      S:  a  MN  [        U Vs/ s H?  o3S   S:  d  M  T" TU5      (       d  M  U[        UR                  S5      5      ;   d  M=  UPMA     snU4S jS9nU" TU5        TS   S:  d  M  STS'   M     U GH  mTS   (       d  TS   (       d
  TS   (       a  M$  TS	   m[        [        T-  [        5      n	[        U Vs/ s H  o3S   S:  d  M  T" TU5      (       d  M  [        US	   T-
  5      U	::  d  M4  [        TU5      (       a  MG  US   TS   :w  a  [        U5      (       d  Me  O1[!        TR                  S5      UR                  S5      5      (       a  M  UPM     snU4S jS9nUSS  H  nSUS'   TTS'   STS'   M     GM     0 n
U  Hd  mTS   (       d  TS   (       d
  TS   (       a  M#  [#        UU4S jU 5       5      (       d  M@  U
R%                  TS   / 5      R'                  T5        Mf     [        U
S S9 H  n[        X   5      S:w  a  M  X   S   m[        U Vs/ s H@  o3S   S:  d  M  T" TU5      (       d  M  US   TS   :X  d  M+  [        TU5      (       a  M>  UPMB     snS  S9n[)        S! U 5       5      n[*        TS	   -  Us=::  a  [,        TS	   -  ::  d  O  M  U" TU5        TS   S:  d  M  STS'   M     U H|  mTS   (       a
  TS   (       a  M  [        U Vs/ s H-  o3S   S:  d  M  T" TU5      (       d  M  US   TS   :X  d  M+  UPM/     snS" S9nU" TU5        TS   TS	   S-
  :  d  Mw  STS'   M~     U  H  m[        STS	   TS   -
  5      TS#'   M     U $ s  snf s  snf s  snf s  snf s  snf s  snf s  snf )$u[  Гасит плановые операции фактическими каскадом A→B→C→C2→D. Чистая функция без сети.
Мутирует plan_ops: ставит o['matched'], o['paid'] (сколько погашено фактами),
o['aggregate'], o['due'] (сколько ещё платить = value − paid).g        paidFr   r\   	aggregater   personr   )	remainingc                    > [        U S   5      [        R                  " [        S9-
  nU[        US   5      s=:*  =(       a    T:*  $ s  $ )Nr>   days)rE   r=   	timedeltaMATCH_WINDOW_DAYS)r   r   lotodays      rD   	in_window match_cascade.<locals>.in_window   sD    qy!H$6$6<M$NNYqy)22U2222rF   c                     U S   U S   -
  nU H8  nUS::  a    g[        US   U5      nUS==   U-  ss'   U S==   U-  ss'   X$-  nM:     g)u   Списывает остатки фактов elig на покрытие планки p (в порядке elig, дробя факт).r   r   ư>r   N)min)r   eligneedr   takes        rD   consumematch_cascade.<locals>.consume  s[    zAfI%At|q~t,DkNd"NfIILD rF   c                 Z    [        U S   5      U S   U R                  S5      =(       d    S4$ )Nr>   r   r\   rI   )rE   rw   os    rD   <lambda>match_cascade.<locals>.<lambda>  s+    Iai4H!G*VWV[V[\bVcVigi3jrF   keyr   r   r   c                 >   > U S   TS   :g  [        U S   5      U S   4$ Nr   r>   r   rE   r   r   s    rD   r   r     )    QwZ1W:%=y6?SUVW^U_$`rF   Tr   r   r   c                     [        U S   5      $ Nr>   r   r   s    rD   r   r   +  s    Iai$8rF   r   rX   c                 >   > U S   TS   :g  [        U S   5      U S   4$ r   r   r   s    rD   r   r   :  r   rF   c                 B   > [        U S   5      [        U S   T-
  5      4$ Nr>   r   )rE   abs)r   pvs    rD   r   r   J  s     Yqy%93qzB;O$PrF   Nr   c              3   v   >#    U  H.  oS    S:  =(       a    T" TU5      =(       a    US   TS   :H  v   M0     g7f)r   r   r   N )r   r   r   r   s     rD   r    match_cascade.<locals>.<genexpr>W  s;     e_dZ[~$U1aUQwZ1W:=UU_ds   69c                     U =(       d    S$ )Nr   r   )cs    rD   r   r   Y  s
    AFFrF   c                 (    [        U S   5      U S   4$ r   r   r   s    rD   r   r   _      Yqy%91W:$FrF   c              3   *   #    U  H	  oS    v   M     g7f)r   Nr   )r   r   s     rD   r   r   `  s     1DqkNDs   c                 (    [        U S   5      U S   4$ r   r   r   s    rD   r   r   m  r   rF   due)rb   rw   r   dictr   sortedr   r   r_   rY   rU   maxMATCH_TOL_PCTMATCH_TOL_ABSr   r   rk   r   
setdefaultr|   sumC2_COVER_LOC2_COVER_HI)plan_opsfact_opsr   r   factsr   plans_orderedr   r   tolcandr   coverr   r   r   s     `          @@@rD   match_cascader      s    &	)&quuV}5+
 155>*A1[>/A(  <DD8aT!uQwZ018ED3	 8)jkM
 [>Qx[AiLk@R@R% A%Q[>D+@qYqRS_q55-;? % A`b 	4V9tAiL  [>Qy\w % L%Q[>D+@qYqRS_qW:73 qzAgJ674?  ('
AEE.4IJ % L 9	:
 4#&DGK '
AfIAiL " [>Qx[AiL!%%-(s8a<% B%Q[>D+@qYqRS_q'!%%*?"@@ % B`b 	4V9tAiL  [>Qx[AiLwZ-"$m4% T%Q[>D+@qYqRS_qqzB/36 .q!4  -.gJ!G*,DIaL  )%3AEE&M155=%Q	 % T
 QR bqA AkNAfIAiL  & D[>Qx[AiLe_deeeOOAgJ+2215	 
 "23t{q KN% S%Q[>D+@qYqRS_qW:73 <KAq<Q % SFH 1D11aj(EM[1W:5MM4V9tAiL 4 ~9% 5%Q[>D+@qYqRS_qW:73 % 5FH 	4V9'
T))AiL  sAgJ623% Oo E2A"L"BT0S5s   ' W!W"
1W"
W"
W"
W'
W'
"
W'
0W'

!W'
/W'
7W,
W,
W,
7W,
/W1
?W1
W1
&W1
9W1
.W1
	W1
W6
&W6
6
W6
W6
W6
W;
,W;
<
W;

W;
c                 N    U S   (       d  gU S   (       a  gU S   XS   -  S-
  :  $ )u  Планка считается оплаченной: матч + покрытие ≥ min_cover.
Гард честности: матч на <50% (партнёр заплатил крохи) — это по сути НЕоплата,
иначе долг спрятался бы в «оплачено меньше плана». Агрегат матчится только при полном покрытии.r   Fr   Tr   r   r   r   )r   	min_covers     rD   settledr   w  s3     Y<~V9	gJ.555rF   c                    [        XU5        U  Vs/ s H  n[        U5      (       a  M  UPM     nnU Vs/ s H  oUS   U:X  d  M  UPM     nn[        U Vs/ s H  n[        US   5      U:  d  M  UPM     snS S9n[        U Vs/ s H#  oUS   U:w  d  M  [        US   5      U:  d  M!  UPM%     snS S9n	U[        R
                  " SS9-   n
[        U Vs/ s H#  oR[        US   5      s=::  a  U
::  d  M  O  M!  UPM%     snS S9nU Vs/ s H#  oR[        US   5      s=::  a  U::  d  M  O  M!  UPM%     snU-   n[        U Vs/ s H  n[        US   5      U:  d  M  UPM     snS	 S9nU(       a  [        US
   S   5      OSnU Vs/ s H  n[        US   5      U:X  d  M  UPM     nnU Vs/ s H  n[        US   5      U:  d  M  UPM     nnU  Vs/ s HI  oUS   U:X  d  M  [        U5      (       d  M  US   (       a  M+  US   S:  d  M6  US   US   S-
  :  d  MG  UPMK     nn[        XgXUXUUS9	$ s  snf s  snf s  snf s  snf s  snf s  snf s  snf s  snf s  snf s  snf )u   Матчит план↔факт и раскладывает непогашенные планки. Чистая функция.

• unpaid       — не-settled планки (неоплаченные + матч <50% + агрегаты с частичным покрытием);
• rest         — «ещё платить» в этом месяце (factMonth==mm), сумма долга = o['due'];
• overdue      — из rest те, у кого дата уже прошла (просрочено);
• stale        — непогашенные планки ПРОШЛЫХ месяцев с прошедшей датой (раньше молча терялись);
• next2w       — непогашенные выплаты на 2 недели вперёд (календарь);
• due_window   — непогашенные от сегодня до границы окна + просроченные этого месяца;
• after_window — непогашенные сразу за границей окна (только ближайший день): окно
                 фиксированной длины режет по живому, и крупный платёж через день
                 после границы должен быть виден;
• fut          — из rest строго будущие (для «ближайшей выплаты»);
• underpaid    — settled планки-люди ТЕКУЩЕГО месяца (покрытие 50–99%): «оплачено X из Y».r   r>   c                     [        U S   5      $ r   r   r   s    rD   r   !classify_unpaid.<locals>.<lambda>  s    V_`abh`iVjrF   r   c                     [        U S   5      $ r   r   r   s    rD   r   r    s    1V9!5rF   r   r   c                     [        U S   5      $ r   r   r   s    rD   r   r        )AfI"6rF   c                     [        U S   5      $ r   r   r   s    rD   r   r    r  rF   r   Nr   r   r   r   )	unpaidrestoverduestalenext2w
due_windowafter_windowfut	underpaid)r   r   r   rE   r=   r   r   )r   r   r   mm
window_endr   r  r  r	  r
  horizonr  r  _after_firstr  r  r  s                     rD   classify_unpaidr    s\    (e,!4AaF46v!;2!5AvD6FA1V9)=)EaFLjkGv_v!;2)=A)AfIBVY^B^Av_57Eh((b11GS19QvY3G*R7*RQ*RQS68F#SV	!F)0D'R
'R!'R!VSV]]JL1)AfI*>*KQL68F-3Yvay()F%Hv!1V9)=)GAvLH
;di&	2U:1dC
;$ IHq+"(<TUVaTbvY% *+F)aj46G*G HI Iv'v%cU^` `# 56F_ TSL I
;Is   H6H6H;H;I 0I II*II
7I
;I
I,I0III
I$I0I
II#&I#8I#I#I# I#)"__doc__r=   rJ   r   r   r   r   r   SETTLED_MIN_COVERRETIRE_MIN_COVERrZ   ra   rE   rQ   rU   r_   rb   rf   r   rk   r{   rv   compiler   ry   r~   r   r   r   r   r   r   r   r  r   rF   rD   <module>r     s  4  	   Z A	KQ5 	G8 I	
	$	&02F	HTVd	fp  sE	j	(.	:DFZ	\hj~	 l	 '(<	 ?I,	 Ycdp	  		 #-.>		 AKL\		 _ijx		
 	
 +5BR`r 0BP\jx
Xh  wA",l	 

<='
.bJ<BDN + 6"`rF   