YAML - YAML

YAML
YAML Logo.svg
Extensões de nome de arquivo .yaml, .yml
Tipo de mídia da Internet Não registrado
lançamento inicial 11 de maio de 2001 ; 20 anos atras ( 11/05/2001 )
Último lançamento
1.2 (Terceira edição)
(1 de outubro de 2009 ; 12 anos atrás ) ( 01/10/2009 )
Tipo de formato Intercâmbio de dados
Formato aberto ? sim
Local na rede Internet yaml .org

YAML ( consulte § História e nome ) é uma linguagem de serialização de dados legível . É comumente usado para arquivos de configuração e em aplicativos onde os dados estão sendo armazenados ou transmitidos. YAML tem como alvo muitos dos mesmos aplicativos de comunicação como Extensible Markup Language (XML), mas tem uma sintaxe mínima que é intencionalmente diferente da SGML . Ele usa recuo no estilo Python para indicar aninhamento e um formato mais compacto que usa para listas e mapas, portanto, os arquivos JSON são YAML 1.2 válidos. [...]{...}

Tipos de dados personalizados são permitidos, mas YAML codifica nativamente escalares (como strings , inteiros e flutuantes ), listas e matrizes associativas (também conhecidas como mapas, dicionários ou hashes). Esses tipos de dados são baseados na linguagem de programação Perl , embora todas as linguagens de programação de alto nível comumente usadas compartilhem conceitos muito semelhantes. A sintaxe centrada em dois pontos, usada para expressar pares de valores-chave , é inspirada nos cabeçalhos de correio eletrônico conforme definido no RFC  822 , e o separador de documento --- é emprestado do MIME ( RFC  2046 ). As sequências de escape são reutilizadas a partir do C , e a quebra automática de espaço em branco para strings de várias linhas é inspirada em HTML . Listas e hashes podem conter listas e hashes aninhados, formando uma estrutura de árvore ; gráficos arbitrários podem ser representados usando aliases YAML (semelhante a XML em SOAP ). YAML deve ser lido e escrito em fluxos, um recurso inspirado no SAX .

O suporte para ler e escrever YAML está disponível para muitas linguagens de programação. Alguns editores de código-fonte, como o Emacs e vários ambientes de desenvolvimento integrados, têm recursos que tornam a edição YAML mais fácil, como dobrar estruturas aninhadas ou destacar erros de sintaxe automaticamente.

A extensão de nome de arquivo oficial recomendada para arquivos YAML é .yamldesde 2006.

História e nome

YAML ( / j ul m əl / , rimas com camelo ) foi proposto pela primeira vez por Clark Evans em 2001, que concebido-lo em conjunto com Ingy Dot Net e Oren Ben-Kiki. Originalmente, YAML significava Yet Another Markup Language , porque foi lançado em uma era que viu uma proliferação de linguagens de marcação para apresentação e conectividade (HTML, XML, SGML, etc). Seu nome inicial pretendia ser uma referência irônica ao cenário da tecnologia, referindo-se ao seu propósito como uma linguagem de marcação com a outra construção, mas foi então reaproveitado como YAML Ain't Markup Language , um acrônimo recursivo , para distinguir seu propósito é orientado a dados, em vez de marcação de documento.

Projeto

Sintaxe

Uma folha de dicas e especificações completas estão disponíveis no site oficial. A seguir está uma sinopse dos elementos básicos.

YAML aceita todo o conjunto de caracteres Unicode, exceto alguns caracteres de controle , e pode ser codificado em qualquer um de UTF-8 , UTF-16 ou UTF-32 . (Embora UTF-32 não seja obrigatório, é necessário que um analisador tenha compatibilidade JSON .)

  • O recuo de espaço em branco é usado para denotar a estrutura; no entanto, caracteres de tabulação não são permitidos como parte desse recuo.
  • Os comentários começam com o sinal numérico ( #), podem começar em qualquer lugar em uma linha e continuar até o final da linha. Os comentários devem ser separados de outros tokens por caracteres de espaço em branco. Se # caracteres aparecerem dentro de uma string, eles são #literais de cardinal ( ).
  • Os membros da lista são indicados por um hífen ( -) com um membro por linha.
    • Uma lista também pode ser especificada colocando o texto entre colchetes ( [...]), com cada entrada separada por uma vírgula .
  • Uma matriz associativa de entrada é representado usando cólon espaço sob a forma chave: valor com uma entrada por linha. YAML exige que os dois pontos sejam seguidos por um espaço para que os valores escalares, como http://www.wikipedia.orggeralmente, possam ser representados sem a necessidade de ser colocados entre aspas.
    • Um ponto de interrogação pode ser usado na frente de uma chave, no formato "? Chave: valor" para permitir que a chave contenha travessões iniciais, colchetes, etc., sem aspas.
    • Uma matriz associativa também pode ser especificada por texto entre chaves ( {...}), com as chaves separadas dos valores por dois pontos e as entradas separadas por vírgulas (os espaços não são necessários para manter a compatibilidade com JSON).
  • Strings (um tipo de escalar em YAML) são normalmente sem aspas , mas podem ser colocadas entre aspas duplas ( ") ou aspas simples ( ').
    • Entre aspas duplas, os caracteres especiais podem ser representados com sequências de escape no estilo C começando com uma barra invertida ( \). De acordo com a documentação, o único escape octal suportado é \0.
    • Entre aspas simples, a única sequência de escape suportada é uma aspa simples dupla ( ''), denotando a própria aspa simples como em 'don''t'.
  • Os escalares de bloco são delimitados com indentação com modificadores opcionais para preservar ( |) ou dobrar ( >) novas linhas.
  • Vários documentos em um único fluxo são separados por três hifens ( ---).
    • Três pontos ( ...) opcionalmente encerram um documento em um fluxo.
  • Os nós repetidos são inicialmente denotados por um " e" comercial ( &) e, posteriormente, referenciados por um asterisco ( *).
  • Os nós podem ser rotulados com um tipo ou tag usando um ponto de exclamação duplo ( !!) seguido por uma string, que pode ser expandida em um URI.
  • Os documentos YAML em um fluxo podem ser precedidos por 'diretivas' compostas por um sinal de porcentagem ( %) seguido por um nome e parâmetros delimitados por espaço. Duas diretivas são definidas em YAML 1.1:
    • A diretiva% YAML é usada para identificar a versão de YAML em um determinado documento.
    • A diretiva% TAG é usada como um atalho para prefixos URI. Esses atalhos podem então ser usados ​​em tags de tipo de nó.

Dois caracteres de sigilo adicionais são reservados em YAML para possível especificação futura: o sinal de arroba ( @) e crase ( `).

Componentes básicos

YAML oferece um estilo "in-line" para denotar matrizes e listas associativas. Aqui está uma amostra dos componentes.

O formato de bloco convencional usa um hífen + espaço para iniciar um novo item na lista.

--- # Favorite movies
- Casablanca
- North by Northwest
- The Man Who Wasn't There

O formato embutido opcional é delimitado por vírgula + espaço e colocado entre colchetes (semelhante ao JSON ).

--- # Shopping list
[milk, pumpkin pie, eggs, juice]

As chaves são separadas dos valores por dois pontos + espaço. Blocos recuados, comuns em arquivos de dados YAML, usam recuo e novas linhas para separar os pares chave / valor. Blocos embutidos, comuns em fluxos de dados YAML, usam vírgula + espaço para separar os pares de chave / valor entre colchetes.

--- # Indented Block
  name: John Smith
  age: 33
--- # Inline Block
{name: John Smith, age: 33}

Strings não requerem aspas. Existem duas maneiras de escrever strings de várias linhas, uma preservando as novas linhas (usando o |caractere) e outra que dobra as novas linhas (usando o >caractere), ambas seguidas por um caractere de nova linha.

data: |
   There once was a tall man from Ealing
   Who got on a bus to Darjeeling
       It said on the door
       "Please don't sit on the floor"
   So he carefully sat on the ceiling

Por padrão, o recuo inicial (da primeira linha) e o espaço em branco final são removidos, embora outro comportamento possa ser especificado explicitamente.

data: >
   Wrapped text
   will be folded
   into a single
   paragraph

   Blank lines denote
   paragraph breaks

O texto dobrado converte novas linhas em espaços e remove os espaços em branco à esquerda.

--- # The Smiths
- {name: John Smith, age: 33}
- name: Mary Smith
  age: 27
- [name, age]: [Rae Smith, 4]   # sequences as keys are supported
--- # People, by gender
men: [John Smith, Bill Jones]
women:
  - Mary Smith
  - Susan Williams

Objetos e listas são componentes importantes no yaml e podem ser misturados. O primeiro exemplo é uma lista de objetos de valor-chave, todas pessoas da família Smith. O segundo os lista por gênero; é um objeto de valor-chave que contém duas listas.

Componentes avançados

Dois recursos que distinguem o YAML dos recursos de outras linguagens de serialização de dados são estruturas e tipos de dados.

As estruturas YAML permitem o armazenamento de vários documentos em um único arquivo, o uso de referências para nós repetidos e o uso de nós arbitrários como chaves.

Para maior clareza, compactação e evitar erros de entrada de dados, o YAML fornece âncoras de nó (usando &) e referências (usando *). As referências à âncora funcionam para todos os tipos de dados (consulte a referência de envio no exemplo abaixo).

Abaixo está um exemplo de fila em um sequenciador de instrumentos em que duas etapas são reutilizadas repetidamente sem serem totalmente descritas a cada vez.

--- # Sequencer protocols for Laser eye surgery
- step:  &id001                  # defines anchor label &id001
    instrument:      Lasik 2000
    pulseEnergy:     5.4
    pulseDuration:   12
    repetition:      1000
    spotSize:        1mm

- step: &id002
    instrument:      Lasik 2000
    pulseEnergy:     5.0
    pulseDuration:   10
    repetition:      500
    spotSize:        2mm
- step: *id001                   # refers to the first step (with anchor &id001)
- step: *id002                   # refers to the second step
- step: *id002

A tipagem explícita de dados raramente é vista na maioria dos documentos YAML, pois o YAML detecta automaticamente os tipos simples. Os tipos de dados podem ser divididos em três categorias: principal, definido e definido pelo usuário. Core são aqueles que se espera que existam em qualquer analisador (por exemplo, floats, ints, strings, listas, mapas, ...). Muitos tipos de dados mais avançados, como dados binários, são definidos na especificação YAML, mas não são compatíveis com todas as implementações. Finalmente, YAML define uma maneira de estender as definições de tipo de dados localmente para acomodar classes, estruturas ou primitivas definidas pelo usuário (por exemplo, flutuadores de precisão quádrupla).

YAML detecta automaticamente o tipo de dados da entidade, mas às vezes alguém deseja converter o tipo de dados explicitamente. A situação mais comum é quando uma string de palavra única que se parece com um número, booleano ou tag requer a desambiguação ao colocá-la entre aspas ou usando uma tag de tipo de dados explícita.

---
a: 123                     # an integer
b: "123"                   # a string, disambiguated by quotes
c: 123.0                   # a float
d: !!float 123             # also a float via explicit data type prefixed by (!!)
e: !!str 123               # a string, disambiguated by explicit type
f: !!str Yes               # a string via explicit type
g: Yes                     # a boolean True (yaml1.1), string "Yes" (yaml1.2)
h: Yes we have No bananas  # a string, "Yes" and "No" disambiguated by context.

Nem toda implementação de YAML tem todos os tipos de dados definidos por especificação. Esses tipos embutidos usam um prefixo de sigilo de exclamação dupla ( !!). Particularmente interessantes não mostrados aqui são conjuntos, mapas ordenados, carimbos de data / hora e hexadecimais. Aqui está um exemplo de dados binários codificados em base64 .

---
picture: !!binary |
  R0lGODdhDQAIAIAAAAAAANn
  Z2SwAAAAADQAIAAACF4SDGQ
  ar3xxbJ9p0qa7R0YxwzaFME
  1IAADs=

Muitas implementações de YAML podem oferecer suporte a tipos de dados definidos pelo usuário para serialização de objetos. Os tipos de dados locais não são tipos de dados universais, mas são definidos no aplicativo usando a biblioteca do analisador YAML. Os tipos de dados locais usam um único ponto de exclamação ( !).

---
myObject: !myClass { name: Joe, age: 15 }

Exemplo

A hierarquia da estrutura de dados é mantida por recuo de contorno.

---
receipt:     Oz-Ware Purchase Invoice
date:        2012-08-06
customer:
    first_name:   Dorothy
    family_name:  Gale

items:
    - part_no:   A4786
      descrip:   Water Bucket (Filled)
      price:     1.47
      quantity:  4

    - part_no:   E1628
      descrip:   High Heeled "Ruby" Slippers
      size:      8
      price:     133.7
      quantity:  1

bill-to:  &id001
    street: |
            123 Tornado Alley
            Suite 16
    city:   East Centerville
    state:  KS

ship-to:  *id001

specialDelivery:  >
    Follow the Yellow Brick
    Road to the Emerald City.
    Pay no attention to the
    man behind the curtain.
...

Observe que as cadeias de caracteres não exigem delimitação entre aspas. O número específico de espaços no recuo não é importante, desde que os elementos paralelos tenham a mesma justificação à esquerda e os elementos aninhados hierarquicamente sejam recuados ainda mais. Este documento de exemplo define uma matriz associativa com 7 chaves de nível superior: uma das chaves, "itens", contém uma lista de 2 elementos, cada elemento sendo ele próprio uma matriz associativa com chaves diferentes. Dados relacionais e remoção de redundância são exibidos: o conteúdo da matriz associativa "enviar para" é copiado do conteúdo da matriz associativa "faturada para" conforme indicado pelos rótulos âncora ( &) e referência ( *). Linhas em branco opcionais podem ser adicionadas para legibilidade. Vários documentos podem existir em um único arquivo / fluxo e são separados por ---. Um opcional ...pode ser usado no final de um arquivo (útil para sinalizar um fim em comunicações em fluxo sem fechar o tubo).

Recursos

Delimitação recuada

Como o YAML depende principalmente da indentação do contorno para a estrutura, ele é especialmente resistente à colisão do delimitador . A insensibilidade do YAML a aspas e colchetes em valores escalares significa que se pode incorporar documentos XML, JSON ou até mesmo YAML dentro de um documento YAML simplesmente recuando-o em um literal de bloco (usando |ou >):

---
example: >
        HTML goes into YAML without modification
message: |

        <blockquote style="font: italic 1em serif">
        <p>"Three is always greater than two,
           even for large values of two"</p>
        <p>--Author Unknown</p>
        </blockquote>
date: 2007-06-01

YAML pode ser colocado em JSON citando e escapando todas as aspas internas. YAML pode ser colocado em XML por escapar caracteres reservados ( <, >, &, ', ") e a conversão de espaços em branco, ou colocando-o em um CDATA secção.

Modelos de dados não hierárquicos

Ao contrário do JSON, que só pode representar dados em um modelo hierárquico com cada nó filho tendo um único pai, YAML também oferece um esquema relacional simples que permite que repetições de dados idênticos sejam referenciados a partir de dois ou mais pontos na árvore, em vez de inseridos redundantemente em esses pontos. Isso é semelhante ao recurso IDREF integrado ao XML. O analisador YAML então expande essas referências nas estruturas de dados totalmente preenchidas que elas implicam quando lidas, portanto, qualquer programa que esteja usando o analisador não precisa estar ciente de um modelo de codificação relacional, ao contrário dos processadores XML, que não expandem as referências. Essa expansão pode melhorar a legibilidade enquanto reduz os erros de entrada de dados em arquivos de configuração ou protocolos de processamento onde muitos parâmetros permanecem os mesmos em uma série sequencial de registros, enquanto apenas alguns variam. Um exemplo é que os registros de "envio para" e "cobrança" em uma fatura são quase sempre os mesmos dados.

Considerações práticas

YAML é orientado por linha e, portanto, muitas vezes é simples converter a saída não estruturada de programas existentes para o formato YAML, mantendo muito da aparência do documento original. Como não há tags de fechamento, colchetes ou aspas para equilibrar, geralmente é fácil gerar YAML bem formado diretamente de instruções de impressão distribuídas em programas não sofisticados. Da mesma forma, os delimitadores de espaço em branco facilitam a filtragem rápida e suja de arquivos YAML usando os comandos orientados por linha em grep, AWK, Perl, Ruby e Python.

Em particular, ao contrário das linguagens de marcação, pedaços de linhas YAML consecutivas tendem a ser documentos YAML bem formados. Isso torna muito fácil escrever analisadores que não precisam processar um documento em sua totalidade (por exemplo, balanceamento de tags de abertura e fechamento e navegação de caracteres entre aspas e escapados) antes de começarem a extrair registros específicos dentro dele. Essa propriedade é particularmente conveniente ao iterar em uma única passagem sem estado, sobre os registros em um arquivo cuja estrutura de dados inteira é muito grande para ser mantida na memória ou para a qual reconstituir a estrutura inteira para extrair um item seria proibitivamente caro.

Contra-intuitivamente, embora sua delimitação recuada possa parecer complicar hierarquias profundamente aninhadas, YAML lida com recuos tão pequenos quanto um único espaço e isso pode atingir uma compactação melhor do que as linguagens de marcação. Além disso, o recuo extremamente profundo pode ser evitado por completo: 1) revertendo para o "estilo inline" (ou seja, formato semelhante a JSON) sem o recuo; ou 2) usando âncoras relacionais para desenrolar a hierarquia para uma forma plana que o analisador YAML reconstituirá de forma transparente na estrutura de dados completa.

Segurança

YAML é puramente uma linguagem de representação de dados e, portanto, não tem comandos executáveis. Embora a validação e a análise segura sejam inerentemente possíveis em qualquer linguagem de dados, a implementação é uma armadilha tão notória que a falta de uma linguagem de comando associada ao YAML pode ser um benefício de segurança relativo.

No entanto, YAML permite tags específicas do idioma para que objetos locais arbitrários possam ser criados por um analisador que ofereça suporte a essas tags. Qualquer analisador YAML que permite a execução de uma instância sofisticada de objetos abre o potencial para um ataque de injeção. Os analisadores Perl que permitem o carregamento de objetos de classes arbitrárias criam os chamados valores "abençoados". Usar esses valores pode desencadear um comportamento inesperado, por exemplo, se a classe usa operadores sobrecarregados. Isso pode levar à execução de código Perl arbitrário.

A situação é semelhante para analisadores Python ou Ruby. De acordo com a documentação PyYAML:

Observe que a capacidade de construir um objeto Python arbitrário pode ser perigosa se você receber um documento YAML de uma fonte não confiável, como a Internet. A função yaml.safe_loadlimita essa capacidade a objetos Python simples, como inteiros ou listas. [...]

PyYAML permite que você construa um objeto Python de qualquer tipo. Até mesmo instâncias de classes Python podem ser construídas usando a !!python/objecttag.

Processamento e representação de dados

A especificação YAML identifica um documento de instância como uma "Apresentação" ou "fluxo de caracteres". As estruturas lógicas primárias em um documento de instância YAML são escalares, sequências e mapeamentos. A especificação YAML também indica algumas restrições básicas que se aplicam a essas estruturas lógicas primárias. Por exemplo, de acordo com a especificação, as chaves de mapeamento não possuem um pedido. Em todos os casos em que a ordem dos nós é significativa, uma sequência deve ser usada.

Além disso, ao definir a conformidade para processadores YAML, a especificação YAML define duas operações principais: despejar e carregar . Todos os processadores compatíveis com YAML devem fornecer pelo menos uma dessas operações e, opcionalmente, ambas. Finalmente, a especificação YAML define um modelo de informação ou "gráfico de representação", que deve ser criado durante o processamento das operações de despejo e carregamento , embora essa representação não precise ser disponibilizada ao usuário por meio de uma API.

Comparação com outros formatos de serialização

Comparação com JSON

A sintaxe JSON é uma base do YAML versão 1.2, que foi promulgado com o propósito expresso de trazer o YAML "em conformidade com JSON como um subconjunto oficial". Embora as versões anteriores do YAML não fossem estritamente compatíveis, as discrepâncias raramente eram perceptíveis e a maioria dos documentos JSON podem ser analisados ​​por alguns analisadores YAML, como o Syck. Isso ocorre porque a estrutura semântica do JSON é equivalente ao "estilo embutido" opcional de escrever YAML. Embora as hierarquias estendidas possam ser escritas em estilo embutido como JSON, este não é um estilo YAML recomendado, exceto quando ajuda na clareza.

YAML tem muitos recursos adicionais ausentes no JSON, incluindo comentários, tipos de dados extensíveis, âncoras relacionais, strings sem aspas e tipos de mapeamento que preservam a ordem das chaves.

Comparação com TOML

Por um lado, YAML é muito mais complexo em comparação com TOML - a especificação YAML foi apontada como tendo 23.449 palavras, enquanto a especificação TOML tinha apenas 3.339 palavras. Por outro lado, YAML é menos prolixo, mais SECO , sintaticamente menos ruidoso e a hierarquia de um documento é óbvia pelo recuo.

Comparação com XML

YAML carece da noção de atributos de tag que são encontrados em XML. Em vez disso, YAML tem declarações de tipo extensível (incluindo tipos de classe para objetos).

O próprio YAML não tem descritores de esquema de documento definidos por linguagem XML que permitem, por exemplo, a autovalidação de um documento. No entanto, existem várias linguagens de descritor de esquema definidas externamente para YAML (por exemplo , Doctrine , Kwalify e Rx) que cumprem essa função. Além disso, a semântica fornecida pelas declarações de tipo definido por linguagem do YAML no próprio documento YAML frequentemente diminui a necessidade de um validador em situações simples e comuns. Além disso, YAXML , que representa estruturas de dados YAML em XML, permite que importadores de esquema XML e mecanismos de saída como XSLT sejam aplicados a YAML.

A comparação de formatos de serialização de dados fornece uma comparação mais abrangente de YAML com outros formatos de serialização.

Software (emissores e analisadores)

Para estruturas de dados fixas, os arquivos YAML podem simplesmente ser gerados usando comandos de impressão que gravam os dados e a decoração específica de YAML. Para despejar dados hierárquicos variáveis ​​ou complexos, no entanto, um emissor YAML dedicado é preferível. Da mesma forma, arquivos YAML simples (por exemplo, pares de valores-chave) são prontamente analisados ​​com expressões regulares. Para estruturas de dados mais complexas ou variáveis, um analisador YAML formal é recomendado.

Existem emissores e analisadores YAML para muitas linguagens populares. A maioria deles é escrita na própria língua nativa. Alguns são ligações de linguagem da biblioteca C libyaml ; eles podem correr mais rápido. Costumava haver outra biblioteca C, chamada Syck , escrita e órfã pelo motivo do sortudo ficar duro : ela não tem manutenção, não há pacote de fontes autorizadas e o site foi sequestrado. Portanto, a única biblioteca C recomendável é libyaml . Foi originalmente desenvolvido por Kirill Simonov. Em 2018, o desenvolvimento foi retomado pelos novos mantenedores Ian Cordasco e Ingy döt Net .

Os programadores C ++ podem escolher entre a biblioteca C libyaml e a biblioteca C ++ libyaml-cpp . Ambos têm bases de código completamente independentes e APIs completamente diferentes . A biblioteca libyaml-cpp ainda tem um número de versão principal 0, indicando que a API pode mudar a qualquer momento, como aconteceu de fato após a versão 0.3. Existe uma implementação focada na gramática escrita em C #, com o objetivo de extensões para os elementos aninhados.

Algumas implementações de YAML, como o YAML.pm de Perl, carregam um arquivo inteiro (fluxo) e o analisa em massa . Outras implementações como PyYaml são preguiçosas e iteram sobre o próximo documento apenas mediante solicitação. Para arquivos muito grandes, nos quais se planeja lidar com os documentos de forma independente, instanciar todo o arquivo antes do processamento pode ser proibitivo. Assim, em YAML.pm, ocasionalmente é necessário dividir um arquivo em documentos e analisá-los individualmente. YAML torna isso fácil, pois isso requer simplesmente a divisão no marcador final do documento, que é definido como três pontos em uma linha por si só. Este marcador é proibido no conteúdo.

Crítica

YAML foi criticado por seus espaços em branco significativos , recursos confusos, padrões inseguros e sua especificação complexa e ambígua:

  • Os arquivos de configuração podem executar comandos ou carregar conteúdos sem que os usuários percebam.
  • Editar arquivos YAML grandes é difícil, pois erros de indentação podem passar despercebidos.
  • A autodetecção de tipo é uma fonte de erros. Por exemplo, sem aspas Yese NOsão convertidos em booleanos; os números da versão do software podem ser convertidos em flutuantes.
  • Arquivos truncados são frequentemente interpretados como YAML válido devido à ausência de terminadores.
  • A complexidade do padrão levou a implementações inconsistentes e tornando a linguagem não portátil.

As falhas percebidas e a complexidade do YAML levaram ao surgimento de alternativas mais rígidas, como StrictYAML e NestedText .

Veja também

Referências

links externos