-
Notifications
You must be signed in to change notification settings - Fork 11
/
Copy pathexcecoes.html
252 lines (239 loc) · 23.3 KB
/
excecoes.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en-us">
<head>
<meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>Exceções</title>
<meta name="author" content="" />
<!--- Blueprint CSS Framework -->
<link rel="stylesheet" href="css/blueprint/screen.css" type="text/css" media="screen, projection">
<link rel="stylesheet" href="css/blueprint/print.css" type="text/css" media="print">
<!--[if IE]>
<link rel="stylesheet" href="css/blueprint/ie.css" type="text/css" media="screen, projection">
<![endif]-->
<!-- CodeRay syntax highlighting CSS -->
<link rel="stylesheet" href="css/coderay.css" type="text/css" />
<!-- Homepage CSS -->
<link rel="stylesheet" href="css/site.css" type="text/css" media="screen, projection" />
</head>
<body>
<div class="container">
<div class="column span-22 prepend-1 append-1 first last" id="header">
<h1 class="title"><a href="index.html" alt="voltar para o início">Tutorial de Ruby do GURU-SP</a></h1>
<hr>
</div>
<div class="column span-17 prepend-1 first">
<p class="title">Exceções</p>
<h2>Lançando uma Exceção</h2>
<p>Uma exceção é um tipo especial de objeto, uma instância da classe <b>Exception</b> ou uma descendente dessa classe que representa um tipo de condição incomum; ela indica que algo de errado aconteceu. Quando isso ocorre, uma exceção é levantada (ou lançada). Por padrão, os programas Ruby terminam quando uma exceção ocorre. Mas é possível declarar tratadores de exceção. Um tratador (handler) de exceção é um bloco de código que é executado se uma exceção ocorre durante a execução de algum outro bloco de código. Levantar uma exceção significa parar a execução normal do programa e transferir o fluxo de controle para o código tratador da exceção onde você pode ou lidar com o problema que foi encontrado ou sair completamente do programa. O que irá acontecer – lidar com o problema ou abortar o programa – depende do que você forneceu um comando de resgate (<b>rescue</b>, que é uma parte fundamental da linguagem Ruby). Se você não forneceu este comando, o programa termina; se você forneceu, o fluxo de controle é passado ao comando <b>rescue</b>.</p>
<p>O Ruby tem algumas classes pré-definidas – Exceptions e suas filhas – que lhe ajudam a lidar com erros que ocorrem em seu programa. A figura a seguir mostra a hierarquia das exceções em Ruby.</p>
<p><img src="images/exception.jpg" title="Hierarquia das exceções no Ruby" alt="Hierarquia das exceções no Ruby" /></p>
<p>Referência: A figura acima é do livro <em>Programming Ruby</em>.</p>
<p>O gráfico acima mostra que a maioria das subclasses estendem uma classe conhecida como StandardError (erro padrão). Estas são as exceções “normais” que os programas Ruby tipicamente tentam tratar. As outras exceções representam condições de mais baixo nível, mais sérias ou com condições menos recuperáveis, e programas normais Ruby normalmente não tentam tratá-las.</p>
<p>O seguinte método lança uma exceção sempre que é chamado. Sua segunda mensagem nunca será impressa. Programa <b>p043raise.rb</b>.</p>
<div class="CodeRay">
<pre><span class="no">1</span> <span class="c"># p043raise.rb</span>
<span class="no">2</span> <span class="r">def</span> <span class="fu">levanta_excecao</span>
<span class="no">3</span> puts <span class="s"><span class="dl">'</span><span class="k">Estou antes do raise.</span><span class="dl">'</span></span>
<span class="no">4</span> raise <span class="s"><span class="dl">'</span><span class="k">Um erro ocorreu</span><span class="dl">'</span></span>
<span class="no">5</span> puts <span class="s"><span class="dl">'</span><span class="k">Estou depois do raise</span><span class="dl">'</span></span>
<span class="no">6</span> <span class="r">end</span>
<span class="no">7</span> levanta_excecao
</pre>
</div>
<p>A saída é:</p>
<div class="CodeRay">
<pre><span class="no">1</span> >ruby p043raise.rb
<span class="no">2</span> Estou antes do raise.
<span class="no">3</span> p043raise.rb:4:in `levanta_excecao': Um erro ocorreu (RuntimeError)
<span class="no">4</span> from p043raise.rb:7
<span class="no">5</span> >Exit code: 1
</pre>
</div>
<p>O método <b>raise</b> é do módulo Kernel. Por padrão, <b>raise</b> cria uma exceção da classe <b>RuntimeError</b>. Para levantar a exceção de uma classe específica, você pode passar o nome da classe como argumento para <b>raise</b>. Refira-se ao programa <b>p044inverse.rb</b></p>
<div class="CodeRay">
<pre><span class="no">1</span> <span class="c"># p044inverse.rb</span>
<span class="no">2</span> <span class="r">def</span> <span class="fu">inverte</span>(x)
<span class="no">3</span> raise <span class="co">ArgumentError</span>, <span class="s"><span class="dl">'</span><span class="k">O argumento não é numérico</span><span class="dl">'</span></span> <span class="r">unless</span> x.is_a? <span class="co">Numeric</span>
<span class="no">4</span> <span class="fl">1.0</span> / x
<span class="no">5</span> <span class="r">end</span>
<span class="no">6</span> puts inverte(<span class="i">2</span>)
<span class="no">7</span> puts inverte(<span class="s"><span class="dl">'</span><span class="k">não é um número</span><span class="dl">'</span></span>)
</pre>
</div>
<p>A saída é:</p>
<div class="CodeRay">
<pre><span class="no">1</span> >ruby p044inverse.rb
<span class="no">2</span> 0.5
<span class="no">3</span> p044inverse.rb:3:in `inverte': O argumento não é numérico (ArgumentError)
<span class="no">4</span> from p044inverse.rb:7
<span class="no">5</span> >Exit code: 1
</pre>
</div>
<p>Lembre-se, métodos que agem como perguntas são geralmente nomeados com um sinal de interrogação no final. <b>is_a?</b> é um método na classe Objeto e retorna verdadeiro ou falso. O modificador <b>unless</b> quando colocado no final de uma expressão significa executa a expressão antecedente ao menos que a condição seja verdadeira (ou seja, somente se ele não for verdadeira).</p>
<p>Definindo novas classes de exceção: Para ser ainda mais específicio sobre um erro, você pode definir sua própria subclasse de exceção:</p>
<div class="CodeRay">
<pre><span class="no">1</span> <span class="r">class</span> <span class="cl">NotInvertibleError</span> < <span class="co">StandardError</span>
<span class="no">2</span> <span class="r">end</span>
</pre>
</div>
<h2>Tratando uma Exceção</h2>
<p>Para fazer o tratamento da exceção, nós colocamos o código que pode lançar uma exceção dentro de um bloco <b>begin-end</b> e usamos uma ou mais cláusulas <b>rescue</b> para contar ao Ruby os tipos de exceção que queremos tratar. É importante notar que o corpo de definição de um método é um bloco <b>begin-end</b> implícito; o <b>begin</b> é omitido, e todo o corpo do método está sujeito ao tratamento de exceção, terminando com o <b>end</b> do método.</p>
<p>O programa p**045handexcp.rb** ilustra isso:</p>
<div class="CodeRay">
<pre><span class="no"> 1</span> <span class="c"># p045handexcp.rb</span>
<span class="no"> 2</span> <span class="r">def</span> <span class="fu">levanta_e_resgata</span>
<span class="no"> 3</span> <span class="r">begin</span>
<span class="no"> 4</span> puts <span class="s"><span class="dl">'</span><span class="k">Estou antes do raise.</span><span class="dl">'</span></span>
<span class="no"> 5</span> raise <span class="s"><span class="dl">'</span><span class="k">Um erro ocorreu</span><span class="dl">'</span></span>
<span class="no"> 6</span> puts <span class="s"><span class="dl">'</span><span class="k">Estou depois do raise</span><span class="dl">'</span></span>
<span class="no"> 7</span> <span class="r">rescue</span>
<span class="no"> 8</span> puts <span class="s"><span class="dl">'</span><span class="k">Fui resgatado.</span><span class="dl">'</span></span>
<span class="no"> 9</span> <span class="r">end</span>
<span class="no"><strong>10</strong></span> puts <span class="s"><span class="dl">'</span><span class="k">Estou depois do bloco begin.</span><span class="dl">'</span></span>
<span class="no">11</span> <span class="r">end</span>
<span class="no">12</span> levanta_e_resgata
</pre>
</div>
<p>A saída é:</p>
<div class="CodeRay">
<pre><span class="no">1</span> >ruby p045handexcp.rb
<span class="no">2</span> Estou antes do raise.
<span class="no">3</span> Fui resgatado.
<span class="no">4</span> Estou depois do bloco begin.
<span class="no">5</span> >Exit code: 0
</pre>
</div>
<p>Observe que o o código interrompido pela exceção nunca é executado. Uma vez que a exceção é tratada, a execução continua imediatamente depois do bloco begin que a a gerou.</p>
<p>Se você escreve uma cláusula <b>rescue</b> sem nenhum parâmetro, o parâmetro será ajustado por padrão para <b>StandardError</b>. Cada cláusula <b>rescue</b> pode especificar múltiplas exceções para serem capturadas. No fim de cada cláusula <b>rescue</b> voce pode passar ao Ruby o nome de uma variável local para receber a exceção correspondente. Os parâmetros para a cláusula <b>rescue</b> podem também ser expressões arbitrárias (incluindo chamadas a métodos) que retornam uma classe do tipo <b>Exception</b>. Se usarmos <b>raise</b> sem parâmetros, ele relançará a exceção.</p>
<p>Você pode empilhar cláusulas de <b>rescue</b> em um bloco begin/rescue. Exceções não tratadas por uma cláusula rescue serão passadas para a próxima:</p>
<div class="CodeRay">
<pre><span class="no"> 1</span> <span class="r">begin</span>
<span class="no"> 2</span> <span class="c"># -</span>
<span class="no"> 3</span> <span class="r">rescue</span> <span class="co">UmTipoDeExcecao</span>
<span class="no"> 4</span> <span class="c"># -</span>
<span class="no"> 5</span> <span class="r">rescue</span> <span class="co">OutroTipoDeExcecao</span>
<span class="no"> 6</span> <span class="c"># -</span>
<span class="no"> 7</span> <span class="r">else</span>
<span class="no"> 8</span> <span class="c"># -</span>
<span class="no"> 9</span> <span class="r">end</span>
</pre>
</div>
<p>Para cada cláusula <b>rescue</b> no bloco <b>begin</b>, o Ruby irá comparar a exceção levantada contra cada um dos parâmetros em questão. O casamento irá acontecer se o nome da exceção na cláusula rescue for do mesmo tipo da última exceção lançada, ou é uma superclasse dessa exceção. O código em uma cláusula <b>else</b> é executado se o código no corpo da declaração begin executa até o final sem exceções. Se uma exceção ocorrer, então a cláusula else obviamente não será executada. O uso de uma cláusula else não é particularmente comum em Ruby.</p>
<p>Se você quer verificar uma exceção resgatada (em que se usou o rescue). você pode mapear o objeto <b>Exception</b> para uma variável com uma cláusula rescue, como mostrado no programa <b>p046excpvar.rb</b></p>
<div class="CodeRay">
<pre><span class="no">1</span> <span class="c"># p046excpvar.rb</span>
<span class="no">2</span> <span class="r">begin</span>
<span class="no">3</span> raise <span class="s"><span class="dl">'</span><span class="k">Uma exceção para teste.</span><span class="dl">'</span></span>
<span class="no">4</span> <span class="r">rescue</span> <span class="co">Exception</span> => e
<span class="no">5</span> puts e.message
<span class="no">6</span> puts e.backtrace.inspect
<span class="no">7</span> <span class="r">end</span>
</pre>
</div>
<p>A saída é:</p>
<div class="CodeRay">
<pre><span class="no">1</span> >ruby p046excpvar.rb
<span class="no">2</span> Uma exceção para teste.
<span class="no">3</span> ["p046excpvar.rb:3"]
<span class="no">4</span> >Exit code: 0
</pre>
</div>
<p>A classe <b>Exception</b> define dois métodos que retornam detalhes a respeito da exceção. O método <b>message</b> retorna uma string que pode prover detalhes legíveis sobre o que aconteceu de errado. O outro método importante é <b>backtrace</b>. Este método retorna um array de strings que representam a pilha de chamada no ponto em que a exceção foi lançada.</p>
<p>Se você precisa de garantia de que algum processamento foi feito no final de um bloco de código, não considerando se uma exceção foi lançada então a cláusula <b>ensure</b> (assegurar-se) deve ser usada após o último <b>rescue</b> e deve conter um pedaço de código que será executado a medida que o bloco termina. O bloco <b>ensure</b> sempre será executado.</p>
<p>Algumas exceções comuns são:</p>
<p>RuntimeError (está é a exceção padrão lançada pelo método <b>raise</b>), NoMethodError, NameError, IOError, TypeError e ArgumentError.</p>
<p>Um Exemplo: Vamos modificar o programa <b>p027readwrite.rb</b> para incluir o tratamento de exceções como mostrado no exemplo <b>p046xreadwrite.rb</b> abaixo.</p>
<div class="CodeRay">
<pre><span class="no"> 1</span> <span class="c"># p046xreadwrite.rb</span>
<span class="no"> 2</span> <span class="c"># Abra e leia um arquivo texto</span>
<span class="no"> 3</span> <span class="c"># Note que visto que um bloco é dado, o arquivo será fechado automaticamente quando o bloco se encerra</span>
<span class="no"> 4</span> <span class="r">begin</span>
<span class="no"> 5</span> <span class="co">File</span>.open(<span class="s"><span class="dl">'</span><span class="k">p014constructs.rb</span><span class="dl">'</span></span>, <span class="s"><span class="dl">'</span><span class="k">r</span><span class="dl">'</span></span>) <span class="r">do</span> |f1|
<span class="no"> 6</span> <span class="r">while</span> line = f1.gets
<span class="no"> 7</span> puts line
<span class="no"> 8</span> <span class="r">end</span>
<span class="no"> 9</span> <span class="r">end</span>
<span class="no"><strong>10</strong></span>
<span class="no">11</span> <span class="c"># Cria um novo arquivo e escreve nele</span>
<span class="no">12</span> <span class="co">File</span>.open(<span class="s"><span class="dl">'</span><span class="k">test.rb</span><span class="dl">'</span></span>, <span class="s"><span class="dl">'</span><span class="k">w</span><span class="dl">'</span></span>) <span class="r">do</span> |f2|
<span class="no">13</span> <span class="c"># use \n para pular para próxima linha</span>
<span class="no">14</span> f2.puts <span class="s"><span class="dl">"</span><span class="k">Criado por Satish</span><span class="ch">\n</span><span class="k">Graças a Deus!</span><span class="dl">"</span></span>
<span class="no">15</span> <span class="r">end</span>
<span class="no">16</span> <span class="r">rescue</span> <span class="co">Exception</span> => msg
<span class="no">17</span> <span class="c"># mostre a mensagem de erro gerada pelo sistema</span>
<span class="no">18</span> puts msg
<span class="no">19</span> <span class="r">end</span>
</pre>
</div>
<div class='box'>
<p>Mensagens de erros impróprias podem prover informações críticas sobre uma aplicação que podem auxiliar ataques a mesma. O problema mais comum ocorre quando mensagens de erro internas como traços de pilha, dumps de bancos de dados e códigos de erro são mostrados ao usuário. Analistas de segurança veem logs e tratamentos de erro como possíveis áreas de risco. É recomendado que as aplicações em produção não usem, por exemplo, uma chamada a <strong>puts e.backtrace.inspect</strong> ao menos que ela esteja sendo enviada para um log que não é visível para o usuário final.</p>
</div>
<h2>Exemplo de validação</h2>
<p>Aqui está um exemplo do livro <em>Ruby Cookbook</em>, mostrando como se pode fazer validação da entrada do usuário.</p>
<div class="CodeRay">
<pre><span class="no"> 1</span> <span class="r">class</span> <span class="cl">Nome</span>
<span class="no"> 2</span> <span class="c"># Define métodos getter padrão mas não métodos setter</span>
<span class="no"> 3</span> attr_reader <span class="sy">:primeiro</span>, <span class="sy">:ultimo</span>
<span class="no"> 4</span> <span class="c"># Quando alguém tenta escrever um primeiro nome, force regras sobre ele.</span>
<span class="no"> 5</span> <span class="r">def</span> <span class="fu">primeiro=</span>(primeiro)
<span class="no"> 6</span> <span class="r">if</span> primeiro == <span class="pc">nil</span> <span class="r">or</span> first.size == <span class="i">0</span>
<span class="no"> 7</span> raise <span class="co">ArgumentError</span>.new(<span class="s"><span class="dl">'</span><span class="k">Todos precisam ter um primeiro nome.</span><span class="dl">'</span></span>)
<span class="no"> 8</span> <span class="r">end</span>
<span class="no"> 9</span> primeiro = primeiro.dup
<span class="no"><strong>10</strong></span> primeiro[<span class="i">0</span>] = primeiro[<span class="i">0</span>].chr.capitalize
<span class="no">11</span> <span class="iv">@primeiro</span> = primeiro
<span class="no">12</span> <span class="r">end</span>
<span class="no">13</span>
<span class="no">14</span> <span class="c"># Quando alguém tenta escrever um último nome, force regras sobre ele.</span>
<span class="no">15</span> <span class="r">def</span> <span class="fu">ultimo=</span>(ultimo)
<span class="no">16</span> <span class="r">if</span> ultimo == <span class="pc">nil</span> <span class="r">or</span> ultimo.size == <span class="i">0</span>
<span class="no">17</span> raise <span class="co">ArgumentError</span>.new(<span class="s"><span class="dl">'</span><span class="k">Todos devem ter um último nome.</span><span class="dl">'</span></span>)
<span class="no">18</span> <span class="r">end</span>
<span class="no">19</span> <span class="iv">@ultimo</span> = ultimo
<span class="no"><strong>20</strong></span> <span class="r">end</span>
<span class="no">21</span>
<span class="no">22</span> <span class="r">def</span> <span class="fu">nome_completo</span>
<span class="no">23</span> <span class="s"><span class="dl">"</span><span class="il"><span class="idl">#{</span><span class="iv">@primeiro</span><span class="idl">}</span></span><span class="k"> </span><span class="il"><span class="idl">#{</span><span class="iv">@ultimo</span><span class="idl">}</span></span><span class="dl">"</span></span>
<span class="no">24</span> <span class="r">end</span>
<span class="no">25</span>
<span class="no">26</span> <span class="c"># Delega para o método setter ao invés de escrever na instância diretamente.</span>
<span class="no">27</span> <span class="r">def</span> <span class="fu">initialize</span>(primeiro, ultimo)
<span class="no">28</span> <span class="pc">self</span>.primeiro = primeiro
<span class="no">29</span> <span class="pc">self</span>.ultimo = ultimo
<span class="no"><strong>30</strong></span> <span class="r">end</span>
<span class="no">31</span> <span class="r">end</span>
<span class="no">32</span>
<span class="no">33</span> jacob = <span class="co">Nome</span>.new(<span class="s"><span class="dl">'</span><span class="k">Jacob</span><span class="dl">'</span></span>, <span class="s"><span class="dl">'</span><span class="k">Berendes</span><span class="dl">'</span></span>)
<span class="no">34</span> jacob.primeiro = <span class="s"><span class="dl">'</span><span class="k">Mary Sue</span><span class="dl">'</span></span>
<span class="no">35</span> jacob.nome_completo <span class="c"># => "Mary Sue Berendes"</span>
<span class="no">36</span> john = <span class="co">Nome</span>.new(<span class="s"><span class="dl">'</span><span class="k">john</span><span class="dl">'</span></span>, <span class="s"><span class="dl">'</span><span class="k">von Neumann</span><span class="dl">'</span></span>)
<span class="no">37</span> john.nome_completo <span class="c"># => "John von Neumann"</span>
<span class="no">38</span> john.primeiro = <span class="s"><span class="dl">'</span><span class="k">john</span><span class="dl">'</span></span>
<span class="no">39</span> john.primeiro <span class="c"># => "John"</span>
<span class="no"><strong>40</strong></span> john.primeiro = <span class="pc">nil</span>
<span class="no">41</span> <span class="c"># ArgumentError: Todos precisam ter um primeiro nome.</span>
<span class="no">42</span> <span class="co">Name</span>.new(<span class="s"><span class="dl">'</span><span class="k">Kero, estrela internacional do futebol e artista de performance</span><span class="dl">'</span></span>, <span class="pc">nil</span>)
<span class="no">43</span> <span class="c"># ArgumentError: Todos precisam ter um último nome.</span>
</pre>
</div>
<p>A classe <b>Nome</b> armazena o primeiro e último nome das pessoas. Ele usa métodos setter para ter certeza de duas regras restritas: todos devem possuir tanto um primeiro quanto um último nome, e o primeiro nome de todas as pessoas deve começar com uma letra maiúscula. A classe <b>Nome</b> foi escrita de um modo que as regras são impostas tanto no construtor quanto depois que o objeto foi criado. Em certas ocasiões você não confia dos dados vindos através dos métodos setter. Nestes casos você deve definir seus próprios métodos para evitar que dados ruins infectem seus objetos. Dentro de uma classe, você pode acessar diretamente as variáveis de instância. Você pode simplesmente associar a uma variável de instância e método setter não será disparado. Se você quer dispará-lo, você precisará chamá-lo explicitamente. Note como, no método <b>Nome#initialize</b> acima, chamamos os métodos <b>primeiro=</b> e <b>ultimo=</b> ao invés de atribuir a @primeiro e @ultimo. Com isso temos certeza de que o código de validação é executado para os valores iniciais de cada objeto da classe <b>Nome</b>. Não podemos apenas dizer <b>primeiro = primeiro</b>, porque <strong>primeiro</strong> é um nome de variável nesse método. Usamos então <strong>self.primeiro</strong> para executar o método <b>primeiro=</b>.</p>
<div class="pagination"><a href="logging-com-ruby.html">Logging com Ruby ></a></div>
</div>
<div class="column span-5 append-1 last">
<p><a href="http://www.gurusp.org" title="Grupo de Usuários Ruby de SP"><img src="images/logo_guru-sp.jpg" title="Logo do GURU-SP" alt="Logo do Guru-SP" /></a></p>
<div class="box">
<p>Este material tem como base o <a href="http://www.rubylearning.com" title="Ruby Learning">tutorial do RubyLearning.com de Satish Talim</a> e foi traduzido por membros do <a href="http://www.gurusp.org" title="Grupo de Usuários Ruby de SP">GURU-SP</a> com a permissão do autor.</p>
<p class="last">Ajude o RubyLearning participando em algum dos <a href="http://www.rubylearning.org" title="cursos do Ruby Learning">cursos pagos</a> ou <a href="http://pledgie.com/campaigns/415" title="Ajude o Ruby Learning">fazendo uma doação para o projeto</a></p>
</div>
<p class="quiet"><a href="index.html" title="índice">Voltar para o índice</a></p>
<h5></h5>
<p class="incr"></p>
</div>
<div class="column span-22 prepend-1 append-1 first last" id="footer">
<hr />
<p>Tuturial de Ruby do <a href="http://www.gurusp.org" title="Grupo de Usuários Ruby de SP">GURU-SP</a>. Este site foi criado com <a href="http://webby.rubyforge.org">Webby</a></p>
</div>
</div>
</body>
</html>