)Ej-ddlmZddlmZddlmZmZmZmZddl m Z ddl m Z m Z mZddlmZddlmZddlmZmZdd lmZdd lmZdd lmZmZdd lmZm Z dd l!m"Z"m#Z#m$Z$m%Z%m&Z&m'Z'm(Z(m)Z)m*Z*m+Z+m,Z,m-Z-m.Z.m/Z/m0Z0m1Z1ddl2m3Z3ddl4m5Z5ddl6m7Z7ddl8m9Z9ddl:m;Z;ddlZ>ddl?m@Z@ddlAZAddlBZBddlCmDZDddlEZEddlFZFddlGZGeEjHeIZJddZK ddZLGddeMZNdS)) annotations)sstruct)Tagtostr binary2numsafeEval)FeatureLibError)LookupDebugInfoLOOKUP_DEBUG_INFO_KEYLOOKUP_DEBUG_ENV_VAR)Parser) FeatureFile)VariableScalarVariableScalarBuilder)builder) maxCtxFont)newTablegetTableModule)otBaseotTables)AlternateSubstBuilderChainContextPosBuilderChainContextSubstBuilderLigatureSubstBuilderMultipleSubstBuilderCursivePosBuilderMarkBasePosBuilderMarkLigPosBuilderMarkMarkPosBuilderReverseChainSingleSubstBuilderSingleSubstBuilderClassPairPosSubtableBuilderPairPosBuilderSinglePosBuilderChainContextualRuleAnySubstBuilder)OpenTypeLibError) VarLibError)OnlineVarStoreBuilder)buildVarDevTable)addFeatureVariationsRaw)normalizeValuepiecewiseLinearMap) defaultdictN)StringIOFcTt||}|||dS)aAdd features from a file to a font. Note that this replaces any features currently present. Args: font (feaLib.ttLib.TTFont): The font object. featurefile: Either a path or file object (in which case we parse it into an AST), or a pre-parsed AST instance. tables: If passed, restrict the set of affected tables to those in the list. debug: Whether to add source debugging information to the font in the ``Debg`` table tablesdebugN)Builderbuild)font featurefiler2r3rs JC:\PYTHON\MyICR_Suite\python\Lib\site-packages\fontTools/feaLib/builder.pyaddOpenTypeFeaturesr96s/dK((G MMuM-----cvtt|}|r||_t||||dS)aeAdd features from a string to a font. Note that this replaces any features currently present. Args: font (feaLib.ttLib.TTFont): The font object. features: A string containing feature code. filename: The directory containing ``filename`` is used as the root of relative ``include()`` paths; if ``None`` is provided, the current directory is assumed. tables: If passed, restrict the set of affected tables to those in the list. debug: Whether to add source debugging information to the font in the ``Debg`` table r1N)r/rnamer9)r6featuresfilenamer2r3r7s r8addOpenTypeFeaturesFromStringr?HsD&5??++K$# k&FFFFFFr:ceZdZeddDZdZdcdZdZdZddd Z d Z d Z d Z d Z dZdZdZdZdZdZdZdZdZdZdZdZdZdZdZdZdZdZd Z d!Z!d"Z"d#Z#d$Z$d%Z%ded&Z&d'Z'ded(Z(d)Z)d*Z*d+Z+d,Z,d-Z-d.Z.d/Z/d0Z0d1Z1d2Z2d3Z3d4Z4d5Z5d6Z6d7Z7gfd8Z8d9Z9d:Z:d;Z; ded<ZZ>e?d?Z@d@ZAdAZBdBZCdCZDdDZEdEZFdFZGdGZHdHZIdIZJdJZKdKZLdLZMdMZNdNZOdOZPdPZQdQZRdRZSdSZTdTZUdUZVdVZWdWZXdXZYdYZZdfd^Z[d_Z\d`Z]dae^j_DZ`dbZadS)gr4c#4K|]}t|VdSN)r).0tags r8 zBuilder.bs<    C      r:) BASEGDEFGPOSGSUBOS/2headhhear<vheaSTATcD||_t|tr|dc|_|_nd|c|_|_||_d|_d|vrN|dj|_td|jD|_tj ||_ t|_d|_d|_d|_d|_t|_d|_i|_d|_d|_d|_g|_iid|_i|_i|_i|_g|_d|_i|_ d|_!t|_"i|_#t|_$i|_%i|_&tOtP|_)d|_*d|_+g|_,d|_-d|_.i|_/i|_0i|_1i|_2i|_3i|_4i|_5i|_6i|_7i|_8i|_9i|_:dS)Nfvarcg|] }|j S)axisTag)rCaxs r8 z$Builder.__init__..s000000r:rF)rIrH);r6 isinstancer parseTreefilegetReverseGlyphMapglyphMapvarstorebuilderaxesr)rfrom_ttfscalar_buildersetdefault_language_systems_script_ lookupflag_lookupflag_markFilterSet_use_extension_language_systemsseen_non_DFLT_script_named_lookups_ cur_lookup_cur_lookup_name_cur_feature_name_lookups_lookup_locations features_required_features_feature_variations_aalt_features_aalt_location_aalt_alternates_aalt_use_extension_ featureNames_featureNames_ids_cv_parameters_cv_parameters_ids_cv_num_named_params_r.listcv_characters_size_parameters_ fontRevision_names_base_horiz_axis_base_vert_axis_ attachPoints_ligCaretCoords_ligCaretPoints_glyphClassDefs_ markAttach_markAttachClassID_markFilterSets_os2_hhea_vhea_stat_conditionsets_)selfr6r7s r8__init__zBuilder.__init__rs!  k; / / :(3T %DNDII(,k %DNDI//11 # T>>V )DI#800di000$$D #8"@"F"FD ),& )-&# #%*"  $!% )+R 8 8"$#%  " "#(  UU!#!ee"$$&!)$// $! $#!!!"$!     r:NFcj1tjj_j|j}nPt|}|jz }|r5dt|}td|dd|vr d|vr d|vr d|vrd|vrd |vrd |vrd D]}||vr|}jr|||jjd ks |jjd ks|jjd kr!t7|x}j|<||_|jvrj|=t=fd d Dr-d jvr$t?jjd _ d|vr2!}|r |jd<ndjvrjd=d|vr2"} | r | jd<ndjvrjd=|s$tFj$%tLr'dSdS)N, z9The following tables were requested but are unsupported: .rIrKrLrMr<rJrNrHrIrc3*K|] }|jvVdSrB)r6)rCrDrs r8rEz Builder.build..s*< !#DIt}==CCEEDN T""" >)FFv&&F 4#77K %)YYvk/B/B%C%C")-)--- V    $ $ & & & V   OO    V   OO    V   OO    V   OO    V   OO    V   OO   # # #C&  NN3''E' 7**5#666 ,q00$1A55#/!33-5c]]: DIcN"'  !!IcN <<<<+;<<< < < C49ATAT-7 -B-BDIf  * V  >>##D &$( &!!49$$If% V  >>##D &$( &!!49$$If%  BJNN#788  NN       r:c||j|}|j|_|j|_|j|_|j||SrB) r6rb lookupflagrc markFilterSetrd extensionrkappend)rlocation builder_classresults r8get_chained_lookup_zBuilder.get_chained_lookup_sQty(33 ,#=. V$$$ r:c|jD]8\}}|||f}|j|g|9dSrB)rerm setdefaultr)rlookup feature_namescriptlangkeys r8add_lookup_to_feature_zBuilder.add_lookup_to_feature_sW 1 > >LFD4.C N % %c2 . . 5 5f = = = = > >r:ct|jrct|j|krK|jj|jkr6|jj|jkr!|j|r|jS|jr|jrtd|||j ||_|j|j_|j|j_|j |j_ |j |j|jr|j|j|j<|jr ||j|j|jS)NOWithin a named lookup block, all rules must be of the same lookup type and flag)rhtyperrbrrccan_add_mappingrir r6rdrrkrrgrjr)rrrmappings r8 get_lookup_zBuilder.get_lookup_sL   $T%&&-77 +t/??? .$2PPP 0099Q# #   T%5 !0  )=H==&*&6#)-)G&%)%8" T-...   J9=9ID  5 6  ! R  ' '(8$:P Q Q Qr:c ^|js |jsdSd|jD}|jdgzD]\}fd|jD}|s!dkrt j|ddM|D]\}}}}|D]}t |ts|g}|D]e}|D]<\} } | | g fd| D=fd|D} d |D} | s| sdSd |jD|_|j } g|_ | |j d|j| r"||t }| |_| r"||t$}| |_||j | dS) Nc4i|]\}}|t|SrR)ry)rCgas r8 z/Builder.build_feature_aalt_..*s$KKKTQaaKKKr:)Naaltc6g|]\\}}}}|k||||fSrRrR)rCrrfeaturelookupsr<s r8rUz/Builder.build_feature_aalt_..,s>4+VT7Wd??w0"??r:rz : Feature z has not been definedc3$K|] }|v|V dSrBrR)rCralts_for_glyphs r8rEz.Builder.build_feature_aalt_..<s622&'1N3J3J3J3J3J3J22r:cLi|]!\}}t|dk||d"S)rlenrCglyphrepls r8rz/Builder.build_feature_aalt_..?s5   *udCIIQRNNE47NNNr:c@i|]\}}t|dk||S)rrrs r8rz/Builder.build_feature_aalt_..Bs*TTTc$iiRSmmmmmr:c4i|]\\}}}}|dk|||f|S)rrR)rCrrrrs r8rz/Builder.build_feature_aalt_..EsA   0'w&  T7 #W   r:)rprritemsrmwarningswarnrVrygetAlternateGlyphsrextendrk start_featurerqrsrr!rr alternates end_feature)rrrrrrr lookuplistrraltssinglemulti old_lookups single_lookup multi_lookuprr<s @@r8rzBuilder.build_feature_aalt_#s" 4+@  F LKT-B-H-H-J-JKKK "1^4DD  NHd8<8L8L8N8NG  tv~~ xxxQUQUQUVWWW29  .gw")J%j$772&0\ ",+1+D+D+F+F+L+L+N+NKE4-7-B-B5"-M-MN*112222+/222   .8.>.>.@.@   UT 0@0@0B0BTTT e  F  48N4H4H4J4J    m   4.8PQQQ  + ,,X7IJJM$*M !  ,++H6KLLL&+L #  [)))))r:c|jsdS|jd}|sPtdx}|jd<|d|jd|_d|_dx|_|_|j|_ dS)NrKs6g?i<_le) r|r6rr decompile tableVersion magicNumbercreatedmodified fontRevisionrrs r8rzBuilder.build_headVs!  F f%% 8(0(8(8 8EDIf% OOJ 2 2 2!$E  *E -7 7EMEN!/r:c|jsdS|jd}|s;tdx}|jd<|d|jd|_d|jvr|jd|_d|jvr|jd|_d|jvr|jd|_d|jvr|jd|_ dSdS)NrL$ caretoffsetascender descenderlinegap) rr6rrrr caretOffsetascentdescentlineGaprs r8rzBuilder.build_hheabsz  F f%% ,(0(8(8 8EDIf% OOJ 2 2 2!+E  DJ & & $ = 9E   # #:j1EL $* $ $ J{3EM  " " Jy1EMMM # "r:cl|jsdS|jd}|s;tdx}|jd<|d|jd|_d|jvr|jd|_d|jvr|jd|_d|jvr|jd|_dSdS)NrMriverttypoascenderverttypodescenderverttypolinegap) rr6rrrrrrrrs r8rzBuilder.build_vheassz  F f%% ,(0(8(8 8EDIf% OOJ 2 2 2!+E   + +:&89EL $* , , J':;EM  * * J'89EMMM + *r:c^d|jD}tddD] }||vr|cS dS)Ncg|] }|j SrR)nameID)rCr<s r8rUz,Builder.get_user_name_id..s77744;777r:i)namesrange)rrnameIDs user_name_ids r8get_user_name_idzBuilder.get_user_name_idsV775;777!#u-- $ $L7**####+ $ $r:cXd}d}|dkrYtj}|j\|_|_|_|_||jvr|j||_nOd|_nF||j vrA|jsn4||jvsJtj }d|_ |j||_ n||j vrtj}d|_|j|df||_|j|df||_|j|df||_|j|d|_|j|df||_t1|j||_|j||_|S)NsizerFeatUILabelNameIDFeatUITooltipTextNameIDSampleTextNameIDParamUILabelNameID_0)rFeatureParamsSizer{ DesignSize SubfamilyID RangeStartRangeEndruSubfamilyNameIDrtFeatureParamsStylisticSetVersionUINameIDrvFeatureParamsCharacterVariantsFormatrwrrrrrxNumNamedParametersFirstParamUILabelNameIDrrz CharCount Character)rrD NO_NAME_IDparamss r8buildFeatureParamszBuilder.buildFeatureParamss  &==/11F %  !"!d,,,)-)?)D&&)*&& D& & &) >d44444!;==!""&"8"= D' ' '<>>FFM'+'>'B'B)*J((F $.2-D-H-H/0*..F *'+&=&A&A():''F #)-(A(E(Ec1(M(MF %-1-D-H-H,-z..F * #4#6s#;<.checkattrs@ , ,ud++,E4+++ , ,r:)ulCodePageRange1ulCodePageRange2)sxHeight sCapHeight usDefaultChar usBreakCharr)usLowerOpticalPointSizeusUpperOpticalPointSize))rr6rrrcalcsizer OS2_format_0rfsTypePanose bFamilyType bSerifStylebWeight bProportion bContrastbStrokeVariation bArmStyle bLetterFormbMidlinebXHeightr4 sTypoAscendersTypoDescender sTypoLineGap usWinAscent usWinDescentr achVendID usWeightClass usWidthClasssetUnicodeRangesbuild_codepages_rKrLrMrNrQrRmaxversion)rrdatarlr4pagesrJs r8rzBuilder.build_OS_2szy  F f%% -(0(8(8 8EDIf%7+N6,B,B,OPPPD OOD$) , , , ty 9X.EL ty #F++2244F (# """ ' "!EL TY & &"&)N";E  di ' '#'9_#=E DI % %!%=!9E  $) # # $ + 6E  49 $ $!%.9s$FFaeFFFFFFr:z$DesignAxis already defined for tag "z".c3$K|] }|jV dSrB) axisOrderrys r8rEz(Builder.addDesignAxis..>s$#R#RAAK#R#R#R#R#R#Rr:z+DesignAxis already defined for axis number r)rrDr r|r)r designAxisrs r8 addDesignAxiszBuilder.addDesignAxis6s tz ) )')DJ| $ >FFTZ -EFFF F F!Iz~III   #R#RL9Q#R#R#R R R!Uj>RUUU  < '' 33333r:c\d|jvr g|jd<|jdD]j}d|jDd|jDkrDd|jDd|jDkr |j|jkrt d|k|jd|dS)NAxisValueRecordsc6h|]}|SrRasFearCns r8 z-Builder.addAxisValueRecord..Ks 222q222r:c6h|]}|SrRrrs r8rz-Builder.addAxisValueRecord..Ls ===!AGGII===r:c6h|]}|SrRrrs r8rz-Builder.addAxisValueRecord..Ms :::1QWWYY:::r:c6h|]}|SrRrrs r8rz-Builder.addAxisValueRecord..Ns AAA!AGGIIAAAr:z8An AxisValueRecord with these values is already defined.)rr  locationsflagsr r)raxisValueRecordrrecord_s r8addAxisValueRecordzBuilder.addAxisValueRecordEs TZ / /-/DJ) *z"45  G22GM222=='<===>>::(9:::AA'@AAABBM_%:::%N %&--o>>>>>r:c|jsdS|jd}|stdd|jd}ig}|D] }g|j< |X|D]T}i}|jdkr |j|d<t |jdkr|jd}|j}t |dkr#||d|j dt |dkr*||d|d|j d t |d kr%|\} } } || | | |j d |j ||d |jD|j d | |Vfd|D} |j d} | s tdx} |j d<g| _ d|jvr9|jd}| |}|std|ddnd|jvr |jd}tj|j | ||dS)NrwzDesignAxes not definedrrrr)rsr<r@)rs linkedValuer<) nominalValue rangeMinValue rangeMaxValuer<c4i|]}|j|jdS)r)rDvalues)rCis r8rz&Builder.build_STAT..s"(S(S(S (S(S(Sr:)rr<cRg|]#}|j|j|j|jd$S))orderingrDr<r)r|rDr )rCr axisValuess r8rUz&Builder.build_STAT..sK    Ku$QU+      r:r<rqzElidedFallbackNameID z; points to a nameID that does not exist in the "name" tablerp)relidedFallbackName)rrr rDrrrrupdater rr6r getDebugNameotlbuildStatTable)rr\axisValueRecordsformat4_locationsrDavr valuesDictrrnominalminValmaxVal designAxes nameTabler r<rs @r8rzBuilder.build_STATWs-z  Fz~~l++ B!":DAA A:>>*<==  % %C"$Jsw    ''# 9# 9 9q==*-)Jw's}%%**"}Q/H%_F6{{a''"))F1Isy*Q*QRRR6{{a''")))//5ay(+ 6{{a''28/"))071717(+ x|,33J????%%(S(SS](S(S(S$'I &,,Z8888       IMM&))  !,4V,<,< ?)iai`i_i^i]i\iYiWiTiiiiRic(g|]}|v|SrRrR)rCp pages2bitss r8rUz,Builder.build_codepages_..s"@@@!Z 1 r: 10c>g|]}t|dddS)N)r)rCrs r8rUz,Builder.build_codepages_..s*333 1TTrT7##333r:)r r)rrnbitsrjrs @r8rjzBuilder.build_codepages_s  !  !   !   !  !  !   !   !   !                  "  !  " #  $?    BA@@@u@@@q $ $A LL   1r6AER<00 $ $99!HHHOHHHH!HHHOHHHH  $ 43U3333r:c|js |jsdStj}d|_||j|_||j|_td}||_ |S)NrrF) r~rrrFr buildBASEAxis HorizAxisVertAxisrr)rrrs r8rzBuilder.buildBASEsw$ T-A 4}! ++D,ABB**4+?@@ &!!  r:cHtj}d|_||_|SNr)r BaseCoordr! Coordinate)rccoords r8buildBASECoordzBuilder.buildBASECoords$"$$  r:cp |sdS|\}}}tj}tj|_||j_t ||j_tj|_g|j_t ||j_t|D] fd|D}tj} d|_ tj |_ tj |j _ | d|j j _g|j j _t d|j j _g|j _ dD]9}|j j j||:t|D]\}} } tj} || | _|| | _d| _|dkr | |j _gtj} || _| | _|j j| t |j j|j _|jj||S)NcHg|]}|ddk|ddS)rrNrR)rCrecordrs r8rUz)Builder.buildBASEAxis..s:!!!%6!9q 3I3Iqrr 3I3I3Ir:rrr@dflt)rAxis BaseTagList BaselineTagr BaseTagCountBaseScriptListBaseScriptRecordBaseScriptCountr BaseScriptTag BaseScript BaseValuesindex DefaultIndexrBaseCoordCountBaseLangSysRecordrrMinMaxMinCoordMaxCoordFeatMinMaxCount DefaultMinMaxBaseLangSysTagBaseLangSysCount)raxisbasesscriptsminmaxminmax_for_scriptrrlanguage min_coord max_coord minmax_record lang_recordrs @r8rzBuilder.buildBASEAxiss  F!%w}#/11',$(+E %&577/1,.1'll+Woo @ @F!!!!)/!!! .00F#)!9F ( 3 5 5F +3+>+@+@F  (8= F1I8N8NF  ( 557F  ( 2:=fQi..F  ( 724F  /AY V V!,6==d>Q>QRS>T>TUUUU289J2K2K L L.)Y ( 1 1 )-)<)">K19K.)6K&%7>>{KKKK14!322F  .   0 7 7 ? ? ? ? r:c6tj}||_t j|j|j|_t j |j |j |j|_ | |_||_|jrdnd|_|jr|j}|red|_||_|}||d|jvr%|jdj|t3|j|j|j |j|jfst5|drt7d}||_|SdS)NirirHVarStorerG)rrGbuildGDEFGlyphClassDef_ GlyphClassDefrbuildAttachListrrZ AttachListbuildLigCaretListrr LigCaretListbuildGDEFMarkAttachClassDef_MarkAttachClassDefbuildGDEFMarkGlyphSetsDef_MarkGlyphSetsDefrr[finishroptimizeremap_device_varidxesr6rrrFr)rrstore varidx_maprs r8rzBuilder.buildGDEFs}!99;;-d.@$-PP1  $"6   #'"C"C"E"E $ ? ? A A%)%:Jzz    N(//11E N) % "^^-- **:666TY&&If%+AA*MMM "!'%    T: & & f%%FFLM4r:c|jr$d|jD}nzi}|jD])}||*|jjD](}|jD]}| D]}d||<)|rtj }||_ |SdS)Nc i|] \}\}}|| SrRrRrCrr_s r8rz3Builder.buildGDEFGlyphClassDef_..<s"LLL FQq!LLLr:r) rrrkrinferGlyphClassesrW markClassesr definitionsglyphSetrr classDefs)rclassesr markClass markClassDefrrs r8rzBuilder.buildGDEFGlyphClassDef_:s   +LLt/C/I/I/K/KLLLGGG- ; ;v7799::::!^7>>@@ + + $-$9++L!-!6!6!8!8++)*++  +--F&F M4r:cd|jD}|sdStj}||_|S)Nc i|] \}\}}|| SrRrRrs r8rz8Builder.buildGDEFMarkAttachClassDef_..Ms"DDDia!QQDDDr:)rrrrr)rrrs r8rz$Builder.buildGDEFMarkAttachClassDef_LsLDD4+;+A+A+C+CDDD  4,..$ r:cg}t|jdD]\}}||t j||jS)Nc|dSrrR)items r8z4Builder.buildGDEFMarkGlyphSetsDef_..Ws 47r:r)rrrrrbuildMarkGlyphSetsDefrZ)rsetsglyphsid_s r8rz"Builder.buildGDEFMarkGlyphSetsDef_Tsm!  & & ( (.B.B     KFC KK    (t}===r:cd|jvr)td|jd<i|jd_|j|jdjt<dS)NDebg)r6rrmrlr rs r8rzBuilder.buildDebg\sP  " " ( 0 0DIf %'DIf  "8<8M &4555r:cR|dvs J||jD] }d|_ g}|jD]}|j|kr||}||du}|t d|j|D]o}t||_tt|j|d|j |t|j<| |pg}|D]} | | +#t$r(}t t||j|d}~wt$rM}|j |t|jj} t t|| |d}~wwxYw|S)Nr)is_named_lookupr)rr<r)rk lookup_indexrget_lookup_name_promote_lookup_typer rrr strrlrr5r' Exception) rrDrrr<resolvedl otLookupsers r8 buildLookups_zBuilder.buildLookups_bs&&&&&&&m ' 'F"&F  m " "F|s""((00D11$dBR1SSH%4O  " "&)'ll#GV 11 HHH%c*3v/B+C+CD q!!!! "  ? ?A ?  ++++# A A A%c!ffaj99q@ ? ? ?05c!.6I6IJS%c!ffh77Q> ?s%5'D F$'#E  F$AFF$c tt|d}d|_tj|_g|j_tj|_g|j_tj|_|||j_ i}i}i}d}t|j |D]>\}}|\} } } ttd|D} t!| } |dko| dk}|| |}t%| dkr|s|s| D]v} |j|t)|||j|t)|<S#t,$rt/jd YswxYw| | f}||}|t%|jj}tj}| |_tj|_|| |j_t=| |j_t%| |j_ |jj!||||<|"| i"| g!||j#| | f| kr||| | f<@t| D]\} }tj}| |_$tj%|_%d|j%_&g|j%_'t| D]\} }tj'}tj(|_(d|j(_)|| | f d |j(_*n |j(_*fd |D|j(_+t%|j(j+|j(_,| d kr|j(|j%_&| |_-|j%j'!|t%|j%j'|j%_.|jj!|t%|jj|j_/t%|jj|j_,t%|jj |j_ |S) Nrcb|dd|dd|dd|dfS)Nrr@rrR)fs r8rz#Builder.makeTable..s+AaDGQqT!Wad1gqt#Dr:r c32K|]}|j |jVdSrB)r*)rCr0s r8rEz$Builder.makeTable..s4'(q~7QAN7Q7Q7Q7Qr:rHrr)rzWfeaLib.Builder subclass needs upgrading to stash debug information. See fonttools#2065.rc g|] }|k| SrRrR)rCrreq_feature_indexs r8rUz%Builder.makeTable..s+000!7H2H2HA2H2H2Hr:r)0getattrrrr ScriptRecordr FeatureRecordrr3Lookuprrmrtupledictfromkeysrany_feature_variationsrrlr-_replaceKeyErrorrrr FeatureTagFeaturer( FeatureParamsryLookupListIndexrrrrn ScriptTagScriptDefaultLangSys LangSysRecordLangSys LookupOrderReqFeatureIndex FeatureIndexr LangSysTag LangSysCountr)rrDrfeature_indicesrequired_feature_indicesrsortFeatureTagrrrr feature_taglookup_indices lookup_key size_feature force_featureix feature_key feature_indexfrec lang_featuressreclangrecr9s @r8rzBuilder.makeTables,#t,,.." #.00(*%$022*,'#.00"&"4"4S"9"9#% ED"4>#7#7#9#9~NNN1 I1 ILC(+ %FD+# ,3N#>22J&=B[F-BL 77 SIIM>""a'' ']'$  :>:OPS:TB;hsh++)#.s2ww77 MG ' 3K+// <+> (!/66t<<::kII;H(&$8&,GMMOO%<%< 7 7 !FM(**D#DN"/++DK)-DK &(*DK %)/ 0C0C0E0E)F)F > >%o"022"*"2"4"4.2+$<$@$@&$$P$P!$,6>18DK..)-G&K-44W===='*4;+D'E'EDK $   ) 0 0 6 6 6 6'*5+;+H'I'I$),U->-L)M)M&'*5+;+B'C'C$ s"AF22GGci}d}|jD]\\}}}}g||<|D]g\}} |j|} g} | D]3} | j|kr| jJ| | jd}4||| | fh|r1|D]\}} t |j|| |dSdS)NFT)rorrrr*rr+r6)rr table_tag feature_varshas_any_variationsrrU variations conditionsetbuildersraw_conditionsetindicesbconditions_and_lookupss r8rzBuilder.makeFeatureVariationssL "/3/G/M/M/O/O N N + Q;(*L %*4*:*:*<*< N N& h#'#6|#D !..Aw)++ >555NN1>222)-&&[)002BG1LMMMM N  7C7I7I7K7K  3 3'Iu&. s*>>qw)+>>>>>>r:TF)rorr)rrUrbrrrerfrgs ` r8rAzBuilder.any_feature_variationss+/+C+I+I+K+K  'OQ7Z+%%*4*:*:*<*<  & h>>>>X>>>>> 444  ur:cdd|jD}||vr||SdS)Nci|]\}}|| SrRrR)rCkvs r8rz,Builder.get_lookup_name_..s<<<1q!<<>>>8>>#3#3#3#35  &**FH+=>>>>>r:cX|jrt|jStdhS)N)rtr)r`rr's r8get_default_language_systems_z%Builder.get_default_language_systems_-s2  ) 1T;<< <./00 0r:c|r|dkrtd|||_d|_d|_||_d|_d|_||_|dkr||_ ||_ dSdS)NrzL'useExtension' keyword for feature blocks is allowed only for 'aalt' featurertr) r rzrerarhrjrbrcrdrqrsrrr< use_extensions r8rzBuilder.start_feature8s  TV^^!^ !% B B D D !%)-&+ 6>>"*D '4D $ $ $ >r:cl|jJd|_d|_d|_d|_d|_d|_dS)NrF)rjrerhrbrcrdr's r8rzBuilder.end_featureIsG%111!% $)-&#r:c||jvrtd|z||jdkrtd|||_d|j|<d|_||_|jd|_d|_dSdS)Nz$Lookup "%s" has already been definedrzpLookup blocks cannot be placed inside 'aalt' features; move it out, and then refer to it with a lookup statementr)rgr rjrirhrdrbrcr|s r8start_lookup_blockzBuilder.start_lookup_blockRs 4& & &!6=x   !V + +!L  !%$(D!+  ! ) D -1D * * * * )r:cp|jJd|_d|_d|_|jd|_d|_dSdS)NFr)rirhrdrjrbrcr's r8end_lookup_blockzBuilder.end_lookup_blockesP$000 $#  ! ) D -1D * * * * )r:c||jvs J|d|_|j|}||||jdSdSrB)rgrhrrj)r lookup_namers r8add_lookup_callzBuilder.add_lookup_callns`d1111;111$[1    ' '0F G G G G G  r:c||_dSrB)r|)rrrevisions r8set_font_revisionzBuilder.set_font_revisionus%r:c t|dksJ|jdvrtd|jz||jtd|d|_|j||jf}|j|dd|df|dks|rrdd|j|<n1|j|g}fd|D|j|<t|j|fg|_|r|j|f}||j vr`td | d |j d |j | d ||j|j |<dSdS) Nrrrz7Language statements are not allowed within "feature %s"zCLanguage statements are not allowed within standalone lookup blocksrrr@cg|]}|v| SrRrR)rCxrs r8rUz(Builder.set_language..s#"N"N"NQg=M=M1=M=M=Mr:z Language z (script z ) has already specified feature z as its required feature) rrjr rhrarmrrrernrv)rrrinclude_defaultrequiredr cur_lookupsrs @r8 set_languagezBuilder.set_languagexs8}}!!!!  !%5 5 5!&(,(>?   ! )!2   |Xt'=>.$$c!ffc!f%=>>   / w ")!!!*DN3  .,,S"55K"N"N"N"Nk"N"N"NDN3  )DL(+C*D E E  B<*Cd---%o!(((( **,,,,/4::<<<<    ,0+AD #C ( ( ( B Br:c"t|}|j|}||St|jdz}||j|<|D]=}||jvr&|j|\}}t d|d||||f|j|<>|S)NrGlyph z3 already has been assigned a MarkAttachmentType at )rrrrrr )rrr#r$rrlocs r8getMarkAttachClass_zBuilder.getMarkAttachClass_s6""%))&11 ?J$)**Q.*-' 6 6E((()%03%o49EE33@ (+HoD U # # r:ct|}|j|}||St|j}||j|<|SrB)rrrr)rrr#r$s r8getMarkFilterSet_zBuilder.getMarkFilterSet_sQ6"""&&v.. ?J$&'''*V$ r:c|dz}||||}||dzz}|#|||}|dz}||_nd|_||_dS)Nrr)rrrcrb)rrrs markAttach markFiltermarkAttachClassrs r8set_lookup_flagzBuilder.set_lookup_flagsz   !"66xLLO_12E  ! 228ZHHMDLE-:D * *-1D * r:c|jdvrtd|jz||jtd||j|dfhkrdSd|_||_d|_d|_||ddddS) Nrz5Script statements are not allowed within "feature %s"zAScript statements are not allowed within standalone lookup blocksrrTF)rr)rjr rerhrarbrcr)rrrs r8 set_scriptzBuilder.set_scripts  !%5 5 5!&(,(>?   ! )!V   ff%5$6 6 6 F )-& (FD5QQQQQr:cg}|D];}|"|fd|D&|d<|S)zHelper for building chain contextual substitutions Given a list of lookup names, finds the LookupBuilder for each name. If an input name is None, it gets mapped to a None LookupBuilder. NcNg|]!}j|j"SrR)rgrr<)rCr0rs r8rUz1Builder.find_lookup_builders_..s,IIIT(,,QV44IIIr:)r)rrlookup_buildersrs` r8find_lookup_builders_zBuilder.find_lookup_builders_sr ! - -J%&&IIIIjIII &&t,,,,r:c|D]<}|j|t|=dSrB)rrr_r)rrr# contourPointsrs r8add_attach_pointszBuilder.add_attach_pointssM N NE   ) )% 7 7 > >} M M M M N Nr:ct|jdkrtd||j||fdS)Nrz9Feature references are only allowed inside "feature aalt")rjr rpr)rr featureNames r8add_feature_referencezBuilder.add_feature_referencesK  !V + +!KX  ""Hk#:;;;;;r:c:|j|dSrB)rtrwrrDs r8add_featureNamezBuilder.add_featureNames s#####r:c:|j|dSrB)rvrwrs r8add_cv_parameterzBuilder.add_cv_parameters $$$$$r:cZ||jvr|j|xxdz cc<dSd|j|<dS)zbAdds new items to ``self.cv_num_named_params_`` or increments the count of existing items.rN)rxrs r8add_to_cv_num_named_paramsz"Builder.add_to_cv_num_named_paramssJ $+ + +  %c * * *a / * * * * *-.D %c * * *r:cF|j||dSrB)rzr)r characterrDs r8add_cv_characterzBuilder.add_cv_character s$ C '' 22222r:c6|r |||f|_dS|||f|_dSrB)rr~)rrrverticalrs r8 set_base_axiszBuilder.set_base_axiss4  =$)7F#;D %*GV$?  ",[*h O 1 / /LFD4!78C N % %c2 . . . . / /r:c||t|}|D]\}}||jvr{||j|krDtdd|d||n&tdd|z|||j|<dS)N)rz7Removing duplicate substitution from "%s" to "%s" at %srz%Already defined substitution for "%s")rr&rrloginforr )rrrrrrss r8add_any_subst_zBuilder.add_any_subst_$s!!(OW!MM!--// ( (JCfn$$FN3///HHQ # %(( *?$))C..P #(FN3   ( (r:c`|jdkrP|D]9\}}|j|g}||vr||:dS|s|s|r|||||dS||d|DdS)Nrci|] \}}|f|f SrRrR)rCrrss r8rz,Builder.add_single_subst..Ds" @ @ @*#ucVeX @ @ @r:)rjrrrrradd_single_subst_chained_r) rrprefixsuffixr forceChain from_glyphto_glyphrs r8add_single_substzBuilder.add_single_subst7s  !V + +(/  * *$ H,77 BGG4''KK))) F  V z   * *8VVW M M M F   @ @  @ @ @     r:c|s|s|r||||||dS|||ft|idSrB)add_multi_subst_chained_rr>)rrrrr replacementsrs r8add_multiple_substzBuilder.add_multiple_substHsr  V z   ) )(FE6< X X X F  Xu\** +     r:c|jdkr>|j|gfd|DdS|s|rj||t }||}|||t}| |||hg||gn||t}||j vrtd|z|||j |<dS)Nrc3$K|] }|v|V dSrBrR)rCrrs r8rEz.Builder.add_alternate_subst..Ws'@@a!4------@@r:z)Already defined alternates for glyph "%s") rjrrrrrrfind_chainable_alternate_substrr_add_contextual_rulerr ) rrrrr replacementchainrrs @r8add_alternate_substzBuilder.add_alternate_substTs$  !V + +(33E2>>D KK@@@@;@@@ @ @ @ F  GV G$$X/GHHE99%@@F~11(.{s C C C1Q C C Cr:)add_ligature_subst_chained_allr r itertoolsproduct)rrrr#rrrs ` r8add_ligature_substzBuilder.add_ligature_substis  V z   , ,&&&+    F6{{ Q!"ExPP P   C C C C (96(B C C C     r:ct|dkr|jr|jdjs|jd}t|jdkr|j|kr|j|kru|j|krjt|jdts"t|jd|jd<|jd |ddS|j t||||dS)a4Add a contextual rule, merging with the last rule if possible. Consecutive rules that share the same prefix, suffix, lookups, and have a single input position can be merged into one rule with broader input coverage. This produces more compact binary tables (often Format 3). rrrN) rrulesis_subtable_breakr#rrrrVr_rrr%)rrr#rrlasts r8rzBuilder._add_contextual_rule~s v;;!   EKO4U ;r?DDK  A%%K6))K6))LG++!$+a.#669%(Q%8%8DKN A%%fQi000 .vvvwOOPPPPPr:ct|rt|rt|std|||t}||}||||||dSN,Empty glyph class in contextual substitution)rr rrrrrrrr#rrrr/s r8add_chain_context_substzBuilder.add_chain_context_substs6{{ #f++ S[[ !> !!(,DEE--g66 !!&&&&(KKKKKr:c|rt|rt|std|||t}||t }|||t }|j|t| }| |||g||gdSr) rr rrfind_chainable_substr!rrrr_keysr)rrrrrrsubrs r8rz!Builder.add_single_subst_chained_s c&kk V !>    +CDD((2DEE ;**85GHHC 7###7<<>>"" !!%$#GGGGGr:cXt|rt|std|||t}|||it }|||t }||j|<||||hg||gdSr) rr rrrrrrr)rrrrrrrrs r8rz Builder.add_multi_subst_chained_s6{{ #f++ !>   +CDD((%)>@TUU ;**85IJJC) E !!%5'FSEJJJJJr:c t|rt|std|||t}|||}|||t }tj|D]G}|j ||} | |krtd|d| d|d|||j |<H|j t||||gdS)Nrz!Conflicting ligature sub rules: 'z ' maps to 'z' and '')rr rrfind_chainable_ligature_substrrrr ligaturesrrrr%) rrrr#rrrrrexistings r8rz#Builder.add_ligature_subst_chained_s)6{{ #f++ !>   +CDD11&+FF ;**85IJJC"F+ + +A}((K88H;&&%eeeheeWbeee +CM!   .vvvuMMNNNNNr:c|std|||t}|j|||fdS)Nr)r rr rr)rr old_prefix old_suffixrrs r8add_reverse_chain_single_substz&Builder.add_reverse_chain_single_substsU Q!"ExPP P!!(,JKK ZW=>>>>>r:c|s|s|r|||||dS||t}|D]\}}|std||||d} |D]O} ||| | #t $r(} tt| | j| d} ~ wwxYwdS)N%Empty glyph class in positioning ruleFpairPosContext) add_single_pos_chained_rr$r makeOpenTypeValueRecordadd_posr'r-r) rrrrposrrr#rs otValueRecordrr2s r8add_single_poszBuilder.add_single_poss)  IV Iz I  ( (663 G G G G G%%h0@AAF!$ I I )?!% < <eE!=!! $IIEIx FFFF+III-c!ffajAAqHII I Is2B  B<#B77B<c|r|std|||t}|||d}|||d}t t t |} t t t |} ||| || |dSNrTr)r rr#rr>rr_ addClassPair) rr glyphclass1value1 glyphclass2value2rv1v2cls1cls2s r8add_class_pair_poszBuilder.add_class_pair_poss U+ U!"I8TT T!!(N;;  ) )(F4 ) P P  ) )(F4 ) P PVC ,,--..VC ,,--..HdBb99999r:c|r|std|||t}|||d}|||d}||||||dSr)r rr#r addGlyphPair) rrglyph1rglyph2rrrrs r8add_specific_pair_poszBuilder.add_specific_pair_poss UV U!"I8TT T!!(N;;  ) )(F4 ) P P  ) )(F4 ) P PHfb&"=====r:c |std|||t}|||||||||dSNr)r rradd_attachmentmakeOpenTypeAnchor)rr glyphclass entryAnchor exitAnchorrs r8add_cursive_poszBuilder.add_cursive_poss U!"I8TT T!!(,=>>    # #Hk : :  # #Hj 9 9      r:c||t}|||||std||D]C\}}|||}|D]%}||j|i|j<&DdSr )rr add_marks_r r rrr<) rrrmarksr baseAnchorr otBaseAnchorrs r8add_mark_base_poszBuilder.add_mark_base_poss""8-?@@ '5111 U!"I8TT T%* R R !J 228ZHHL R REQ ((r229>BB R R Rr:c4||t}g}|std||D]V}i}|||||D]#\}} ||||| j<$||W|D] } ||j| < dSr )rrr rr r<rr) rrr componentsrcomponentAnchorsranchors ligAnchorrrs r8add_mark_lig_poszBuilder.add_mark_lig_poss""8->?? U!"I8TT T - -EG OOHgu 5 5 5(- W W$ 9*.*A*A(I*V*V ''  # #G , , , , 8 8E'7G e $ $ 8 8r:c||t}|||||std||D]C\}}|||}|D]%}||j|i|j<&DdSr )rrrr r  baseMarksrr<) rrrrrrrrbaseMarks r8add_mark_mark_poszBuilder.add_mark_mark_pos+s""8-?@@ '5111 U!"I8TT T%* ! ! !J 228ZHHL% ! !!!,,Xr::N ! ! !r:ct|rt|rt|std|||t}||}||||||dS)N0Empty glyph class in contextual positioning rule)rr rrrrrs r8add_chain_context_poszBuilder.add_chain_context_pos8s6{{ #f++ S[[ !BH !!(,BCC--g66 !!&&&&(KKKKKr:c|rt|rt|std|||t}g}|jD]\}}}}||g} |D]\} } | | d||| d} ||| | } | 0| |t} || | D]}| ||| | | t|t| ks J|| fd|D} | ||| || dS)Nr#Frcg|]\}}|SrRrR)rCrrqs r8rUz3Builder.add_single_pos_chained_..[s$$$1!$$$r:)rr rrrrrrfind_chainable_single_posrr$rrr)rrrrrrtargetsrrsubsr#rsotValuerrs r8rzBuilder.add_single_pos_chained_As #f++ S[[ !BH   +ABB %  $ $ Aq!W NN7 # # # #  MFE} D!!!22%3G11'67KKC{..x9IJJs### 6 6 HeW5555 KK    3xx3t99$$$sDk$$$$$$$$ !!%FFFFFr:c j|D]\}}|jD]}|jD]}||jvr?||t j|j}|j|f|j|<J|j|d} |j| krtd|d| d|j|dS)z)Helper for add_mark_{base,liga,mark}_pos.rrz cannot be in both @z and @N) rr#rrr copydeepcopyanchorr<r ) rr lookupBuilderrrrrmark otMarkAnchorexistingMarkClasss r8rzBuilder.add_marks_^s!  LAy ) 5   (/88::  D=#666'+'>'>$dmL4G&H&H(( 6?^\4R +D11,9,?,Ea,H)$>->>>"1/#'44):):):INN!L (##?    r:c:|j|dSrB)rhadd_subtable_break)rrs r8r4zBuilder.add_subtable_breakqs ++H55555r:c|j|d\}}|r||krtd|d||||f|j|<dS)NNNrz& was assigned to a different class at )rrr )rrr glyphClassoldClass oldLocations r8setGlyphClass_zBuilder.setGlyphClass_tsr $ 4 8 8 M M+  J..!/55++'  (28&<U###r:c|D]}|||d|D]}|||d|D]}|||d|D]}|||ddS)Nrr@rr)r:)rr baseGlyphsligatureGlyphs markGlyphscomponentGlyphsrs r8add_glyphClassDefzBuilder.add_glyphClassDef~s  4 4E   % 3 3 3 3# 4 4E   % 3 3 3 3 4 4E   % 3 3 3 3$ 4 4E   % 3 3 3 3 4 4r:c6|D]}||jvr ||j|<dSrB)rrrr#caretsrs r8add_ligatureCaretByIndex_z!Builder.add_ligatureCaretByIndex_s7 5 5ED000.4$U+ 5 5r:crt|ts|S|||\}}|||fS|SrB)rVrmakeVariablePos)rrcaretdefaultdevices r8 makeLigCaretzBuilder.makeLigCaretsH%00 L..x??  V$ $r:cXfd|D}|D]}|jvr |j|<dS)Nc<g|]}|SrR)rJ)rCrGrrs r8rUz3Builder.add_ligatureCaretByPos_..s)III$##He44IIIr:)rrBs`` r8add_ligatureCaretByPos_zBuilder.add_ligatureCaretByPos_sUIIIII&III 5 5ED000.4$U+ 5 5r:cD|j|||||gdSrB)r}r)rrr r-r.r/r0s r8add_name_recordzBuilder.add_name_records) FJ 66JKKKKKr:c||j|<dSrB)rrrrss r8 add_os2_fieldzBuilder.add_os2_fields #r:c||j|<dSrB)rrQs r8add_hhea_fieldzBuilder.add_hhea_field 3r:c||j|<dSrB)rrQs r8add_vhea_fieldzBuilder.add_vhea_fieldrUr:cbd|jvrtd|||jvrtd|d|d|jDfd|D}d|jvr2|jdjfd|D}||j|<dS) NrPz?Cannot add feature variations to a font without an 'fvar' tablezCondition set 'z/' has the same name as a previous condition setcBi|]}|j|j|j|jfSrR)rSminValue defaultValuemaxValue)rCrs r8rz,Builder.add_conditionset..s:    L4=$*;T]K   r:c vi|]5\}\}}|t||t||f6SrR)r,)rCrDbottomtopaxisMaps r8rz,Builder.add_conditionset..sZ   #]fc vws|44sGCL11   r:avarcRi|]"\}tfd|D#S)c3PK|] }vrt|n|V!dSrB)r-)rCrqrrs r8rEz6Builder.add_conditionset...sU=AGOO&q'$-888QRr:)r>)rCcondition_rangerrs @r8rz,Builder.add_conditionset..sg *D/ e,r:)r6r rr\rsegments)rrrrsr`rs @@r8add_conditionsetzBuilder.add_conditionsets  " "!Q  $% % %!V#VVV             ',kkmm     TY  i'0G .3[[]] E$)C   r: varscalarrreturntuple[int, int | None]cN|j|jtd||js|j|dfS |j||j\}}n##t $r}td||d}~wwxYwd}||dkrt|}||fS)zMake a pos statement from a VariableScalar, returning the default value, and optionally the variation index if the scalar genuinely requires variation too.Nz5Can't define a variable scalar in a non-variable fontz,Failed to compute deltas for variable scalarl)r[r^r does_vary default_valueadd_to_variation_storer(r*)rrrgrHrr2rIs r8rFzBuilder.makeVariablePoss   '4+>+F!G " F&44Y??E E !0GG4/NGUU   !>     *!4!4%e,,Fs#A'' B1BBcd}t|ts'|!tjt |}||fS|||\}}||t d|||fS)N4Can't define a device coordinate and variable scalar)rVrr buildDevicer?rFr )rrg deviceTablerrIrHs r8 makeAnchorPoszBuilder.makeAnchorPoss)^44 %&k):):;;f$ $..xCC  +"9!F r:c|dSd\}}|j&tjt|j}|j&tjt|j}||j|j|\}}||j|j|\}}tj|||j ||}|S)zast.Anchor --> otTables.AnchorNr6) xDeviceTablerrpr? yDeviceTablerrry buildAnchor contourpoint)rrr.deviceXdeviceYrrv otlanchors r8r zBuilder.makeOpenTypeAnchors >4%   *od6+>&?&?@@G   *od6+>&?&?@@G''&2ExPP 7''&2ExPP 7OAq&*=wPP r:ci|]D\}}}}|d|d|ddz||fES)ReservedrrN) startswithlower)rCrr<isDevices r8rzBuilder. sb AtXqz** Q $qrr("T8$4r:c:|sdSi}|jD]\}\}}t||d}|s|r%tjt |||<Ct |trv|dddz} | d| ddz} t|| rtd|| ||\||<} | | || <|||<|r|s|j rddinddi}tj |} | S) z&ast.ValueRecord --> otBase.ValueRecordNrrDevicerroYAdvanceXAdvance) _VALUEREC_ATTRSrr:rrpr?rVrrr rFr buildValue) rrrqrvrastNameotNamerval otDeviceName feaDeviceNamerIvalRecs r8rzBuilder.makeOpenTypeValueRecordse 4 +/+?+E+E+G+G ! ! 'G'fh!Wd++C  ! _T#YY776 C00 !%ac{X5 ,Q 5 5 7 7,qrr:J J 1m,,)NPX&*%9%9(C%H%H"6 F%'-B|$ 6  D" D$%JC*aZOB## r:NFrB)F)rgrrhri)b__name__ __module__ __qualname__rrrr5rrrrrrrrr(rrrur~rrrjrrrrrrrrr3rrrAr+rxrzrrrrrrrrrrrrrrrrrrrrrrrrr staticmethodrrrrrrrrr rrrr!r$rrr4r:r@rDrJrMrOrRrTrWrfrFrrr rvalueRecordFormatrrrRr:r8r4r4as i       O G!G!G!R<<<<|>>>     :1*1*1*f 0 0 0222" : : :$$$---^4RURURUh((( 4 4 4???$S S S j+4+4+4Z    ***X!!!F$>>>NNN !!!FgggR. ???2 1 1 15555"$$$2222&222HHH&&&+B+B+BZ$ ! ! !RRR* NNN<<<$$$%%%///333>@==== / / / (((&   $IN     ///*   *QQ\Q,LLL H H H K K KOOO4???III(:::>>>    RRR 8 8 8 ! ! !LLLGGG:&666=== 4 4 4555 555 LLL      ()()()T<      $*$<O r:r4r)NNF)O __future__rfontTools.miscrfontTools.misc.textToolsrrrrfontTools.feaLib.errorr fontTools.feaLib.lookupDebugInfor r r fontTools.feaLib.parserr fontTools.feaLib.astrfontTools.feaLib.variableScalarrrfontTools.otlLibrrfontTools.otlLib.maxContextCalcrfontTools.ttLibrrfontTools.ttLib.tablesrrfontTools.otlLib.builderrrrrrrrrrr r!r"r#r$r%r&fontTools.otlLib.errorr'fontTools.varLib.errorsr(fontTools.varLib.varStorer)fontTools.varLib.builderr*fontTools.varLib.featureVarsr+fontTools.varLib.modelsr,r- collectionsr.r,rior/loggingrr getLoggerrrr9r?objectr4rRr:r8rs"""""""""""""EEEEEEEEEEEE222222 +*****,,,,,,QQQQQQQQ++++++6666664444444433333333$433333//////;;;;;;555555@@@@@@FFFFFFFF######  g!!....&7<GGGG2MMMMMfMMMMMr: