eaiovnaovbqoebvqoeavibavo 3 "6]~@sdZdZddlZddlZddlZddlZddlmZddlmZddl m Z m Z m Z m Z mZddlmZeZGdd d ejZGd d d eZGd d d eZGdddeZddZdS)zHelper classes for tests.ZMITN)TestCase) BeautifulSoup)CharsetMetaAttributeValueCommentContentMetaAttributeValueDoctype SoupStrainer)HTMLParserTreeBuilderc@s:eZdZeddZddZddZd dd Zd d ZdS) SoupTestcCstS)N)default_builder)selfr /usr/lib/python3.6/testing.pyr szSoupTest.default_buildercKs"|jd|j}t|fd|i|S)z*Build a Beautiful Soup object from markup.builder)popr r)r markupkwargsrr r rsoup sz SoupTest.soupcCs |jj|S)z[Turn an HTML fragment into a document. The details depend on the builder. )r Ztest_fragment_to_document)r rr r r document_for%szSoupTest.document_forNcCs8|j}t||d}|dkr|}|j|j|j|dS)N)r)r r assertEqualdecoder)r Zto_parseZcompare_parsed_torobjr r rassertSoupEquals,s  zSoupTest.assertSoupEqualscCs<d}x2|jD](}|r0|j||j|j||j|}q WdS)zyEnsure that next_element and previous_element are properly set for all descendants of the given element. N)Z descendantsr next_elementprevious_element)r elementZearlierer r rassertConnectedness4s  zSoupTest.assertConnectedness)N) __name__ __module__ __qualname__propertyr rrrrr r r rr s   r c@seZdZdZddZddZddZdd Zd d Zd d Z ddZ ddZ ddZ ddZ ddZddZddZddZddZd d!Zd"d#Zd$d%Zd&d'Zd(d)Zd*d+Zd,d-Zd.d/Zd0d1Zd2d3Zd4d5Zd6d7Zd8d9Zd:d;Z dd?Z"d@dAZ#dBdCZ$dDdEZ%dFdZdGdHZ&dIdJZ'dKdLZ(dMdNZ)dOdPZ*dQdRZ+dSdTZ,dUdVZ-dWdXZ.dYdZZ/d[d\Z0d]d^Z1d_d`Z2dadbZ3dcddZ4dedfZ5dgdhZ6didjZ7dkdlZ8dmdnZ9dodpZ:dqS)rHTMLTreeBuilderSmokeTestaCA basic test of a treebuilder's competence. Any HTML treebuilder, present or future, should be able to pass these tests. With invalid markup, there's room for interpretation, and different parsers can handle it differently. But with the markup in these tests, there's not much room for interpretation. cCs4x.dD]&}|jd}|j|}|jd|jqWdS)zmVerify that all HTML4 and HTML5 empty element (aka void element) tags are handled correctly. areabasebrcolembedhrimginputkeygenlinkmenuitemmetaparamsourcetrackwbrspacerframeTN)r#r$r%r&r'r(r)r*r+r,r-r.r/r0r1r2r3r4)rnew_tagris_empty_element)r namerr6r r rtest_empty_element_tagsIs   z0HTMLTreeBuilderSmokeTest.test_empty_element_tagscCsF|jd}tj|d}tj|}|j|jt|j|j|jdS)Nz foo)rpickledumpsloadsr __class__rr)r treedumpedloadedr r r!test_pickle_and_unpickle_identityUs    z:HTMLTreeBuilderSmokeTest.test_pickle_and_unpickle_identitycCsf|j|\}}|jd}|j|jt|j|||jt|dt|||j|jjdddS)z8Assert that a given doctype string is handled correctly.rNfoo)_document_with_doctypecontentsrr>rstrlenp)r doctype_fragmentZ doctype_strrdoctyper r rassertDoctypeHandled^s   z-HTMLTreeBuilderSmokeTest.assertDoctypeHandledcCs"d|}|d}|j|}||fS)z5Generate and parse a document with the given doctype.z z

foo

)r)r rIrJrrr r rrDls z/HTMLTreeBuilderSmokeTest._document_with_doctypecCs|jd|jddS)z?Make sure normal, everyday HTML doctypes are handled correctly.htmlz4html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"N)rK)r r r rtest_normal_doctypesss z-HTMLTreeBuilderSmokeTest.test_normal_doctypescCs(|jd}|jd}|jd|jdS)Nz rr5)rrErstrip)r rrJr r rtest_empty_doctypeys  z+HTMLTreeBuilderSmokeTest.test_empty_doctypecCsd}|j|dS)Nznhtml PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd")rK)r rJr r rtest_public_doctype_with_url~sz5HTMLTreeBuilderSmokeTest.test_public_doctype_with_urlcCs|jddS)Nz$foo SYSTEM "http://www.example.com/")rK)r r r rtest_system_doctypesz,HTMLTreeBuilderSmokeTest.test_system_doctypecCs|jddS)Nz#xsl:stylesheet SYSTEM "htmlent.dtd")rK)r r r rtest_namespaced_system_doctypesz7HTMLTreeBuilderSmokeTest.test_namespaced_system_doctypecCs|jddS)Nz#xsl:stylesheet PUBLIC "htmlent.dtd")rK)r r r rtest_namespaced_public_doctypesz7HTMLTreeBuilderSmokeTest.test_namespaced_public_doctypecCs4d}|j|}|j|jdjdd|jdddS)zJA real XHTML document should come out more or less the same as it went in.s Hello. Goodbye. zutf-8 N)rrencodereplace)r rrr r rtest_real_xhtml_documents  z1HTMLTreeBuilderSmokeTest.test_real_xhtml_documentcCs(d}|j|}|jdt|jddS)ztWhen a namespaced XML document is parsed as HTML it should be treated as HTML with weird tag names. s.contentr:zns1:fooN)rrrGfind_all)r rrr r rtest_namespaced_htmls z-HTMLTreeBuilderSmokeTest.test_namespaced_htmlcCsBd}|j|}|j||jd}|j|}|j||jddS)Nzsutf8)rrrrV)r rrr r rtest_processing_instructions   z4HTMLTreeBuilderSmokeTest.test_processing_instructioncCstj|jdS)zMake sure you can copy the tree builder. This is important because the builder is part of a BeautifulSoup object, and we want to be able to copy that. N)copydeepcopyr )r r r r test_deepcopysz&HTMLTreeBuilderSmokeTest.test_deepcopycCs.|jd}|j|jj|jt|jddS)zA

tag is never designated as an empty-element tag. Even if the markup shows it as an empty-element tag, it shouldn't be presented that way. z

z

N)rZ assertFalserHr7rrF)r rr r r!test_p_tag_is_never_empty_elements z:HTMLTreeBuilderSmokeTest.test_p_tag_is_never_empty_elementcCs(|jdd|jdd|jdddS)zA tag that's not closed by the end of the document should be closed. This applies to all tags except empty-element tags. z

z

zzz
z
N)r)r r r rtest_unclosed_tags_get_closeds  z6HTMLTreeBuilderSmokeTest.test_unclosed_tags_get_closedcCs.|jd}|j|jj|jt|jddS)zA
tag is designated as an empty-element tag. Some parsers treat

as one
tag, some parsers as two tags, but it should always be an empty-element tag. z

z
N)r assertTruer%r7rrF)r rr r r#test_br_is_always_empty_element_tags z)r)r r r rtest_nested_formatting_elementssz8HTMLTreeBuilderSmokeTest.test_nested_formatting_elementscCs(d}|j|}|jd|jdddS)Nz Ordinary HEAD element test Hello, world! ztext/javascriptscripttype)rrfind)r rLrr r rtest_double_heads  z)HTMLTreeBuilderSmokeTest.test_double_headcCsjd}|j||j|}|jdd}|j|jt|jdd}|j||j|jdd}|j||jdS)Nz

foobaz

Zfoobar)textrCbaz)rrrgrr>rrr)r rrZcommentrCrjr r r test_comments     z%HTMLTreeBuilderSmokeTest.test_commentcCstd}d}|j||j||j|}|j|jj||j|}|j|jj||jd}|j|jjddS)zWhitespace must be preserved in
 and zN)rrrZpreZprettifyZtextarea)rZ
pre_markupZtextarea_markuprr
r
r-test_preserved_whitespace_in_pre_and_textareas




zFHTMLTreeBuilderSmokeTest.test_preserved_whitespace_in_pre_and_textareacCs.d}|j|d}|j|d}|j|dS)z+Inline elements can be nested indefinitely.zInside a B tagz!

A nested tag

z/

A doubly nested tag

N)r)r Zb_tagZ nested_b_tagZdouble_nested_b_tagr r rtest_nested_inline_elements s   z4HTMLTreeBuilderSmokeTest.test_nested_inline_elementscCs6|jd}|j}|j|jjjd|j|jjddS)zBlock elements can be nested.z*

Foo

ZFooN)r blockquoterrHbstring)r rrnr r r test_nested_block_level_elementss z9HTMLTreeBuilderSmokeTest.test_nested_block_level_elementscCsd}|j|d|jddS)z$One table can go inside another one.z[zh
Here's another table:
foo
Here's another table:
foo
z{
Foo
Bar
Baz
N)r)r rr r rtest_correctly_nested_tabless z5HTMLTreeBuilderSmokeTest.test_correctly_nested_tablescCs(d}|j|}|jdg|jjddS)Nz1
Zcssclass)rrZdiv)r rrr r r(test_deeply_nested_multivalued_attribute0s zAHTMLTreeBuilderSmokeTest.test_deeply_nested_multivalued_attributecCs(d}|j|}|jddg|jddS)Nzarors)rrrL)r rrr r r"test_multivalued_attribute_on_html8s z;HTMLTreeBuilderSmokeTest.test_multivalued_attribute_on_htmlcCs|jdddS)Nzz)r)r r r r3test_angle_brackets_in_attribute_values_are_escaped@szLHTMLTreeBuilderSmokeTest.test_angle_brackets_in_attribute_values_are_escapedcCs|jdddS)Nz$

• AT&T is in the s&p 500

z,

\u2022 AT&T is in the s&p 500

)r)r r r r3test_strings_resembling_character_entity_referencesCszLHTMLTreeBuilderSmokeTest.test_strings_resembling_character_entity_referencescCs"d}|j|}|jd|jjdS)Nz%

“Hello” -☃

u“Hello” -☃)rrrHrp)r rrr r r*test_entities_in_foreign_document_encodingKs zCHTMLTreeBuilderSmokeTest.test_entities_in_foreign_document_encodingcCs8d}|jd||jd||jd||jd|dS)Nu

z

z

z

z

)r)r expectr r r0test_entities_in_attributes_converted_to_unicodeWs    zIHTMLTreeBuilderSmokeTest.test_entities_in_attributes_converted_to_unicodecCs8d}|jd||jd||jd||jd|dS)Nu

piñata

z

piñata

z

piñata

z

piñata

z

piñata

)r)r rzr r r*test_entities_in_text_converted_to_unicode^s    zCHTMLTreeBuilderSmokeTest.test_entities_in_text_converted_to_unicodecCs|jdddS)Nz#

I said "good day!"

z

I said "good day!"

)r)r r r r,test_quot_entity_converted_to_quotation_markeszEHTMLTreeBuilderSmokeTest.test_quot_entity_converted_to_quotation_markcCs,d}|jd||jd||jd|dS)Nu�z�z�z �)r)r rzr r rtest_out_of_range_entityis  z1HTMLTreeBuilderSmokeTest.test_out_of_range_entitycCs<|jd}|jd|jjjj|jd|jj|j|dS)zDMostly to prevent a recurrence of a bug in the html5lib treebuilder.z!

foo

rHN)rrZh2rprr8rHr)r rr r rtest_multipart_stringsos z/HTMLTreeBuilderSmokeTest.test_multipart_stringscCs|jdd|jdddS)zqVerify consistent handling of empty-element tags, no matter how they come in through the markup. z


z


N)r)r r r rr9vs cCs,d}|j|}|jd|jj|j|dS)z8Prevent recurrence of a bug in the html5lib treebuilder.z? foo N)rZassertNotEqualrLbodyr)r contentrr r r#test_head_tag_between_head_and_body}s z N)rrZarticle)r rrr r rtest_multiple_copies_of_a_tags  z6HTMLTreeBuilderSmokeTest.test_multiple_copies_of_a_tagcCs^d}|j|}|j||j|j}|jd|jd|jd|jd|jd|jddS) zParsers don't need to *understand* namespaces, but at the very least they should not choke on namespaces or lose data.s4zhttp://www.w3.org/1999/xhtmlZxmlnsz"http://www.w3.org/1998/Math/MathMLz xmlns:mathmlzhttp://www.w3.org/2000/svgz xmlns:svgN)rrrVrL)r rrrLr r rtest_basic_namespacess z.HTMLTreeBuilderSmokeTest.test_basic_namespacescCs(d}|j|}|jddg|jddS)NsrCbarrs)rrru)r rrr r r-test_multivalued_attribute_value_becomes_lists zFHTMLTreeBuilderSmokeTest.test_multivalued_attribute_value_becomes_listcCs"d}|j|}|jd|jjdS)NuDSacré bleu!u Sacré bleu!)rrrrp)r rrr r rtest_can_parse_unicode_documents z8HTMLTreeBuilderSmokeTest.test_can_parse_unicode_documentcCs*td}|jd|d}|j|jddS)z2Parsers should be able to work with SoupStrainers.roz&A bold statement)Z parse_onlyz boldN)rrrr)r Zstrainerrr r rtest_soupstrainersz*HTMLTreeBuilderSmokeTest.test_soupstrainercCs|jdddS)Nzz)r)r r r r7test_single_quote_attribute_values_become_double_quotesszPHTMLTreeBuilderSmokeTest.test_single_quote_attribute_values_become_double_quotescCsd}|j|dS)Nz'a)r)r rir r r7test_attribute_values_with_nested_quotes_are_left_aloneszPHTMLTreeBuilderSmokeTest.test_attribute_values_with_nested_quotes_are_left_alonecCs.d}|j|}d|jd<|j|jjddS)Nz'azBrawls happen at "Bob's Bar"attrz:a)rrCrr)r rirr r r:test_attribute_values_with_double_nested_quotes_get_quoteds   zSHTMLTreeBuilderSmokeTest.test_attribute_values_with_double_nested_quotes_get_quotedcCs|jdd|jdddS)Nz+z/z.fooz2foo)r)r r r r.test_ampersand_in_attribute_value_gets_escapeds zGHTMLTreeBuilderSmokeTest.test_ampersand_in_attribute_value_gets_escapedcCs|jddS)Nz/)r)r r r r7test_escaped_ampersand_in_attribute_value_is_left_aloneszPHTMLTreeBuilderSmokeTest.test_escaped_ampersand_in_attribute_value_is_left_alonecCsd}d}|j||dS)Nz-

<<sacré bleu!>>

u#

<<sacré bleu!>>

)r)r riexpectedr r r1test_entities_in_strings_converted_during_parsingszJHTMLTreeBuilderSmokeTest.test_entities_in_strings_converted_during_parsingcCs"d}|j|}|j|jjddS)Ns

Foo

u ‘Foo’)rrrHrp)r Zquoterr r r)test_smart_quotes_converted_on_the_way_ins  zBHTMLTreeBuilderSmokeTest.test_smart_quotes_converted_on_the_way_incCs|jd}|j|jjddS)Nz   r:u  )rrrurp)r rr r r0test_non_breaking_spaces_converted_on_the_way_ins zIHTMLTreeBuilderSmokeTest.test_non_breaking_spaces_converted_on_the_way_incCs0d}djd}|j|}|j|jjd|dS)Nz-

<<sacré bleu!>>

u#

<<sacré bleu!>>

zutf-8)rVrrrH)r rirrr r r&test_entities_converted_on_the_way_outs  z?HTMLTreeBuilderSmokeTest.test_entities_converted_on_the_way_outcCsHd}|jd}|j|}|jd}|jdd}|jd}|j||dS)Nu

Sacré bleu!

z iso-8859-1zutf-8z ISO-Latin-1)rVrrWr)r unicode_htmlZiso_latin_htmlrresultrr r rtest_real_iso_latin_documents     z5HTMLTreeBuilderSmokeTest.test_real_iso_latin_documentcCsLd}|jd}|j|}|j|jd|jd|j|jd|jddS)Nsk
Shift-JISŃR[fBOꂽ{̃t@CłB
z shift-jiszutf-8euc_jp)rrrrV)r shift_jis_htmlrrr r rtest_real_shift_jis_documents   z5HTMLTreeBuilderSmokeTest.test_real_shift_jis_documentcCsBd}|j|dd}|jdks t|j|jd|jdjddS)NsHebrew (ISO 8859-8) in Visual Directionality

Hebrew (ISO 8859-8) in Visual Directionality

iso8859-8)Z from_encoding iso-8859-8zutf-8)rr)rZoriginal_encodingAssertionErrorrrVr)r Zhebrew_documentrr r rtest_real_hebrew_document$s z2HTMLTreeBuilderSmokeTest.test_real_hebrew_documentcCs`d}d|}|j|}|jdddi}|d}|jd||jt|t|jd|jd dS) NzEzj %s Shift-JIS markup goes here.r.z http-equivz Content-typerztext/html; charset=x-sjisztext/html; charset=utf8r[)rrgrrb isinstancerrV)r meta_tagrr parsed_metarr r r'test_meta_tag_reflects_current_encoding1s  z@HTMLTreeBuilderSmokeTest.test_meta_tag_reflects_current_encodingcCs^d}d|}|j|}|jddd}|d}|jd||jt|t|jd|jddS) Nz'zj %s Shift-JIS markup goes here.r.encoding)idcharsetzx-sjisr[)rrgrrbrrrV)r rrrrrr r r3test_html5_style_meta_tag_reflects_current_encodingMs  zLHTMLTreeBuilderSmokeTest.test_html5_style_meta_tag_reflects_current_encodingcCs*|jd}d|jd<|jd|jjdS)Nz textrrCztext)rrurr)r datar r r5test_tag_with_no_attributes_can_have_attributes_addedes  zNHTMLTreeBuilderSmokeTest.test_tag_with_no_attributes_can_have_attributes_addedN);rrr __doc__r9rBrKrDrMrOrPrQrRrSrXrZr\r_r`rarcrdrhrkrlrmrqrrrtrvrwrxryr{r|r}r~rrrrrrrrrrrrrrrrrrrrrrr r r rr"?sr             r"c@seZdZddZddZddZddZd d Zd d Zd dZ ddZ ddZ ddZ ddZ ddZddZddZddZdd Zd!d"Zd#d$Zd%S)&XMLTreeBuilderSmokeTestcCsF|jd}tj|d}tj|}|j|jt|j|j|jdS)Nz foor:)rr;r<r=rr>rr)r r?r@rAr r rrBls    z9XMLTreeBuilderSmokeTest.test_pickle_and_unpickle_identitycCs|jd}|j|jddS)Nzs. )rrrV)r rr r rtest_docstring_generatedus z0XMLTreeBuilderSmokeTest.test_docstring_generatedcCs$d}|j|}|j||jddS)Ns, r[)rrrV)r rrr r rtest_xml_declarationzs z,XMLTreeBuilderSmokeTest.test_xml_declarationcCs$d}|j|}|j||jddS)Ns< r[)rrrV)r rrr r rr\s z3XMLTreeBuilderSmokeTest.test_processing_instructioncCs$d}|j|}|j|jd|dS)zGA real XHTML document should come out *exactly* the same as it went in.s Hello. Goodbye. zutf-8N)rrrV)r rrr r rrXs z0XMLTreeBuilderSmokeTest.test_real_xhtml_documentcCs"d}|j|}|j||jdS)Ns )rrrV)r docrr r rtest_nested_namespacess z.XMLTreeBuilderSmokeTest.test_nested_namespacescCs0d}t|d}d|j_|j}|jd|kdS)Nz/ zlxml-xmlzconsole.log("< < hey > > ");s< < hey > >)rrerprVrb)r rrZencodedr r r5test_formatter_processes_script_tag_for_xml_documentss  zMXMLTreeBuilderSmokeTest.test_formatter_processes_script_tag_for_xml_documentscCs"d}|j|}|jd|jjdS)Nu?Sacré bleu!u Sacré bleu!)rrrootrp)r rrr r rrs z7XMLTreeBuilderSmokeTest.test_can_parse_unicode_documentcCs$d}|j|}|jt|j|dS)Nzb2012-07-02T20:33:42Zcd)rrrFZrss)r rrr r rtest_popping_namespaced_tags z3XMLTreeBuilderSmokeTest.test_popping_namespaced_tagcCs |jd}|j|jdddS)Nzlatin1s/ )rrrV)r rr r r(test_docstring_includes_correct_encodings z@XMLTreeBuilderSmokeTest.test_docstring_includes_correct_encodingcCs0dddd}|j|}|j|jd|dS) z 0r: szutf-8Ni)rrrV)r rrr r rtest_large_xml_documents z/XMLTreeBuilderSmokeTest.test_large_xml_documentcCs|jdd|jddS)Nz

z

z

foo

)r)r r r r9test_tags_are_empty_element_if_and_only_if_they_are_emptys zQXMLTreeBuilderSmokeTest.test_tags_are_empty_element_if_and_only_if_they_are_emptycCs8d}|j|}|j}|jd|d|jd|ddS)NzThis tag is in the a namespaceThis tag is in the b namespacezhttp://example.com/zxmlns:azhttp://example.net/zxmlns:b)rrr)r rrrr r rtest_namespaces_are_preserveds  z5XMLTreeBuilderSmokeTest.test_namespaces_are_preservedcCs$d}|j|}|jt|j|dS)NzN

20010504

)rrrFrH)r rrr r rtest_closing_namespaced_tags z3XMLTreeBuilderSmokeTest.test_closing_namespaced_tagcCs$d}|j|}|jt|j|dS)Nzs)rrrFrC)r rrr r rtest_namespaced_attributess z2XMLTreeBuilderSmokeTest.test_namespaced_attributescCs$d}|j|}|jt|j|dS)Nzbar)rrrFrC)r rrr r r(test_namespaced_attributes_xml_namespaces z@XMLTreeBuilderSmokeTest.test_namespaced_attributes_xml_namespacecCsd}|j|}|jdt|jd|jdt|jd|jdt|jd|jdt|jddd |jdt|jddgdS) Na foo bar baz tagr:zns1:tagzns2:tagvalue)key)rrrGrY)r rrr r rtest_find_by_prefixed_names  z2XMLTreeBuilderSmokeTest.test_find_by_prefixed_namecCs2d}|j|}|j}tj|}|j|j|jdS)Nzf )rZdocumentr]rprefix)r ZxmlrrZ duplicater r r!test_copy_tag_preserves_namespaces   z9XMLTreeBuilderSmokeTest.test_copy_tag_preserves_namespaceN)rrr rBrrr\rXrrrrrrrrrrrrrr r r rrjs$     rc@s8eZdZdZddZddZddZdd Zd d Zd S) HTML5TreeBuilderSmokeTestz2Smoke test for a tree builder that supports HTML5.cCsdS)Nr )r r r rrXsz2HTML5TreeBuilderSmokeTest.test_real_xhtml_documentcCs"d}|j|}|jd|jjdS)Nz
zhttp://www.w3.org/1999/xhtml)rrru namespace)r rrr r rtest_html_tags_have_namespaces z7HTML5TreeBuilderSmokeTest.test_html_tags_have_namespacecCs6d}|j|}d}|j||jj|j||jjdS)Nzzhttp://www.w3.org/2000/svg)rrZsvgrZcircle)r rrrr r rtest_svg_tags_have_namespace s  z6HTML5TreeBuilderSmokeTest.test_svg_tags_have_namespacecCs6d}|j|}d}|j||jj|j||jjdS)Nz5z"http://www.w3.org/1998/Math/MathML)rrZmathrZmsqrt)r rrrr r rtest_mathml_tags_have_namespaces  z9HTML5TreeBuilderSmokeTest.test_mathml_tags_have_namespacecCsPd}|j|}|jt|jdt|j|jdd|jd|jdjjdS)Nz3rz$?xml version="1.0" encoding="utf-8"?rL)rrbrrErrrr8)r rrr r r$test_xml_declaration_becomes_comments  z>HTML5TreeBuilderSmokeTest.test_xml_declaration_becomes_commentN) rrr rrXrrrrr r r rrs rcsddfdd}|S)Nc_sdS)Nr )Ztestargsrr r rnothing!szskipIf..nothingcsrS|SdS)Nr )Z test_item) conditionrr r decorator$szskipIf..decoratorr )rreasonrr )rrrskipIf sr)rZ __license__r;r] functoolsZunittestrZbs4rZ bs4.elementrrrrrZ bs4.builderr r r objectr"rrrr r r rs(   %/#