[TFUI] Re: Factors affecting UI testability

Phlip <[email protected]> Wed, 28 Jan 2009 07:20:52 -0800
Newsgroups gmane.comp.programming.test-first-user-interfaces
Message-ID <[email protected]>
--2i49sSTze4qnFjaoCjM-cMl-Af6t-vXRuozWw5G
Content-Type: text/plain; charset=ISO-8859-1
Content-Transfer-Encoding: 7bit

Sai wrote:

> I have been thinking about the points which affect UI testability for
> sometime. When it comes to unit testing there are specific points like
> Dependency Injection, usage of Singletons as factors which affect it.
> 
> Similarly it must be possible to get a set of points which we must be
> able to do or avoid to help UI testability. I need your help in
> collecting these points so that it will help us while we think about
> design for testability at UI level.
> 
> Some points to get started
> 
> 1) Building custom controls like grids or tables either from scratch
> or from available controls. Sometimes I have seen people drawing their
> own controls which makes testing extremely difficult

If you are using an off-the-shelf control, such as an edit field, you can TDD it 
by building its form, running production code to push data into it, then 
querying the data out with the control's accessor methods. I am only talking 
about TDDing from inside the same language and platform as that form - not 
external UI testing.

If you invent a custom grid, or if you override the hooks in a standard control 
to write your own special effects, then you must TDD the new art and input 
itself. You can do that by intercepting your graphical paint methods at a level 
equivalent to Gdk or Cairo. Then tests can query the paint methods back and 
determine they are correct. You TDD the inputs by putting trace statements 
inside your input handlers that reflect input events, then click or type on the 
control, and convert the trace output into sample inputs for your test case.

Once the control works, then you can trust its accessor methods, and the 
business-level TDD can access your data the same as with a standard control.

> 2) Auto generation of UI code. Most of the time it leaves us with
> randomly generated locators

The best thing about auto generation is you are not TDDing your generator 
itself. So if you can TDD the script that you send into the generator, then your 
unit tests save a lot of labor and noise by not generating at all.

We do this all the time in Rails, with that ubiquitous and infamous IU 
generator, XHTML. Test-side parsers, such as .has_xpath or .has_selector 
(meaning a CSS selector), or assert_xpath, are really tests that...

  - render the generating script from production code
  - parse the script (and assert it parses correctly)
  - drill down into its contents to isolate one context
  - TDD that business logic deposited the correct data inside that context
  - not feed the script into the generator (your browser)

So any generator script you use, you gotta get (or write) a parser script for it.

> 3) Not using normal locators like id, name which makes testing complex.

There are situations where that does not work.

However, almost all of our TDD in Rails Views depends on...

  - generate a unique id for each container
  - use assert_xpath{ with a block } to isolate that container
  - use assert_xpath inside that block to detect logical data

All these assertions intend to provide the clearest possible assertions at fault 
time. Constraining those blocks like that lets their fault diagnostics reflect 
only their inner context. When an assertion fails, it does not spew out an 
entire page! I don't know why, but other XPath test assertions don't let you use 
a block to constrain your context...

> 4) Using technologies which don't have testability in built like Javafx.

We must come to a point, as an industry, where we start rejecting technologies 
that can't be tested.

Until then, any port in a storm. I test JavaScript the same as XHTML - by 
parsing it into a lite database, and then querying the database to detect 
logical data. If, for example, the JavaScript is an Ajax response containing 
JavaScript to update a DOM object and push in new XHTML content, I parse down to 
that string, evaluate it, and stick it into the current XHTML context. Then 
subsequent assert_xpath calls can detect important fields in the content.

Nobody else in the industry does this, and I don't know why...

> 5) Highly asynchronous process.

If you suspect a process might need threads, try as hard as possible to avoid 
them. Invent your process, via TDD, without asynchronicity. Build your algorithm 
to use time slicing, and TDD both the individual time slices and their gestalt. 
This forces your code to have the kind of good structure it will need if you 
then must make it asynchronous.

Call your time slices from a dispatcher, such as your windows's Timer event. If 
the process does not work like this, only then should you move the dispatching 
into a thread.

> Please let me know about your thoughts and challenges you faced in UI
> testability.

I intend to blog up a complete dissertation on each of these things. Quite 
frankly, the biggest challenge for me has been trying to help the industry make 
TDD for GUIs as easy as it is for me and my teams.

-- 
   Phlip

--2i49sSTze4qnFjaoCjM-cMl-Af6t-vXRuozWw5G
Content-Type: text/html; charset=ISO-8859-1
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>Sai wrote:<br>
<br>
&gt; I have been thinking about the points which affect UI testability for<br>
&gt; sometime. When it comes to unit testing there are specific points like<br>
&gt; Dependency Injection, usage of Singletons as factors which affect it.<br>
&gt; <br>
&gt; Similarly it must be possible to get a set of points which we must be<br>
&gt; able to do or avoid to help UI testability. I need your help in<br>
&gt; collecting these points so that it will help us while we think about<br>
&gt; design for testability at UI level.<br>
&gt; <br>
&gt; Some points to get started<br>
&gt; <br>
&gt; 1) Building custom controls like grids or tables either from scratch<br>
&gt; or from available controls. Sometimes I have seen people drawing their<br>
&gt; own controls which makes testing extremely difficult<br>
<br>
If you are using an off-the-shelf control, such as an edit field, you can TDD it <br>
by building its form, running production code to push data into it, then <br>
querying the data out with the control's accessor methods. I am only talking <br>
about TDDing from inside the same language and platform as that form - not <br>
external UI testing.<br>
<br>
If you invent a custom grid, or if you override the hooks in a standard control <br>
to write your own special effects, then you must TDD the new art and input <br>
itself. You can do that by intercepting your graphical paint methods at a level <br>
equivalent to Gdk or Cairo. Then tests can query the paint methods back and <br>
determine they are correct. You TDD the inputs by putting trace statements <br>
inside your input handlers that reflect input events, then click or type on the <br>
control, and convert the trace output into sample inputs for your test case.<br>
<br>
Once the control works, then you can trust its accessor methods, and the <br>
business-level TDD can access your data the same as with a standard control.<br>
<br>
&gt; 2) Auto generation of UI code. Most of the time it leaves us with<br>
&gt; randomly generated locators<br>
<br>
The best thing about auto generation is you are not TDDing your generator <br>
itself. So if you can TDD the script that you send into the generator, then your <br>
unit tests save a lot of labor and noise by not generating at all.<br>
<br>
We do this all the time in Rails, with that ubiquitous and infamous IU <br>
generator, XHTML. Test-side parsers, such as .has_xpath or .has_selector <br>
(meaning a CSS selector), or assert_xpath, are really tests that...<br>
<br>
- render the generating script from production code<br>
  - parse the script (and assert it parses correctly)<br>
  - drill down into its contents to isolate one context<br>
  - TDD that business logic deposited the correct data inside that context<br>
  - not feed the script into the generator (your browser)<br>
<br>
So any generator script you use, you gotta get (or write) a parser script for it.<br>
<br>
&gt; 3) Not using normal locators like id, name which makes testing complex.<br>
<br>
There are situations where that does not work.<br>
<br>
However, almost all of our TDD in Rails Views depends on...<br>
<br>
- generate a unique id for each container<br>
  - use assert_xpath{ with a block } to isolate that container<br>
  - use assert_xpath inside that block to detect logical data<br>
<br>
All these assertions intend to provide the clearest possible assertions at fault <br>
time. Constraining those blocks like that lets their fault diagnostics reflect <br>
only their inner context. When an assertion fails, it does not spew out an <br>
entire page! I don't know why, but other XPath test assertions don't let you use <br>
a block to constrain your context...<br>
<br>
&gt; 4) Using technologies which don't have testability in built like Javafx.<br>
<br>
We must come to a point, as an industry, where we start rejecting technologies <br>
that can't be tested.<br>
<br>
Until then, any port in a storm. I test JavaScript the same as XHTML - by <br>
parsing it into a lite database, and then querying the database to detect <br>
logical data. If, for example, the JavaScript is an Ajax response containing <br>
JavaScript to update a DOM object and push in new XHTML content, I parse down to <br>
that string, evaluate it, and stick it into the current XHTML context. Then <br>
subsequent assert_xpath calls can detect important fields in the content.<br>
<br>
Nobody else in the industry does this, and I don't know why...<br>
<br>
&gt; 5) Highly asynchronous process.<br>
<br>
If you suspect a process might need threads, try as hard as possible to avoid <br>
them. Invent your process, via TDD, without asynchronicity. Build your algorithm <br>
to use time slicing, and TDD both the individual time slices and their gestalt. <br>
This forces your code to have the kind of good structure it will need if you <br>
then must make it asynchronous.<br>
<br>
Call your time slices from a dispatcher, such as your windows's Timer event. If <br>
the process does not work like this, only then should you move the dispatching <br>
into a thread.<br>
<br>
&gt; Please let me know about your thoughts and challenges you faced in UI<br>
&gt; testability.<br>
<br>
I intend to blog up a complete dissertation on each of these things. Quite <br>
frankly, the biggest challenge for me has been trying to help the industry make <br>
TDD for GUIs as easy as it is for me and my teams.<br>
<br>
-- <br>
   Phlip<br>
</p>
    </div>  

    <!--~-|**|PrettyHtmlStart|**|-~-->
    <span width="1" style="color: white;">__._,_.___</span>
    <!-- Start the section with Message In topic -->
    <div id="ygrp-actbar">
              <span class="left">
          <a href="http://groups.yahoo.com/group/TestFirstUserInterfaces/message/1027;_ylc=X3oDMTM0N2w2YWNvBF9TAzk3MzU5NzE0BGdycElkAzg3NDQ3MDQEZ3Jwc3BJZAMxNzA1MDA3MjA3BG1zZ0lkAzEwMjcEc2VjA2Z0cgRzbGsDdnRwYwRzdGltZQMxMjMzMTU2MDYyBHRwY0lkAzEwMjc-">
            Messages in this topic          </a> (<span class="bld">1</span>)
        </span>
        <a href="http://groups.yahoo.com/group/TestFirstUserInterfaces/post;_ylc=X3oDMTJwaWE3YnVuBF9TAzk3MzU5NzE0BGdycElkAzg3NDQ3MDQEZ3Jwc3BJZAMxNzA1MDA3MjA3BG1zZ0lkAzEwMjcEc2VjA2Z0cgRzbGsDcnBseQRzdGltZQMxMjMzMTU2MDYy?act=reply&messageNum=1027">
          <span class="bld">
            Reply          </span> (via web post)
        </a>  | 
        <a href="http://groups.yahoo.com/group/TestFirstUserInterfaces/post;_ylc=X3oDMTJlcGM1MGNvBF9TAzk3MzU5NzE0BGdycElkAzg3NDQ3MDQEZ3Jwc3BJZAMxNzA1MDA3MjA3BHNlYwNmdHIEc2xrA250cGMEc3RpbWUDMTIzMzE1NjA2Mg--" class="bld">
          Start a new topic        </a>
          </div> 
    <!-------     Start Nav Bar  ------>
    <!-- |**|begin egp html banner|**| -->
    <div id="ygrp-vitnav">
                <a href="http://groups.yahoo.com/group/TestFirstUserInterfaces/messages;_ylc=X3oDMTJla21xMmptBF9TAzk3MzU5NzE0BGdycElkAzg3NDQ3MDQEZ3Jwc3BJZAMxNzA1MDA3MjA3BHNlYwNmdHIEc2xrA21zZ3MEc3RpbWUDMTIzMzE1NjA2Mg--">Messages</a>  
            |    <a href="http://groups.yahoo.com/group/TestFirstUserInterfaces/files;_ylc=X3oDMTJmMXZpamRhBF9TAzk3MzU5NzE0BGdycElkAzg3NDQ3MDQEZ3Jwc3BJZAMxNzA1MDA3MjA3BHNlYwNmdHIEc2xrA2ZpbGVzBHN0aW1lAzEyMzMxNTYwNjI-">Files</a>  
            |    <a href="http://groups.yahoo.com/group/TestFirstUserInterfaces/photos;_ylc=X3oDMTJlN2dqbmF0BF9TAzk3MzU5NzE0BGdycElkAzg3NDQ3MDQEZ3Jwc3BJZAMxNzA1MDA3MjA3BHNlYwNmdHIEc2xrA3Bob3QEc3RpbWUDMTIzMzE1NjA2Mg--">Photos</a>  
            |    <a href="http://groups.yahoo.com/group/TestFirstUserInterfaces/links;_ylc=X3oDMTJmdjUycnM0BF9TAzk3MzU5NzE0BGdycElkAzg3NDQ3MDQEZ3Jwc3BJZAMxNzA1MDA3MjA3BHNlYwNmdHIEc2xrA2xpbmtzBHN0aW1lAzEyMzMxNTYwNjI-">Links</a>  
            |    <a href="http://groups.yahoo.com/group/TestFirstUserInterfaces/database;_ylc=X3oDMTJjdGNtcjF1BF9TAzk3MzU5NzE0BGdycElkAzg3NDQ3MDQEZ3Jwc3BJZAMxNzA1MDA3MjA3BHNlYwNmdHIEc2xrA2RiBHN0aW1lAzEyMzMxNTYwNjI-">Database</a>  
            |    <a href="http://groups.yahoo.com/group/TestFirstUserInterfaces/polls;_ylc=X3oDMTJmcDQzNzlhBF9TAzk3MzU5NzE0BGdycElkAzg3NDQ3MDQEZ3Jwc3BJZAMxNzA1MDA3MjA3BHNlYwNmdHIEc2xrA3BvbGxzBHN0aW1lAzEyMzMxNTYwNjI-">Polls</a>  
            |    <a href="http://groups.yahoo.com/group/TestFirstUserInterfaces/members;_ylc=X3oDMTJlZWI0NW1rBF9TAzk3MzU5NzE0BGdycElkAzg3NDQ3MDQEZ3Jwc3BJZAMxNzA1MDA3MjA3BHNlYwNmdHIEc2xrA21icnMEc3RpbWUDMTIzMzE1NjA2Mg--">Members</a>  
            |    <a href="http://groups.yahoo.com/group/TestFirstUserInterfaces/calendar;_ylc=X3oDMTJkdXN0bWoxBF9TAzk3MzU5NzE0BGdycElkAzg3NDQ3MDQEZ3Jwc3BJZAMxNzA1MDA3MjA3BHNlYwNmdHIEc2xrA2NhbARzdGltZQMxMjMzMTU2MDYy">Calendar</a>  
    </div>  
    <!-- |**|end egp html banner|**| -->

                        <div id="ygrp-grft">
          

        </div>
      
                  <div id="ygrp-mkp">
      <div id="hd">MARKETPLACE</div>
      <div id="ads">
                  <div class="ad">
            <hr noshade="noshade" size="1"><a href="http://us.ard.yahoo.com/SIG=13rh8968d/M=493064.12016295.13271503.10835568/D=groups/S=1705007207:MKP1/Y=YAHOO/EXP=1233163263/L=/B=V7plJUPDhEQ-/J=1233156063053234/A=5530388/R=0/SIG=11nuutlas/*http://explore.yahoo.com/groups/kraftmealsmadesimple/">From kitchen basics to easy recipes - join the Group from Kraft Foods
</a>          </div>
                              </div>
    </div>
      
    <!-- yahoo logo -->
    <!-- |**|begin egp html banner|**| -->
    <div id="ygrp-ft">
      <a href="http://groups.yahoo.com/;_ylc=X3oDMTJkczVtZDhnBF9TAzk3MzU5NzE0BGdycElkAzg3NDQ3MDQEZ3Jwc3BJZAMxNzA1MDA3MjA3BHNlYwNmdHIEc2xrA2dmcARzdGltZQMxMjMzMTU2MDYy">
      <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=X3oDMTJmbG5kamlrBF9TAzk3MzU5NzE0BGdycElkAzg3NDQ3MDQEZ3Jwc3BJZAMxNzA1MDA3MjA3BHNlYwNmdHIEc2xrA3N0bmdzBHN0aW1lAzEyMzMxNTYwNjI-">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=X3oDMTJkMjhwdXA4BF9TAzk3MzU5NzE0BGdycElkAzg3NDQ3MDQEZ3Jwc3BJZAMxNzA1MDA3MjA3BHNlYwNmdHIEc2xrA2hwZgRzdGltZQMxMjMzMTU2MDYy">
        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">
	      		<div id="vithd">Recent Activity</div>
		<ul style="list-style-type:none; padding: 0; margin: 2px 0;">
		    
		    
		    
		    
		    
		    
		</ul>
	      	      <a href="http://groups.yahoo.com/group/TestFirstUserInterfaces;_ylc=X3oDMTJlcjU5OWJvBF9TAzk3MzU5NzE0BGdycElkAzg3NDQ3MDQEZ3Jwc3BJZAMxNzA1MDA3MjA3BHNlYwN2dGwEc2xrA3ZnaHAEc3RpbWUDMTIzMzE1NjA2Mg--">
		Visit Your Group	      </a>
	    </div> 
	    	    	      
	    <!-- Network content -->
	    	          <div id="nc">
              <div class="ad">
                      <div id="hd1">Yahoo! Finance</div> 
<p><a href="http://us.ard.yahoo.com/SIG=13oq32ab0/M=493064.12016257.12445664.8674578/D=groups/S=1705007207:NC/Y=YAHOO/EXP=1233163263/L=/B=WrplJUPDhEQ-/J=1233156063053234/A=4507179/R=0/SIG=12de4rskk/*http://us.rd.yahoo.com/evt=50284/*http://finance.yahoo.com/personal-finance">It's Now Personal</a></p> 
<p>Guides, news,</p> 
<p>advice & more.</p>                   </div>
                    <div class="ad">
                      <div id="hd1">New web site?</div> 
<p><a href="http://us.ard.yahoo.com/SIG=13oil49ru/M=493064.12016308.12445700.8674578/D=groups/S=1705007207:NC/Y=YAHOO/EXP=1233163263/L=/B=W7plJUPDhEQ-/J=1233156063053234/A=3848642/R=0/SIG=131eshi2t/*http://searchmarketing.yahoo.com/arp/srchv2.php?o=US2004&cmp=Yahoo&ctv=Groups3&s=Y&s2=&s3=&b=50">Drive traffic now.</a></p> 
<p>Get your business</p> 
<p>on Yahoo! search.</p>                  </div>
                    <div class="ad">
                      <div id="hd1">Everyday Wellness</div> 
<p><a href="http://us.ard.yahoo.com/SIG=13oor14n8/M=493064.12662708.12980600.8674578/D=groups/S=1705007207:NC/Y=YAHOO/EXP=1233163263/L=/B=XLplJUPDhEQ-/J=1233156063053234/A=5349272/R=0/SIG=11nhsqmjq/*http://advision.webevents.yahoo.com/EverydayWellness/">on Yahoo! Groups</a></p> 
<p>Find groups that will</p> 
<p>help you stay fit.</p>                  </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=1027/stime=1233156062/nc1=4507179/nc2=3848642/nc3=5349272" width="1" height="1"> <br>
	
	<span  style="color: white;">__,_._,___</span>
	<!--~-|**|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;
	}
	#ygrp-tpmsgs{
	    font-family: Arial;	
	    clear: both;
	}
	#ygrp-vitnav{
		padding-top: 10px;
		font-family: Verdana;
		font-size: 77%;
		margin: 0;
	}
	#ygrp-vitnav a{
		padding: 0 1px;
	}
	#ygrp-actbar{
		clear: both;
		margin: 25px 0;
		white-space:nowrap;
		color: #666;
		text-align: right;
	}
	#ygrp-actbar .left{
		float: left;
		white-space:nowrap;
	}
	.bld{font-weight:bold;}
	#ygrp-grft{
		font-family: Verdana;
		font-size: 77%;
		padding: 15px 0;
	}
	#ygrp-ft{
	  font-family: verdana;
	  font-size: 77%;
	  border-top: 1px solid #666; 
	  padding: 5px 0; 
	}
	#ygrp-mlmsg #logo{
	  padding-bottom: 10px;
	}

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

	#reco-grpname{
        font-weight: bold;
        margin-top: 10px;
  	}
	#reco-category{
        	font-size: 77%;
	}
	#reco-desc{
        	font-size: 77%;
	}

	#ygrp-vital{
		background-color: #e0ecee;
		margin-bottom: 20px;
		padding: 2px 0 8px 8px;
	}
	#ygrp-vital #vithd{
		font-size: 77%;
		font-family: Verdana;
		font-weight: bold;
		color: #333;
		text-transform: uppercase;
	}
	#ygrp-vital ul{
		padding: 0;
		margin: 2px 0;
	}
	#ygrp-vital ul li{
	  list-style-type: none;
	  clear: both;
	  border: 1px solid #e0ecee;  
	}
	#ygrp-vital ul li .ct{
	  font-weight: bold;
	  color: #ff7900;
	  float: right;
	  width: 2em;
	  text-align:right;
	  padding-right: .5em;
	}
	#ygrp-vital ul li .cat{
	  font-weight: bold;
	}
	#ygrp-vital a{
		text-decoration: none;
	}

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

	#ygrp-sponsor #hd{
		color: #999;
		font-size: 77%;
	}
	#ygrp-sponsor #ov{
		padding: 6px 13px;
		background-color: #e0ecee;
		margin-bottom: 20px;
	}
	#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}
	-->
	</style>
	</head>
	<!--~-|**|PrettyHtmlEnd|**|-~-->
	</html><!--End group email -->


--2i49sSTze4qnFjaoCjM-cMl-Af6t-vXRuozWw5G--