Olá mundo com uma torção


17

Seu objetivo : escrever um pedaço de código que resultará no resultado clássico de "Olá, mundo!" sendo impresso em STDOUT ou equivalente.

Regras : O código deve estar inteiramente impresso ASCII. Todo o código deve estar funcional - a remoção de qualquer caractere de contagem único deve alterar o resultado ou fazer com que o código não funcione. Todas as variáveis ​​devem ser usadas após a atribuição. Literais de caracteres e cadeias devem ser necessários para a saída - ou seja, a substituição de qualquer literal de caractere ou qualquer caractere dentro de uma literal de cadeia por outro caractere deve ser capaz de alterar o resultado (e não via efeito da sequência de escape - substituindo caractere por barra invertida ou equivalente)

(NOTA: a regra final foi editada em)

Pontuação : é aqui que fica interessante. A pontuação mais alta ganha conforme determinado pelo número de caracteres, de acordo com as regras típicas do boliche de código. Mas o uso repetido de caracteres resultará em deduções de pontos. Especificamente...

  1. O uso repetido de qualquer caractere alfanumérico (az, AZ, 0-9) resultará em uma dedução de 3 pontos por repetição (o primeiro uso não resulta em dedução).
  2. O uso repetido da pontuação básica ([!? .-, ": ';]) - incluindo os colchetes - resultará em uma dedução de 2 pontos por repetição.
  3. O uso repetido de outros caracteres ASCII {`~ @ # $% ^ & * _ + = | \ /> <} - incluindo os colchetes - resultará em uma dedução de 4 pontos por repetição.
  4. O uso repetido de espaços, tabulações e novas linhas resultará em uma dedução de 1 ponto por repetição. Ou seja, apenas o primeiro uso de um espaço, guia ou nova linha contará para o seu total.

Nota: os comentários não contam para o total, apesar dos caracteres que marcam o início / fim de um comentário. Por exemplo, em C / C ++, se você tiver /* This is a comment */, ele contará duas barras e dois asteriscos, mas nada entre eles.

Alguns exemplos (nota: usando Julia como linguagem de exemplo) ...

print("Hello, world!");

Total de caracteres visíveis: 22
Contém espaço: +1
Alfanuméricos repetidos: -12 para llor Pontuação
repetida: -2 para "
Pontuação final: 22 + 1-12-2 = 9

print("Hel",char(108),"o, wor",0x108,"d!"); # 0x108 makes a Uint8 that prints as ASCII

Total de caracteres: 43 (não conta nenhum caractere depois de #, que é o caractere de comentário)
Contém espaço: +1
Alfanuméricos repetidos: -18 para rr1008 Pontuação
repetida: -24 para () "" "" ",,,,,
Final pontuação: 43 + 1-24-18 = 2

xy=STDOUT
m="Hello, world!"
print(xy,m);

Total de caracteres visíveis: 37
Contém nova linha: +1
Contém espaço: +1
Alfanuméricos repetidos: -18 para xyllor Pontuação
repetida: -4 para ",
outro ASCII repetido: -4 para =
Pontuação final: 37 + 1 + 1-18-4 -4 = 13

Alguns códigos inválidos ...

x=2;print("Hello,world!")  

Problema: xestá atribuído, mas não usado.

print("Hello,"*" world!")  

Problema: *é desnecessário, o resultado será o mesmo sem ele.

k=1
if k>0
  print("Hello, world!")
else
  print("abcghjmquvxyzABCDEFGIJKLMNOPQRSTUVWXYZ_+*-&|")
end  

Problema: O segundo printcomando não será executado. Além disso, a remoção de caracteres entre aspas no segundo printcomando não altera a saída.

x="Hello, world!";
print(x)  

Problema: a remoção da nova linha não altera o resultado ou causa o erro (em Julia, ponto e vírgula é necessário apenas se vários comandos estiverem na mesma linha, caso contrário, apenas suprime o valor de retorno).

print("Hellos\b, world!")  

Problema: o spersonagem não afeta o resultado, pois é apagado \b. Isso é aceitável se feito por meio de code ( "Hello",char(100),"\b, world!"), mas não pode ser feito por meio de literais de string ou de caracteres.

Calculadora de pontuação conveniente - http://jsfiddle.net/4t7qG/2/ - graças a Maçaneta



11
Isto parece relevante para a sua discussão meta.codegolf.stackexchange.com/questions/777/...
Martin Ender

3
Eu criei um JSFiddle onde você pode colocar seu código e ele automaticamente descobrirá sua pontuação. Você gostaria de editar um link para ele no post?
Maçaneta

11
@ Dennis - se o seu programa produz uma nova linha por causa do comando, não há problema (por exemplo, println em Julia imprime e depois adiciona uma nova linha no final). Mas não deve fazer parte da cadeia.
Glen O

11
@ Cararter - basicamente, sim. Mas as restrições e deduções a tornam não trivial.
Glen O

Respostas:


17

Perl - 96

(Muito bom, considerando a pontuação máxima teórica de 97)

s{}[Hel0o, w3$=d!];y<"#%&'*.124578:?@BCDEFGIJKLMNOQ/-9>(
    6PRSTUVWXYZ^_`abfghjmqvxz|~\cAk-u)+print

(Observe que a segunda linha começa com um \tcaractere de tabulação real )

O código tem 98 caracteres e contém todos os caracteres ASCII exatamente uma vez, mais um extra -.
98 - 2 = 96

Não há literais de string aqui, mas a remoção de qualquer caractere único interrompe o programa.

Desobuscação

Existem 3 instruções neste programa (bem, na verdade 2, mas eu abusei +como algum tipo de separador de instruções)

  1. s{}[Hel0o, w3$=d!]
    Este é um caso muito esticado do operador sed. É mais comumente escrito como s/a/b/, ou s:a:b:, mas o perl permite muito mais fantasia aqui:, s(a)(b) s(a)^b^ s(a)[b]e até mesmo s qaqbq.
    Ele substitui uma sequência vazia (interna {}) por Hel0o w360d!(interna []) ( $=interpola 60por padrão). Devido à falta de um ~=operador, ele opera $_.

  2. y<"#%&'*.124578:?@BCDEFGIJKLMNOQ/-9>(\n\t6PRSTUVWXYZ^_`abfghjmqvxz|~\cAk-u)
    Este também é um caso muito esticado, mas de um troperador, que também é chamado y( y< >( )).
    Vejamos a tabela de substituição:
    " # %&'*.124578:?@BCDEFGIJKLMNOQ /-9
    \n\t6PRSTUVWXYZ^_`abfghjmqvxz|~\cA k-u
    movi alguns caracteres para que a string existente não seja quebrada. A única parte que realmente funciona aqui é /-9-> k-u. Ele substitui 0por l, 3com oe 6com r.
    Novamente, por falta de ~=operador, ele opera. $_
    Agora, temos a frase completa na $_variável.

  3. print
    A falta de argumentos faz com que ela imprima apenas a $_variável.


Não conheço Perl o suficiente para comentar sobre isso - qual é o conjunto de caracteres entre o <e o + fazendo?
Glen O

@GlenO Only /-9e k-usão realmente usados ​​para transformar a string. O resto é um lixo de tamanho igual . Se você remover apenas um caractere, os conjuntos ficarão desalinhados e o programa não exibirá "Olá, mundo!" não mais.
Mniip

Nesse caso, de que maneira o "lixo" está sendo executado? Ou seja, de que maneira é funcional? Se é apenas um preenchedor que é ignorado pelo código, é equivalente a um código não em execução dentro de uma condicional.
Glen O

3
@GlenO Não é. Para as especificações: a <...> removal of any single counting character must change the result or cause the code to not function.remoção de 1 caractere em qualquer lugar o quebra. Você pode fazer isso removendo 2 caracteres, mas isso não está nas regras.
Mniip

2
All code must be functional. Você está claramente dobrando as regras, no mínimo. Não estou dizendo "isso quebra as regras", mas é definitivamente questionável.
Glen O

7

Esta resposta foi criada antes da adição da regra sobre literais de strings e não participa do concurso.

#include <iostream>
int main(){std::cout<<56+"  !$%^&*?12347890-_QWERTYUIOPASDFGJKLZXVBNM,.qypfghjk:zvbHel\x6Co, world!";}

É completamente legítimo. : P Se você remover qualquer caractere dessa sequência, ela será impressa ello, world!.


Inclua a pontuação do seu código na sua resposta.
precisa

Também não mudará sua pontuação, mas os espaços ao redor <<precisam ser removidos.
Martin Ender

11
Hmmm ... enquanto aplaudo sua resposta, ela revelou principalmente um pequeno buraco nas minhas restrições. Vou dar um voto positivo e fico feliz que outras pessoas façam o mesmo, se quiserem, mas estarei editando em uma restrição adicional.
Glen O

11
OK, além do meu comentário anterior, agora adicionei uma restrição declarando que os literais de seqüência de caracteres e caracteres devem ser relevantes - a substituição de caracteres dentro deles deve ser capaz de alterar o resultado. Isso permite if 'x'>'w'técnicas, mas bloqueia "k \ bH" para resultar em "H", por exemplo. Sinta-se livre para contribuir com uma segunda resposta após a restrição adicionada.
Glen O

4

CJam, 94

{'H"EJO, WoRLD!"el96A+c/~_-3=0$@}"# 
`&^<>|;:?.()[]\1aBCdfFgGhiIjkKmMnNpPqQrsStTuUvVwxXyYzZ"254b87%*

Experimente online! Observe que deve haver um tabulador antes do avanço de linha. O SE não gosta de tabuladores, então você terá que inseri-lo manualmente.

  • 100 caracteres
  • alnum repetido: -0 ()
  • pontuação repetida: -6 ("" ")
  • outro repetido: -0 ()
  • espaço em branco repetido: -0 ()

Pontuação total: 94

Eu usei o código a seguir para verificar se nenhum dos caracteres dentro da string pode ser removido:

"#  
`&^<>|;:?.()[]\1aBCdfFgGhiIjkKmMnNpPqQrsStTuUvVwxXyYzZ"
:A,,{_A\<A@)>+254b87%}%`

Ele imprime uma matriz mostrando o número de vezes Olá, mundo! seria impresso se o caractere correspondente ao índice fosse removido.


Quando eu o executo no seu link, ele produz "Olá, mundo!" seis vezes seguidas. Além disso, o que a cadeia de caracteres está fazendo?
Glen O

Acho que a nova linha é o erro - removê-la faz com que funcione.
Glen O

Problema de copiar e colar. Deve haver um tabulador logo antes do LF. Parece que o SE não me permite fazer isso ... A string é considerada um número base-254 ( 254b). O módulo de resultado final 7 deve ser 1, para que o bloco de código anterior seja executado uma vez. Vou precisar de um módulo para tornar cada personagem necessário.
Dennis

Bem, depois de adicionar a guia ausente (que "corrige" o código), remover o Z, o Tou provavelmente alguns outros caracteres não altera o resultado.
Glen O

Eu interpretei terrivelmente uma parte da sua pergunta. Está consertado agora.
Dennis

3

Ruby, 28 41

Apenas para começar as respostas com uma solução no espírito da pergunta:

print"He#{?l*2}o, "+'world!'if[$`&(9<=>6)^7|~8-5/3.1%0x4]

Pontuação (acho que entendi direito):

  • 57 caracteres
  • alnum repetido: -12 ( orli)
  • pontuação repetida: -4 ( "')
  • outro repetido: -0
  • espaço em branco repetido: -0

Parece bom para mim, em termos de pontuação. Não é necessário incluir penalidades que não se aplicam, mas não prejudica a inclusão delas.
Glen O

O .no 3.1pode ser removido sem problema. Como pode o xem0x4 ou o- in 8-5.

3

PHP, 1 (sim, um ponto!)

Usando caracteres mágicos para gerar uma soma de verificação, que na forma binária corresponde a "Inferno", "o, w", "orld" e "!".

Normalmente, gosto de encontrar brechas, mas desta vez decidi jogar de acordo com o espírito e a intenção do concurso. Todo personagem e sua posição são essenciais para a saída. Os únicos lugares que você pode substituir são nomes de variáveis ​​que não são valores literais, o espaço em branco entre phpe foreachque PHPtrata como equivalente e o uso de 'vs "que PHPtrata como semelhante.

<?php foreach(array('_MC:`~+V4@SbHR/l[J','dN#UB`5!Rv^NG@D}','9gm6L&-kuD','8OM97g.q]XQ0')as$j)print(hash("crc32",$j,1))?>

Para sua informação, estas são algumas outras seqüências mágicas e hashes de interesse:

E.D}S:  Hell
9UDIRQ: Hell
N\7&*`%:    orld
UWX[E^O:    orld
mAHzDEb:    !   
uLJ7Ck&:    Hell
B+bG5mYJ:   Hell
:OvMzuOR:   !   
TgYR9g!6k:  o, w
NkFN`!8mI:  o, w
N#VA\j~}J[: Hell
vEl*]@0XQ5: o, w
9gm6L&-kuD: orld
*}{Xg@HN`\: !   
Pj@Y44uA6YJ:    Hell
|7OX0VF8gv}:    !   
DLRJAjgMj}\:    !   
!0bT*D}O4Lw:    orld
YGN97^v7ZY`:    Hell
++~bL/kP:|]W:   o, w
8OM97g.q]XQ0:   !   
l^m-DqZ^g[&+:   !   
Ewu]Rv~*DHQ7:   Hell
JIqjgF|S!\`8l:  Hell
b4l!MEG7vTu6/:  Hell
+B:zEq*J\k-Cm:  !   
_}E7wZD76^`Y9AU:    orld
q:Nq-~+_S7~N9Hz:    !   

As funções ainda código se eu remover o \t, \nou o espaço. Não é um especialista em PHP, mas ;parece opcional também.
mniip

@mniip - Edições feitas. Eu não sabia que o ponto e vírgula era opcional em alguns casos.

3

Befunge-98 , 97 pontos!

"v!dlrow ,h
B[CDEFGIJkLMNOPH
$<QRSTUV@|5cg1fe':-%\64*ab+7_/89}{0  j2
WXYZK`.=#>]
s()impq	n 3~
Atuxz&;y^ ?

Experimente online!

A guia está entre o qe o n.

Usa um truque semelhante à resposta anterior do Befunge para preencher as linhas com os caracteres restantes, mas evita o uso de caracteres duplicados na seção de execução. A remoção de qualquer um dos caracteres não executados resulta no deslocamento das partes em execução, geralmente terminando em loops infinitos ou imprimindo a saída incorreta.

Como funciona

Realmente, a única parte executada se parece com:

"v!dlrow ,h
         k     H
$<      @|5cg1fe':-%\64*ab+7
         >]
        ^ ?

Primeiro, ele usa uma cadeia de caracteres literal para adicionar , world!à pilha. Isso evita dois" s.

$<      @|5cg1fe':-%\64*ab+7

Isso adiciona Helloà pilha usando uma variedade de métodos para evitar caracteres duplicados. $aparece o excesso de espaço causado pelo literal da string de quebra automática.

7+adiciona 7 ao hfinal do literal da string para criar o o . ba*46\%:calcula 111, o valor ascii de le o duplica.

'e adiciona e à pilha.

f1g recebe o personagem em 1,15, que é o H

Em seguida, reutiliza a ,sequência para imprimir o todo Hello, world!. O resto são apenas mudanças de direção para navegar até o final @.


1

Ruby, 78

Mais regras abusam, eu acho, sem saber exatamente qual seria o patch. Utiliza uma sequência longa e verifica a soma do resultado; portanto, qualquer exclusão ou alteração fará com que o programa falhe. Provavelmente poderia ser otimizado um pouco para remover a duplicação de algumas letras e obter espaço em branco.

puts('Hello, world!')if%["\#$&*+-/:;<>?@ABCDEFGIJKLMNOPQRSTUVWXYZ^_`abcghjknqvxyz{|}~123].sum==4980

3
O problema é que tudo depois e incluindo o ifpode ser removido.
seequ

@ TheRare - nada de errado com isso, desde que ifele realmente funcione e as coisas depois que ainda obedeçam às regras.
Glen O

@GlenO Mas não é contado como "código removível"? Apenas puts('Hello, world!')funcionaria. Eu acho que as regras precisam esclarecer se isso é legítimo.
seequ

@ TheRare - em retrospectiva, eu provavelmente deveria ter usado uma varredura "um subconjunto do código não deveria ser capaz de produzir a mesma saída", mas acho que não devo continuar alterando as regras. Como estão, desde que o código seja funcional e não arbitrário e siga as outras regras, é legítimo. No mínimo, esse método de solução não é possível na maioria dos idiomas (a edição que fiz encerrou uma brecha que funciona na maioria dos idiomas).
Glen O

@GlenO Você é o juiz. Apenas peça para excluir esses comentários, se achar desnecessários.
seequ

1

PHP, 2257

Brecha: a barra invertida foi omitida nas especificações e na calculadora de pontuação!

Esse código conta o número de ocorrências de barras invertidas em cada sequência e imprime um equivalente ASCII. Substituir qualquer barra invertida por outro caractere ou excluir uma barra invertida causa um erro de análise ou altera o resultado.

Um recurso interessante sobre barras invertidas e PHPé que elas precisam ser escapadas, para que dobre a pontuação automaticamente! Você pode dobrar, triplicar, etc., a pontuação multiplicando o número de barras invertidas, mas não queria ser ganancioso, e acho que pode exceder os limites do que você pode inserir.

<?php foreach(array('\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\','\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\','\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\','\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\','\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\','\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\','\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\','\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\','\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\','\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\','\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\','\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\','\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\')as$x)print(chr(substr_count($x,"\\")))?>

É claramente nada mais que um erro de digitação na descrição, não uma brecha. Além do mais, você já sabia disso. A descrição diz explicitamente "outros caracteres ASCII". Quando você ler isso, ele será editado para incluí-lo.
Glen O

Em particular, a barra invertida estava na fonte da pergunta, mas eu não tinha percebido que a havia tratado como uma sequência de escape.
Glen O

Isso não é uma mudança nas regras, está corrigindo um erro de digitação menor. A barra invertida estava nas regras, apenas não estava sendo exibida (para ver isso por si mesmo, clique no botão "editado" e depois em "marcação lado a lado"). E os outros não estão explorando brechas, estão explorando recursos de seus idiomas.
Glen O

1

Befunge - 87

"dlrow ,olleH"bk,                                                                   v
!#$%&'()*+-./0123456789:;  <=>?ABCDEFGIJKLMNOPQRSTUVWXYZ[\]^_`acfghijmnpqstuvxyz{|}~@

A primeira linha vale quatro pontos devido a toda a repetição, mas não há caracteres duplicados na segunda linha. A única string literal neste código é dlrow ,olleH, que é revertida e impressa como saída. A remoção de qualquer caractere desconectará ov final da primeira linha do @final da segunda, fazendo com que o programa nunca termine. Se o vpróprio for removido, o código entrará em um loop infinito imprimindo a saída correta.



0

Acc !!, -138 (e sim, isso é negativo 138)

Embora essa possa não ser exatamente a melhor pontuação que eu já recebi no PPCG, duvido que possa ser maior do que isso no Acc !!

108
Write 72
Write 101
Count i while i-2 {
	Write _
}
Write _+3
Write 44
Write 32
Write 119
Write 111
Write 114
Write _
Write 100
Write 33

Experimente online!

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.