
    gn                     x   S SK r S SKrS SKJrJrJr  S SKJr  S SKJ	r	  S SK
Jr  S SKJrJrJr  Sr " S S	\5      rS
 rS rS r  S)S jrS rS rS rS rS rS rS rS rS rS r S r!S r"S r#S r$S r% " S S\5      r& " S S \5      r' " S! S"\5      r( " S# S$\5      r) " S% S&\5      r* " S' S(\5      r+g)*    N)write_dot_fileverify_and_dotverify_graph)KCCError)ndr_pack)misc)DEBUGDEBUG_FNWARN    c                   $    \ rS rSrSrS rS rSrg)ReplInfo#   zRepresents information about replication

NTDSConnections use one representation a replication schedule, and
graph vertices use another. This is the Vertex one.

c                 J    SU l         SU l        SU l        S U l        SU l        g )Nr     )costintervaloptionsscheduledurationselfs    1/usr/lib/python3/dist-packages/samba/kcc/graph.py__init__ReplInfo.__init__*   s%    	    c                 X    [        U5      U l        [        U R                  5      U l        g)zVConvert the schedule and calculate duration

:param schedule: the schedule to convert
N)convert_schedule_to_repltimesr   total_scheduler   )r   r   s     r   set_repltimes_from_schedule$ReplInfo.set_repltimes_from_schedule1   s     
 6h?&t}}5r   )r   r   r   r   r   N)__name__
__module____qualname____firstlineno____doc__r   r    __static_attributes__ r   r   r   r   #   s    6r   r   c                 \    U c  gSnU  H  nUS:w  d  M  XS-  -  nUS-  nUS:w  a  M  M!     U$ )zReturn the total number of 15 minute windows in which the schedule
is set to replicate in a week. If the schedule is None it is
assumed that the replication will happen in every 15 minute
window.

This is essentially a bit population count.
r   r      r(   )r   totalbytes      r   r   r   :   sH     EaiAXEQJD ai  Lr   c                     U b  U R                   S   c  S/S-  $ / nU R                   S   R                  n[        S5       H-  nUR                  X#S-     S-  S-  X#S-  S-      S-  -  5        M/     U$ )a  Convert NTDS Connection schedule to replTime schedule.

Schedule defined in  MS-ADTS 6.1.4.5.2
ReplTimes defined in MS-DRSR 5.164.

"Schedule" has 168 bytes but only the lower nibble of each is
significant. There is one byte per hour. Bit 3 (0x08) represents
the first 15 minutes of the hour and bit 0 (0x01) represents the
last 15 minutes. The first byte presumably covers 12am - 1am
Sunday, though the spec doesn't define the start of a week.

"ReplTimes" has 84 bytes which are the 168 lower nibbles of
"Schedule" packed together. Thus each byte covers 2 hours. Bits 7
(i.e. 0x80) is the first 15 minutes and bit 0 is the last. The
first byte covers Sunday 12am - 2am (per spec).

Here we pack two elements of the NTDS Connection schedule slots
into one element of the replTimes list.

If no schedule appears in NTDS Connection then a default of 0x11
is set in each replTimes slot as per behaviour noted in a Windows
DC. That default would cause replication within the last 15
minutes of each hour.
r      T            r*   )	dataArrayslotsrangeappend)r   timesdatais       r   r   r   N   s    6 8--a08v{Ea &&D2Ydq5kC'A-!eai31FGH  Lr   c                    [        5       n[        U R                  UR                  5      Ul        U R                  UR                  -  Ul        U R                  c  S/S-  U l        UR                  c  S/S-  Ul        [        U R                  UR                  5       VVs/ s H	  u  p4X4-  PM     snnUl        [        UR                  5      Ul        [        U R                  UR                  -   [        5      Ul	        U$ s  snnf )a  Generate an repl_info combining two others

The schedule is set to be the intersection of the two input schedules.
The duration is set to be the duration of the new schedule.
The cost is the sum of the costs (saturating at a huge value).
The options are the intersection of the input options.
The interval is the maximum of the two intervals.

:param info_a: An input replInfo object
:param info_b: An input replInfo object
:return: a new ReplInfo combining the other 2
   r/   )r   maxr   r   r   zipr   r   minr   	MAX_DWORD)info_ainfo_binfo_cabs        r   combine_repl_inforE   u   s     ZF&//6??;FO^^fnn4FN &2+&2+),V__foo)NO)Nqu)NOFO$V__5FOfkkFKK/;FKM	 Ps   !Dc                 
   [        5       nU R                   GH  nSnU R                   H
  n/ Ul        M     UR                   H=  n	U	R                  nU	R                   H  nUR                  R                  U	5        M      M?     U(       d  Ub  [        R                  " S UR                   5       6  V
Vs/ s H1  u  pU
R                  R                  UR                  R                  4PM3     nn
nU R                   Vs/ s H  oR                  R                  PM     nnUb  [        SU< 3UXS9  U(       aI  [        XSS9nU(       a8  [        SU-  5        U H  u  pn[        U<S S	U	< 35        M     [        S
5      e[        XS5        [        XU5        [        XS5        [        XU5        GM     [!        U 5        [        U SU5        U(       d  Ub  U V	s/ s HC  n	U	R"                  R                  R                  U	R$                  R                  R                  4PME     nn	U R                   Vs/ s H  oR                  R                  PM     nnSn['        SXUU[        X4S9  [)        X5      u  nn[        U SS5        U R                   H<  nUR+                  5       (       a	  SUl        M!  UR.                  R0                  Ul        M>     U(       d  Ub  U V	s/ s HC  n	U	R"                  R                  R                  U	R$                  R                  R                  4PME     nn	U R                   Vs/ s H  oR                  R                  PM     nnSn['        SXUU[        UUS9  / nU H  nUR                  u  nnUR                  UL d  UR                  UL d  M2  UR3                  5       (       d  UR3                  5       (       aF  UR,                  [4        :w  a2  SUl        UR,                  UR,                  :  a  UU4UR                  SS& UR                  U5        M     U(       d  Ub  U V	Vs/ s H4  n	U	R                   Vs/ s H  nUR                  R                  PM     snPM6     nn	nUR9                  S U 5       5        U R                   Vs/ s H  nUR                  R                  PM     nnSn['        SXUU[        USUS9	  UU4$ s  sn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n	f s  snf )a[  Find edges for the intersite graph

From MS-ADTS 6.2.2.3.4.4

:param graph: a kcc.kcc_utils.Graph object
:param my_site: the topology generator's site
:param label: a label for use in dot files and verification
:param verify: if True, try to verify that graph properties are correct
:param dot_file_dir: if not None, write Graphviz dot files here
Nc              3   d   #    U  H&  n[         R                  " UR                  S 5      v   M(     g7f)r0   N)	itertoolscombinationsvertices).0edges     r   	<genexpr>*get_spanning_tree_edges.<locals>.<genexpr>   s+      !:-8T "+!7!7q!I!I-8s   .0edgeset_)rJ   label)complete	connected)rJ   
propertiesz spanning tree edge set %s FAILEDz>18z: zspanning tree failedFT)multi_edge_forest
prekruskal)rP   rS   debugverifydot_file_dirEDGE_TYPE_ALLr   postkruskalc              3      #    U  HQ  oR                   (       a  M  [        UR                  5       Vs/ s H  nUR                  R                  PM     snv   MS     g s  snf 7fN)directedreversedrJ   site
site_dnstr)rK   exs      r   rM   rN     sO      A$-qZZ;%-ajj%9;%9 FF--%9;$-;s   A A  AA r(   zpost-one-way-partial)rP   rS   rV   rW   r]   rX   )setedge_setrJ   edgescon_typer6   rH   chainr_   r`   r   r   r	   r   dijkstraprocess_edge_setsetup_verticesv1v2r   kruskalis_reddist_to_red	repl_infor   is_blackr?   r]   extend)graphmy_siterP   rW   rX   internal_edgese_setedgeTypevra   rC   rD   graph_edgesgraph_nodeserrorspdocverify_propertiesoutput_edges
components	edge_listrL   wrb   s                           r   get_spanning_tree_edgesr      s{    UNAAG   AzzHZZq!   
 \- %??!:-2[[!:;<;  $q FF--qvv/@/@A;  <
 7<nnEn66,,nKE'x9;(3B %k1JL<xGH%+	cAq12 &,"#9:: 	%( 	~6 	$' 	~6Y  ^ 5UD.1) .0 .1 		,,addii.B.BC . 	 027..A.Qvv((.A2|[U"35$	A
  'u=L*
 UOU+^^88::AMKK,,AM	  ) .0 .1 		,,addii.B.BC . 	 027..A.Qvv((.A2}k"/@"6$0	2 I }}166W' 1**,,!**,,)+ $==1==0'(!tDMM!$T"  ) )+ )1 45::>:a)):> ) 	 + 	 A$-A 	A 38..A.Qqvv((.A-{"/@"6 $$0		2 j  O<
 FD0A*0A0 ? + BsD   58S>S A
S%6S* A
S/:S4:S> S9.S> T9S>c                    [        5       nXl        / Ul        UR                   HI  u  pE[	        U5      U;   d  M  UR                  R                  UR                  [	        U5      5      5        MK     UR                  UR                  l        UR                  UR                  l	        UR                  UR                  l
        UR                  R                  UR                  5        Xl        SUl        U$ )a  Set up a MultiEdge for the intersite graph

A MultiEdge can have multiple vertices.

From MS-ADTS 6.2.2.3.4.4

:param con_type: a transport type GUID
:param  site_link: a kcc.kcc_utils.SiteLink object
:param guid_to_vertex: a mapping between GUIDs and vertices
:return: a MultiEdge
F)	MultiEdge	site_linkrJ   	site_liststrrr   getr   rp   r   r   r    r   rf   r]   )rf   r   guid_to_vertexra   	site_guidsite_dns         r   create_edger     s     	AKAJ'11	y>^+JJn00Y@A 2 !~~AKK#++AKK$--AKKKK++I,>,>?JAJHr   c                     [        5       n[        R                  " 5       Ul        U R                   H0  nUR
                  U:X  d  M  UR                  R                  U5        M2     U$ )zSet up an automatic MultiEdgeSet for the intersite graph

From within MS-ADTS 6.2.2.3.4.4

:param graph: the intersite graph object
:param transport_guid: a transport type GUID
:return: a MultiEdgeSet
)MultiEdgeSetr   GUIDguidre   rf   r6   )rs   transport_guidrv   r   s       r   create_auto_edge_setr   5  sM     NEEJ[[	/KKy) ! Lr   c                 l   U R                    H  nUR                  5       (       a$  [        UR                  l        SUl        SUl        OSUR                  l        Xl        Xl        SUR                  l        SUR                  l        SUR                  l	        SUR                  l
        SUl        M     g)a_  Initialise vertices in the graph for the Dijkstra's run.

Part of MS-ADTS 6.2.2.3.4.4

The schedule and options are set to all-on, so that intersections
with real data defer to that data.

Refer to the convert_schedule_to_repltimes() docstring for an
explanation of the repltimes schedule values.

:param graph: an IntersiteGraph object
:return: None
Nr   r   r   F)rJ   is_whiter?   rp   r   rootcomponent_idr   r   r   r   demoted)rs   rx   s     r   rj   rj   H  s     ^^::<<(AKKAF!AN AKKFN (#%	 r   c           	         [        XU5      n[        U5      S:  ad  [        R                  " U5      u  pEnUR                   H)  nUR
                   H  nXLd  M	  [        XXgU5        M     M+     [        U5      S:  a  Mc  gg)zPerform Dijkstra's algorithm on an intersite graph.

:param graph: an IntersiteGraph object
:param edge_type: a transport type GUID
:param include_black: boolean, whether to include black vertices
:return: None
r   N)setup_dijkstralenheapqheappopre   rJ   try_new_path)	rs   	edge_typeinclude_blackqueuer   r   vertexrL   rx   s	            r   rh   rh   h  sh     5];E
e*q."]]51FLLD]]? vQ? # ! e*q.r   c                    / n[        U 5        U R                   H  nUR                  5       (       a  M  UR                  5       (       a  U(       a  XR                  ;  d  XR
                  ;  a%  [        UR                  l        SUl	        SUl
        My  [        R                  " X4R                  R                  UR                  U45        M     U$ )zCreate a vertex queue for Dijksta's algorithm.

:param graph: an IntersiteGraph object
:param edge_type: a transport type GUID
:param include_black: boolean, whether to include black vertices
:return: A heap queue of vertices
NT)rj   rJ   r   rq   accept_blackaccept_red_redr?   rp   r   r   r   r   heappushr   )rs   r   r   r   r   s        r   r   r   z  s     E5..??oo!4!44!6!66$-F!FK!FNNN5#3#3#8#8&++v"NO ! Lr   c                    [        UR                  UR                  5      nUR                  UR                  R                  :  d$  UR                  UR                  R                  :  a`  UR                  Ul        UR
                  Ul        XTl        [        R                  " XR                  R                  UR                  U45        gg)zHelper function for Dijksta's algorithm.

:param graph: an IntersiteGraph object
:param queue: the empty queue to initialise.
:param vfrom: Vertex we are coming from
:param edge: an edge to try
:param vto: the other Vertex
:return: None
N)	rE   rp   r   r   r   r   r   r   r   )rs   r   vfromrL   vtonew_repl_infos         r   r   r     s     &eoot~~FM 	S]]///!7!77:: --%u}}11388SAB	 	8r   c                     U R                  5       (       a  gXR                  ;  a4  XR                  ;  a$  [        U R                  l        SU l        SU l        ggg)zDemote non-white vertices that accept only white edges

This makes them seem temporarily like white vertices.

:param vertex: a Vertex()
:param edge_type: a transport type GUID
:return: None
NT)r   r   r   r?   rp   r   r   r   )r   r   s     r   check_demote_vertexr     sT      
--	-	//	/ ) 
0 
.r   c                 l    U R                  5       (       a  gSU R                  l        X l        SU l        g)zmUn-demote non-white vertices

Set a vertex's to an undemoted state.

:param vertex: a Vertex()
:return: None
Nr   F)r   rp   r   r   r   )r   s    r   undemote_vertexr     s.     FKFNr   c                    Ucf  U R                    HU  nUR                   H  n[        XCR                  5        M     [	        XU5        UR                   H  n[        U5        M     MW     gUR                    H  n[	        XU5        M     g)zFind internal edges to pass to Kruskal's algorithm

:param graph: an IntersiteGraph object
:param e_set: an edge set
:param internal_edges: a set that internal edges get added to
:return: None
N)re   rJ   r   rf   process_edger   )rs   rv   ru   rL   r   s        r   ri   ri     sk     }KKD--#FMM: (n5--' (	   KKDn5  r   c                    / nUR                    H@  nUR                  UR                  UR                  R                  UR
                  U45        MB     [        SU-  5        UR                  5         US   u  pVpxUR                    H  nUR                  b  UR                  c  M  UR                  c  M.  UR                  c  M=  UR                  c  ML  UR                  c  M[  UR                  UR                  :w  d  Mw  [        XXU5        M     g)zFind the set of all vertices touching an edge to examine

:param graph: an IntersiteGraph object
:param examine: an edge
:param internal_edges: a set that internal edges get added to
:return: None
zvertices is %sr   N)rJ   r6   colorrp   r   ndrpacked_guidr	   sortr   r   add_int_edge)	rs   examineru   rJ   rx   r   r   r   bestvs	            r   r   r     s     H!++"2"2A4D4DaHI  

X
%&MMO'{E>>!QVV^ +ZZ#^^'VV1>>1B r   c                    UR                   nUR                   nUR                  5       =(       a    UR                  5       nU(       a6  UR                  UR                  ;  d  UR                  UR                  ;  a  gO5UR                  UR                  ;  d  UR                  UR                  ;  a  g[        UR                  UR                  5      nUR                  S:X  a  g[        XR                  5      n	U	R                  S:X  a  gUR                  UR                  :  a  Xepe[        XVXyUR                  UR                  5      n
UR                  U
5        g)a  Add edges between compatible red and black vertices

Internal edges form the core of the tree -- white and RODC
vertices attach to it as leaf nodes. An edge needs to have black
or red endpoints with compatible replication schedules to be
accepted as an internal edge.

Here we examine an edge and add it to the set of internal edges if
it looks good.

:param graph: the graph object.
:param internal_edges: a set of internal edges
:param examine: an edge to examine for suitability.
:param v1: a Vertex
:param v2: the other Vertex
Nr   )r   rn   rf   r   r   rE   rp   r   r   InternalEdger   add)rs   ru   r   rk   rl   root1root2red_redriri2
newIntEdges              r   r   r     s   " GGEGGElln/GE$8$88u';';; <


%"4"4
4U%7%77 
2<<	6B	{{a
B 1 1
2C
||q e222ueG':J:J%//1J z"r   c                    U R                    H
  n/ Ul        M     [        U R                    Vs/ s H  o3R                  5       (       a  M  UPM     sn5      n[	        U5      nUR                  5         SnSn/ nSnU[        U5      :  ap  X   n	[        U	R                  5      n
[        U	R                  5      nXLa(  US-  n[        XU	5        Xl        UR                  U
5        US-  nU[        U5      :  a  Mp  U[        U5      4$ s  snf )a-  Perform Kruskal's algorithm using the given set of edges

The input edges are "internal edges" -- between red and black
nodes. The output edges are a minimal spanning tree.

:param graph: the graph object.
:param edges: a set of edges
:return: a tuple of a list of edges, and the number of components
r   r*   )rJ   re   rc   r   listr   r   find_componentrk   rl   add_out_edger   discard)rs   re   rx   rb   r   expected_num_tree_edgescount_edgesr   indexra   parent1parent2s               r   rm   rm   3  s     ^^  DAzz|aDEJKE 
JJL  KLE
#e*
L & &!1Ka0#* w'
 #e*
 Z((1 Es   D
Dc                     U R                   U L a  U $ U nUR                   ULa  UR                   nUR                   ULa  M  UnU nUR                   ULa%  UR                   nX!l         UnUR                   ULa  M%  U$ )zKruskal helper to find the component a vertex belongs to.

:param vertex: a Vertex
:return: the Vertex object representing the component
)r   )r   currentr   ns       r   r   r   [  s     f$G


g
-&& 

g
- DG


d
*  # 

d
*
 Kr   c                    UR                   nUR                  n[        5       nSUl        UR                  Ul        UR
                  R                  U5        UR
                  R                  U5        UR                  Ul        UR                  Ul	        UR                  U5        UR                  R                  U5        UR                  R                  U5        g)zKruskal helper to add output edges

:param graph: the InterSiteGraph
:param output_edges: the list of spanning tree edges
:param e: the edge to be added
:return: None
FN)rk   rl   r   r]   r   rJ   r6   e_typerf   rp   re   )rs   r   ra   rk   rl   ees         r   r   r   r  s     
B	
B 
BBK;;BLKKrKKr((BK;;BLHHOOBHHOOBr   c                 d   0 n[        5       nUR                  5        Hn  u  px[        X5      n	Xyl        [	        UR
                  5      U	l        UR                  R                  U	5        UR                  U/ 5      n
U
R                  U	5        Mp     [        5       nUR                  5        HG  u  p[        X-U5      nUR                  UR                  5        UR                  R                  U5        MI     U(       a  [        S5        UR                   R                  [#        Xb5      5        Xl        U$ )a2  Set up an IntersiteGraph based on intersite topology

The graph will have a Vertex for each site, a MultiEdge for each
siteLink object, and a MultiEdgeSet for each siteLinkBridge object
(or implied siteLinkBridge).

:param part: the partition we are dealing with
:param site_table: a mapping of guids to sites (KCC.site_table)
:param transport_guid: the GUID of the IP transport
:param sitelink_table: a mapping of dnstrs to sitelinks
:param bridges_required: boolean, asking in vain for something to do
     with site link bridges
:return: a new IntersiteGraph
z-Samba KCC ignores the bridges required option)IntersiteGraphitemsVertexr   r   r   r   rJ   r   
setdefaultr6   rc   r   updatere   r   rd   r   connected_vertices)part
site_tabler   sitelink_tablebridges_requiredr   gr   r_   r   guid_verticesr   site_link_dnr   new_edges                  r   setup_graphr     s      NA%++-	# ( 8	

v&11)R@V$ . #1#7#7#9~-/!!("3"34	H	 $: <=JJNN':;-Hr   c                   4    \ rS rSrSr\" SS5      u  rrrr	Sr
g)VertexColori  zEnumeration of vertex coloursr   r2   r(   N)r"   r#   r$   r%   r&   r5   redblackwhiteunknownr'   r(   r   r   r   r     s    '#(A; S%r   r   c                   6    \ rS rSrSrS rS rS rS rS r	Sr
g	)
r   i  zintersite graph representation of a Site.

There is a separate vertex for each partition.

:param site: the site to make a vertex of.
:param part: the partition.
c                     Xl         X l        [        R                  U l        / U l        / U l        / U l        [        5       U l	        X l
        S U l        X l        SU l        SU l        SU l        g )NFr   )r_   r   r   r   r   re   r   r   r   rp   r   r   r   r   r   r   )r   r_   r   s      r   r   Vertex.__init__  s`    		 ((

 !		 r   c                 ^   [         R                  U l        U R                  R                  R                  5        Hp  u  pUR                  U R                  R                  5      nUc  M/  UR                  5       (       d  [         R                  U l          g[         R                  U l        Mr     g)zGColor to indicate which kind of NC replica the vertex contains
        N)r   r   r   r_   	dsa_tabler   get_current_replicar   nc_dnstr
is_partialr   r   )r   dnstrdsareps       r   color_vertexVertex.color_vertex  s|     !&&
))--335JE))$))*<*<=C{ >>##(__
(..
 6r   c                 |    U R                   [        R                  :w  d   eU R                   [        R                  :H  $ r\   )r   r   r   r   r   s    r   rn   Vertex.is_red  s-    zz[00010

koo-.r   c                 |    U R                   [        R                  :w  d   eU R                   [        R                  :H  $ r\   )r   r   r   r   r   s    r   rq   Vertex.is_black  /    zz[00010

k///0r   c                 |    U R                   [        R                  :w  d   eU R                   [        R                  :H  $ r\   )r   r   r   r   r   s    r   r   Vertex.is_white  r   r   )r   r   r   r   r   re   r   r   r   r   rp   r   r_   N)r"   r#   r$   r%   r&   r   r   rn   rq   r   r'   r(   r   r   r   r     s     /6/11r   r   c                       \ rS rSrSrS rSrg)r   i  z$Graph for representing the intersitec                 l    [        5       U l        [        5       U l        [        5       U l        S U l        g r\   )rc   rJ   re   rd   r   r   s    r   r   IntersiteGraph.__init__  s%    U
"&r   )r   rd   re   rJ   Nr"   r#   r$   r%   r&   r   r'   r(   r   r   r   r     s
    .'r   r   c                       \ rS rSrSrS rSrg)r   i  zDefines a multi edge setc                      SU l         / U l        g )Nr   )r   re   r   s    r   r   MultiEdgeSet.__init__  s    	
r   )re   r   Nr   r(   r   r   r   r     s
    "r   r   c                       \ rS rSrSrS rSrg)r   i  z#An "edge" between multiple verticesc                 Z    S U l         / U l        S U l        [        5       U l        SU l        g )NT)r   rJ   rf   r   rp   r]   r   s    r   r   MultiEdge.__init__  s'    !r   )rf   r]   rp   r   rJ   Nr   r(   r   r   r   r     s
    -r   r   c                   H    \ rS rSrSrS rS rS rS rS r	S r
S	 rS
 rSrg)r   i  zAn edge that forms part of the minimal spanning tree

These are used in the Kruskal's algorithm. Their interesting
feature isa that they are sortable, with the good edges sorting
before the bad ones -- lower is better.
c                 L    Xl         X l        X0l        X@l        XPl        X`l        g r\   )rk   rl   r   rp   r   r   )r   rk   rl   redredrepleTyper   s          r   r   InternalEdge.__init__$  s     "r   c                     [        U R                  U R                  U R                  U R                  U R
                  U R                  45      $ r\   )hashrk   rl   r   rp   r   r   r   s    r   __hash__InternalEdge.__hash__,  s:    GGTWWdllDNNDKKNN  	r   c                 $    X:  + =(       a    X:  + $ r\   r(   r   others     r   __eq__InternalEdge.__eq__1  s    4$44r   c                      X:  =(       d    X:  $ r\   r(   r  s     r   __ne__InternalEdge.__ne__4  s    |+u|+r   c                 
    X:  $ r\   r(   r  s     r   __gt__InternalEdge.__gt__7  s
    |r   c                     X:  + $ r\   r(   r  s     r   __ge__InternalEdge.__ge__:  s    r   c                     X:  + $ r\   r(   r  s     r   __le__InternalEdge.__le__=  s    r   c                 X   U R                   UR                   :w  a  U R                   $ U R                  R                  UR                  R                  :w  a-  U R                  R                  UR                  R                  :  $ U R                  R                  UR                  R                  :w  a-  U R                  R                  UR                  R                  :  $ U R                  R
                  UR                  R
                  :w  a-  U R                  R                  UR                  R                  :  $ U R                  R
                  UR                  R
                  :w  a-  U R                  R                  UR                  R                  :  $ U R                  UR                  :  $ )aZ  Here "less than" means "better".

From within MS-ADTS 6.2.2.3.4.4:

SORT internalEdges by (descending RedRed,
                       ascending ReplInfo.Cost,
                       descending available time in ReplInfo.Schedule,
                       ascending V1ID,
                       ascending V2ID,
                       ascending Type)
)	r   rp   r   r   rk   r   r   rl   r   r  s     r   __lt__InternalEdge.__lt__@  s    <<5==(<<>>%//"6"66>>&&)=)===>>""eoo&>&>>>>**U__-E-EEE77<<588==(77))EHH,C,CCC77<<588==(77))EHH,C,CCC{{U\\))r   )r   r   rp   r   rk   rl   N)r"   r#   r$   r%   r&   r   r  r  r  r  r  r  r!  r'   r(   r   r   r   r     s/    #
5,  *r   r   )NFN),rH   r   samba.kcc.graph_utilsr   r   r   samba.kcc.kcc_utilsr   	samba.ndrr   samba.dcerpcr   samba.kcc.debugr	   r
   r   r?   objectr   r   r   rE   r   r   r   rj   rh   r   r   r   r   ri   r   r   rm   r   r   r   r   r   r   r   r   r   r(   r   r   <module>r)     s   ,   N N (   1 1	6v 6.($N< @E)-D!N6&@@$4C,( 6(C@.#b%)P.:,^/& /
<1V <1~'V '6  >*6 >*r   