Re: [TFUI] asserting HTML by example

Jason Citron <[email protected]> Wed, 11 Mar 2009 22:33:22 -0700
Newsgroups gmane.comp.programming.test-first-user-interfaces
Message-ID <[email protected]>
--EYE-5-e-vYm-5XuxFHl25sXLf9znU57-MrxWjbW
Content-Type: text/plain; charset=US-ASCII
Content-Transfer-Encoding: 7bit

For structural HTML testing you should check out assert_select. It comes
with Rails 2.0.

Useful for testing XML too.

http://api.rubyonrails.org/classes/ActionController/Assertions/SelectorAssertions.html

On Wed, Mar 11, 2009 at 10:27 PM, Phlip <[email protected]> wrote:

>   extremists:
>
> HTML is easy to test and hard to test well. A unit test must intercept and
> parse
> it, hopefully _before_ it goes thru a web server.
>
> I just wrote an assertion which turns that problem on its head. Instead of
> asserting how to parse that HTML, we will assert how to build an example of
> HTML
> that the production HTML must match.
>
> This post is the high-level, language-agnostic, overview of these
> announcement
> posts:
>
> http://www.ruby-forum.com/topic/181145#792950
>
> Here's the example:
>
> user = users(:Moses)
> get :edit_user, :id => user.id # fetches a web page
>
> assert_xhtml do
>
> form :action => '/users' do
> fieldset do
> legend 'Personal Information'
> label 'First name'
> input :type => 'text',
> :name => 'user[first_name]'
> :value => user.first_name
> end
> end
>
> end
>
> That's all. Inside the assertion's block, you declare the HTML you want,
> using a
> Builder notation. (Nokogiri, in Ruby's case.)
>
> The assertion skips over any intervening elements, such as <ul>, <table>,
> etc,
> that the block did not build. In the above example, <fieldset> only needs
> to
> appear somewhere inside the <form> - not necessarily its first element. But
>
> those <label> and <input> fields must appear somewhere inside that
> <fieldset>,
> and in the given order!
>
> To create this assertion in your language, start with your nearest HTML
> builder.
> Allow the user-programmer to build an example, then traverse its DOM, and
> convert each item into an XPath seeking that item in the production HTML.
> Declare a match if all the specified attributes match, and if most of the
> text
> matches - disregarding blanks.
>
> Then, for each match, recursively match each built child element, applying
> its
> XPath relative to the current node in the production HTML's DOM.
>
> When you find a fault, build an error message by rendering the current
> nodes to
> HTML, and return this out of your loop statements. This Gist explicates the
>
> algorithm:
>
> http://gist.github.com/76136
>
> The algorithm essentially matches two trees, depth-first and in-order. The
> example HTML must be a subset of the production HTML.
>
> If you survive all that recursing and matching then your assertion passes.
> You
> verified a huge number of details, using extremely lean code, and you
> ignored
> many more details, allowing them to change freely as you upgrade your
> website.
>
> --
> Phlip
> http://www.zeroplayer.com/
>  
>


[Non-text portions of this message have been removed]


--EYE-5-e-vYm-5XuxFHl25sXLf9znU57-MrxWjbW
Content-Type: text/html; charset=US-ASCII
Content-Transfer-Encoding: 7bit



<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
</head>




<body style="background-color: #ffffff;">

<!--~-|**|PrettyHtmlStartT|**|-~-->
<div id="ygrp-mlmsg" style="width:655px; position:relative;">
<div id="ygrp-msg" style="width: 470px; margin:0; padding:0 25px 0 0; float:left; z-index:1;">
<!--~-|**|PrettyHtmlEndT|**|-~-->

    <div id="ygrp-text">
            <p>For structural HTML testing you should check out assert_select. It comes<br>
with Rails 2.0.<br>
<br>
Useful for testing XML too.<br>
<br>
<a href="http://api.rubyonrails.org/classes/ActionController/Assertions/SelectorAssertions.html">http://api.rubyonra<wbr>ils.org/classes/<wbr>ActionController<wbr>/Assertions/<wbr>SelectorAssertio<wbr>ns.html</a><br>
<br>
On Wed, Mar 11, 2009 at 10:27 PM, Phlip &lt;<a href="mailto:phlip2005%40gmail.com">phlip2005@gmail.<wbr>com</a>&gt; wrote:<br>
<br>
&gt;   extremists:<br>
&gt;<br>
&gt; HTML is easy to test and hard to test well. A unit test must intercept and<br>
&gt; parse<br>
&gt; it, hopefully _before_ it goes thru a web server.<br>
&gt;<br>
&gt; I just wrote an assertion which turns that problem on its head. Instead of<br>
&gt; asserting how to parse that HTML, we will assert how to build an example of<br>
&gt; HTML<br>
&gt; that the production HTML must match.<br>
&gt;<br>
&gt; This post is the high-level, language-agnostic, overview of these<br>
&gt; announcement<br>
&gt; posts:<br>
&gt;<br>
&gt; <a href="http://www.ruby-forum.com/topic/181145#792950">http://www.ruby-<wbr>forum.com/<wbr>topic/181145#<wbr>792950</a><br>
&gt;<br>
&gt; Here's the example:<br>
&gt;<br>
&gt; user = users(:Moses)<br>
&gt; get :edit_user, :id =&gt; user.id # fetches a web page<br>
&gt;<br>
&gt; assert_xhtml do<br>
&gt;<br>
&gt; form :action =&gt; '/users' do<br>
&gt; fieldset do<br>
&gt; legend 'Personal Information'<br>
&gt; label 'First name'<br>
&gt; input :type =&gt; 'text',<br>
&gt; :name =&gt; 'user[first_<wbr>name]'<br>
&gt; :value =&gt; user.first_name<br>
&gt; end<br>
&gt; end<br>
&gt;<br>
&gt; end<br>
&gt;<br>
&gt; That's all. Inside the assertion's block, you declare the HTML you want,<br>
&gt; using a<br>
&gt; Builder notation. (Nokogiri, in Ruby's case.)<br>
&gt;<br>
&gt; The assertion skips over any intervening elements, such as &lt;ul&gt;, &lt;table&gt;,<br>
&gt; etc,<br>
&gt; that the block did not build. In the above example, &lt;fieldset&gt; only needs<br>
&gt; to<br>
&gt; appear somewhere inside the &lt;form&gt; - not necessarily its first element. But<br>
&gt;<br>
&gt; those &lt;label&gt; and &lt;input&gt; fields must appear somewhere inside that<br>
&gt; &lt;fieldset&gt;,<br>
&gt; and in the given order!<br>
&gt;<br>
&gt; To create this assertion in your language, start with your nearest HTML<br>
&gt; builder.<br>
&gt; Allow the user-programmer to build an example, then traverse its DOM, and<br>
&gt; convert each item into an XPath seeking that item in the production HTML.<br>
&gt; Declare a match if all the specified attributes match, and if most of the<br>
&gt; text<br>
&gt; matches - disregarding blanks.<br>
&gt;<br>
&gt; Then, for each match, recursively match each built child element, applying<br>
&gt; its<br>
&gt; XPath relative to the current node in the production HTML's DOM.<br>
&gt;<br>
&gt; When you find a fault, build an error message by rendering the current<br>
&gt; nodes to<br>
&gt; HTML, and return this out of your loop statements. This Gist explicates the<br>
&gt;<br>
&gt; algorithm:<br>
&gt;<br>
&gt; <a href="http://gist.github.com/76136">http://gist.<wbr>github.com/<wbr>76136</a><br>
&gt;<br>
&gt; The algorithm essentially matches two trees, depth-first and in-order. The<br>
&gt; example HTML must be a subset of the production HTML.<br>
&gt;<br>
&gt; If you survive all that recursing and matching then your assertion passes.<br>
&gt; You<br>
&gt; verified a huge number of details, using extremely lean code, and you<br>
&gt; ignored<br>
&gt; many more details, allowing them to change freely as you upgrade your<br>
&gt; website.<br>
&gt;<br>
&gt; --<br>
&gt; Phlip<br>
&gt; <a href="http://www.zeroplayer.com/">http://www.zeroplay<wbr>er.com/</a><br>
&gt;  <br>
&gt;<br>
<br>
[Non-text portions of this message have been removed]<br>
<br>
</p>
 

    </div>  

    <!--~-|**|PrettyHtmlStart|**|-~-->
    <div width="1" style="color: white; clear: both;">__._,_.___</div>

             
    <!-- Start the section with Message In topic -->
    <div id="ygrp-actbar" style="clear: both; margini-bottom: 25px; white-space:nowrap; color: #666; text-align: right;">
              <span class="left" style="float: left; white-space:nowrap;">
          <a href="http://groups.yahoo.com/group/TestFirstUserInterfaces/message/1037;_ylc=X3oDMTM0ZGI5NWFsBF9TAzk3MzU5NzE0BGdycElkAzg3NDQ3MDQEZ3Jwc3BJZAMxNzA1MDA3MjA3BG1zZ0lkAzEwMzgEc2VjA2Z0cgRzbGsDdnRwYwRzdGltZQMxMjM2ODM2MDI1BHRwY0lkAzEwMzc-">
            Messages in this topic          </a> (<span class="bld" style="font-weight:bold;">2</span>)
        </span>
        <a href="http://groups.yahoo.com/group/TestFirstUserInterfaces/post;_ylc=X3oDMTJwNW85a25nBF9TAzk3MzU5NzE0BGdycElkAzg3NDQ3MDQEZ3Jwc3BJZAMxNzA1MDA3MjA3BG1zZ0lkAzEwMzgEc2VjA2Z0cgRzbGsDcnBseQRzdGltZQMxMjM2ODM2MDI1?act=reply&messageNum=1038">
          <span class="bld" style="font-weight:bold;">
            Reply          </span> (via web post)
        </a>  | 
        <a href="http://groups.yahoo.com/group/TestFirstUserInterfaces/post;_ylc=X3oDMTJlZnRwYTFyBF9TAzk3MzU5NzE0BGdycElkAzg3NDQ3MDQEZ3Jwc3BJZAMxNzA1MDA3MjA3BHNlYwNmdHIEc2xrA250cGMEc3RpbWUDMTIzNjgzNjAyNQ--" class="bld" style="font-weight:bold;">
          Start a new topic        </a>
          </div> 
    <!-------     Start Nav Bar  ------>
    <!-- |**|begin egp html banner|**| -->
    <div id="ygrp-vitnav" style="padding-top: 10px; font-family: Verdana; font-size: 77%; margin: 0;">
                <a href="http://groups.yahoo.com/group/TestFirstUserInterfaces/messages;_ylc=X3oDMTJlN2VxNmQ3BF9TAzk3MzU5NzE0BGdycElkAzg3NDQ3MDQEZ3Jwc3BJZAMxNzA1MDA3MjA3BHNlYwNmdHIEc2xrA21zZ3MEc3RpbWUDMTIzNjgzNjAyNQ--">Messages</a>  
            |    <a href="http://groups.yahoo.com/group/TestFirstUserInterfaces/files;_ylc=X3oDMTJmNWhpZjk3BF9TAzk3MzU5NzE0BGdycElkAzg3NDQ3MDQEZ3Jwc3BJZAMxNzA1MDA3MjA3BHNlYwNmdHIEc2xrA2ZpbGVzBHN0aW1lAzEyMzY4MzYwMjU-">Files</a>  
            |    <a href="http://groups.yahoo.com/group/TestFirstUserInterfaces/photos;_ylc=X3oDMTJlamRjdDFqBF9TAzk3MzU5NzE0BGdycElkAzg3NDQ3MDQEZ3Jwc3BJZAMxNzA1MDA3MjA3BHNlYwNmdHIEc2xrA3Bob3QEc3RpbWUDMTIzNjgzNjAyNQ--">Photos</a>  
            |    <a href="http://groups.yahoo.com/group/TestFirstUserInterfaces/links;_ylc=X3oDMTJmaDBhbDNkBF9TAzk3MzU5NzE0BGdycElkAzg3NDQ3MDQEZ3Jwc3BJZAMxNzA1MDA3MjA3BHNlYwNmdHIEc2xrA2xpbmtzBHN0aW1lAzEyMzY4MzYwMjU-">Links</a>  
            |    <a href="http://groups.yahoo.com/group/TestFirstUserInterfaces/database;_ylc=X3oDMTJjMmFlZThxBF9TAzk3MzU5NzE0BGdycElkAzg3NDQ3MDQEZ3Jwc3BJZAMxNzA1MDA3MjA3BHNlYwNmdHIEc2xrA2RiBHN0aW1lAzEyMzY4MzYwMjU-">Database</a>  
            |    <a href="http://groups.yahoo.com/group/TestFirstUserInterfaces/polls;_ylc=X3oDMTJmNjQ5bHQzBF9TAzk3MzU5NzE0BGdycElkAzg3NDQ3MDQEZ3Jwc3BJZAMxNzA1MDA3MjA3BHNlYwNmdHIEc2xrA3BvbGxzBHN0aW1lAzEyMzY4MzYwMjU-">Polls</a>  
            |    <a href="http://groups.yahoo.com/group/TestFirstUserInterfaces/members;_ylc=X3oDMTJlY2Q4OWNyBF9TAzk3MzU5NzE0BGdycElkAzg3NDQ3MDQEZ3Jwc3BJZAMxNzA1MDA3MjA3BHNlYwNmdHIEc2xrA21icnMEc3RpbWUDMTIzNjgzNjAyNQ--">Members</a>  
            |    <a href="http://groups.yahoo.com/group/TestFirstUserInterfaces/calendar;_ylc=X3oDMTJkbmFmaGU3BF9TAzk3MzU5NzE0BGdycElkAzg3NDQ3MDQEZ3Jwc3BJZAMxNzA1MDA3MjA3BHNlYwNmdHIEc2xrA2NhbARzdGltZQMxMjM2ODM2MDI1">Calendar</a>  
    </div>  
    <!-- |**|end egp html banner|**| -->

                <div id="ygrp-grfd" style="font-family: Verdana; font-size: 77%; padding: 15px 0;">
                  

              </div>
    
    <!-- yahoo logo -->
    <!-- |**|begin egp html banner|**| -->
    <div id="ygrp-ft" style="font-family: verdana; font-size: 77%; border-top: 1px solid #666; padding: 5px 0;">
      <a href="http://groups.yahoo.com/;_ylc=X3oDMTJkdWJiZ2YwBF9TAzk3MzU5NzE0BGdycElkAzg3NDQ3MDQEZ3Jwc3BJZAMxNzA1MDA3MjA3BHNlYwNmdHIEc2xrA2dmcARzdGltZQMxMjM2ODM2MDI1">
      <img src="http://us.i1.yimg.com/us.yimg.com/i/yg/img/logo/ma_grp_160.gif" height="15" width="106" border="0" alt="Yahoo! Groups"></a> <br>
      <a href="http://groups.yahoo.com/group/TestFirstUserInterfaces/join;_ylc=X3oDMTJmMWE3Njg4BF9TAzk3MzU5NzE0BGdycElkAzg3NDQ3MDQEZ3Jwc3BJZAMxNzA1MDA3MjA3BHNlYwNmdHIEc2xrA3N0bmdzBHN0aW1lAzEyMzY4MzYwMjU-">Change settings via the Web</a> (Yahoo! ID required) <br>
      Change settings via email: <a href="mailto:TestFirstUserInterfaces-digest-hHKSG33TihhbjbujkaE4pw@public.gmane.org?subject=Email Delivery: Digest">Switch delivery to Daily Digest</a> | <a href = "mailto:TestFirstUserInterfaces-traditional-hHKSG33TihhbjbujkaE4pw@public.gmane.org?subject=Change Delivery Format: Traditional">Switch format to Traditional</a> <br>

      <a href="http://groups.yahoo.com/group/TestFirstUserInterfaces;_ylc=X3oDMTJkMjl0c29wBF9TAzk3MzU5NzE0BGdycElkAzg3NDQ3MDQEZ3Jwc3BJZAMxNzA1MDA3MjA3BHNlYwNmdHIEc2xrA2hwZgRzdGltZQMxMjM2ODM2MDI1">
        Visit Your Group 
      </a> |
      <a href="http://docs.yahoo.com/info/terms/">
        Yahoo! Groups Terms of Use      </a> |
      <a href="mailto:TestFirstUserInterfaces-unsubscribe-hHKSG33TihhbjbujkaE4pw@public.gmane.org?subject=">
        Unsubscribe      </a> 
    </div>     <!-- |**|end egp html banner|**| -->
  </div> <!-- ygrp-msg -->

  
  <!-- Sponsor -->
  <!-- |**|begin egp html banner|**| -->
  <div id="ygrp-sponsor" style="width:160px; float:right; clear:none; margin:0 0 25px 0; background: white;">
    <!-- Network content -->
    
<!-- Start Recommendations -->
<div id="ygrp-reco">
     </div>
<!-- End Recommendations -->

	    <!-- Start vitality -->
	    <div id="ygrp-vital" style="background-color: #e0ecee; margin-bottom: 20px; padding: 2px 0 8px 8px;">
	      		<div id="vithd" style="font-size: 77%; font-family: Verdana; font-weight: bold; color: #333; text-transform: uppercase;">Recent Activity</div>
		<ul style="list-style-type:none; padding: 0; margin: 2px 0;">
		    
		    
		    
		    
		    
		    
		</ul>
	      	      <a href="http://groups.yahoo.com/group/TestFirstUserInterfaces;_ylc=X3oDMTJlZXFxdHNxBF9TAzk3MzU5NzE0BGdycElkAzg3NDQ3MDQEZ3Jwc3BJZAMxNzA1MDA3MjA3BHNlYwN2dGwEc2xrA3ZnaHAEc3RpbWUDMTIzNjgzNjAyNQ--">
		Visit Your Group	      </a>
	    </div> 
	    	    	      
	    <!-- Network content -->
	    	      <div style="background-color:#EEEEEE; margin-bottom:20px; padding:10px 8px;">    <div id="nc">
              <div class="ad" style="color:#628C2A; font-family:Arial; font-weight:bold;">
                        <div id="hd1">Give Back</div>
  <p><a href="http://us.lrd.yahoo.com/_ylc=X3oDMTJtZGtuaDBzBF9TAzk3MzU5NzE0BF9wAzEEZ3JwSWQDODc0NDcwNARncnBzcElkAzE3MDUwMDcyMDcEc2VjA25jbW9kBHNsawNicmFuZARzdGltZQMxMjM2ODM2MDI1;_ylg=1/SIG=11314uv3k/**http%3A//brand.yahoo.com/forgood" style="text-decoration:none; color:#1E66AE; font-weight: normal;">Yahoo! for Good</a></p>
  <p style="color: #000000; font-weight: normal;">Get inspired</p>
  <p style="color: #000000; font-weight: normal;">by a good cause.</p>
                  </div>
                    <div class="ad" style="color:#628C2A; font-family:Arial; font-weight:bold;">
                        <div id="hd1">Y! Toolbar</div>
  <p><a href="http://us.lrd.yahoo.com/_ylc=X3oDMTJvZmJuZ2FwBF9TAzk3MzU5NzE0BF9wAzIEZ3JwSWQDODc0NDcwNARncnBzcElkAzE3MDUwMDcyMDcEc2VjA25jbW9kBHNsawN0b29sYmFyBHN0aW1lAzEyMzY4MzYwMjU-;_ylg=1/SIG=11c6dvmk9/**http%3A//toolbar.yahoo.com/%3F.cpdl=ygrps" style="text-decoration:none; color:#1E66AE; font-weight: normal;">Get it Free!</a></p>
  <p style="color: #000000; font-weight: normal;">easy 1-click access</p>
  <p style="color: #000000; font-weight: normal;">to your groups.</p>
                  </div>
                    <div class="ad" style="color:#628C2A; font-family:Arial; font-weight:bold;">
                        <div id="hd1">Yahoo! Groups</div>
  <p><a href="http://groups.yahoo.com/start;_ylc=X3oDMTJvYmlhbTYzBF9TAzk3MzU5NzE0BF9wAzMEZ3JwSWQDODc0NDcwNARncnBzcElkAzE3MDUwMDcyMDcEc2VjA25jbW9kBHNsawNncm91cHMyBHN0aW1lAzEyMzY4MzYwMjU-" style="text-decoration:none; color:#1E66AE; font-weight: normal;">Start a group</a></p>
  <p style="color: #000000; font-weight: normal;">in 3 easy steps.</p>
  <p style="color: #000000; font-weight: normal;">Connect with others.</p>
                  </div>
          </div>
</div>
	    
	  </div> 	  <!-- |**|end egp html banner|**| -->
	  <div style="clear:both; color: #FFF; font-size:1px;">.</div>
	</div> 		  <img src="http://geo.yahoo.com/serv?s=97359714/grpId=8744704/grpspId=1705007207/msgId=1038/stime=1236836025/nc1=1/nc2=2/nc3=3" width="1" height="1"> <br>
	
	<div style="color: white; clear: both;">__,_._,___</div>
	<!--~-|**|PrettyHtmlEnd|**|-~-->
	</body>
	<!--~-|**|PrettyHtmlStart|**|-~-->
	<head>
<style type="text/css">
<!--
#ygrp-mkp{
  border: 1px solid #d8d8d8;
  font-family: Arial;
  margin: 14px 0px;
  padding: 0px 14px;
}
#ygrp-mkp hr{
  border: 1px solid #d8d8d8;
}
#ygrp-mkp #hd{
  color: #628c2a;
  font-size: 85%;
  font-weight: bold;
  line-height: 122%;
  margin: 10px 0px;
}
#ygrp-mkp #ads{
  margin-bottom: 10px;
}
#ygrp-mkp .ad{
  padding: 0 0;
}
#ygrp-mkp .ad a{
  color: #0000ff;
  text-decoration: none;
}
-->
</style>
</head>
	<head>
<style type="text/css">
<!--
#ygrp-sponsor #ygrp-lc{
  font-family: Arial;
}
#ygrp-sponsor #ygrp-lc #hd{
  margin: 10px 0px;
  font-weight: bold;
  font-size: 78%;
  line-height: 122%;
}
#ygrp-sponsor #ygrp-lc .ad{
  margin-bottom: 10px;
  padding: 0 0;
}
-->
</style>
</head>
	<head>
	<style type="text/css">
	<!--
	#ygrp-mlmsg {font-size:13px; font-family: arial,helvetica,clean,sans-serif;*font-size:small;*font:x-small;}
	#ygrp-mlmsg table {font-size:inherit;font:100%;}
	#ygrp-mlmsg select, input, textarea {font:99% arial,helvetica,clean,sans-serif;}
	#ygrp-mlmsg pre, code {font:115% monospace;*font-size:100%;}
	#ygrp-mlmsg * {line-height:1.22em;}
	#ygrp-text{
	    font-family: Georgia;	
	}
	#ygrp-text p{
	    margin: 0 0 1em 0;
	}

	dd.last p a {
          font-family: Verdana;
          font-weight: bold;
	}

	#ygrp-vitnav{
		padding-top: 10px;
		font-family: Verdana;
		font-size: 77%;
		margin: 0;
	}
	#ygrp-vitnav a{
		padding: 0 1px;
	}
	#ygrp-mlmsg #logo{
	  padding-bottom: 10px;
	}

	#ygrp-reco {
	margin-bottom: 20px;
	padding: 0px;
	}
	#ygrp-reco #reco-head {
		font-weight: bold;
		color: #ff7900;
	}

	#reco-category{
        	font-size: 77%;
	}
	#reco-desc{
        	font-size: 77%;
	}

	#ygrp-vital a{
		text-decoration: none;
	}

	#ygrp-vital a:hover{
	  text-decoration: underline;
	}

	#ygrp-sponsor #ov ul{
		padding: 0 0 0 8px;
		margin: 0;
	}
	#ygrp-sponsor #ov li{
		list-style-type: square;
		padding: 6px 0;
		font-size: 77%;
	}
	#ygrp-sponsor #ov li a{
		text-decoration: none;
		font-size: 130%;
	}
	#ygrp-sponsor #nc{
	  background-color: #eee;
	  margin-bottom: 20px;
	  padding: 0 8px;
	}
	#ygrp-sponsor .ad{
		padding: 8px 0;
	}
	#ygrp-sponsor .ad #hd1{
		font-family: Arial;
		font-weight: bold;
		color: #628c2a;
		font-size: 100%;
		line-height: 122%;
	}
	#ygrp-sponsor .ad a{
		text-decoration: none;
	}
	#ygrp-sponsor .ad a:hover{
		text-decoration: underline;
	}
	#ygrp-sponsor .ad p{
		margin: 0;
	}
	o{font-size: 0; }
	.MsoNormal{
	   margin: 0 0 0 0;
	}
	#ygrp-text tt{
	  font-size: 120%;
	}
	blockquote{margin: 0 0 0 4px;}
	.replbq{margin:4}

dd.last p span {
  margin-right: 10px;
  font-family: Verdana;
  font-weight: bold;
}

dd.last p span.yshortcuts {
  margin-right: 0;
}

div.photo-title a,
div.photo-title a:active,
div.photo-title a:hover,
div.photo-title a:visited {
    text-decoration: none;
}

div.file-title a,
div.file-title a:active,
div.file-title a:hover,
div.file-title a:visited {
    text-decoration: none;
}

#ygrp-msg p {
    clear: both;
    padding: 15px 0 3px 0;
    overflow: hidden;
}

#ygrp-msg p span {
    color: #1E66AE;
    font-weight: bold;
}

div#ygrp-mlmsg #ygrp-msg p a span.yshortcuts {
    font-family: Verdana;
    font-size: 10px;
    font-weight: normal;
}

#ygrp-msg p a {
    font-family: Verdana;
    font-size: 10px;
}

#ygrp-mlmsg a {
    color: #1E66AE;
}

div.attach-table div div a {
    text-decoration: none;
}

div.attach-table {
    width: 400px;
}

	-->
	</style>
	</head>
	<!--~-|**|PrettyHtmlEnd|**|-~-->
	</html><!--End group email -->


--EYE-5-e-vYm-5XuxFHl25sXLf9znU57-MrxWjbW--