-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathfuncionamento.html
487 lines (468 loc) · 23.4 KB
/
funcionamento.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
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
<!DOCTYPE HTML>
<!--
Synchronous by TEMPLATED
templated.co @templatedco
Released for free under the Creative Commons Attribution 3.0 license (templated.co/license)
-->
<html>
<head>
<title>CoAP</title>
<meta http-equiv="content-type" content="text/html; charset=utf-8" />
<meta name="description" content="" />
<meta name="keywords" content="" />
<link href='http://fonts.googleapis.com/css?family=Lato:300,400,700,900' rel='stylesheet' type='text/css'>
<!--[if lte IE 8]><script src="js/html5shiv.js"></script><![endif]-->
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script>
<script src="js/skel.min.js"></script>
<script src="js/skel-panels.min.js"></script>
<script src="js/init.js"></script>
<script type="text/javascript">
function gerarLinkEmail(nome, usuario, dominio, assunto) {
document.write("<a href=\"mailto");
document.write(":" + usuario + "@");
document.write(dominio + "?subject=" + assunto + "\">" + nome + ' - ' + usuario + "@" + dominio + "<\/a>");
}
</script>
<noscript>
<link rel="stylesheet" href="css/skel-noscript.css" />
<link rel="stylesheet" href="css/style.css" />
</noscript>
<!--[if lte IE 8]><link rel="stylesheet" href="css/ie/v8.css" /><![endif]-->
<!--[if lte IE 9]><link rel="stylesheet" href="css/ie/v9.css" /><![endif]-->
</head>
<body>
<div id="wrapper">
<!-- Header -->
<div id="header">
<div class="container">
<!-- Logo -->
<div id="logo">
<h1><a href="#">Constrained Application Protocol</a></h1>
<span><a href="#">(CoAP)</a></span>
</div>
<!-- Nav -->
<nav id="nav">
<ul>
<li><a href="index.html">Fundamentação Teórica</a></li>
<li class="active"><a href="funcionamento.html">Funcionamento do CoAP</a></li>
<li><a href="aplicacoes.html">Aplicações</a></li>
<li><a href="conclusao.html">Conclusão</a></li>
<br>
<li><a href="perguntas.html">Perguntas</a></li>
<li><a href="referencias.html">Referências bibliográficas</a></li>
</ul>
</nav>
</div>
</div>
<!-- /Header -->
<div id="page">
<div class="container">
<div class="row">
<div class="3u">
<section id="sidebard2">
<header>
<h2>2) Funcionamento do CoAP</h2>
</header>
<ul class="style1">
<li class="first"><span class="fa fa-check"></span><a href="#2.1">2.1 Estrutura</a></li>
<li><span class="fa fa-check"></span><a href="#2.2">2.2 Modelo e fluxo de mensagens</a></li>
<li><span class="fa fa-check"></span><a href="#2.3">2.3 Modelo requisição/resposta</a></li>
<li><span class="fa fa-check"></span><a href="#2.4">2.4 Intermediários e Cache</a></li>
<li><span class="fa fa-check"></span><a href="#2.5">2.5 Formato da mensagem</a></li>
<li><span class="fa fa-check"></span><a href="#2.6">2.6 Correlação de mensagens e desduplicação</a></li>
<li><span class="fa fa-check"></span><a href="#2.7">2.7 Controle de congestionamento</a></li>
<li><span class="fa fa-check"></span><a href="#2.8">2.8 Parâmetros de Transmissão</a></li>
<li><span class="fa fa-check"></span><a href="#2.9">2.9 Protocolo de segurança para CoAP</a></li>
</ul>
</section>
</div>
<div class="9u skel-cell-important">
<section id="content">
<header>
<h2><a name="2.1">2.1 Estrutura</a></h2>
</header>
<figure>
<img src="images/CamadasAbstratasCoAP.png" alt="Camadas do CoAP"/>
<figcaption><span>Figura 2:</span> Camadas Abstratas do CoAP.</figcaption>
<figcaption class="sublegenda">Reproduzido de RFC 7252.</figcaption>
</figure>
<header>
<h2><a name="2.2">2.2 Modelo e fluxo de mensagens</a></h2>
</header>
<p>
O modelo de mensagens do CoAP é baseado na troca de mensagens de ponta a ponta através do
protocolo UDP. São 4 os tipos de mensagens usadas no protocolo CoAP :
</p>
<li>
<strong>Confirmável (CON) :</strong> Mensagens que precisam ser confirmadas. Quando
nenhum pacote é perdido, cada mensagem deste tipo resulta em uma mensagem do tipo
<italic>acknowledgement</italic> ou do tipo <italic>reset</italic>.
</li>
<br>
<li>
<strong>Não Confirmável (NON) :</strong> Mensagens que não necessitam confirmação. Esse
tipo de mensagem é usado para dados que são repetidos regularmente para requisito
de aplicação, como mensagens repetidas de um sensor.
</li>
<br>
<li>
<strong><italic>Acknowledgement</italic> (ACK) :</strong> Confirma que uma mensagem confirmável chegou.
Essa mensagem não indica o sucesso ou a falha de um <italic>request</italic>
encapsulado na mensagem confirmável.
</li>
<br>
<li>
<strong><italic>Reset</italic> (RST) :</strong> Indica que uma mensagem específica (Confirmável ou
Não Confirmável) foi recebida, entretanto por falta de contexto, a mensagem não pôde ser processada.
Essa condição é normalmente causada quando um nó de recebimento foi reiniciado e a mensagem enviada
não foi devidamente interrompida.
</li>
<br>
<p>
A confiabilidade é fornecida marcando uma mensagem como confirmável (CON). Uma mensagem
confirmável é retransmitida usando um tempo limite padrão entre retransmissões,
até o destinatário, enviando uma mensagem de confirmação (ACK) com o mesmo ID de mensagem.
</p>
<figure>
<img src="images/TransmissaoMensagemConfiavel.png" alt="Mensagem Confirmável"/>
<figcaption><span>Figura 3:</span> Transmissão de Mensagem Confirmável (CON).</figcaption>
<figcaption class="sublegenda">Reproduzido de RFC 7252.</figcaption>
</figure>
<p>
Quando um destinatário não é capaz de processar uma mensagem como confirmável, ele
responde com uma mensagem <italic>Reset</italic> (RST) no lugar de <italic>Acknowledgement</italic> (ACK).
</p>
<p>
Uma mensagem que não requer transmissão confiável (por exemplo, mensagens que são repetidas regularmente
em aplicações, assim como leituras repetidas de um sensor) pode ser enviada como uma mensagem não confirmável (NON).
Estas não são reconhecidas, mas ainda têm um ID de mensagem para detecção duplicada. Quando um destinatário não for
capaz de processar uma mensagem não confirmável, pode-se responder com uma mensagem de <italic>Reset</italic> (RST).
</p>
<figure>
<img src="images/TransmissaoNaoConfiavel.png" alt="Mensagem Não Confirmável"/>
<figcaption><span>Figura 4:</span> Transmissão de Mensagem Não Confirmável (NON).</figcaption>
<figcaption class="sublegenda">Reproduzido de RFC 7252.</figcaption>
</figure>
<p>
Como o CoAP é executado sobre UDP, que é um protocolo não confiável, também suporta o
uso dos endereços <italic>multicast</italic> IP de destino, permitindo solicitações
<italic>multicast</italic> CoAP, como precaução para evitar o congestionamento da resposta.
</p>
<header>
<h2><a name="2.3">2.3 Modelo requisição/resposta</a></h2>
</header>
<p>
Um <italic>request</italic> (requisição) pode ser enviado através de uma mensagem CON (confirmável) ou
NON (não confirmável), e, se estiver imediatamente disponível, deve ser enviada uma mensagem ACK para a
mensagem CON. Isso é a chamada resposta <italic>piggybacked</italic>.
(Não há motivo para enviar um ACK separado para uma resposta <italic>piggybacked</italic>, já que o cliente
retransmitirá o <italic>request</italic> caso a mensagem ACK seja perdida).
</p>
<figure>
<img src="images/fig1mensagem.png" alt="Respostas Piggybacked"/>
<figcaption><span>Figura 5:</span> Dois <italic>requests</italic> GET com respostas <italic>piggybacked</italic>.</figcaption>
<figcaption class="sublegenda">Reproduzido de RFC 7252.</figcaption>
</figure>
<p>
Caso o servidor não esteja apto a responder imediatamente um <italic>request</italic> de uma mensagem CON, ele
simplesmente responde com um ACK vazio. Dessa forma o cliente sabe que pode parar de retransmitir o
<italic>request</italic>. Quando a resposta estiver pronta para ser enviada, o servidor envia uma nova mensagem CON.
</p>
<figure>
<img src="images/fig2mensagem.png" alt="GET com respostas separada"/>
<figcaption><span>Figura 6:</span> Um <italic>request</italic> GET com resposta separada.</figcaption>
<figcaption class="sublegenda">Reproduzido de RFC 7252.</figcaption>
</figure>
<p>
Caso um <italic>request</italic> seja enviado através de uma mensagem NON, então a resposta é enviada usando uma
nova mensagem NON.
</p>
<figure>
<img src="images/fig3mensagem.png" alt="Request e resposta NON"/>
<figcaption><span>Figura 7:</span> Um <italic>request</italic> e uma resposta, ambos NON.</figcaption>
<figcaption class="sublegenda">Reproduzido de RFC 7252.</figcaption>
</figure>
<header>
<h2><a name="2.4">2.4 Intermediários e Cache</a></h2>
</header>
<p>
O protocolo suporta o armazenamento de respostas com a finalidade de atender de forma
eficiente aos pedidos. O armazenamento em cache simples é ativado usando informações de
atualização e validade transportadas com respostas CoAP. Um cache pode ser localizado em
um nó (ponto final) ou um intermediário.
</p>
<p>
<italic>Proxying</italic> é útil em redes limitadas por diversos motivos, inclusive por limitar o
tráfego na rede, melhorar a performance, acessar recursos de "<italic>sleeping devices</italic>", e por
motivos de segurança. O <italic>proxy</italic> de <italic>request</italic> de um nó na extremidade é suportado no
protocolo. Quando usado um <italic>proxy</italic>, a URI do "recurso a ser solicitado será incluído na
solicitação, enquanto o endereço IP de destino é setado como o endereço de IP do <italic>proxy</italic>.
</p>
<p>
Como o CoAP foi projetado de acordo com a arquitetura REST, e por isso exibe
funcionalidades similares ao protocolo HTTP, é possível traçar um paralelo entre os dois
protocolos, mapeando de CoAP para HTTP e vice-versa. Tal mapeamento pode ser usado para
realizar a interface HTTP REST usando CoAP ou para converter entre HTTP e CoAP. Essa
conversão pode ser realizada por um <italic>proxy</italic> de protocolo cruzado
("<italic>cross-proxy</italic>"), o qual converte o método ou código de resposta, tipo de mídia
e opções para o recurso HTTP correspondente.
</p>
<header>
<h2><a name="2.5">2.5 Formato da mensagem</a></h2>
</header>
<figure>
<img src="images/CabecalhoCoAP.png" alt="Cabeçalho do CoAP"/>
<figcaption><span>Figura 8:</span> Cabeçalho do CoAP.</figcaption>
<figcaption class="sublegenda">Reproduzido de RFC 7252.</figcaption>
</figure>
<p>
CoAP é baseado na troca de mensagens compactadas que, por padrão, são transportadas pelo
UDP (ou seja, cada mensagem do CoAP ocupa uma seção de dados de um datagrama UDP).
As mensagens do CoAP são codificadas em um simples formato binário. O formato da
mensagem começa com um cabeçalho de tamanho fixo de 4 <italic>bytes</italic>. Seguido por um valor
de <italic>token</italic> de comprimento variável, que pode ter entre 0 a 8 <italic>bytes</italic> de
comprimento. Seguido pelo valor de <italic>token</italic>, vem uma sequência de zeros ou mais.
</p>
<li>
<strong>Versão (Ver) :</strong> <italic>unsigned int</italic> de 2 <italic>bits</italic>.
Indica o número de versão do CoAP. Implementações dessa especificação DEVEM estabelecer esse campo em 1 (01 binário).
Outros valores são reservados para versões futuras. Mensagens com número de versão
desconhecido DEVEM ser silenciosamente ignoradas.
</li>
<br>
<li>
<strong>Tipo (T) :</strong> <italic>unsigned int</italic> de 2 <italic>bits</italic>.
Indica se a mensagem é de um dos tipos:
<br>
<br> - Confirmável (0)
<br> - Não-confirmável (1)
<br> - Confirmação (2)
<br> - Reset (3)
</li>
<br>
<li>
<strong>Comprimento de <italic>Token</italic> (TKL) :</strong> <italic>unsigned int</italic> de 4
<italic>bits</italic>. Indica o tamanho da variável do <italic>token</italic>, que pode variar de 0 a 8
<italic>bytes</italic>. Comprimentos de 9 a 15 são reservados e não devem ser enviados.
É um campo sempre gerado pelo cliente CoAP.
</li>
<br>
<li>
<strong>Código (<italic>Code</italic>) :</strong> <italic>unsigned int</italic> de 8 <italic>bits</italic>, dividido em 3
<italic>bits</italic> para classe (<italic>bits</italic> mais
significantes) e 5 <italic>bits</italic> para detalhes (<italic>bits</italic> menos significantes).
A classe pode indicar uma requisição (0), resposta de sucesso (2), resposta de erro do
cliente (4), ou resposta de erro do servidor (5). (Todas as outras classes são
reservadas). Em casos especiais no código 0.00 indica uma mensagem vazia.
</li>
<br>
<li>
<strong>ID da mensagem :</strong> <italic>unsigned int</italic> de 16 <italic>bits</italic>. Usada para detectar
mensagens duplicadas e equiparar mensagens do tipo de Confirmação/Reset para mensagens do tipo
Confirmável/Não Confirmável.
</li>
<br>
<br>
<header>
<h2><a name="2.6">2.6 Correlação de mensagens e desduplicação</a></h2>
</header>
<p>
Uma mensagem ACK ou RST é relacionada com uma mensagem CON e NON através de uma mensagem
de ID junto com o endereço do nó correspondente.
A mensagem ID é gerada pelo transmissor de uma mensagem CON ou NON e incluída no cabeçalho do
CoAP. A mensagem ID deve ecoar um ACK ou RST do cliente.
Além disso, a mesma mensagem ID deve esperar o <italic>Exchange Lifetime</italic>
(tempo de espera pelo ACK após uma mensagem CON ser enviada) terminar para ser
reenviada em uma comunicação com o mesmo nó.
</p>
<p>
Para uma mensagem ACK ou RST combinar com uma CON ou NON , a mensagem ID e nó de
origem do ACK ou RST devem combinar com a mensagem ID e nó de destino do CON ou NON.
</p>
<header>
<h2><a name="2.7">2.7 Controle de congestionamento</a></h2>
</header>
<p>
Com o intuito de não causar congestionamento, clientes (incluindo <italic>proxies</italic>) DEVEM
estritamente limitar o número de interações excepcionais externas simultâneas que eles
mantêm com determinado servidor (incluindo <italic>proxies</italic>) para <italic>NSTART</italic>.
</p>
<p>
Uma <italic>outstanding interaction</italic> (interação excepcional) é tanto uma CON que ainda não
recebeu um ACK, mas ainda está esperando ou um request que não recebeu nem uma resposta
nem um ACK, mas que ainda está esperando (que pode ocorrer ao mesmo tempo, contando como
apenas uma interação excepcional). O valor padrão de <italic>NSTART</italic> para essa
especificação é de 1.
</p>
<p>
Depois de esgotado o tempo de recebimento do ACK (<italic>Exchange Lifetime</italic>),
o cliente deixa de esperar a resposta para a CON enviada. Otimizações de controle de congestionamento
adicionais permitem definir condições de parada de espera do ACK, de modo que um <italic>endpoint</italic>
não inunde o fluxo da rede no envio para outro nó de extremidade que não responde.
</p>
<header>
<h2><a name="2.8">2.8 Parâmetros de Transmissão</a></h2>
</header>
<p>
A transmissão de mensagens é controlada pelos parâmetros especificados na tabela a seguir:
</p>
<figure>
<img src="images/tabela1.png" alt="Parâmetros do CoAP"/>
<figcaption><span>Tabela 1:</span> Parâmetros do Protocolo CoAP.</figcaption>
<figcaption class="sublegenda">Reproduzido de RFC 7252.</figcaption>
</figure>
<header>
<h2><a name="2.9">2.9 Protocolo de segurança para CoAP</a></h2>
</header>
<p>
Assim como para HTTP existe um protocolo de segurança para transporte de mensagens
(TLS - <italic>Transport Layer Security</italic>) que atua sobre o TCP, o CoAP também é
protegido através do Datagram TLS (DTLS) que atua sobre o UDP, chamado CoAPs.
Na prática, DTLS é TLS com configurações para lidar com a natureza não confiável do transporte de mensagens UDP.
</p>
<figure>
<img src="images/DTLS.png" alt="Camada com DTLS"/>
<figcaption><span>Figura 9:</span> Pilha das camadas com inclusão do CoAP protegido pelo DTLS.</figcaption>
<figcaption class="sublegenda">Reproduzido de RFC 7252.</figcaption>
</figure>
<p><strong>Modos de segurança:</strong></p>
<li>
<strong><italic>NoSec</italic> :</strong> não há segurança na camada de transporte. É o único modo no qual o DTLS está desabilitado,
deixando a segurança, caso precise, para as camadas de níveis mais baixos.
</li>
<br>
<li>
<strong><italic>Pre-shared key</italic> (PSKs) :</strong> conjunto de chaves que foram previamente estabelecidas
e permitem que os nós saibam quais os outros que podem estabelecer conexões.
</li>
<br>
<li>
<strong><italic>Raw Public Key</italic> :</strong> é um par assimétrico de chaves sem certificado.
O dispositivo também tem uma identificação calculada pela chave e uma lista de identidade
dos nós com os quais pode se comunicar.
</li>
<br>
<li>
<strong><italic>Certificates</italic> :</strong> adiciona um certificado X.509 ao par assimétrico de chaves
e usa <italic>Trusted Third Party</italic> (TTP) para validar a autenticidade dos nós.
</li>
<br>
<p>
Ambos os nós da conexão devem ser clientes DTLS. A sessão deve ser iniciada na porta adequada e deve-se primeiro
estabelecer a conexão (através do <italic>handshake</italic>) para então começar a transmitir mensagens.
</p>
<p>
Além disso, também é importante que durante uma interação entre cliente e servidor usando DTLS,
o <italic>request</italic> de um cliente, de qualquer tipo, deve conter sessão, <italic>timestamp</italic>
e <italic>Message ID</italic> correspondentes. O mesmo vale para a resposta do <italic>request</italic>.
</p>
</section>
<div style="text-align: center">
<a href="index.html" class="button" style="float: left"><< Anterior</a>
<a href="#" class="button">Topo</a>
<a href="aplicacoes.html" class="button" style="float: right">Próximo >></a>
</div>
</div>
</div>
</div>
</div>
<!-- Footer -->
<div id="footer">
<div class="container">
<div class="row">
<div class="3u">
<section id="box1">
<header>
<h2>Links úteis</h2>
</header>
<ul class="style3">
<li class="first">
<p class="linkButton"><a href="http://www.poli.ufrj.br/" target="_blank">Escola
Politécnica da UFRJ</a></p>
</li>
<li>
<p class="linkButton"><a href="https://www.gta.ufrj.br/" target="_blank">Grupo de
Teleinformática e Automação da UFRJ</a></p>
</li>
<li>
<p class="linkButton"><a href="https://www.del.ufrj.br/"
target="_blank">Departamento de Engenharia Eletrônica e de Computação da
UFRJ</a></p>
</li>
</ul>
</section>
</div>
<div class="6u">
<section id="box2">
<header>
<h2>Autores</h2>
<ul class="style1">
<li class="first">
<script type="text/javascript">
gerarLinkEmail('ARYANE BARROS MACIEL DA SILVA', 'ary.maciel', 'poli.ufrj.br', 'Feedback sobre o site do CoAP...');
</script>
</li>
<li>
<script type="text/javascript">
gerarLinkEmail('FELIPE FADUL DE CARVALHO', 'felipe.fadul', 'poli.ufrj.br', 'Feedback sobre o site do CoAP...');
</script>
</li>
<li>
<script type="text/javascript">
gerarLinkEmail('MARIANA DABUL NAZARIO', 'mariana.dabul', 'poli.ufrj.br', 'Feedback sobre o site do CoAP...');
</script>
</li>
<noscript>
<em>Endereço de email protegido por JavaScript. Por favor, ative o JavaScript
para visualizar o email.</em>
</noscript>
</ul>
</header>
<div style="text-align: justify">
<p>Este trabalho foi desenvolvido por alunos de graduação do curso de Engenharia
Eletrônica e de Computação da Universidade Federal do Rio de Janeiro para a
disciplina Redes de Computadores I durante o período de 2019.1. Compreende um estudo
sobre o protocolo CoAP, apresentando suas principais características,
funcionamento e aplicações.</p>
</div>
</section>
</div>
<div class="3u">
<section id="box3">
<header>
<h2>Contato</h2>
</header>
<div style="text-align: justify">
<p>
Fique à vontade para comentar sobre o trabalho enviando-nos um e-mail ou acessando-o no
<a href="https://github.com/felipefadul/CoAP" target="_blank">GitHub</a>.
</p>
</div>
</section>
</div>
<div style="text-align: justify">
"Este trabalho foi totalmente produzido pelos autores que declaram não terem violado os direitos
autorais de terceiros, sejam eles pessoas físicas ou jurídicas. Havendo textos, tabelas e
figuras transcritos de obras de terceiros com direitos autorais protegidos ou de domínio público
tal como ideias e conceitos de terceiros, mesmo que sejam encontrados na Internet, os mesmos
estão com os devidos créditos aos autores originais e estão incluídas apenas com o intuito de
deixar o trabalho autocontido. O(s) autor(es) tem(êm) ciência dos Artigos 297 a 299 do Código
Penal Brasileiro e também que o uso do artifício de copiar/colar texto de outras fontes e outras
formas de plágio é um ato ilícito, condenável e passível de punição severa. No contexto da
Universidade a punição não precisa se restringir à reprovação na disciplina e pode gerar um
processo disciplinar que pode levar o(s) aluno(s) à suspensão;"
</div>
</div>
</div>
</div>
<!-- Copyright -->
<div id="copyright">
<div class="container">
Design by <a href="http://templated.co" target="_blank">TEMPLATED</a> - Images: <a
href="http://unsplash.com" target="_blank">Unsplash</a> (<a href="https://unsplash.com/license"
target="_blank">CC0</a>)
</div>
</div>
</div>
</body>
</html>