ð¿/gÜìýžÞ¬zˆ{™­1mŸ�Ì‰T~LWý&Kæ:,¸W>r¯k±�”u‹%ÄÞU•R  ½•øOÍ;¤£?Ä�¨JF+ƒØž>•Œ/Ï¤vþ@…¸õ°$¶Pä„¸[ª$¢0‹*±¤çÕÁ0�,™ïºÙk—‘`m­™�g!ó2Ú®J¸ó¦gµºšrŠˆöEID>8i-=sE¢³>uü_Eûì!‹¾ø]'¨Kx†@�‰‰ØÉÁ`o�¿Ë6þ²üÙé4Zé#B=C×˜isæŒ6¸ãÜ—†–îï}¥Î¥pdÙó9qbZ{¦ –™ç«;»+'û�³ýùàlÃƒfÐ	TdM|„ÀŠC73C$Õ�†®–qY¡±ì�×ø…BhÅÜ€/šÌ†œFÌ²&¨Õ8³Î¢Í–8xÌoÆÊMÌ1=ù¼(b=tJâ`Ñ/È´&fm2â@¸ÄÍaž»»k]¥ŽÀ´:Ñ°ÔwË7äs[¸�=Qc­¶*Ÿ½"}�"n›8ÿ]y=Î8ŒwírŸ÷2O¾Y•A8S�GR÷È|—×äçw®¢+z™áÜqÛË- p¸&ÉZúREÿ^€ç=×Â*%ÐEì£/ë °±ODžlè{ªc¡—‰x‡�’q)jât¬'÷÷z¿‘Y Ñ8œ2,¯­Ê¤q{ƒmÛwÞ{?9CýäÈ;øC £L€§)áîà_DPMC‘-´‡×zý”ø�\ègü±+ä“@òY;d¢| ÏÅAÍŠ±?HVÐ˜�m¼¼÷uÄ”d�Y´™™x5RÓJf¸ zÀX¸+¦Ì@U#}’æ–e‰‘,hàË÷‰€�jG@‚¥¯pjž¡ƒI=ø�GÝ(OŸ·È3Á!$“:ø»iªæhØm@‹FÚÑ:‰žêvsn‹¼ù>6?L–�°V=±ËvV¥1:÷eZÑÖ:ÄG»æù+hWhzÜÏÞa“¿ë&QÇ�þ5Vð3ÍÁåN¢ïÈ˜ÍÞ	X!ŒâfRVÀ‡îÔÙØ—‚Ì 6Dë×š$ïjý®¯~Øç�NÔ�ÍÇc&z]„‰Ò#ÇxhÐŽ+šÏiKýú0¡ªºwñdïpÇòPx3²t¹VÙPGå‹·«ÀÄîêŠç®Òã2tã°4("¹­Óài*ìÜ’Q%ZIB}¯z”OÈXŠJY4Ìm�Î‰á„E´[o#�™Á;µ�mµ§TË“¾®ÄÝ’*koG¯˜µ³L�‹M¯”U®êøºt"+ ôtðÔß¹‡PÖ‰…~Š_Ë:¶:
Ó7-ÝºŒÒ—_¥­^Cu×‹$øI)�I*Pf½›62ˆxdEÍõÅl†FDcÊyT�#ñ˜á—ž¶ú|‘ŒF/¿‘˜àsWáJ_Å–i$å›Y¾óÖ˜�5ÿîç�ÃZÐU>½…æÏiªà2œQ{üuIº‡Û«—qè�Î‰á„E´[o#�™Á;z©”€‡0·ÔïŸ£ãÃ–,ÿPóÏãÒ�¼ßõÕÀ«„ ¨òÒWüµ×´ˆ&á•I·éèXG±PÙAEÒü²VœÛ£`=Ð/Aþˆƒ‡A÷&¤mþñðx,ãàÍt±‘‚Õoèä.ÎÐ²UÅó1Ý«Q—cÛûð©/ˆeèº‚õxÙŽô|$,Ð/Aþˆƒ‡A÷&¤mþ"Ä(èµ€°-%¡3¼wG¡{9�è¦&y{4.�Ñ±öŸ©­ˆ�±ÁÇï™«0¿”Ï½5«‘ú¬nT-—/u¨¤Çw%8VqªPÌ×ÀvUñ~æN%ˆÌÄ|8ôéŠøã‚#Ÿ\Ì¾S¥:öœ+7Sµ"v¸FÓ3:§'´Ò›…›ç¶Ð/Aþˆƒ‡A÷&¤mþáì4œ,å‡ºõ(õ5ï$»:uàó†g.ì¬0œèW§H©+nÍ+›L=M+îì¸ÍgÌÙê¡%�ü
Uƒuø˜Qâ–­YÌi¾àÈ~á†Kw*7üŽPi	'Q´RÖ®�‘†JÞ ŠÚÿœ-©¬úÍæ0ÇË�Ì\$1jLY|1Ùc�¯*ÿ|�Ã«P§Ã•Î|r7„¬<ârâÎ~Ÿ´Ìõ(Q–T06Õî]¾è,`™øm,4CŸ¹›Ç“éavàÕ,ôë•Ü�Š‘ÈþwÚÈ]!oXÎVÆYÙ»uÒçlcð¹öµÀÿ»w‘Ûó#�ñ±õUþ?NJaòõRÒÒÚ~“Þ6f§ðyq‹³D‰Jï„"“¨”£d5=Ç½c¶átzž·Âheî3ÞÝšê67üxkß¿6~ÇI†8JdÞcåm›¬¿>:òÙÒ‘¼ž^þjjhç ºã/|J6èg¬ç¹¥Ý„pÁ”/øÙ8o8ý‡+dÈéx%åñ`20t!"ð–Ikú\¼O[—µ8Ý“ &‡›|;ãQhíd(F(äu	âY;TeÑUVÙIŒV$6’ Ô_ÝÜ8mùÀÐ¸Ë>ì(vð1¤¡å£øYÄy™¼~‚ËŒ	p©|#Kì€5$q‹è[áÚÑm÷j‘<&ÆÃSypÀ[0òý0©YEûƒ–ìÀøOIs¯Nª³idÔÝø½³©ü–']Þì­qâ%˜çÅ¢ªËÆé€;íó°¬"ôQô-�Áé:ì•’§2¥’ç~6çò}o�eÛš·™ÑìÅ°1š¼EP|†–�ToX=Ž{{m‡Tð²xR»eƒåÈjçéÍ>§â+¤©¤HÍ^­]óÞKÓ7@Rx�«ðÍ;O-`tÝß^b¤W144»šü¬ (Y$�Ïkv.*Ùõd3Ã?;eºÎøDÐæ0)7ò+:Ã.¦7A$‡0uu¤¦f…‘¬/åïŠ=,Y(3¬?°ÈööçCÑ÷ZçrieŒMË9;	u¦›ú�ládmHæ�©y,IÜvÑ¢ƒ¡{9�è¦&y{4.�Ñ±ö(±2ZX©§|´]…FJ¡BIÝ·Ë›‹FsS• ,`_w%8VqªPÌ×ÀvUñ~Y,ô?ª¼	bÛØ‚2?ÕˆTi–Žc�§£ùÒ»’�tö
A”çÈÞËÞñ Ä½«F"+}lréÍæ[4Á»¥v´øÖ—©cÁ†«t¨Ã—®7dWÀ63Ž9‚‡êƒF?ú¼XLšÛ­"äsnÿ‚h>ò: 1
ñb<bB¶†ÿ
~vú™áæq¾ìûQóV�‡â{ƒšêpXÆïêPæÊ™ãúŠXË,×íŽ3ûòdBÛÐÓIÝð#Wèu{?~¯Å1ÚÕ®2)àdQtehëù®û°^Wiå~8X«;ã‘zpš1Åä¦Wc»èIÀþm¯¨uUp¿I!Ž£áZ'O)‘/¾Ã%cw°ý×Ý
.	âÒLð8´,üïCýYC{@Ñ�çÑŽ[•§ÜÁ)Ò9š²®tÞ3ow�F­ðžE1Ÿó—;³]|ÝˆøÇ<¼žê´6pE$¬�²9zž·Âheî3ÞÝšê67/M“.‹[bÕ¼'_â«|Ò[ã?—Mx
Mdº5ÚGˆWÿU…èCõý_¦t.�9f‹$^yþoÉ$ƒñ	„/ÊÍr��¦“B¾óH�Fb!Û%üÃÔeVxå
ìõÀ}&+¾)ÿbæT}8$ÔC£žIáðÃÕ¶ç
Øëž�c§]!2<…i�¥ lvŽ Î½Uƒ72yý ø×ºkŠØ’(â˜œí.ê•³C”a(eò?Bhá;ÄÿQÒIÅSN~ºøõt‡•”(Ê¼ˆ{–VNp÷“>Œ{-‡&—më* J�†çà=ìlaQ<á.ß°ÅœþÉ‡k ¸\m¦É,‰)4Tš2Î�Ö�f%U g<ƒ*X¸X“¹¨£¥qßŒóª÷ïêM9þC/}©lÄ¶nœt5¦ðçÃxÇAf€F€«�£—ÈSèe-,6�ÚhnY›û«Îô®~çLA�Gž9E
Ý·ø}(KaD@ º‰á†µ�™—'ÏÇ™º¬d�+8ú:’]¶§²øôºÀ¨ì@©#–Ó„¢ÐýøÃúxg�©\�[^&Ò��ä>ù™Ý·g.®Ã�˜rži{;ÐíÌ[2æ¶X<s‹š~ÒFyªÓAeq”˜ Îê ¤6©ØÍØû;™¦�
y¹OÙåhY(¦£¥e†Ãõ!¸þU„\©èrã+JF~¶G¥Ùò‡
L-ŠF7åýA#H0Ÿ¨‡Ò&Á�Ýw'—ÿÕ_1Õ&ˆ©‰À+f¨Ý•ÆëÊ¾ÝyU-
°bŠ/|Äé�ÿ¨Ìö`‹¾•Ä¬L 0>¬A1=ÀËûÌ)¿ÒlÝÔZåðž\Â<ï]*ç5§ZWð’ÞÏ¼Zâ�Uq^Ó9™þŒ¸™,Ö´4š†'‰\pl×�+Sþu�°ã*¶8Tfåû(Ü\àš	VçW–ÄŸ1C³ìt1­ü~¹‰ã´bjÔºp:*ßôòhd†·béö=fÀ·cZ…_Wæ2óRF¥ñÖ	¯ŸyôB²¤Ê$»°Bþ›ŽðÈÕpŒkŒÂdHD'æÆû�6¸'ÈØ˜‘ŒF/¿‘˜àsWáJ_Å–i‡E�±Sû2<OýwD€~œzc¥G1{çQ$B§F(úÌ:�œ÷”›ú>7ªJÕãiÔárWÊÊt	 ùÛÂßç‹ûNƒ{OlmÜjÝŽ^™mNžF>-ï Ê¯¯@¶ÃhÚ¿x Â"„r»A™ùÇ<$¤H"¶ÜÖwÃÒë–«ÿ²‡ûô*<Ãë¦�‚þõ?á+–aìšÀº�Þ§¹#u+	•â=ç“ŸÕœ…¤Új:Óf“éjuZé.†!§øÅ'½—@‚Ë)¤«RÉÔr6mˆóæƒO—ÑØwþyäj…‡‹ÀyÑÆÚ«»Êw¥"L]	ê„‰CÖ0nöWB¤m³E\�&¼Óœû¢,^+ir¿í›éÚéÿ6áòd2ž»au<)9$7g‰œ4>ŠÐz(uI4j´SäR©SÓ[4¤(¬y¸~65»’úÕ£–
¬"Ý.q¦P�<‚¬A<\Ž-¸�êó‹#aòÒWüµ×´ˆ&á•I·éèX\’ÆXa–£HLUGÍ	€kÒòÒWüµ×´ˆ&á•I·éèXçÙÃÍµžZ%j)88Ë3mS¹1‹â5ÿ~¸uOxñR‹ÏòÒWüµ×´ˆ&á•I·éèXpÓ¥ueáà±X$Àÿm÷kË´Îb×Z‘²œKWå²5|Ö¡PˆÌF âi�âY@éJy4Š[i9b~ÒAº�ü—n)vñô+à&ƒþÔdMj…íðù}.®—A‡LmS>^þgN<·K0ûzÈ îbÝîí½›ÙJFZ            # We want to fix up these paths
                path_list = value.split(";")
                new_list = FixFilenames(path_list, os.path.dirname(ARGUMENTS[1]))
                node.setAttribute(name, ";".join(new_list))
            if not value:
                node.removeAttribute(name)


def CleanupVcproj(node):
    """For each sub node, we call recursively this function."""
    for sub_node in node.childNodes:
        AbsoluteNode(sub_node)
        CleanupVcproj(sub_node)

    # Normalize the node, and remove all extraneous whitespaces.
    for sub_node in node.childNodes:
        if sub_node.nodeType == Node.TEXT_NODE:
            sub_node.data = sub_node.data.replace("\r", "")
            sub_node.data = sub_node.data.replace("\n", "")
            sub_node.data = sub_node.data.rstrip()

    # Fix all the semicolon separated attributes to be sorted, and we also
    # remove the dups.
    if node.attributes:
        for (name, value) in node.attributes.items():
            sorted_list = sorted(value.split(";"))
            unique_list = []
            for i in sorted_list:
                if not unique_list.count(i):
                    unique_list.append(i)
            node.setAttribute(name, ";".join(unique_list))
            if not value:
                node.removeAttribute(name)

    if node.childNodes:
        node.normalize()

    # For each node, take a copy, and remove it from the list.
    node_array = []
    while node.childNodes and node.childNodes[0]:
        # Take a copy of the node and remove it from the list.
        current = node.childNodes[0]
        node.removeChild(current)

        # If the child is a filter, we want to append all its children
        # to this same list.
        if current.nodeName == "Filter":
            node_array.extend(FlattenFilter(current))
        else:
            node_array.append(current)

    # Sort the list.
    node_array.sort(CmpNode())

    # Insert the nodes in the correct order.
    for new_node in node_array:
        # But don't append empty tool node.
        if new_node.nodeName == "Tool":
            if new_node.attributes and new_node.attributes.length == 1:
                # This one was empty.
                continue
        if new_node.nodeName == "UserMacro":
            continue
        node.appendChild(new_node)


def GetConfiguationNodes(vcproj):
    # TODO(nsylvain): Find a better way to navigate the xml.
    nodes = []
    for node in vcproj.childNodes:
        if node.nodeName == "Configurations":
            for sub_node in node.childNodes:
                if sub_node.nodeName == "Configuration":
                    nodes.append(sub_node)

    return nodes


def GetChildrenVsprops(filename):
    dom = parse(filename)
    if dom.documentElement.attributes:
        vsprops = dom.documentElement.getAttribute("InheritedPropertySheets")
        return FixFilenames(vsprops.split(";"), os.path.dirname(filename))
    return []


def SeekToNode(node1, child2):
    # A text node does not have properties.
    if child2.nodeType == Node.TEXT_NODE:
        return None

    # Get the name of the current node.
    current_name = child2.getAttribute("Name")
    if not current_name:
        # There is no name. We don't know how to merge.
        return None

    # Look through all the nodes to find a match.
    for sub_node in node1.childNodes:
        if sub_node.nodeName == child2.nodeName:
            name = sub_node.getAttribute("Name")
            if name == current_name:
                return sub_node

    # No match. We give up.
    return None


def MergeAttributes(node1, node2):
    # No attributes to merge?
    if not node2.attributes:
        return

    for (name, value2) in node2.attributes.items():
        # Don't merge the 'Name' attribute.
        if name == "Name":
            continue
        value1 = node1.getAttribute(name)
        if value1:
            # The attribute exist in the main node. If it's equal, we leave it
            # untouched, otherwise we concatenate it.
            if value1 != value2:
                node1.setAttribute(name, ";".join([value1, value2]))
        else:
            # The attribute does not exist in the main node. We append this one.
            node1.setAttribute(name, value2)

        # If the attribute was a property sheet attributes, we remove it, since
        # they are useless.
        if name == "InheritedPropertySheets":
            node1.removeAttribute(name)


def MergeProperties(node1, node2):
    MergeAttributes(node1, node2)
    for child2 in node2.childNodes:
        child1 = SeekToNode(node1, child2)
        if child1:
            MergeProperties(child1, child2)
        else:
            node1.appendChild(child2.cloneNode(True))


def main(argv):
    """Main function of this vcproj prettifier."""
    global ARGUMENTS
    ARGUMENTS = argv

    # check if we have exactly 1 parameter.
    if len(argv) < 2:
        print(
            'Usage: %s "c:\\path\\to\\vcproj.vcproj" [key1=value1] '
            "[key2=value2]" % argv[0]
        )
        return 1

    # Parse the keys
    for i in range(2, len(argv)):
        (key, value) = argv[i].split("=")
        REPLACEMENTS[key] = value

    # Open the vcproj and parse the xml.
    dom = parse(argv[1])

    # First thing we need to do is find the Configuration Node and merge them
    # with the vsprops they include.
    for configuration_node in GetConfiguationNodes(dom.documentElement):
        # Get the property sheets associated with this configuration.
        vsprops = configuration_node.getAttribute("InheritedPropertySheets")

        # Fix the filenames to be absolute.
        vsprops_list = FixFilenames(
            vsprops.strip().split(";"), os.path.dirname(argv[1])
        )

        # Extend the list of vsprops with all vsprops contained in the current
        # vsprops.
        for current_vsprops in vsprops_list:
            vsprops_list.extend(GetChildrenVsprops(current_vsprops))

        # Now that we have all the vsprops, we need to merge them.
        for current_vsprops in vsprops_list:
            MergeProperties(configuration_node, parse(current_vsprops).documentElement)

    # Now that everything is merged, we need to cleanup the xml.
    CleanupVcproj(dom.documentElement)

    # Finally, we use the prett xml function to print the vcproj back to the
    # user.
    # print dom.toprettyxml(newl="\n")
    PrettyPrintNode(dom.documentElement)
    return 0


if __name__ == "__main__":
    sys.exit(main(sys.argv))
