Imprimer un négatif de votre code


100

Considérons un carré de caractères ASCII imprimables (points de code 0x20 à 0x7E) pour la longueur du côté N , comme suit (ici, N = 6 ):

=\    
 g \  
7     
m+y "g
  L ~ 
e> PHq

Nous avons également besoin que chaque ligne et chaque colonne contiennent au moins 1 caractère espace et 1 caractère non espace . (L'exemple ci-dessus le satisfait.)

Nous définissons le négatif d'un tel carré comme étant un carré de même taille, où chaque espace est remplacé par un non-espace et inversement. Par exemple, ce qui suit serait un négatif valide de l'exemple ci-dessus:

  1234
a b cd  
 ZYXWV
   !  
{} [ ] 
  ?   

Le choix des caractères non-d'espaces est sans importance (tant qu'ils appartiennent à la plage ASCII imprimable).

Le défi

Vous devez écrire un programme, avec un code source carré avec une longueur de côté N> 1 , qui affiche un négatif de lui-même sur STDOUT. Les espaces de fin doivent être imprimés. Vous pouvez ou non imprimer une nouvelle ligne de fin.

Les règles habituelles de quine s'appliquent également, vous ne devez donc pas lire votre propre code source, directement ou indirectement. De même, vous ne devez pas assumer un environnement REPL, qui imprime automatiquement la valeur de chaque expression entrée.

Le gagnant est le programme avec la plus faible longueur du côté N . En cas d'égalité, la soumission contenant le moins de caractères non espaces du code source l'emporte. S'il y a toujours égalité, la première réponse l'emporte.


La valeur de retour d'une fonction est-elle acceptée ou doit-elle être imprimée sur STDOUT?
Paul Guyot

1
@PaulGuyot Pour ce défi, veuillez vous en tenir aux programmes complets et à STDOUT (en tant que variante quine).
Martin Ender

Vous devez préciser que la taille du tableau doit être N> 0 . Je vois que votre exemple spécifie N> 1 (et vouliez-vous dire N> = 1 ?), Mais ce n'est pas dans les règles proprement dites.
imallett

2
@imallett impliqué par "Nous avons également besoin que chaque ligne et chaque colonne contiennent au moins 1 caractère espace et 1 caractère non-espace". Attendez. Non, ce n'est pas. Bon point. Cela implique cependant que N == 0 || N> 1.
John Dvorak

1
@jpcooper Oui, c'est un carré, mais cela ne satisfait pas "Nous avons également besoin que chaque ligne et chaque colonne contiennent au moins 1 espace et 1 caractère non-espace." parce que les m premières colonnes ne contiennent pas d'espaces et que les n dernières colonnes ne contiennent pas de non-espaces.
Martin Ender

Réponses:


18

CJam, 4 x 4 (8 non-espaces)

 L _
{ _ 
 _ }
_ p 

Essayez-le en ligne dans l' interprète CJam .

Sortie

{ _ 
 _ }
{ _ 
 _ }

Comment ça fonctionne

  • Lpousse un tableau vide et _pousse une copie de celui-ci.

  • Le bloc

    { _ 
     _ }
    

    pousse ce bloc sur la pile.

  • _pousse une copie du bloc de code et l’ pimprime, suivie d’un saut de ligne.

  • Enfin, l'interprète imprime tous les éléments restants de la pile: deux tableaux vides n'affectant pas la sortie et le bloc de code d'origine.

Version alternative

 L ~
{ _ 
 p }
_ ~ 

Essayez-le en ligne dans l' interprète CJam .

Sortie

{ _ 
 p }
{ _ 
 p }

Comment ça fonctionne

  • Lpousse un tableau vide et le vide ~. La pile est à nouveau vide.

  • Le bloc

    { _ 
     p }
    

    pousse ce bloc sur la pile.

  • _pousse une copie du bloc et ~exécute la copie.

    L' _intérieur de la copie du bloc poussera une copie du bloc d'origine, qui psera imprimée, suivie d'un saut de ligne.

  • Enfin, l'interprète imprime l'élément restant sur la pile: le bloc de code d'origine.


104

Perl, 7 × 7 (42 non-espaces)

for$i( 
1..56 )
{$_= $i
%8? $i%
7? $":7
: $/;1;
 print}

Sortie:

      7
     7 
    7  
   7   
  7    
 7     
7      

10
C'est l'un des morceaux de code les plus cool que j'ai vus depuis longtemps.
Kasran

Simple et simple, mais assez ennuyeux. Encore +1.
Nova

8
Ce serait encore plus cool si elle affichait un 7fait de 7. :)
AL

1
@AL Juste besoin de 8 caractères supplémentaires (7 espaces et une nouvelle ligne).
Qix

77

CJam, 4X4 ( 12 10 non-espaces)

 6, 
SS +
* 4/
 N* 

Sortie:

0  1
  2 
 3  
4  5

Version précédente avec 12 non-espaces:

 4a4
* 4S
** 4
/N* 

Et la sortie est

4   
 4  
  4 
   4

Comme l'a souligné Martin, cette version a

  • 4 espaces,
  • 4 * ,
  • 4 4 ,
  • 4 autres personnages, et
  • 4 4 comme sortie

;)

Essayez-le en ligne ici


22
Il a également 4 votes positifs, mais je suis sur le point de gâcher cela pour vous. Pardon! :-D
ossifrage

7
Peut-être que nous pouvons l'obtenir à 44? +1 :)
Poignée de porte

4
Gardez le rythme jusqu'à 4 ^ 4
Optimizer

17
Est-ce que 4 ^ 4 == 0? ;)
zennehoy

1
Ouais, je n'aime pas le fait que bit par bit XOR ait volé le symbole qui aurait dû être utilisé pour les exposants. Réduit la lisibilité du code, honnêtement.
SuperJedi224

50

Marbelous - 16x16

....@0..@1....  
@3..0A08..@2  ..
/\--....>1  ..Hp
..@2..\\  =0@3..
ss..//  --\\\\..
@0/\  @1/\Hp..!!
:s  #the-cake-is
  2020#a-pie/lie

Testez-le ici! Les espaces vides, les panneaux cylindriques et les bibliothèques incluses doivent tous être vérifiés.

Sortie

              07
            06  
          05    
        04      
      03        
    02          
  01            
01              

Explication

Il y a deux cartes ici: la carte principale (illustrée ci-dessous) et la sscarte, qui ne prend aucune entrée et produit deux espaces (0x20) vers STDOUT.

Une cellule vide équivaut à un ..et tout ce qui suit #est un commentaire.

Image du conseil

Chaque tick, sssort deux espaces à STDOUT.

Le chemin vert est une simple boucle qui génère une nouvelle ligne (0x0A) à la fin de chaque 7ème tick.

Le chemin bleu affichera les nombres ( Hpimprime une bille sous la forme de deux chiffres hexadécimaux) présents dans la sortie, à la fin de chaque sixième tick.

Après avoir imprimé 01une fois, la boucle se termine et suit le chemin rouge qui duplique cette bille.

Un duplicata est imprimé (le second 01) et l'autre est envoyé sur le chemin noir, qui termine le tableau à la !!cellule. En raison de l'emplacement de l' Hpélément utilisé dans cette dernière impression, le 01symbole apparaît avant les deux espaces du même tick, plutôt qu'après, le comportement de tous les autres Hpappels.


9
Upvoting pour la représentation graphique de la source.
Riking

35

Python - 11x11

import re
[print(
    re.sub(
"0",   " ",
bin(x)[
2:].zfill(
11)))for x
in[19,15,
1920,116,
15,1,5,3,
3,3, 67]]

Sortie

      1  11
       1111
1111       
    111 1  
       1111
          1
        1 1
         11
         11
         11
    1    11

C'est une solution assez désordonnée et ennuyeuse, mais je pensais juste montrer que ...

  1. Cela peut être fait en Python
  2. Si vous pouvez compresser des informations sur votre code plus courtes que votre code, vous pouvez retirer quelque chose comme ceci :)

Cette solution tire parti du fait que, si vous êtes entre parenthèses en Python, vous pouvez alors scinder votre code en plusieurs lignes et ajouter des espaces de manière arbitraire sans obtenir un IndentationError. Une autre façon de procéder est de terminer la ligne par une barre oblique inversée.


33

Python - 7x7 (37 non-espaces)

print( 
'%+7s' 
'\n'%1 
*6+'%' 
'-7s'% 
111111 
      )

Sortie

      1
      1
      1
      1
      1
      1
111111 

Utilise l'ancien %opérateur de formatage de chaîne de Python pour effectuer le travail: +7et -7s'occupe de la justification droite / gauche, et du dernier espace pour faire correspondre la parenthèse fermante printen particulier. En préparant la chaîne de format, nous avons également

  • concaténation automatique des littéraux de chaîne sur plusieurs lignes, et
  • répétition de chaîne par multiplication (nous donnant plusieurs champs de remplacement pour le prix d'un)

18

JavaScript (9x9)

 i=9;q=""
; for(;++
i< 91;){;
var q=q+(
!(i% 10.0
)?1:" ");
;i%9|| (q
+="\n") }
alert(q) 

Sortie

1        
 1       
  1      
   1     
    1    
     1   
      1  
       1 
        1

Remarques

J'ai créé et joué au golf (au mieux de mes capacités) pour un carré de diagonale de toute taille n:

q="";for(i=***n***;++i<***n^2+n+1***;i%***n***||(q+="\n"))q+=i%***n+1***?"0":1

remplacement des nombres *** asdf *** par des constantes dépendant de la longueur du côté n, par exemple pour n = 6:

q="";for(i=6;++i<43;i%6||(q+="\n"))q+=i%7?" ":1

Mais, même si ce code a une longueur de 46, je ne pouvais pas obtenir l'espace constant pour s'aligner avec un espace dans la diagonale du code jusqu'à ce qu'il soit aussi gros qu'un 9x9, avec une ligne perdue (la 5ème)

Edit: Modifié pour ajouter alert (). Avant:

 i=9;q=""
; while((
++ i)<91)
{q= q+""+
""+( "")+
(!((i %10
))?1:" ")
;i%9||( q
+="\n")} 

Ahh, oui, oups, je vois ce que vous voulez dire. Je le répare maintenant, désolé.
Kuilin Li

Vous avez des variables globales unitialisées là-bas: P
Tomáš Zato

16

CJam, 5x5, 12 non-espaces

Pas un gagnant, mais je voulais ajouter une soumission plutôt petite et clairsemée , car la plupart des réponses n'imprimaient qu'une diagonale.

 1 ]
D * S
 * 5
/ N *
 1 ; 

empreintes

1 1 1
 1 1 
1 1 1
 1 1 
1 1 1

Testez-le ici.

Les deux derniers caractères du code, ne font rien, donc il n'a que 10 octets de code réel. Pour une grille plus petite, je pourrais même la réduire de deux octets supplémentaires à 8, mais cela ne tient pas en 3x3 et ce code ne fonctionne pas pour des tailles de grille uniformes.

Comment ça fonctionne:

1]           "Push [1].";
  D*         "Repeat 13 times.";
    S*       "Riffle with spaces.";
      5/     "Split into runs of five elements.";
        N*   "Join those with line breaks.";
          1; "Push and pop a 1. No-op.";

Les réponses éclatées de CJam et de Pythy sont de loin mes préférées sur le site. Avoir un vote positif, style Reddit.
Soham Chowdhury

14

Befunge , 9x9

Je ne sais pas pourquoi j'ai fait ça. Cela a pris beaucoup trop de temps. J'ai un mal de tête énorme maintenant.

8>v_20gv 
v9<^v#<4 
1@,/<>^6 
v1,*$:<p 
->,!-^87 
:^*25<^g 
_88g,^^4 
9vp\v#6< 
        @

Sortie:

        @
        @
        @
        @
        @
        @
        @
        @
$$$$$$$$ 

Quelques explications

Le code permet gde lire les @caractères de la grille "à la volée" (ainsi que l'espace final @ / 2) et pde modifier la boucle pour écrire la dernière ligne de sortie.

Chaque caractère du code est utilisé à un moment donné, sous forme de code ou de données (les 9et @les deux dernières lignes).

J'ai dû faire beaucoup de contournements pour que le code fonctionne. Le pointeur d'instruction effectue plusieurs intersections pendant l'exécution, dont certaines sont sautées. (Je ne pouvais utiliser aucune instruction là-bas pour des directions différentes car ils interviendraient. Il n'y a pas de NOP.) Ailleurs, j'ai soit réutilisé le même personnage, soit je l'ai tout simplement défait (voir $:au milieu).

J'ai aussi fait du travail créatif sur la pile:

  • Quand la boucle d'écriture de caractères (interne) se termine (tous les espaces sont faits pour cette ligne), la pile a n,0. Je dois ensuite décrémenter n. La solution évidente serait $1-, mais j'ai réussi à le raccourcir en utilisant !-.
  • Lorsque la boucle d'écriture de ligne (extérieure) se termine (toutes les lignes normales imprimées), la pile a un 0. J'ai ensuite organisé le changement de code ( 20g46p7g46\p) pour l'utiliser 0, au lieu de perdre 2 caractères $0.

Befunge obtient toujours un +1 de moi. Nice avec le !-; c'est quelque chose que je ferais. Anecdote: dans Funge-98, zc'est un NOP.
Kasran

@ Kasran ouais. zne figurait pas sur le wiki et je présente pour le codage, ce qui signifie une non-commande retournée la direction IP. Quasiment tout le monde a dû refactoriser 70% du code en raison d’un endroit qui devrait être NOP.
PurkkaKoodari

L'avantage de faire cela est que votre code fonctionnera dans Befunge-95 (ce qui, à mon avis, n'a pas de NOP non-espace) ainsi que 98; Puisqu'il est beaucoup plus difficile d'utiliser 95, j'ai toujours trouvé ces réponses très impressionnantes.
Kasran

13

Python 3, 8x8

Il y a 50 caractères non-espace et 14 espaces. La dernière ligne a un caractère inutile, mais tout le reste est nécessaire.

(*_,q,n 
)=p=''' 
       p
'''[2:] 
print(p 
*2+q*7, 
n+p*4+p 
[0:-1]) 

Sortie:

       p
       p
ppppppp 
       p
       p
       p
       p
       p

2
Juste essayé de jouer avec (a,*b,c)="12345"... cession étoilée est intéressant :)
Sp3000

@ sp3000 sorte de haskell-esque. J'utilise python beaucoup plus que haskell, comment ne pas le savoir?
undergroundmonorail

11

Ruby, 8x8

 (0...8)
. map(){
|x |$><<
32. chr*
x+[x ]*'
'<<32 .\
chr*(7 -
x)+?\n} 

Sortie:

0       
 1      
  2     
   3    
    4   
     5  
      6 
       7


9

C ++, 12x12

Edit: Donc, je suis devenu un peu obsédé par ce défi et j'ai réussi à le réduire de 17x17 à 12x12. Il m'a fallu un peu de temps pour réaliser que je pouvais utiliser /**/comme délimiteur de jeton. Ce code tire parti du fait qu'une épissure de ligne fonctionne toujours dans Clang avec un espace après, bien qu'elle donne des avertissements et ruine la colorisation du code par Xcode.

#include<c\ 
stdio>/***/ 
int/**/mai\ 
n(){for(in\ 
t/**/i=0;i\ 
<12;++i)pr\ 
intf(i^8?"\ 
           \
|\n":"~~~~\ 
~~~~~~~\x2\ 
0\n");}/**/ 

Sortie:

           |
           |
           |
           |
           |
           |
           |
           |
~~~~~~~~~~~ 
           |
           |
           |

5

Befunge-98 , 8x8 (56 non-espaces [11 nops])

Remarque: dans l’intérêt d’un bon sport sportif, cela lit sa propre source via ', ce qui en fait un tricheur pour certains. Lire le débat ici .

Programme

 07'?>:8v
v y+da:%<
<v ':vj!-
,+# '<zzv
v1#a vj!<
>z,\1 -\v
z>+,$v z<
1_@#:<v -
zzzzzv<z 

Sortie

(       
 ,      
  &     
   %    
    $   
     #  
      " 
       !

Explication

La version non-golfée

07'?>:8%:ad+y-!jv>'n,$v
  !jv   a,\1-\v > 's,  
    >         >       v
    v-1_@#:           <

(le non-espace et l'espace sont remplacés par 'n et' pour plus de lisibilité.)

Cette solution est basée sur le fait qu'en utilisant un index [0, width ^ 2) mod, la largeur du carré peut vous dire si vous êtes au bout de la ligne ou en diagonale. Comme tous les espaces sont placés le long de la diagonale, il est facile de savoir quand imprimer un non-espace!

En pseudocode

const int WIDTH = 8
push 0    //Because of the way the 'y' instruction works when picking
int row=7 //8-1 rows
int i=63  //Starting at the end allows for the cheaper i != 0
do
{
    pick variable row from the stack bottom + 1//ad+y
    if(i%WIDTH == row)
    {
        print non-space
    }
    else
    {
        print space
        if(i%WIDTH == 0)
        {
            print new-line
            --row
        }
    }
  --i
}
while(i != 0);

Discussion

J'en suis très fier, même si j'aurais aimé pouvoir transformer chaque non-espace en non-nop. Je suis également fier de ne pas avoir utilisé le trope standard Befunge get-increment-put! Il imprime différents symboles pour le non-espace parce que j'avais la place pour ça et que je ne voulais pas être ennuyeux.

Essayez-le sur Windows avec BefungeSharp !


4

CJam, 4 x 4 (8 non-espaces)

 N a
` S 
 * N
X $ 

Essayez-le en ligne dans l' interprète CJam .

Sortie

[ " 
 " ]
[ " 
 " ]

Comment ça fonctionne

  • Npousse un saut de ligne sous forme de chaîne singleton. aenveloppe cette chaîne dans un tableau.

  • ` inspecte le résultat, c'est-à-dire qu'il pousse une représentation sous forme de chaîne du tableau.

    Voici le résultat:

    ["
    "]
    
  • S*joint la chaîne résultante (tableau de caractères), en séparant ses éléments à l'aide d'espaces. En d'autres termes, il met un espace entre toutes les paires de caractères adjacents de la chaîne.

    Voici le résultat:

    [ " 
     " ]
    
  • N pousse un autre saut de ligne.

  • X$ copie l’élément de pile à l’index 1 (en partant du haut), c’est-à-dire la chaîne multiligne.

  • Enfin, l'interprète imprime tous les éléments de la pile: la chaîne multiligne d'origine, le saut de ligne et la copie de la chaîne multiligne.


4

SOGL V0.12 , 2x2 (2 non-espaces)

2 
 ╚

Essayez-le ici!

Sortie

 /
/ 

Explication

Dans SOGL, toutes les lignes, à l'exception de la dernière, sont en train de remplacer des lignes - elle remplace partout dans le code continu le dernier caractère de la ligne précédé de tout ce qui précède. SO la 1ère ligne est ici replace space with 2 in the next line.
Ensuite, la ligne suivante 2╚est exécutée: 2appuie sur 2 et crée une diagonale de taille 2.


3

CBM BASIC v2.0 (8 × 8)

Une amélioration par rapport à ma réponse précédente , utilisant une approche complètement différente:

1s=56/8 
2?sP7); 
3?"?":: 
4s=s-+1 
5ifsgO2 
6?-8^6; 
7?sP1): 
       8

Sortie:

       ?
       ?
       ?
       ?
       ?
       ?
       ?
-262144 

3

Rubis, 8x8 7x7

 print(
 (?f+"\
 "*6+?\
 )*6).!
 $><<"\
 f"<<!1
;      

Sortie:

f      
f      
f      
f      
f      
f      
 ffalse

Version précédente, 8x8 avec 20 espaces:

  puts((
  "ff"+#
  ?\s*6+
  ?\n)*7
  );$><<
  ?\s*2+
  ?f;p:p
.!

Sortie:

ff     
ff     
ff     
ff     
ff     
ff
ff     
  ffalse

3

Pushy , carré 4x4

Non concurrente car la langue postdate le défi:

Code:

 H32
2 C4
:" } 
\o/

Les sorties:

d   
 d  
  d 
   d

Essayez-le en ligne!

Parce que les espaces ne sont pas pertinents dans Pushy, le code est facilement arrangé pour correspondre au négatif de sa sortie. Le programme actuel ressemble à ceci:

H      \ Push char 100, 'd'
32 2C  \ Push char 32, a space, and make 2 extra copies
       \ We now have the string 'd   '
4:     \ 4 times do:
  "    \   Print the string
   }   \   Cyclically shift it right, once

Les barres obliques inverses commencent un commentaire, la fin \o/est donc là pour compléter le négatif, et a l'air cool.


Alternativement, pour le même score, on peut avoir les solutions suivantes:

Code    Output

 35;    #
3 2j     #
2C 4      #
:"}        #

K 36     #
33 2      #
Ct4        #
 :}"    #

3

Haskell, 10 × 10

main=let{ 
0&c='\32' 
!c;n&c=c! 
'\32'>>(n 
-1)&c;a!b 
=putStrLn 
$(b<$[1.. 
10])++[a] 
}in(9&'*' 
         )

Définit une fonction d'assistance a ! bimprimant une ligne du formulaire bbbbbbbbbaet une fonction récursive n & cimprimant des nlignes du formulaire ccccccccc␣suivies d'une ligne du formulaire ␣␣␣␣␣␣␣␣␣c.

Utilise <$( fmap constencore) sur une plage pour répéter un caractère. Notez que cette option <$est uniquement disponible sans importation depuis GHC 7.10, ce qui est postérieur à ce défi. Je ne suis pas tout à fait sûr si cela rend cette soumission non compétitive.

Rien de vraiment excitant avec le choix de la disposition ou de l’algorithme ici; Je n'avais pas beaucoup d'octets à épargner et c'est juste une chance que les coupures de lignes se produisent putStrLncomme elles le faisaient.



3

05AB1E , 3x3 (6 octets autres que des espaces )

 3Ð
Λ q
°° 

Sortie:

3  
 3 
  3

Essayez-le en ligne.

Explication:

3Ð       # Push three 3s to the stack
  Λ      # Canvas with parameters num; filler; pattern
         #  num: The amount of characters to display (3)
         #  filler: The character to display ('3')
         #  pattern: The available options are single-digit integers in the range [0,7]
         #           indicating the direction to print in.
         #           (Option 3 is a top-left to bottom-right diagonal line)
    q    # Exit the program
°°       # no-ops to complete the pattern

2

Perl, 6x6 (26 non-espaces)

J'ai passé un bon moment à les regarder et j'étais sûr qu'il y aurait une solution Perl plus petite que 7x7 ... un défi très amusant! Cette solution nécessite -E.

say+( 
$"x5, 
"5$/" 
)x5,5 
x5,$" 
     ;

Usage:

perl -E 'say+( 
$"x5, 
"5\n" 
)x5,5 
x5,$" 
     ;'

Sortie:

     5
     5
     5
     5
     5
55555 

2

CBM BASIC v2.0 (9 × 9)

0dA8,7,6 
1dA5,4, 3
2dA2,1 ,0
3rEs: rem
4?sP s)::
5:? "*";:
6p =8---s
7 ?sPp):?
 8ifsgO3:

Sortie:

        *
       * 
      *  
     *   
    *    
   *     
  *      
 *       
*        

1

C (gcc) , 7x7 8x8

EDIT: La version précédente avait un comportement incorrect.

 main(i)
{ for(;i
<9 ;pri\
ntf ("%\
*d%" "*\
c",i, 1,
9-i,10 )
,i++);} 

Essayez-le en ligne!


" Nous avons également besoin que chaque ligne et chaque colonne contiennent au moins 1 caractère espace et 1 caractère non espace . " Il manque un caractère non espace à votre première colonne.
Kevin Cruijssen

@KevinCruijssen D'une manière ou d'une autre, j'ai raté le critère des colonnes, elles sont donc toutes fausses. Je vais refaire quand j'ai un vrai ordinateur à portée de main.
gastropner

1

Gelée , 4 x 4 (12 non-espaces)

 4=þ
¢ +⁴
¢+ ⁴
¢ỌY

Essayez-le en ligne!

Sortie:

!   
 !  
  ! 
   !

C'était très amusant.

Comment ça fonctionne

 4=þ    Link 1 (nilad): Generate an identity matrix of size 4
¢ +⁴    Link 2 (nilad): Add 16 to above
¢+ ⁴    Link 3 (nilad): Add 16 again
¢ỌY     Main link (nilad): Convert the above to ASCII chars, and join by newline

Partie facile: Jelly ignore les espaces (tant que seules les commandes intégrées à un octet sont utilisées).

Partie dure: Chaque ligne de Jelly est un lien (ou une fonction) distinct, il n’est donc pas très court d’étendre une déclaration constante sur plusieurs lignes. L'utilisation d'un littéral de chaîne est un bon candidat, mais vous ne savez pas comment générer le négatif.

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.