
    .`i                        d Z ddlmZ ddlZddlmZ ddlmZ ddlmZ ddl	m
Z
 ddlmZmZ dd	lmZmZmZ dd
lmZ ddlmZ ddlmZ ddlmZ ddlmZmZmZ ddlmZ ddl m!Z! ddl"m#Z#m$Z$ ddl%m&Z& ddl'm(Z( ddl)m*Z* ddl+m,Z, ddl-m.Z.m/Z/m0Z0 ddl1m2Z2m3Z3m4Z4m5Z5m6Z6  ee7          Z8 G d dej9                  Z: G d dej9                  Z; G d dej9                  Z<e
 G d d e0                      Z= G d! d"e.e&          Z>dS )#z?Inference-only LLaMA model compatible with HuggingFace weights.    )IterableN)nn)Llama4TextConfig)	Attention)support_torch_compile)CacheConfig
VllmConfig)get_ep_group$get_tensor_model_parallel_world_size tensor_model_parallel_all_gather)init_logger)ChunkedLocalAttention)SharedFusedMoE)RMSNorm)QKVParallelLinearReplicatedLinearRowParallelLinear)QuantizationConfig)get_rope)default_weight_loadermaybe_remap_kv_scale_name)MixtureOfExperts)sequence_parallel_chunk)current_platform)is_torch_equal_or_newer   )LlamaForCausalLMLlamaMLP
LlamaModel)AutoWeightsLoaderPPMissingLayerextract_layer_index	fast_topkis_pp_missing_parameterc                        e Zd Zedej        dej        dededeej        ej        f         f
d            Z	dde
d	ef fd
Zd Z xZS )	Llama4MoEhidden_statesgating_outputtopkrenormalizereturnc                     t          ||d          \  }}t          j        |                                          }||                    t          j                  fS Ndim)r#   torchsigmoidfloattoint32)r'   r(   r)   r*   router_scoresrouter_indicess         u/home/jaya/work/projects/VOICE-AGENT/VIET/agent-env/lib/python3.11/site-packages/vllm/model_executor/models/llama4.pycustom_routing_functionz!Llama4MoE.custom_routing_functionF   sS     )2-2(N(N(N%~m&9&9&;&;<<~00==>>     vllm_configprefixc                    t                                                       |j        j        }|j        }|j        }t                      | _        |j        | _	        |j
        | _        t                      j        | _        t                      j        | _        | j                                        | _        |j        }t)          |j        |j        dd | d          | _        t1          |j        |d|d| dd| j                  | _        |r|j        nd }|r|j        nd| _        |r|j        nd| _        |j        | _        | j        | _        d| _         |j        | _!        | j!        | j        z   | _"        | j"        | j        z  | _#        tI          | j        |j        |j        |j        tJ          j&        |d	dd|| d
| j        | j        | j                  | _'        d S )NFz.router)biasquant_configr=   siluz.shared_expert)hidden_sizeintermediate_size
hidden_actr@   r?   r=   reduce_results
disable_tpr   r   Tz.experts)shared_expertsnum_expertstop_krB   r9   rC   apply_router_weight_on_inputrE   r*   r@   r=   is_sequence_parallelenable_eplbnum_redundant_experts)(super__init__model_config	hf_configparallel_configr@   r   tp_sizenum_experts_per_tokrI   use_sequence_parallel_moerK   r
   device_groupep_grouprank_in_groupep_ranksizeep_sizerC   r   rB   num_local_expertsrouterr   shared_experteplb_configrL   rM   n_redundant_expertsn_routed_expertsn_logical_expertsn_shared_expertsn_local_expertsn_physical_expertsn_local_physical_expertsr   r&   r9   experts)	selfr<   r=   configrR   r@   intermediate_size_moer_   	__class__s	           r8   rO   zLlama4MoE.__init__R   s   )3%5"/;==/
$3$M!$3#~~3}))++ & 8&$%%%
 
 
 &*3%,,, 0	
 	
 	
 6ENo11$:IT?66u1<CK--! 	  &,%=!%!6%&$*$<"&"69Q"Q(,(?4<(O%%-0,*$-$E3)- %&&&!%!:("&":
 
 
r:   c                 H   |j         d         }| j        rt          |          }|                     |          \  }}|                     ||          \  }}||z   }| j        rt          |d          }|d |         }n%| j        dk    r| j                            |          }|S )Nr   )r'   router_logitsr   )shaperK   r   r]   rg   r   rS   &maybe_all_reduce_tensor_model_parallel)rh   r'   
num_tokensrm   _
shared_out
routed_outexperts_outs           r8   forwardzLlama4MoE.forward   s    "(+
$ 	C3MBBM;;}55q!%'' ". "
 "

J !:-$ 	:;JJK%kzk2KK\A,MM K r:   )r;   )__name__
__module____qualname__staticmethodr1   Tensorintbooltupler9   r	   strrO   ru   __classcell__rk   s   @r8   r&   r&   E   s        	?|	?|	? 	? 		?
 
u|U\)	*	? 	? 	? \	??
 ?
J ?
 ?
 ?
 ?
 ?
 ?
 ?
B      r:   r&   c                        e Zd Z	 	 	 	 	 	 ddedededed	ed
edz  dedededz  deddf fdZ	de
j        de
j        fdZde
j        de
j        de
j        fdZ xZS )Llama4Attention    NFr;   ri   rB   	num_headsnum_kv_headsmax_position_embeddingsr@   r?   bias_o_projcache_configr=   r+   c           
         t                                                       t          |
          | _        || _        |j        | _        | j        | j                 dk    | _        |j        o| j         | _        t                      }|| _	        | j	        |z  dk    sJ | j	        |z  | _
        || _        | j        |k    r| j        |z  dk    sJ n|| j        z  dk    sJ t          d| j        |z            | _        |j        | _        | j
        | j        z  | _        | j        | j        z  | _        | j        dz  | _        | j        o|j        | _        t'          |dd          | _        t'          |dd          | _        || _        | j
        | j        z  | _        | j        r't1          | j        |j        dt4          j        	          nd | _        t;          || j        | j	        | j        |||
 d
          | _        t?          | j	        | j        z  ||||
 d          | _         d}|o|!                                dk    }|r|j"        dk    rd}| j        stG          | j        ||j$        |          nd | _%        | j         o|j&        }|rtN          ntP          } || j
        | j        | j        f| j        |	||
 dd|r	d|j&        ini | _)        d S )Nr   r   g      floor_scaleg      @
attn_scaleg?F)rB   eps
has_weightdtype	.qkv_proj)rB   	head_sizetotal_num_headstotal_num_kv_headsr?   r@   r=   z.o_proj)
input_sizeoutput_sizer?   r@   r=   Tggufllama)max_positionrope_parametersis_neox_stylez.attn)r   r   r@   r=   attention_chunk_size)*rN   rO   r"   	layer_idxrB   no_rope_layersnopeuse_qk_normr   r   r   r   maxr   head_dimq_sizekv_sizescalingattn_temperature_tuninggetattrr   r   r   n_repr   rms_norm_epsr1   float32qk_normr   qkv_projr   o_projget_name
model_typer   r   
rotary_embr   r   r   attn)rh   ri   rB   r   r   r   r@   r?   r   r   r=   rS   r   is_ggufuse_chunked_local_attnattn_clsrk   s                   r8   rO   zLlama4Attention.__init__   sX    	,V44&$3'71<	!-?di-688(#g-2222-8"."g-- *W499999 T4499994#:g#EFFnt}4(4=8}d*'+y'SV5S$"6=&AA!&,<<'>$^t'88
 G M' m	     	 *#m 0#6%'''
 
 
 (+dm;#%%%%
 
 
 D<#8#8#:#:f#D 	"v(G33!M 9H4 & 6+	     	 &*Y!N63N,BQ((	HNML
 *%%###
 
 *')DEE
 
			r:   	positionsc                     t          j        |dz   | j        z            }t          j        |dz             | j        z  dz   }|                    d          S )Ng      ?r.   )r1   floorr   logr   	unsqueeze)rh   r   r   r   s       r8   _get_attn_scalezLlama4Attention._get_attn_scale  sP    Y_0@@AAYus{++do=C
##B'''r:   r'   c                    |                      |          \  }}|                    | j        | j        | j        gd          \  }}}| j        |                     |||          \  }}| j        |                    d| j                  }|                     |                                                              d| j                  	                    |j
                  }|                    d| j                  }|                     |                                                              d| j                  	                    |j
                  }| j        r9| j        r2|                     |          }||z  	                    |j
                  }|                     |||          }	|                     |	          \  }
}|
S r-   )r   splitr   r   r   r   reshaper   r3   r4   r   r   r   r   r   r   )rh   r   r'   qkvrq   qkvr   attn_outputoutputs              r8   ru   zLlama4Attention.forward  s}   
 }--Q))T[$,E2)NN1a?&??9a33DAq<# 		"dm,,AQWWYY''//DK@@CCAGLLA		"dm,,AQWWYY''//DLAADDQWMMA ' 	-DI 	---i88JZ##AG,,Aii1a((KK,,	r:   )r   NFFNr;   )rv   rw   rx   r   r{   r   r|   r   r~   rO   r1   rz   r   ru   r   r   s   @r8   r   r      s;        (,26!+/e
 e
 e
 e
 	e

 e
 "%e
 )4/e
 e
 e
 "D(e
 e
 
e
 e
 e
 e
 e
 e
N( (%, ( ( ( (!<! |! 
	! ! ! ! ! ! ! !r:   r   c            
            e Zd Z	 	 ddedededz  ddf fdZdej        d	ej        d
ej        dz  de	ej        ej        f         fdZ
 xZS )Llama4DecoderLayerr;   Nr<   r=   ri   r+   c                    t                                                       |p|j        j        }|j        }|j        }t          |          | _        |j        | j                 dk    | _	        |j
        | _
        |j        }t          || j
        |j        |j        ||dd|| d
  
        | _        |j        dk    o| j        dz   |j        z  dk    }|rt#          || d          | _        n't'          | j
        |j        d|d| d	          | _        t+          |j
        |j        
          | _        t+          |j
        |j        
          | _        d S )Nr   Fz
.self_attn)
ri   rB   r   r   r   r@   r?   r   r   r=   r   z.feed_forward)r<   r=   rA   )rB   rC   rD   r@   r?   r=   )r   )rN   rO   rP   rQ   r   r@   r"   r   r   global_layerrB   r   r   num_attention_headsnum_key_value_heads	self_attninterleave_moe_layer_stepr&   feed_forwardr   intermediate_size_mlpr   r   input_layernormpost_attention_layernorm)	rh   r<   r=   ri   r   r@   r   is_moe_layerrk   s	           r8   rO   zLlama4DecoderLayer.__init__>  s    	=;3="/"/,V44"1$.AQF!-"("@((03$;%%(((
 
 
 ,q0 M!#v'GG1L 	  	 )' ///! ! !D
 !) ,"(">!) ///! ! !D  'v'9v?RSSS(/F$7)
 )
 )
%%%r:   r   r'   residualc                     ||}|                      |          }n|                      ||          \  }}|                     ||          }|                     ||          \  }}|                     |          }||fS )N)r   r'   )r   r   r   r   )rh   r   r'   r   s       r8   ru   zLlama4DecoderLayer.forwardr  s     $H 00??MM&*&:&:=(&S&S#M8-XX #'"?"?x"X"Xx))-88h&&r:   )r;   N)rv   rw   rx   r	   r~   r   rO   r1   rz   r}   ru   r   r   s   @r8   r   r   =  s         *.	2
 2
2
 2
 !4'	2

 
2
 2
 2
 2
 2
 2
h'<' |' ,%	'
 
u|U\)	*' ' ' ' ' ' ' 'r:   r   c                        e Zd Zdeddededee         f fdZ	 dded	ej	        d
e
eej        f         dee         deeeeeef                  dedefdZdeeeej	        f                  dee         fdZ xZS )Llama4Modelr;   )r=   
layer_typer<   r=   r   c                    |j         j        j        | _        |j        j        j        | _        t                      	                    |||           d S Nr<   r=   r   )
rP   rQ   r\   rH   rR   r_   rM   r`   rN   rO   )rh   r<   r=   r   rk   s       r8   rO   zLlama4Model.__init__  sQ     '3=O'3I 	  	[JWWWWWr:   Tnameloaded_weightparams_dictloaded_paramsexpert_params_mappingfusedr+   c                    d}|r<|j         dk    r1|                    dd          }d|v r|                    dd          }|D ]\  }}	}
}|}|r&|	                    d          \  }}}}| d| }	| d	}|	|vr7|                    |	|          }t          ||           r^|                    d
          s|                    d          r||vr||         }|j        }|rNd|v r|dv sJ |dk    rdnd}||         }t          |          }| j	        |         j
        j        j        }||dk                                                                                        |j                  }|j        t%          j                    k    p#|j        j        o|                                dk    }|j        j        dk    rO|rMt/          d          s>|                    t0          j                  |                             |j                  }n||         }|d                                         }
n	  ||||||
           |                    |           d}|S )a,  
        Load MoE expert weights.

        Args:
            name: The name of the weight to load.
            loaded_weight: The weight to load.
            params_dict: The dictionary of module parameters.
            loaded_params: The set of already loaded parameters.
            expert_params_mapping: The mapping of expert parameters. Must be
                generated by SharedFusedMoE.make_expert_params_mapping().
            fused: Whether the expert weights are fused into a single weight
                tensor or are separate weight tensors for each expert.
                When fused is True, loaded_weight should have shape of:
                [num_experts, hidden_in, hidden_out] for gate/up/down proj and
                [hidden_out, hidden_in] for the others like router.
                When fused is False, loaded_weight should have shape of:
                [hidden_out, hidden_in].

        Returns:
            True if loaded_weight is one of MoE weights and the MoE expert
            weights are loaded successfully, False otherwise.
        F   r.   experts.gate_up_proj   r/   .weightz.bias_biasw13)w1w3r   r   r   Ncpuz2.11.0shard_id	expert_idT)ndim	transposechunkr   replacer$   endswithweight_loaderr"   layersr   rg   
expert_mapnonzeroflattenr4   devicer   r   	fp8_dtypeis_floating_pointelement_sizetyper   r1   float16itemadd)rh   r   r   r   r   r   r   expert_param_loaded
param_nameweight_namer   r   new_loaded_weighte_strrq   proj_strfull_param_nameparamr   	shard_idxr   r   local_expert_indicesis_fp8_dtypes                           r8   load_moe_expert_weightsz#Llama4Model.load_moe_expert_weights  s   B $
  	?]'1,,)33B;;M
 &-- - 3 3A2 3 > > =R Y	' Y	'8JY !.  3(3(9(9#(>(>%q(A!&3333 *222
 $&& #ll;
CCO 'tT22  g&&*.--*@*@k))0E!/M + O++#|3333%-%5%51I(9)(D%
 055	![3@HS
)#r)  -455	 ) $5#:(244$ $ */A B-::<<A	 ! *05>>( ? 7 A A ?
 ->,@,@,O,O0-".455 *) ->>R,S) 4Q 7 < < > >I  M!!#    o..."&""r:   weightsc           	      X   g d}d}t          j        | ddd| j        | j                  }t          j        | dddd	          }t	          |                                           }t                      }|D ]\  }d
v sdv rd}|}| j        ~| j                                      x}	rb||	         }
t          |
dt                    }|                                dk    r|n|d         } ||
|           |                    |	           |D ]\  }}}|vsdv r                    d          rdv s                    ||          t          |           rO                    d          rt!          |          w|         }
t          |
dt                    }|t          k    r ||
|           n ||
||           |                                nG|                     |||||          rt          |           rg d}dv rt%          fd|D                       r|         }
t          |
dt                    }t          |dd          rddv rdnd}                    d          r6|j        t(          j        k    r!|j        dk    r|                    dd          } ||
||d           n ||
|           |                               s|         }
t          |
dt                    } ||
|           |                               |S ) N))r   z.q_projr   )r   z.k_projr   )r   z.v_projr   ).gate_up_projz
.gate_projr   )r  z.up_projr   F	gate_proj	down_projup_proj)ckpt_gate_proj_nameckpt_down_proj_nameckpt_up_proj_namerH   rM   gate_up_projr   )r  r  r  rH   r   zexperts.down_projTr   r   rg   )z.k_scalez.v_scaler   scale)r   )w13_input_scalew13_weight_scalew2_input_scalew2_weight_scalezexperts.c              3       K   | ]}|v V  	d S N ).0
scale_namer   s     r8   	<genexpr>z+Llama4Model.load_weights.<locals>.<genexpr>  s9       . .+5J$&. . . . . .r:   supports_moe_loadingw2_w2r   weight_scaler   r.   r   r   )r   make_expert_params_mappingrH   r`   dictnamed_parameterssetr@   get_cache_scaler   r   r0   r   r   r   r$   r   r	  anyr   r1   float8_e4m3fnr   r   )rh   r
  stacked_params_mappingfused_experts_paramsr   expert_params_mapping_fusedr   r   r   r  r  r   r   r   r   scale_namesr   s                   @r8   load_weightszLlama4Model.load_weights#  sg   "
 "
 "
  % !/ I + +'("&":!
 !
 !
 '5&O . +,'
 '
 '
# 4002233"%%% $+ H	( H	(D- &--1D1L1L'+$(C%
  ,"/??EEE
 - $J/ '@U V V%2%6%6%8%8A%=%=MM=QRCS  e]333!!*--- 6L m( m(1
K d**i4.?.?
 MM":;;A@Kt@S@S<<Z@@D +466 
 ==)) !4T;GGD|  $D) '@U V V $999!M%7777!M%AAA!!$''' //!!). 0     +466 
   %%# . . . .9D. . . + +% (-E$+0E% %M }.DeLL <+0D==44d !MM.99L - 3u7J J J - 2a 7 7,9,C,CB,K,KM &!=$UV     &e];;;!%%d+++ $D) '@U V Ve]333!!$''' r:   )T)rv   rw   rx   r   r	   r~   r   rO   r1   rz   r$  r   	Parameterr&  listr}   r{   r|   r	  r   r.  r   r   s   @r8   r   r     sS        /AX X X  X 	X
 +,X X X X X X( L# L#L# |L# #r|+,	L#
 3xL#  $E#sC*<$=>L# L# 
L# L# L# L#\rHU33D-E$F r3s8 r r r r r r r rr:   r   c                        e Zd Zg dddgdZdddedef fd	Zd
 ZdededdfdZ	de
fdededee
         fdZdeeeej        f                  dee         fdZdedej        deeej        f         fdZ xZS )Llama4ForCausalLM)q_projk_projv_projr  r  )r   r  r;   )r=   r<   r=   c                \   |j                                         }|                    |j         j                   |j         j        dk    }|                    d|          |j         j        _        t                      	                    ||t                     |                                  d S )Ni   r   r   )rP   try_get_generation_configupdateoverride_generation_configmax_model_lengetrQ   r   rN   rO   r   set_moe_parameters)rh   r<   r=   
gen_configdefault_attn_temperature_tuningrk   s        r8   rO   zLlama4ForCausalLM.__init__  s     -GGII
+2MNNN*5*B*PSX*X'EO^^%'FF
 F
 *B 	#F?Q 	 	
 	
 	
 	!!!!!r:   c                    g | _         g | _        d }| j        j        D ]t}t	          |t
                    rt	          |t                    sJ t	          |j        t                    r+|j        }| j        	                    |j        j
                   u|Td| _        d| _        d| _        d| _        d| _        d| _        d| _        d| _        t&                              d           d S t+          | j                  | _        d| _        |j        | _        |j        | _        |j        | _        |j        | _        |j        | _        |j        | _        d S )Nr   z)No Llama4MoE layer found in model.layers.r   )expert_weights
moe_layersmodelr   
isinstancer!   r   r   r&   appendrg   num_moe_layersnum_expert_groupsnum_logical_expertsnum_physical_expertsnum_local_physical_expertsnum_routed_expertsnum_shared_expertsrM   loggerwarninglenrb   re   rf   ra   rc   r`   )rh   example_moelayers      r8   r<  z$Llama4ForCausalLM.set_moe_parameters  sT    Z& 	C 	CE%00 e%788888%,i88 C#0&&u'9'ABBB"#D%&D"'(D$()D%./D+&'D#&'D#)*D&NNFGGGGG"%do"6"6D%&D"'2'DD$(3(FD%.9.RD+&1&BD#&1&BD#)4)HD&&&r:   rH  rI  r+   Nc                 L   | j         |k    sJ || _        || _         || j        z
  | _        | j        j        D ]l}t          |t                    rt          |j        t                    r:|j        }||_
        ||_        | j        |_        |j                                         md S r  )rI  rH  rG  rM   rB  r   rC  r!   r   r&   rf   re   r`   rg   update_expert_map)rh   rH  rI  rP  moes        r8    update_physical_experts_metadataz2Llama4ForCausalLM.update_physical_experts_metadata  s    
 .2LLLLL$8!*D'%9D<T%T"Z& 		0 		0E%00 %,i88 0(/I,)=&*.*D'--///		0 		0r:   r   c                 &    t          |||          S r   )r   )rh   r<   r=   r   s       r8   _init_modelzLlama4ForCausalLM._init_model%  s"     #Fz
 
 
 	
r:   r
  c                      t            j        j        rdgnd           } fd|D             }|                    |          S )Nzlm_head.)skip_prefixesc                 B    g | ]\  }}                     ||          S r  )permute_qk_weight_for_rotary)r  r   r   rh   s      r8   
<listcomp>z2Llama4ForCausalLM.load_weights.<locals>.<listcomp>4  s=     
 
 
#m --dMBB
 
 
r:   )r    ri   tie_word_embeddingsr.  )rh   r
  loaders   `  r8   r.  zLlama4ForCausalLM.load_weights/  sl    "+/;+JTJ<<PT
 
 

 
 
 
'.
 
 
 ""7+++r:   r   r   c                 V    dt           j        dt          dt          f fd}|                    d          }|d         dk    }|d         dk    o|j        t           j        k    }|s|r?d	|v sd
|v r || j        j        |          }nd|v sd|v r || j        j	        |          }||fS )Nwn_headsis_weight_scalec                    j         j        |z  }j         j        }| j        t          j        k    r| j        d         dz  |k    r|dz  }n0| j        t          j        k    r|r| j        d         dz  |k    r|dz  }|                     |||z  dz  d|          	                    dd          
                    ||          S )Nr   r      )ri   r   rB   r   r1   uint8rn   r)  viewr   r   )r_  r`  ra  attn_inattn_outrh   s        r8   permutez?Llama4ForCausalLM.permute_qk_weight_for_rotary.<locals>.permute@  s     k*W4G{.H w%+%%!'!*q.H*D*D#q=
 5...# /GAJOx//#r> w7 2a 7HEE1a(++r:   r   r.   r   r"  wkr4  wqr3  )
r1   rz   r{   r|   r   r   r)  ri   r   r   )rh   r   r   rh  modules	is_weightis_nvfp4_weight_scales   `      r8   rZ  z.Llama4ForCausalLM.permute_qk_weight_for_rotary:  s   	u| 	c 	D 	 	 	 	 	 	4 **S// BK8+	BK>)Xm.AUEX.X 	  	- 	w(g"5"5 '!K3)! !
 H$7$7 '!K3)! ! ]""r:   )rv   rw   rx   packed_modules_mappingr	   r~   rO   r<  r{   rT  r   r   rV  r   r}   r1   rz   r&  r.  rZ  r   r   s   @r8   r2  r2    su       222$i0 
 BD " " "z "3 " " " " " " !I !I !IF0!0 %(0 
	0 0 0 0. /A	
 

 
 +,	
 
 
 
	,HU33D-E$F 	,3s8 	, 	, 	, 	,6#6# |6# 
sEL 	!	6# 6# 6# 6# 6# 6# 6# 6#r:   r2  )?__doc__collections.abcr   r1   r   transformersr   vllm.attention.layerr   vllm.compilation.decoratorsr   vllm.configr   r	   vllm.distributedr
   r   r   vllm.loggerr   <vllm.model_executor.layers.attention.chunked_local_attentionr   $vllm.model_executor.layers.fused_moer   $vllm.model_executor.layers.layernormr   !vllm.model_executor.layers.linearr   r   r   'vllm.model_executor.layers.quantizationr   +vllm.model_executor.layers.rotary_embeddingr   -vllm.model_executor.model_loader.weight_utilsr   r   %vllm.model_executor.models.interfacesr    vllm.model_executor.models.utilsr   vllm.platformsr   vllm.utils.torch_utilsr   r   r   r   r   utilsr    r!   r"   r#   r$   rv   rL  Moduler&   r   r   r   r2  r  r:   r8   <module>r     sv  & F E $ $ $ $ $ $        ) ) ) ) ) ) * * * * * * = = = = = = / / / / / / / /         
 $ # # # # #      @ ? ? ? ? ? 8 8 8 8 8 8         
 G F F F F F @ @ @ @ @ @        C B B B B B D D D D D D + + + + + + : : : : : : 9 9 9 9 9 9 9 9 9 9              
X		c c c c c	 c c cLO O O O Obi O O OdF' F' F' F' F' F' F' F'R N N N N N* N N Nb
X# X# X# X# X#(*: X# X# X# X# X#r:   