[TFUI] Re: [TIP] running away from RSpec

Phlip <[email protected]> Sat, 12 Feb 2011 14:26:52 -0800
Newsgroups gmane.comp.programming.test-first-user-interfaces,gmane.comp.python.testing.general
Message-ID <[email protected]>
--2Pv7MOx5JunN8j2-zSR4AlJF4uCDRVorvwHJqQz
Content-Type: text/plain; charset=ISO-8859-1
Content-Transfer-Encoding: quoted-printable

Alfredo Deza wrote:

> For the past few weeks I have been thinking a lot about RSpec and why the=
re
> is no clear, definite answer when someone asks:

Because, frankly, it sucks. See below...

> =A0"I'm looking for a Python equivalent of RSpec. Where can I find such a
> thing?"

We tried RSpec at Integralnet, for several months, and it's a ton of
syntactic sugar around one tiny granule of salt.

In pseudo-code:

  setUp
      x =3D 42

      specs using x

      setUp
         y =3D 43

         specs using x and y

That's all there is to it - "subcontexts". The incredibly trivial feat
of nesting two setUp definitions so a test can use fixtures from both.

The rest is nothing but everted assertion syntax, and 'clever strings'
in place of stodgy_method_names. Oh, and every fixture and reusable
assertion you write for TestCase, you gotta write it again for RSpec,
because it uses a completely different framework.

You /could/ do all that in Python, even without too much self. clutter. But=
...

RSpec is incredibly over-represented in the Ruby space for a simple
reason - it presents the empty promise of Behavior Driven Development.

The _point_ of BDD is your civilian clients (your Onsite Customer) can
author test scenarios without worrying about _any_ programming syntax:

Scenario: Run one multiplechoice question through the system.

    Given a multiplechoice question FM_Color asking
             "What is your favorite color of fuzzy motorcycle?"

      And its answers are Teal, Puce, and Cyan
      And Puce is correct
      And user D42 answers Teal to question FM_Color
      And user D43 answers Puce to question FM_Color
      And user D44 answers Cyan to question FM_Color
      And user D45 answers Teal to question FM_Color

     When a manager requests a report on FM_Color
     Then the report contains Teal 2, Puce 1, and Cyan 1

      And the report's title is
              "What is your favorite color of fuzzy motorcycle?"

      And the Puce answer is correct

After I give a non-technical client a BDD scenario like that, they
will typically clone-and-modify it, or write their own, without any
prompting. You get the perfect intersection of business requirements
and technical specifications.

Those strings match regular expressions, so they can transparently
accommodate grammar (?:is|are), and can validate that 2, for example,
is a number and not characters.

In my Morelia system, the regular expressions are __doc__ strings on
step_() methods, embedded in NORMAL TestUnit test suites.

In other words, I did not invent a whole new unit test layer, just to
be able to put literate behavior scenarios on top. Here's some steps:

    def step_a_question_asking_(self, question_type, question_name, questio=
n):
        r'a (multiplechoice|rating) question (\w+) asking "([^"]+)"'

        self.question_type =3D question_type
        self.question_name =3D question_name
        self.question =3D question
        self.params =3D []

    def step_its_answers_are_(self, answers):
        r'its answers (?:is|are) (.*)'

        self.answers =3D split_and(answers)
        self.save_question()

(Note that I'd like to merge split_and(), not shown, and (.*), to
achieve better validation, if my regexp chops were up to it!)

> Ok, if that is so, then why there are so many projects (most of them alre=
ady
> un-maintained) that try to give
> some RSpec features to Python?

Because (ahem) Python under-represents TDD and BDD, so there's no clear lea=
der.

Also because many of those projects are ... "ambitious" (meaning
"cluttered"), and they would require the kind of community support
that Watir, Cucumber, and RSpec take for granted. The program author
can't do it all alone - only customers can drive Agile projects!

Here's my sauce:

http://c2.com/cgi/wiki?MoreliaViridis

It _appears_ unmaintained for a simple reason - since writing it 13
months ago, I have never stopped using it, and I have never needed to
add a feature to it. (If anyone has any suggestions, I have time
available these days to add some!)

> Isn't that how we came about UnitTesting? (e.g. "hey that's JUnit and see=
ms
> good let's implement that in Python")

That was >10 years ago. >sigh<

--=20
=A0 Phlip
=A0 http://c2.com/cgi/wiki?ZeekLand

--2Pv7MOx5JunN8j2-zSR4AlJF4uCDRVorvwHJqQz
Content-Type: text/html; charset=ISO-8859-1
Content-Transfer-Encoding: quoted-printable




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







<body style=3D"background-color: #fff;">
<span style=3D"display:none">&nbsp;</span>

<!--~-|**|PrettyHtmlStartT|**|-~-->
<div id=3D"ygrp-mlmsg" style=3D"position:relative;">
  <div id=3D"ygrp-msg" style=3D"z-index: 1;">
<!--~-|**|PrettyHtmlEndT|**|-~-->

    <div id=3D"ygrp-text" >
=20=20=20=20=20=20
=20=20=20=20=20=20
      <p>Alfredo Deza wrote:<br>
<br>
&gt; For the past few weeks I have been thinking a lot about RSpec and why =
there<br>
&gt; is no clear, definite answer when someone asks:<br>
<br>
Because, frankly, it sucks. See below...<br>
<br>
&gt; =A0&quot;I'm looking for a Python equivalent of RSpec. Where can I fin=
d such a<br>
&gt; thing?&quot;<br>
<br>
We tried RSpec at Integralnet, for several months, and it's a ton of<br>
syntactic sugar around one tiny granule of salt.<br>
<br>
In pseudo-code:<br>
<br>
setUp<br>
      x =3D 42<br>
<br>
specs using x<br>
<br>
setUp<br>
         y =3D 43<br>
<br>
specs using x and y<br>
<br>
That's all there is to it - &quot;subcontexts&quot;. The incredibly trivial=
 feat<br>
of nesting two setUp definitions so a test can use fixtures from both.<br>
<br>
The rest is nothing but everted assertion syntax, and 'clever strings'<br>
in place of stodgy_method_names. Oh, and every fixture and reusable<br>
assertion you write for TestCase, you gotta write it again for RSpec,<br>
because it uses a completely different framework.<br>
<br>
You /could/ do all that in Python, even without too much self. clutter. But=
...<br>
<br>
RSpec is incredibly over-represented in the Ruby space for a simple<br>
reason - it presents the empty promise of Behavior Driven Development.<br>
<br>
The _point_ of BDD is your civilian clients (your Onsite Customer) can<br>
author test scenarios without worrying about _any_ programming syntax:<br>
<br>
Scenario: Run one multiplechoice question through the system.<br>
<br>
Given a multiplechoice question FM_Color asking<br>
             &quot;What is your favorite color of fuzzy motorcycle?&quot;<b=
r>
<br>
And its answers are Teal, Puce, and Cyan<br>
      And Puce is correct<br>
      And user D42 answers Teal to question FM_Color<br>
      And user D43 answers Puce to question FM_Color<br>
      And user D44 answers Cyan to question FM_Color<br>
      And user D45 answers Teal to question FM_Color<br>
<br>
When a manager requests a report on FM_Color<br>
     Then the report contains Teal 2, Puce 1, and Cyan 1<br>
<br>
And the report's title is<br>
              &quot;What is your favorite color of fuzzy motorcycle?&quot;<=
br>
<br>
And the Puce answer is correct<br>
<br>
After I give a non-technical client a BDD scenario like that, they<br>
will typically clone-and-modify it, or write their own, without any<br>
prompting. You get the perfect intersection of business requirements<br>
and technical specifications.<br>
<br>
Those strings match regular expressions, so they can transparently<br>
accommodate grammar (?:is|are), and can validate that 2, for example,<br>
is a number and not characters.<br>
<br>
In my Morelia system, the regular expressions are __doc__ strings on<br>
step_() methods, embedded in NORMAL TestUnit test suites.<br>
<br>
In other words, I did not invent a whole new unit test layer, just to<br>
be able to put literate behavior scenarios on top. Here's some steps:<br>
<br>
def step_a_question_asking_(self, question_type, question_name, question):<=
br>
        r'a (multiplechoice|rating) question (\w+) asking &quot;([^&quot;]+=
)&quot;'<br>
<br>
self.question_type =3D question_type<br>
        self.question_name =3D question_name<br>
        self.question =3D question<br>
        self.params =3D []<br>
<br>
def step_its_answers_are_(self, answers):<br>
        r'its answers (?:is|are) (.*)'<br>
<br>
self.answers =3D split_and(answers)<br>
        self.save_question()<br>
<br>
(Note that I'd like to merge split_and(), not shown, and (.*), to<br>
achieve better validation, if my regexp chops were up to it!)<br>
<br>
&gt; Ok, if that is so, then why there are so many projects (most of them a=
lready<br>
&gt; un-maintained) that try to give<br>
&gt; some RSpec features to Python?<br>
<br>
Because (ahem) Python under-represents TDD and BDD, so there's no clear lea=
der.<br>
<br>
Also because many of those projects are ... &quot;ambitious&quot; (meaning<=
br>
&quot;cluttered&quot;), and they would require the kind of community suppor=
t<br>
that Watir, Cucumber, and RSpec take for granted. The program author<br>
can't do it all alone - only customers can drive Agile projects!<br>
<br>
Here's my sauce:<br>
<br>
<a href=3D"http://c2.com/cgi/wiki?MoreliaViridis">http://c2.com/cgi/wiki?Mo=
reliaViridis</a><br>
<br>
It _appears_ unmaintained for a simple reason - since writing it 13<br>
months ago, I have never stopped using it, and I have never needed to<br>
add a feature to it. (If anyone has any suggestions, I have time<br>
available these days to add some!)<br>
<br>
&gt; Isn't that how we came about UnitTesting? (e.g. &quot;hey that's JUnit=
 and seems<br>
&gt; good let's implement that in Python&quot;)<br>
<br>
That was &gt;10 years ago. &gt;sigh&lt;<br>
<br>
-- <br>
=A0 Phlip<br>
=A0 <a href=3D"http://c2.com/cgi/wiki?ZeekLand">http://c2.com/cgi/wiki?Zeek=
Land</a><br>
</p>

    </div>
=20=20=20=20=20

    <!--~-|**|PrettyHtmlStart|**|-~-->
    <div style=3D"color: #fff; height: 0;">__._,_.___</div>

=20=20=20=20=20=20=20=20
=20=20
=20=20=20
    <div id=3D"ygrp-actbar" style=3D"clear: both; margin-bottom: 10px; whit=
e-space: nowrap; color: #666; padding-top: 15px;">
      <div>
        <a href=3D"mailto:[email protected]?subject=3DRe%3A%20%5BTIP%5D%2=
0running%20away%20from%20RSpec" style=3D"margin-right: 0; padding-right: 0;=
">
	  Reply to <span style=3D"font-weight: 700;">sender</span></a> |
        <a href=3D"mailto:[email protected]?subject=
=3DRe%3A%20%5BTIP%5D%20running%20away%20from%20RSpec">
	  Reply to <span style=3D"font-weight: 700;">group</span></a> |
        	  <a href=3D"http://groups.yahoo.com/group/TestFirstUserInterfaces=
/post;_ylc=3DX3oDMTJwOTBxZDZnBF9TAzk3MzU5NzE0BGdycElkAzg3NDQ3MDQEZ3Jwc3BJZA=
MxNzA1MDA3MjA3BG1zZ0lkAzEwNjkEc2VjA2Z0cgRzbGsDcnBseQRzdGltZQMxMjk3NTQ5NjIx?=
act=3Dreply&messageNum=3D1069">Reply <span style=3D"font-weight: 700;">via =
web post</span></a> |
            	<a href=3D"http://groups.yahoo.com/group/TestFirstUserInterfac=
es/post;_ylc=3DX3oDMTJlcHFnczBtBF9TAzk3MzU5NzE0BGdycElkAzg3NDQ3MDQEZ3Jwc3BJ=
ZAMxNzA1MDA3MjA3BHNlYwNmdHIEc2xrA250cGMEc3RpbWUDMTI5NzU0OTYyMQ--" style=3D"=
font-weight: 700;">Start a New Topic</a>
      </div>

                <a href=3D"http://groups.yahoo.com/group/TestFirstUserInter=
faces/message/1069;_ylc=3DX3oDMTM0OXYxMHNsBF9TAzk3MzU5NzE0BGdycElkAzg3NDQ3M=
DQEZ3Jwc3BJZAMxNzA1MDA3MjA3BG1zZ0lkAzEwNjkEc2VjA2Z0cgRzbGsDdnRwYwRzdGltZQMx=
Mjk3NTQ5NjIxBHRwY0lkAzEwNjk-">Messages in this topic</a>
          (<span style=3D"font-weight: 700;">1</span>)
          </div>=20
<!------- Start Nav Bar ------>

<!-- |**|begin egp html banner|**| -->
<div id=3D"ygrp-vital" style=3D"background-color: #e0ecee; font-family: Ver=
dana; font-size: 10px; margin-bottom: 10px; padding: 10px;">
      <span id=3D"vithd" style=3D"font-weight: bold; color: #333; text-tran=
sform: uppercase; ">Recent Activity:</span>

    <ul style=3D"list-style-type: none; margin: 0; padding: 0; display: inl=
ine;">
                                                    </ul>
=20=20=20=20
  <div style=3D"clear: both; padding-top: 2px; color: #1e66ae;">
    <a href=3D"http://groups.yahoo.com/group/TestFirstUserInterfaces;_ylc=
=3DX3oDMTJlY2ZxMm9mBF9TAzk3MzU5NzE0BGdycElkAzg3NDQ3MDQEZ3Jwc3BJZAMxNzA1MDA3=
MjA3BHNlYwN2dGwEc2xrA3ZnaHAEc3RpbWUDMTI5NzU0OTYyMQ--" style=3D"text-decorat=
ion: none;">Visit Your Group</a>
  </div>
</div>

        <div id=3D"ygrp-grft" style=3D"font-family: Verdana; font-size: 12p=
x; padding: 15px 0;">
=20=20=20=20=20=20
<!-- |**|begin egp html banner|**| -->

      To unsubscribe, email:<BR>
TestFirstUserInterfaces-unsubscribe-hHKSG33TihhbjbujkaE4pw@public.gmane.org<BR>
=20=20=20=20=20=20
<!-- |**|end egp html banner|**| -->

    </div>
            <div id=3D"ygrp-mkp" style=3D"border: 1px solid #d8d8d8; clear:=
 both; float: left; font-family: Arial; margin: 5px 0 10px 0; padding: 0 10=
px;">
      <div id=3D"hd" style=3D"color: #628c2a; font-size: 85%; font-weight: =
700; line-height: 122%; margin: 10px 0;">MARKETPLACE</div>
      <div id=3D"ads" style=3D"margin-bottom: 10px;">
                          <div class=3D"ad" style=3D"color: #628C2A; font-f=
amily: Arial; font-weight: 700; padding: 0 0;">
                        <p><a href=3D"http://global.ard.yahoo.com/SIG=3D15o=
itadmc/M=3D493064.14543977.14365476.10835568/D=3Dgroups/S=3D1705007207:MKP1=
/Y=3DYAHOO/EXP=3D1297556822/L=3D36caa5d0-36f7-11e0-aed9-2f438664c7e7/B=3DU9=
sbB0wNPRg-/J=3D1297549622528558/K=3DcHyTAZcV5lxDRop0ZIMfMw/A=3D6078812/R=3D=
0/SIG=3D114ae4ln1/*http://dogandcatanswers.yahoo.com/">Get great advice abo=
ut dogs and cats.  Visit the Dog & Cat Answers Center.</a></p><script langu=
age=3Djavascript>
if(window.yzq_d=3D=3Dnull)window.yzq_d=3Dnew Object();
window.yzq_d['U9sbB0wNPRg-']=3D'&U=3D13c8v1o32%2fN%3dU9sbB0wNPRg-%2fC%3d493=
064.14543977.14365476.10835568%2fD%3dMKP1%2fB%3d6078812%2fV%3d1';
</script><noscript><img width=3D1 height=3D1 alt=3D"" src=3D"http://us.bc.y=
ahoo.com/b?P=3D36caa5d0-36f7-11e0-aed9-2f438664c7e7&T=3D1dgn5k0ig%2fX%3d129=
7549622%2fE%3d1705007207%2fR%3dgroups%2fK%3d5%2fV%3d2.1%2fW%3dH%2fY%3dYAHOO=
%2fF%3d655151492%2fH%3dY29udGVudD0iWWFob29fVGVjaDtHbztXaWRnZXRzO1dlYnNpdGVf=
U2VydmljZXM7UG9kY2FzdHM7RmxpY2tyO1lhaG9vX1NlYXJjaF9NYXJrZXRpbmc7RmluYW5jZTt=
CcmllZmNhc2U7Q2FsZW5kYXI7IiBkaXNhYmxlc2h1ZmZsaW5nPSIxIiBzZXJ2ZUlkPSIzNmNhYT=
VkMC0zNmY3LTExZTAtYWVkOS0yZjQzODY2NGM3ZTciIHNpdGVJZD0iNDQ1MjU1MSIgdFN0bXA9I=
jEyOTc1NDk2MjI1MTg5NDAiIA--%2fQ%3d-1%2fS%3d1%2fJ%3d3B5EC442&U=3D13c8v1o32%2=
fN%3dU9sbB0wNPRg-%2fC%3d493064.14543977.14365476.10835568%2fD%3dMKP1%2fB%3d=
6078812%2fV%3d1"></noscript>          </div>
                          <div class=3D"ad" style=3D"color: #628C2A; font-f=
amily: Arial; font-weight: 700; padding: 0 0;">
                          <hr style=3D"border: 1px solid #d8d8d8;">
                        <p><a href=3D"http://global.ard.yahoo.com/SIG=3D15o=
iufe0p/M=3D493064.14543979.14365478.13298430/D=3Dgroups/S=3D1705007207:MKP1=
/Y=3DYAHOO/EXP=3D1297556822/L=3D36caa5d0-36f7-11e0-aed9-2f438664c7e7/B=3DUt=
sbB0wNPRg-/J=3D1297549622528558/K=3DcHyTAZcV5lxDRop0ZIMfMw/A=3D6060255/R=3D=
0/SIG=3D1194m4keh/*http://us.toolbar.yahoo.com/?.cpdl=3Dgrpj">Stay on top o=
f your group activity without leaving the page you're on - Get the Yahoo! T=
oolbar now.</a></p> <script language=3Djavascript>
if(window.yzq_d=3D=3Dnull)window.yzq_d=3Dnew Object();
window.yzq_d['UtsbB0wNPRg-']=3D'&U=3D13cd88mvn%2fN%3dUtsbB0wNPRg-%2fC%3d493=
064.14543979.14365478.13298430%2fD%3dMKP1%2fB%3d6060255%2fV%3d1';
</script><noscript><img width=3D1 height=3D1 alt=3D"" src=3D"http://us.bc.y=
ahoo.com/b?P=3D36caa5d0-36f7-11e0-aed9-2f438664c7e7&T=3D1dhmkqvjo%2fX%3d129=
7549622%2fE%3d1705007207%2fR%3dgroups%2fK%3d5%2fV%3d2.1%2fW%3dH%2fY%3dYAHOO=
%2fF%3d2148223220%2fH%3dY29udGVudD0iWWFob29fVGVjaDtHbztXaWRnZXRzO1dlYnNpdGV=
fU2VydmljZXM7UG9kY2FzdHM7RmxpY2tyO1lhaG9vX1NlYXJjaF9NYXJrZXRpbmc7RmluYW5jZT=
tCcmllZmNhc2U7Q2FsZW5kYXI7IiBkaXNhYmxlc2h1ZmZsaW5nPSIxIiBzZXJ2ZUlkPSIzNmNhY=
TVkMC0zNmY3LTExZTAtYWVkOS0yZjQzODY2NGM3ZTciIHNpdGVJZD0iNDQ1MjU1MSIgdFN0bXA9=
IjEyOTc1NDk2MjI1MTg5NDAiIA--%2fQ%3d-1%2fS%3d1%2fJ%3d3B5EC442&U=3D13cd88mvn%=
2fN%3dUtsbB0wNPRg-%2fC%3d493064.14543979.14365478.13298430%2fD%3dMKP1%2fB%3=
d6060255%2fV%3d1"></noscript>          </div>
              </div>
    </div>
=20=20
<div id=3D"ft" style=3D"font-family: Arial; font-size: 11px; margin-top: 5p=
x; padding: 0 2px 0 0; clear: both;">
  <a href=3D"http://groups.yahoo.com/;_ylc=3DX3oDMTJkZ25xODZrBF9TAzk3MzU5Nz=
E0BGdycElkAzg3NDQ3MDQEZ3Jwc3BJZAMxNzA1MDA3MjA3BHNlYwNmdHIEc2xrA2dmcARzdGltZ=
QMxMjk3NTQ5NjIx" style=3D"float: left;"><img src=3D"http://l.yimg.com/a/i/u=
s/yg/logo/us.gif" height=3D"15" width=3D"137" alt=3D"Yahoo! Groups" style=
=3D"border: 0;"/></a>
  <div style=3D"color: #747575; float: right;">Switch to: <a href=3D"mailto=
:TestFirstUserInterfaces-traditional-hHKSG33TihhbjbujkaE4pw@public.gmane.org?subject=3DChange Deliv=
ery Format: Traditional" style=3D"text-decoration: none;">Text-Only</a>, <a=
 href=3D"mailto:TestFirstUserInterfaces-digest-hHKSG33TihhbjbujkaE4pw@public.gmane.org?subject=3DEm=
ail Delivery: Digest" class=3D"margin-rt" style=3D"text-decoration: none;">=
Daily Digest</a> &bull; <a href=3D"mailto:TestFirstUserInterfaces-unsubscri=
[email protected]?subject=3DUnsubscribe" style=3D"text-decoration: none;">=
Unsubscribe</a> &bull; <a href=3D"http://docs.yahoo.com/info/terms/" style=
=3D"text-decoration: none;">Terms of Use</a></div>
</div>

<!-- |**|end egp html banner|**| -->

  </div> <!-- ygrp-msg -->

  <!-- Sponsor -->
  <!-- |**|begin egp html banner|**| -->
  <div id=3D"ygrp-sponsor" style=3D"width:160px; float:right; clear:none; m=
argin:0 0 25px 0; background: #fff;">

<!-- Start Recommendations -->
<div id=3D"ygrp-reco">
     </div>
<!-- End Recommendations -->



  </div>   <!-- |**|end egp html banner|**| -->

  <div style=3D"clear:both; color: #FFF; font-size:1px;">.</div>
</div>

  <img src=3D"http://geo.yahoo.com/serv?s=3D97359714/grpId=3D8744704/grpspI=
d=3D1705007207/msgId=3D1069/stime=3D1297549621/nc1=3D3848642/nc2=3D5898817/=
nc3=3D4507179" width=3D"1" height=3D"1"> <br>

<div style=3D"color: #fff; height: 0;">__,_._,___</div>
<!--~-|**|PrettyHtmlEnd|**|-~-->

</body>

<!--~-|**|PrettyHtmlStart|**|-~-->
<head>
  <style type=3D"text/css">
  <!--
  #ygrp-mkp {
  border: 1px solid #d8d8d8;
  font-family: Arial;
  margin: 10px 0;
  padding: 0 10px;
}

#ygrp-mkp hr {
  border: 1px solid #d8d8d8;
}

#ygrp-mkp #hd {
  color: #628c2a;
  font-size: 85%;
  font-weight: 700;
  line-height: 122%;
  margin: 10px 0;
}

#ygrp-mkp #ads {
  margin-bottom: 10px;
}

#ygrp-mkp .ad {
  padding: 0 0;
}

#ygrp-mkp .ad p {
  margin: 0;
}

#ygrp-mkp .ad a {
  color: #0000ff;
  text-decoration: none;
}
  #ygrp-sponsor #ygrp-lc {
  font-family: Arial;
}

#ygrp-sponsor #ygrp-lc #hd {
  margin: 10px 0px;
  font-weight: 700;
  font-size: 78%;
  line-height: 122%;
}

#ygrp-sponsor #ygrp-lc .ad {
  margin-bottom: 10px;
  padding: 0 0;
}

  a {
    color: #1e66ae;
  }

  #actions {
    font-family: Verdana;
    font-size: 11px;
    padding: 10px 0;
  }

  #activity {
    background-color: #e0ecee;
    float: left;
    font-family: Verdana;
    font-size: 10px;
    padding: 10px;
  }

  #activity span {
    font-weight: 700;
  }

  #activity span:first-child {
    text-transform: uppercase;
  }

  #activity span a {
    color: #5085b6;
    text-decoration: none;
  }

  #activity span span {
    color: #ff7900;
  }

  #activity span .underline {
    text-decoration: underline;
  }

  .attach {
    clear: both;
    display: table;
    font-family: Arial;
    font-size: 12px;
    padding: 10px 0;
    width: 400px;
  }

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

  .attach img {
    border: none;
    padding-right: 5px;
  }

  .attach label {
    display: block;
    margin-bottom: 5px;
  }

  .attach label a {
    text-decoration: none;
  }
=20=20
  blockquote {
    margin: 0 0 0 4px;
  }

  .bold {
    font-family: Arial;
    font-size: 13px;
    font-weight: 700;
  }

  .bold a {
    text-decoration: none;
  }

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

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

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

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

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

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

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

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

  .green {
    color: #628c2a;
  }

  .MsoNormal {
    margin: 0 0 0 0;
  }

  o {
    font-size: 0;
  }

  #photos div {
    float: left;
    width: 72px;
  }

  #photos div div {
    border: 1px solid #666666;
    height: 62px;
    overflow: hidden;
    width: 62px;
  }

  #photos div label {
    color: #666666;
    font-size: 10px;
    overflow: hidden;
    text-align: center;
    white-space: nowrap;
    width: 64px;
  }

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

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

  .replbq {
    margin: 4px;
  }

  #ygrp-actbar div a:first-child {
   /* border-right: 0px solid #000;*/
    margin-right: 2px;
    padding-right: 5px;
  }

  #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-mlmsg #logo {
    padding-bottom: 10px;
  }

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

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

  #ygrp-msg p#attach-count span {
    color: #1E66AE;
    font-weight: 700;
  }

  #ygrp-reco #reco-head {
    color: #ff7900;
    font-weight: 700;
  }

  #ygrp-reco {
    margin-bottom: 20px;
    padding: 0px;
  }

  #ygrp-sponsor #ov li a {
    font-size: 130%;
    text-decoration: none;
  }

  #ygrp-sponsor #ov li {
    font-size: 77%;
    list-style-type: square;
    padding: 6px 0;
  }=20

  #ygrp-sponsor #ov ul {
    margin: 0;
    padding: 0 0 0 8px;
  }

  #ygrp-text {
    font-family: Georgia;
  }

  #ygrp-text p {
    margin: 0 0 1em 0;
  }

  #ygrp-text tt {
    font-size: 120%;
  }

  #ygrp-vital ul li:last-child {
    border-right: none !important;=20
  }=20
  -->
  </style>
</head>

<!--~-|**|PrettyHtmlEnd|**|-~-->
</html>
<!-- end group email -->


--2Pv7MOx5JunN8j2-zSR4AlJF4uCDRVorvwHJqQz--