-
Notifications
You must be signed in to change notification settings - Fork 0
/
2008-12.html
401 lines (282 loc) · 21.9 KB
/
2008-12.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
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
<!DOCTYPE html>
<html lang="en-us" dir="ltr" itemscope itemtype="http://schema.org/Article">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1"/>
<title>Blogue do Caloni</title>
<meta name="author" content="Caloni" />
<meta name="generator" content="txt2blog 0.0.1">
<meta property="og:title" content="Blogue do Caloni"/>
<meta property="og:type" content="website"/>
<meta property="og:url" content="http://www.caloni.com.br"/>
<meta property="og:image" content="/img/about-brand.png"/>
<meta property="og:description" content="Write for computers, people and food."/>
<link href="/index.xml" rel="feed" type="application/rss+xml" title="Blogue do Caloni"/>
<link rel="stylesheet" type="text/css" href="/css/custom.css"/>
<link rel="stylesheet" type="text/css" href="/css/jquery-ui.css"/>
<script src="/js/jquery-1.12.4.js"></script>
<script src="/js/jquery-ui.js"></script>
<script src="/js/copy_clipboard.js"></script>
<script>
var quick_search_posts = [
];
</script>
<script src="/js/quick_search.js"></script>
<script src="/js/list.js"></script>
<link rel="icon" href="/img/favicon.ico"/>
</head>
<body style="min-height:100vh;display:flex;flex-direction:column">
<nav class="navbar has-shadow is-white"
role="navigation" aria-label="main navigation">
<div class="container">
<div class="navbar-brand">
<a class="navbar-item" href="months.html">
<div class="is-4"><b>caloni::2008-12</b></div>
</a>
</div>
</div>
</nav>
<div class="container">
<div class="column">
<div style="min-height:56vh">
<div style="padding-bottom: 1em;"></div>
<ul style="list-style: none;">
<li><small><a href="2008-12.html#basico_do_basico_ponteiros">Básico do básico: ponteiros</a></small></li>
<li><small><a href="2008-12.html#basico_do_basico_tipos">Básico do básico: tipos</a></small></li>
<li><small><a href="2008-12.html#basico_do_basico_binario">Básico do básico: binário</a></small></li>
<li><small><a href="2008-12.html#houaissparababylon_versao_11">HouaissParaBabylon versão 1.1</a></small></li>
</ul>
<span id="basico_do_basico_ponteiros" title="Básico do básico: ponteiros"/></span>
<section id="section_basico_do_basico_ponteiros">
<p class="title"><a href="2008-12.html#basico_do_basico_ponteiros">#</a> Básico do básico: ponteiros</p>
<span class="title-heading">Caloni, 2008-12-06 <a href="coding.html">coding</a><a href="2008-12.html"> <sup>[up]</sup></a> <a href="javascript:;" onclick="copy_clipboard('section#section_basico_do_basico_ponteiros')"><sup>[copy]</sup></a></span>
<p>Nessas últimas semanas tenho gastado meu tempo junto da mais nova pupila da SCUA, aspirante a programadora em C e Install Shield Script. Minha tarefa? Explicar tudo, desde o mais simples, como **variáveis**, até as coisas não tão triviais, como **símbolos de depuração**.</p>
<p>Posso afirmar que tem sido muito compensador ativar algumas partes do meu cérebro que acreditava nem mais existirem. Rever velhos conceitos, apesar de manjados, nos dá a oportunidade de lembrar que as coisas mais complexas que construímos no dia-a-dia se baseiam em um punhado de preceitos básicos que é essencial ter na cabeça. E nunca esquecê-los.</p>
<p>Meu amigo costuma chamar esses preceitos básicos de **fundamentais**. Isso por um bom motivo lógico e semântico: tudo que aprendemos de básico sobre qualquer área de conhecimento serve-nos de **base** para suportar as outras coisas que virão a ser entendidas na mesma área de conhecimento. Ou seja: é **a parte mais importante a ser aprendida**. Sem ela, a base, não nos é possível construir nada **sólido** e **duradouro**. Sem ela, toda a estrutura construída _a posteriori_ se rompe e vai abaixo.</p>
<p>Foi partindo desse princípio que me preocupei com esmero para explicar as peças mais fundamentais do conhecimento em jogo, formadoras da cabeça de um programador para sempre, seja em C como em qualquer outra linguagem. E como nada é bem explicado sem formar imagens na cabeça, aproveitei para desenhar alguns esboços no papel. O resultado desses esboços é esse artigo.</p>
<h4>Ponteiro: o eterno vilão da história</h4>
<p>Não tenho a presunção de conseguir explicar 100% para alguém iniciante o que são ponteiros em C, como usá-los e como se proteger deles. Definitivamente ponteiro não é um conceito simples, apesar de básico, e posso dizer sem vergonha que demorei cerca de seis meses no meu aprendizado em C pra entender completamente tudo relacionado com ponteiros. Demorou, quebrei a cabeça, mas depois nunca mais esqueci.</p>
<p>De acordo com o meu amigo <a href="http://www.sk5.com.br">Rafael</a>, a melhor definição que usei até hoje para explicar esse conceito envolvia um armário repleto de gavetas, todas numeradas em ordem de posição (1, 2, 3...). Cada gaveta podia guardar qualquer coisa, inclusive o número de outra gaveta em um pedaço de papel. Com isso, eu poderia guardar em uma gaveta aleatória o que eu precisava guardar e escrever o "endereço" dessa gaveta em um pedaço de papel e guardá-lo na gaveta número 1, por exemplo. Com isso poderia até esquecer a posição onde está o que eu guardei, pois bastava abrir a gaveta número 1 e ler a posição em que estava essa gaveta.</p>
<p>Deve ter ficado óbvio, mas se não ficou: o armário é a memória RAM, as gavetas são váriáveis e as gavetas onde guardamos pedaços de papel são ponteiros, que não deixam de ser variáveis, e apontam para outras gavetas que são... adivinha? Outras variáveis!</p>
<img src="img/basico_do_basico_ponteiros_pointers_drawer.gif"/>
<img src="img/basico_do_basico_ponteiros_draft_pointers_strings_arrays.jpg"/>
<p>Outros conceitos que costumo utilizar é relacionar a memória RAM com a memória do programa e contar a memória como se contam carneirinhos. Dessa forma fica fácil pelo menos entender dois conceitos fundamentais na arte dos ponteiros: memória e endereço.</p>
<h4>Practice makes perfect</h4>
<p>O segundo passo, acredito eu, é entender como a memória é dimensionada através do programa, e como o tipo molda a representação dos bits e bytes através das ligações de silício, mas isso fica pra mais tarde. Temos que programar, e é isso que vai de fato fazer a diferença no aprendizado de uma linguagem como C. Nada como uma boa mistura de teoria e prática para gerar um concreto armado que irá suportar um Empire State de conhecimento.</p>
<p>Por isso, segue uma lista de tarefas interessantes para exercitar o conceito de ponteiros:</p>
<p> * Criar funções que modificam números passados como parâmetro.</p>
<p> * Criar funções que modificam texto passado como parâmetro.</p>
<p> * Alocar e desalocar memória dinamicamente.</p>
<p>Tarefas mais específicas da minha área e que uso o tempo todo:</p>
<p> * Escrever e ler texto em arquivos.</p>
<p> * Escrever e ler no registro do Windows.</p>
<p> * Obter o endereço de uma função do Windows dinamicamente. E chamá-la.</p>
<pre>
Nota: Não use as classes superiores de C++ nem referências. Estou falando de estudar ponteiros nua e cruamente. Não seja preguiçoso. Algumas coisas devem ser feitas da maneira mais "primitiva" até se entender com o que se está lidando. Lembre-se que os melhores programadores possuem os alicerces mais fortes.
</pre>
<h4>Bônus Points: Fantoches!</h4>
<p>Este <a href="https://www.youtube.com/watch?v=5VnDaHBi8dM<a href="posts.html?q=vídeo">vídeo</a>ab_channel=Napalm">vídeo</a> é o mais didático do universo sobre como funcionam ponteiros em C. Veja e mostre pros seus filhos.</p>
</section><hr/>
<span id="basico_do_basico_tipos" title="Básico do básico: tipos"/></span>
<section id="section_basico_do_basico_tipos">
<p class="title"><a href="2008-12.html#basico_do_basico_tipos">#</a> Básico do básico: tipos</p>
<span class="title-heading">Caloni, 2008-12-12 <a href="coding.html">coding</a><a href="2008-12.html"> <sup>[up]</sup></a> <a href="javascript:;" onclick="copy_clipboard('section#section_basico_do_basico_tipos')"><sup>[copy]</sup></a></span>
<p>Um tipo nada mais é que do que uma forma (ô) de bolo, que **molda a memória** como acharmos melhor moldá-la. Bom, para isso fazer sentido é necessário explicar memória, que é um conceito **mais básico ainda**.</p>
<p>A memória é **qualquer lugar** onde eu possa **guardar alguma coisa**. No artigo anterior era um punhado de gavetas. Mas poderiam muito bem ser caixas de presente. Ou um caderno. Ou até uma placa de memória RAM. O que sua criatividade quiser.</p>
<img src="img/basico_do_basico_tipos_sx9fYjS.gif"/>
<p>O importante no conceito de memória, computacionalmente falando, é saber que ela pode guardar qualquer tipo de informação, mas ela **não sabe o que você está guardando**. E eis que surge o segredo do **tipo**: ele conta para você, e seu programa, o que de fato está guardado na memória.</p>
<p>Vamos exemplificar.</p>
<h4>Este artigo é um punhado de números na memória</h4>
<p>Computadores trabalham muito bem com números. A própria memória só guarda valores numéricos. Porém, se é dessa forma, como conseguimos abrir o Bloco de Notas e digitar algum texto?</p>
<p>Para entender essa "mágica" é necessário vir à tona o conceito de **representação**, um tema que ainda pode dar muito pano pra manga quando estudarmos base numérica. Por enquanto, basta saber que uma representação é um **faz-de-conta** em que todos concordam com o que for dito. Por exemplo: Faz de conta que a letra 'A' é o número 65. Dessa forma, sempre que for visto o número 65, de agora em diante, será vista a letra 'A' no lugar.</p>
<p>Existem alguns faz-de-conta que são muito difundidos entre e humanidade informática. Um deles é chamado **tabela ASCII** (se pronuncia "ásqui"). É uma forma de todos conseguirem entender os textos de todo mundo. Abaixo podemos ver a representação de todas as letras maiúsculas na codificação ASCII:</p>
<pre>
Número Letra
====== =====
65 A
66 B
67 C
68 D
69 E
70 F
71 G
72 H
73 I
74 J
75 K
76 L
77 M
78 N
79 O
80 P
81 Q
82 R
83 S
84 T
85 U
86 V
87 W
88 X
89 Y
90 Z
</pre>
<p>Agora, imagine que você digitou o seguinte texto no bloco de notas:</p>
<pre>
CASA
</pre>
<p>Como esse texto é guardado na memória de um computador, se ele só entende números?</p>
<p>Através da nossa já conhecida tabela ASCII! Na verdade, números são armazenados na memória, mas por representarem as letras 'C', 'A', 'S' e 'A', são traduzidos de volta para o formato texto pelo Bloco de Notas, que conhece o que guardou na memória.</p>
<img src="img/basico_do_basico_tipos_W9jtDwK.gif"/>
<h4>A memória pode guardar qualquer coisa com números</h4>
<p>A técnica de representação pode guardar qualquer coisa na memória como números que serão traduzidos por algum programa que consiga abrir aqueles dados. Dessa forma podemos não só armazenar texto, como imagens, vídeos, páginas web e até mesmo os próprios programas que os abrem!</p>
<p>Na programação do dia-a-dia, as coisas funcionam da mesma forma. As tão faladas variáveis reservam um espaço de memória para guardar alguma coisa, mas só sabemos o que essa alguma coisa é através do tipo da variável:</p>
<pre>
// a variável idade (espaço de memória)
// pode guardar um número (tipo)</font>
int idade;
// a variável nome (espaço de memória) pode
// guardar o nome de alguém de até 99 letras (tipo)
char nome[100];
// a variável cad (espaço de memória) pode
// guardar o cadastro de uma pessoa (tipo)
Cadastro cad;
</pre>
<p>Esses elementos, na memória, são um bando de número que, sem os tipos, não possuem significado algum, como podemos ver na depuração do programa abaixo:</p>
<img src="img/basico_do_basico_tipos_interpretacao_de_memoria_texto_e_numeros.png"/>
<pre>
Note que os números não estão aqui representados em decimal, onde se esperaria 35 e 42, pois a representação formal da memória geralmente está no formato hexadecimal, transformando esses números em 0x23 e 0x2a, respectivamente. Para entender essa diferença cabe estudar um pouco sobre base numérica, outro tema básico do programador sólido.
</pre>
<h4>Practice makes perfect</h4>
<p>Nada é bem aprendido se não for apreendido. Algumas tarefas programáticas que podem fixar o conceito de tipo estão listadas abaixo:</p>
<pre>
</pre>
<p> * Usar **printf **especificando tipos diversos (%d, %s, %f, %p, ...) para a mesma variável, inclusive correndo o risco de gerar algumas exceções.</p>
<pre>
</pre>
<p> * Usar **scanf** especificando diversas variáveis para o mesmo tipo (%d, %s, %f, %p, ...), vendo o resultado da leitura da entrada do usuário na memória.</p>
<pre>
</pre>
<p> * Tentar copiar o conteúdo de uma variável para outra variável de **tipo diferente**. Sempre analise a memória para ver o resultado.</p>
<h4>Outros faz-de-conta bem famosos</h4>
<p> * <a href="http://pt.wikipedia.org/wiki/Extremidade_(ordena%C3%A7%C3%A3o)">Ordenação de extremidades</a>: O problema Little Endian e Big Endian.</p>
<p> * <a href="http://pt.wikipedia.org/wiki/UNICODE">UNICODE</a>: Por um conjunto de letras universal.</p>
<p> * <a href="http://pt.wikipedia.org/wiki/Convers%C3%A3o_de_base_num%C3%A9rica">Base numérica</a>: O que são binário e hexadecimal e como eles afetam nossa vida.</p>
</section><hr/>
<span id="basico_do_basico_binario" title="Básico do básico: binário"/></span>
<section id="section_basico_do_basico_binario">
<p class="title"><a href="2008-12.html#basico_do_basico_binario">#</a> Básico do básico: binário</p>
<span class="title-heading">Caloni, 2008-12-18 <a href="coding.html">coding</a><a href="2008-12.html"> <sup>[up]</sup></a> <a href="javascript:;" onclick="copy_clipboard('section#section_basico_do_basico_binario')"><sup>[copy]</sup></a></span>
<p>Apesar do tema binário, o assunto de hoje no fundo remete-nos a todo e qualquer tipo de **representação**. É o faz-de-conta um pouco mais intenso, vindo das profundezas da matemática e dominado com maestria pela nossa mente e sua capacidade lógica de abstrair.</p>
<p>Como todos sabemos, nós, seres humanos, somos dotados de dez dedos: cinco em cada mão. Isso influenciou fortemente nosso sistema de contagem de coisas, e, como consequência, nossa forma de representar números.</p>
<p>No entanto, números serão sempre números, independente de seres humanos e de dedos. Outros seres inteligentes de outras galáxias poderiam representar os mesmo números, sendo um conceito lógico independente de raça, usando qualquer outra forma e quantidade de símbolos. Por falar em símbolos, nós temos **dez**, a saber:</p>
<pre>
0, 1, 2, 3, 4, 5, 6, 7, 8, 9
</pre>
<p>Outros seres poderiam usar, sei lá, dois:</p>
<pre>
0, 1
</pre>
<p>É lógico que esse '0' e esse '1' podem ser representados por outros sinais, como pedra e pau, cara e coroa, tico e teco, e por aí vai a valsa.</p>
<p>O importante é que seriam na quantidade de **dois**.</p>
<h4>Último detalhe</h4>
<p>O nosso sistema de representação ainda possui algumas características singulares, como o **valor posicional**. Os mesmos dez símbolos, quando colocados em **posições diversas**, assumem **valores diversos**.</p>
<p>Dessa forma, quando esgotamos todos os símbolos e chegamos a nove, para irmos ao dez começamos a repetir os símbolos, mas em outra posição:</p>
<pre>
7,
8,
9,
10!
</pre>
<p>A nova posição do símbolo '1' possui o próximo valor após o nove. O zero, como sabemos, apenas **marca posições** e não possui valor algum. Se valesse algo, seria somado, como no número 111, que é uma **soma de três valores distintos posicionados de acordo**:</p>
<pre>
100 +
10 +
1
===
111
</pre>
<p>Pronto! Eis toda a base de nosso sistema numérico. O resto é historinha pra boi dormir. Com isso é possível até mudarmos de base, ou seja, o número de símbolos usados, conforme nos convier.</p>
<h4>Mudando de base</h4>
<p>Para nos comunicarmos com a raça alienígena que usa dois símbolos poderíamos contar seguindo o mesmo princípio:</p>
<pre>
0,
1,
10,
11,
100,
101,
110,
111,
...
</pre>
<img src="img/basico_do_basico_binario_jQTGnH6.gif"/>
<p>O valor do número, como sabemos, depende de sua posição. Mas, calma lá! O 111 logo acima não é idêntico ao 111 que vimos anteriormente, pois **mudamos a base**! Agora só temos dois símbolos para representar números, quando antes tínhamos dez.</p>
<p>O "segredo" do valor posicional também está na base, pois o zero, apesar de não possuir valor, marca a quantidade de símbolos que foram utilizados para se esgotar uma posição qualquer. Dessa forma, enquanto o nosso conhecido 10 (dez) vale todos os símbolos não-nulos (nove) mais um (nove + um = dez), o outro 10 (um-zero) da raça alienígena de dois dedos também vale todos os símbolos deles nã-nulos (um) mais um (um + um = dois).</p>
<h4>Contando em binário?</h4>
<p>Como não faz parte do tema, não vou explicar como o sistema binário foi importante para a definição de uma arquitetura simples o suficiente para ser expandida a níveis nunca antes imaginados de processamento e comprimida em espaços que muitos diriam não caber qualquer coisa de útil que fosse. No entanto, apesar de brilhante, o binário no dia-a-dia do programador gera alguns problemas. Principalmente se o programador escreve seus cálculos de **ponteiros em binário**.</p>
<p>Para entender isso, basta lembrar que, atualmente, a quantidade de memória RAM que é contada e, portanto, valor dos ponteiros que apontam para ela, é muito grande **até **para nosso sistema decimal, que possui, relembrando, dez símbolos. O que dirá, então, um sistema que possui meros dois símbolos para representar, digamos, **três gigabytes**:</p>
<pre>
11000000000000000000000000000000
</pre>
<p>São tantos zeros que aqueles bugs de _leak _de memória, famosos por levar tempo para ser corrigidos, seriam mais famosos ainda, pois o tempo gasto para se entender alguma coisa no meio de ponteiros dessa magnitude seria astronômico!</p>
<p>E, claro, ainda poderia ficar pior, se fosse depurado um desses novíssimos sistemas de 64 bits:</p>
<pre>
10011101101101101101101101101101101101101101
</pre>
<h4>Contando de dezesseis em dezesseis</h4>
<p>Eu sei que não vou conseguir explicar tudo sobre bases numéricas em apenas um miniartigo. Porém, vamos dar uma rápida olhada no famoso hexadecimal, que foi o que nos salvou de lidar com os numerozinhos acima.</p>
<p>Nesse sistema, a representação dos número ocupa **menos espaço ainda** que o sistema decimal, pois usa **dezesseis **símbolos distintos, usando as letras de A a F após os já conhecidos símbolos decimais:</p>
<pre>
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, A, B, C, D, E, F
</pre>
<p>A grande vantagem de contar as coisas em dezesseis é que sua representação **será sempre um múltiplo de dois**, o que facilita a conversão para o sistema binário: em um único número hexadecimal cabem quatro números binários, ou **quatro bits**.</p>
<pre>
Bin. Hexa Dec.
0000 0 0
0001 1 1
0010 2 2
0011 3 3
0100 4 4
0101 5 5
0110 6 6
0111 7 7
1000 8 8
1001 9 9
1010 A 10
1011 B 11
1100 C 12
1101 D 13
1110 E 14
1111 F 15
</pre>
<p>Tabelinha básica, fácil de achar em qualquer lugar da internet, mas colocada aqui apenas para relembrar a relação entre as três bases.</p>
<p>Bom, acho que é isso. Já ultrapassei o limite do teórico, porque na verdade o que importa aqui, para captar de fato o binário dos fatos, é **praticar**:</p>
<h4>Coisas para pensar a dois</h4>
<p> * Conte em binário quando não estiver fazendo nada. É simples e ajuda a fixar. Dessa forma: um, um-zero, um-um, um-zero-zero, um-um-zero, um-um-um, ...</p>
<p> * Decore a relação entre os números hexadecimal e binário. Você pode até esquecer isso depois, mas o esforço para decorar será útil para fixar. E nunca se sabe quando você terá que reaver a <a href="posts.html?q=MBR">MBR</a> de um cliente seu.</p>
<pre>
</pre>
<p> * Estude a lógica por trás da tabela ASCII e seus valores binários. Irá descobrir que existem relações muito óbvias entre letras, números (maíusculos e minúsculos) e sinais. Tente decorar.</p>
</section><hr/>
<span id="houaissparababylon_versao_11" title="HouaissParaBabylon versão 1.1"/></span>
<section id="section_houaissparababylon_versao_11">
<p class="title"><a href="2008-12.html#houaissparababylon_versao_11">#</a> HouaissParaBabylon versão 1.1</p>
<span class="title-heading">Caloni, 2008-12-30 <a href="projects.html">projects</a><a href="2008-12.html"> <sup>[up]</sup></a> <a href="javascript:;" onclick="copy_clipboard('section#section_houaissparababylon_versao_11')"><sup>[copy]</sup></a></span>
<p>Saindo mais um do forno.</p>
<p>Essa nova versão do conversor do dicionário Houaiss para Babylon corrige o problema de não encontrar o Houaiss 1.0. O problema ocorria porque o conversor se baseava na localização do desinstalador para encontrar o dicionário. Na primeira versão do dicionário o desinstalador fica na pasta c:\Windows, onde obviamente não estava o dicionário.</p>
<p>Nessa nova versão, além de procurar o caminho do dicionário no registro (desinstalador) e antes de pedir para o usuário o caminho correto é tentado o caminho padrão de instalação, %programfiles%\Houaiss. Se mesmo assim o dicionário não existir continuamos perguntando para o usuário, que tem a opção de dizer onde está instalado o dicionário no disco rígido ou apontar diretamente para o CD de instalação.</p>
</section><hr/>
<span style="float: left;">
<a href="2008-11.html">[2008-11]</a>
<a href="2009-01.html">[2009-01]</a>
</span>
</div>
</div>
</section>
<footer class="footer">
<div class="container">
</div>
</footer>
</body>
</html>