Quali sono gli svantaggi dei tabstops elastici? [chiuso]


83

Guarda qui: una tipica guerra santa su schede vs spazi .

Ora guarda qui: tabstops elastici . Tutti i problemi sono stati risolti e sono stati aggiunti molti nuovi comportamenti molto utili.

linguette elastiche

I tabstops elastici sono anche menzionati nella discussione tra tabs e spazi? Perchè no? Ci sono svantaggi dell'idea elastica tabstop così seria che nessuno li ha mai implementati in un editor popolare?

EDIT : mi scuso per aver dato troppa enfasi al "perché non sono menzionati". Non era proprio quello che intendevo; quella domanda è forse anche fuori tema. Quello che intendo veramente è, quali sono i maggiori svantaggi di questo che impediscono una più ampia adozione di un'idea ovviamente vantaggiosa? (in un mondo ideale in cui tutto lo supporta già)

(Si scopre che c'è già una richiesta su Microsoft Connect per un'implementazione di Visual Studio di tabstops elastici e una richiesta anche in Eclipse . Inoltre c'è una domanda che si pone su altri editor che implementano tabstops elastici )


4
Questa sarebbe un'ottima domanda per ux.stackexchange.com
JonnyBoats,

11
Non sono mai menzionati nella discussione "tab contro spazi" perché non c'è quasi modo per un programmatore che lavora di usare queste cose. Forse se avessi un'implementazione di Eclipse, VS, gvim ed emacs, ciò potrebbe cambiare.
Paul Tomblin,

2
L'idea mi piace molto, ma è solo quando vivi per un mese o giù di lì che sai davvero quali sono le insidie. Come sempre, ci sono alcuni casi in cui fa cose che non ti aspetteresti ...
Chris Burt-Brown,

3
@ ChrisBurt-Brown Questo è sempre un rischio, sì. Anche IntelliSense ha le sue insidie, come sostituire il testo quando non lo volevi. Nel complesso, tuttavia, IntelliSense in C # è stata una grande vittoria grassa.
Roman Starkov,

4
Lo voglio nel blocco note ++ ... Lo voglio ora
Ben Brocka,

Risposte:


32

Le guerre sante sono soggettive

I tabstops elastici di Nick sono un concetto straordinario che potrebbe aiutare molte persone a concordare una soluzione praticabile, anche se dubito fortemente che finirebbe completamente questa Guerra Santa: è, dopotutto, anche una questione di gusti e molti programmatori non si muoveranno a pochi centimetri dalla loro posizione su questo argomento, anche a scapito del compromesso. Quindi quello sarebbe un primo motivo.

Ad esempio, molte persone sul lato degli "spazi" non lo apprezzeranno perché richiede un ulteriore elemento logico nel software per un rendering decente (ad esempio, semplicemente la visualizzazione di un changeset nella visualizzazione web del tuo SCM).

Problemi di implementazione

Ma la ragione più ovvia è solo la sua barriera tecnica all'ingresso : è un concetto fondamentalmente diverso da quello che è stato implementato per un certo numero di anni (se non decenni) negli IDE e negli editor di testo. Richiederebbe di riscriverne alcuni per elaborare le linee in modo piuttosto diverso, il che rende difficile per i sistemi più vecchi e più grandi che hanno maggiori probabilità di soffrire di un accoppiamento profondo e stretto nel loro codice di elaborazione delle linee. È, tuttavia, molto più facile da fare quando si inizia da zero (si pensi demo di Nick o di Go 's tabwriter pacchetto).

Per un aneddoto personale, ricordo di essermi avvicinato all'autore un po 'di tempo fa per chiedere se ci fosse un supporto per gli emacs in vista, e in questo caso particolare lo ha menzionato come la ragione per cui non è banale. Ha anche chiesto aiuto alla comunità per aiutare a implementare questa funzione e portarla alle masse.

Ci importa abbastanza?

Un terzo motivo è che alcuni sviluppatori non sono così aggrappati alla questione e non si preoccupano così tanto che farebbero il possibile per sostenere lo sforzo. Nella maggior parte dei casi, il conflitto di spazi contro schede non è un blocco del business, quindi non c'è così tanta spinta dietro il problema.

Se lo vuoi, dovrai lottare per questo. Che è fattibile nel software open source. E se cambi abbastanza di questi, quelli a codice chiuso dovranno seguire il rischio di perdere parte della loro base di utenti, anche se in parte così piccola.

Quindi, se lo vuoi, dai una mano a Nick.


(fuori tema) Mi chiedo spesso come altri tipi di funzionalità "questo è bello ma molto minore" possano mai trasformarsi in prodotti come Visual Studio. Sembra che qualcuno nel team abbia semplicemente trovato il tempo di implementarlo per motivi personali. Pensa a digitare in più righe alla volta in Visual Studio, ad esempio; non è come decine di migliaia di persone lo hanno chiesto, ma mi piace piuttosto.
Roman Starkov,

3
@romkyns: per quanto riguarda molte cose, ci vuole un solo insider tranquillo o mille voci che urlano alle porte.
Hayylem,

35

Molte volte ho dovuto combattere con un elaboratore di testi per far apparire il documento come desiderato senza qualche regola automatica nascosta che controlla il posizionamento delle mie parole. Non voglio passare un secondo a cercare di capire perché l'editore insista nel mettere quelle parole lì.


11
Nemmeno io. Sono pienamente d'accordo con questo sentimento, dal momento che tali regole mi frustrano davvero. Ma questo è diverso in due modi. Uno: proprio come i tablet ora, non devi usarli se non vuoi. Puoi lasciare solo il testo dei tuoi colleghi se li utilizza. Due: i tabstops elastici non hanno regole nascoste, ma palesemente ovvie. Il comportamento è completamente naturale - forse anche più naturale dei tradizionali tabstops, che si verificano in una posizione arbitraria, di solito irrilevante, all'interno del testo. Questo è il motivo per cui nessuno usa più i tabstops per qualcosa di diverso dal rientro.
Timwi,

10
@Timwi: la domanda era elencare gli svantaggi. L'ho fatto.
mhoran_psprep,

14
Potrebbe non essere ovvio dalla GIF, ma l'unica cosa da capire è che quando si preme "TAB", tutto ciò che viene dopo verrà correttamente allineato verticalmente. Non è come un word processor. Prova la demo interattiva effettiva al link che ho pubblicato e vedrai quanto è naturale.
Roman Starkov,

3
@mhoran_psprep: Abbastanza giusto, apprezzo il tuo contributo. Immagino che stessimo esaminando diverse interpretazioni della domanda. Stai elencando gli svantaggi di te stesso usando la funzione, mentre pensavo che si trattasse di svantaggi dell'introduzione della funzione (cioè renderla disponibile e non obbligatoria ).
Timwi,

27

Questa è la prima volta che ne ho sentito parlare. Non sono sicuro che siano una buona idea ma sembrano poco utili poiché disponiamo di strumenti (come il rientro) che già formattano automaticamente il codice.

Cosa succede quando apro i tuoi intelligenti tabstops elastici in vim e lo modifico? La scheda si ripulisce automaticamente o ti rimane un casino?

Gli svantaggi principali, come li vedo, sono probabilmente la rottura dei diff, il controllo della versione e la non compatibilità con gli editor che non li supportano. Forse è necessario apportare molte modifiche al codice per supportarli e ci sono cose più importanti della funzione "ancora un'altra cosa per formattare il codice". Dopotutto, possiamo usare tutti quelli indentche fanno tutto quanto sopra se la memoria serve.


9
Che atteggiamento di pensiero arretrato. Diamo alcun progresso a causa preferiti, strumenti obsoleti per anziani non possono far fronte solo ancora ! (L'ironia, ovviamente, è che questi strumenti (come vim) sono open-source, quindi se fosse davvero importante per te, potresti (e probabilmente dovresti ) aggiungere un supporto elastico tabstop ad esso)
Timwi,

14
@Timwi: ti manca completamente il punto che stavo sollevando. Cosa succede quando il tuo file di codice viene analizzato da qualcosa che non è a conoscenza dei tabstops elastici? Ti ritrovi con un casino o possono farcela? Che dire di controllo versione e differenze? Il solo desiderio che tutti gli strumenti supportino $ feature non è realistico, anche se quegli strumenti sono open source.
Sardathrion,

14
@Timwi: supponi che tutti trovino i tablet elastici fantastici come pensi che lo siano. Questo potrebbe non esser vero.
Sardathrion,

7
@Sardathrion ha ragione. Cosa succede quando devo remotare nel mio server * nix senza alcun sistema di finestre installato e devo esaminare un po 'di codice con Vim / Emacs / Pico / Qualunque cosa? Se esiste un meccanismo in modo che sia leggibile andrebbe bene ... altrimenti sarebbe un incubo. Non vedo comunque che il vantaggio delle linguette elastiche sia così benefico. Posso già formattare automaticamente il mio codice per vedere come dovrebbe negli IDE che uso.
Rig

7
Il punto di controllo della versione è buono - non credo che la gente apprezzerà un editor che inizia silenziosamente a cambiare il posizionamento / formato dei commenti nel codice arbitrariamente lontano dal codice che stanno modificando (vedi la sezione magenta nell'animazione di OP gif). Sarebbe utile avere un'implementazione di riferimento con cui giocare, ma ciò che vedo finora non è notevole - emacs fa già molto di tutto questo, solo con un paio di tasti extra (che probabilmente è una buona cosa).
mcmcc,

13

Ad essere sincero, non li trovo così utili una volta superata l'eccitazione iniziale. Ad esempio, non mi piacciono comunque i commenti alla fine di una riga: inserisco sempre i miei commenti su una riga separata. Con ciò, le linguette elastiche perdono il loro uso principale.

Dopodiché, puoi ovviamente usarli per allineare argomenti di funzioni (e parametri) e lunghi elenchi di assegnazioni.

Ma per il primo tendo a indentare tutti gli argomenti di un livello aggiuntivo e questo funziona perfettamente con me:

void foo(
    int x,
    int y,
    string z
)

E non vedo alcun bisogno di cambiarlo.

E per quanto riguarda l'allineamento dei compiti, non lo faccio. Metto singoli spazi attorno ai compiti, tutto qui. Inoltre, tendo a raggruppare molti compiti insieme, quindi raramente si verificano problemi di leggibilità.

In sintesi, le linguette elastiche hanno un'utilità assolutamente zero per me. Questa è ovviamente una preferenza molto personale che può variare, ma trovo che funzioni bene e immagino che la mancanza di supporto per le linguette elastiche sia dovuta al fatto che altre persone pensano allo stesso modo.

Se un editore li implementare, ho ancora non utilizzarle.


Apprezzato. Sembra che potresti volere felicemente usare anche un carattere a larghezza variabile se volessi, dal momento che non allinei comunque nulla di diverso dall'inizio della linea. Visual Studio ha un supporto abbastanza buono per questo, in realtà, e il boost di leggibilità è buono.
Roman Starkov,

1
@romkyns Ne abbiamo discusso e nel corso di uno ho provato a usare un font proporzionale per la programmazione per un po 'di tempo. Il risultato è stato che i caratteri a faccia singola funzionano meglio, anche se si ignora il rientro. A parte questo, attualmente sto lavorando esclusivamente su Vim e sulla console, nessuno dei quali con ogni probabilità supporterà mai caratteri proporzionali.
Konrad Rudolph,

1
@romkyns Detto questo, questi problemi sono risolvibili (o forse anche risolti, con un font proporzionale progettato per la programmazione). Ma ancora non vedo davvero la necessità.
Konrad Rudolph,

13

Uno svantaggio è che non funziona se si desidera l'allineamento su un gruppo di linee e quindi il rientro sul successivo, poiché raggruppa i punti di tabulazione delle linee adiacenti.

def foo( bar,
         xyzzy ):
         wibble() # Too much indentation

Quello che volevo:

def foo( bar,
         xyzzy ):
    wibble()

Per le lingue con parentesi graffe questo potrebbe essere meno un problema, poiché di solito puoi risolverlo posizionando la parentesi graffa di apertura su una linea a sé stante (come nell'animazione), ma per le lingue sensibili agli spazi bianchi, questo diventa rapidamente un dolore, e finisci per ricorrere all'utilizzo degli spazi.


Concordato. L'implementazione di Nick non funziona molto bene per linguaggi come Python.
Roman Starkov,

3
Perché non dovrebbe funzionare? Questa non è una limitazione fondamentale, l'algoritmo deve solo essere consapevole del linguaggio. Ma in una certa misura questo è vero anche oggi, Vim ad esempio definisce regole di rientro diverse a seconda della lingua. Questo potrebbe facilmente accogliere il rientro di Python.
Konrad Rudolph,

1
@KonradRudolph No, non potevano. Il sorteggio di tabstops elastici è la capacità di indentare / indentare automaticamente gruppi di testo insieme. Un semplice esempio è la fine di un'istruzione "if": si tenta di annullare il rientro perché si sta uscendo dall'istruzione, ma i tabstop elastici "intelligenti" decidono che si intende anche rimuovere il rientro dalla riga o due sopra, ecc. e così via ... E se devi raggruppare esplicitamente il testo insieme, allora - qual è il punto? È più lavoro per farlo che riparare da soli i rientri ...
Izkata,

1
@Izkata Unindenting manualmente avrebbe (dovrebbe) semplicemente terminare il gruppo corrente. Perché dovresti mai controllare il rientro con i fermi della linguetta elastica manualmente? Non lo faresti, quindi l'algoritmo sa che quando lo fai, termina un blocco, non disincaricare il blocco sopra.
Konrad Rudolph,

1
Oh, buon punto. Hmm ... forse potresti far rientrare il doppio degli argomenti? Quindi wibble()avrebbe un solo rientro e quindi non sarebbe allineato con gli argomenti della funzione?
Ajedi32

12

Perché non facciamo semplicemente il carattere di tabulazione verticale (VT, ASCII 11) per indicare l'uso di tabstops elastici? Non serve a nulla in alcun linguaggio di programmazione tradizionale, ma viene analizzato come uno spazio bianco valido in tutti loro, AFAIK.

Ciò significherebbe che l'uso di tabstops elastici non è più una convenzione esternalizzata (ad es. "Questo file è stato formattato con tabstops elastici, per favore attivali") ma qualcosa a cui accetti caso per caso.

Gli editor di testo esistenti di solito visualizzano un glifo o un singolo spazio al posto di una scheda verticale. Questo non è l'ideale, ma un piccolo prezzo da pagare, IMO.


10

Non sono menzionati perché non sono implementati nella maggior parte degli IDE degli editor di testo; sono una novità di scarsa utilità in un progetto.

Gli spazi sono stati usati per organizzare la programmazione sin dai tempi delle schede perforate. Sono arrivate le schede e qualcuno ovviamente ha pensato che fossero una buona idea (si sbagliavano: p).

Nei giorni in cui i più moderni editor possono convertire automaticamente le schede in spazi ... sono abbastanza inutili.

Dover installare ancora un altro strumento per gestire qualcosa di così banale come le schede rispetto agli spazi certamente non mi attira, e non penso che lo farebbe per la maggior parte dei miei colleghi.


Ho cancellato i commenti mentre scendevano in insulto.
ChrisF

1
Ho solo pensato di sottolineare che il motivo principale per cui mi piace l'idea dei tabstops elastici non è perché risolve il problema delle schede rispetto agli spazi, ma a causa del comportamento mostrato nella GIF nella domanda originale; allineamento automatico e indolore. Inoltre, per le differenze VCS c'è l'ulteriore vantaggio che in questo esempio non sono state richieste modifiche agli spazi bianchi.
Ajedi32

"Dover installare ancora un altro strumento ..." non è un argomento abbastanza valido ... Come se non ci fossero già abbastanza strumenti utilizzati.
Milind R

@MilindR Sia che lo consideri un argomento abbastanza valido o meno, è il motivo per cui (all'epoca tre anni fa) non avrei avuto interesse in questo. Ci sono molti strumenti usati che fanno qualcosa di utile non è un motivo per aggiungerne un altro che, in realtà, non aggiunge nulla al tuo ambiente.
TZHX,

Atteggiamenti come questo sono il motivo per cui aziende come MS decidono di costringere gli utenti a nuove UX ... Rabbrividisco al pensiero di cosa accadrebbe se lo stesso atteggiamento venisse applicato ai floppy -> transizione CD.
Milind R,

4

Penso che troverebbero molto utile se gli IDE li supportassero (Microsoft!). Una volta che le persone hanno scoperto di poter schiaffeggiare le loro fioriere sul lato e di averle ben leggibili, lo faranno. Potresti aggiungere più commenti al codice sorgente all'improvviso (il che può essere solo una buona cosa).

Suppongo che potremmo anche aggiungere commenti "tooltip" all'elenco di "sarebbe bello se ...", così i tuoi blocchi di commenti di grandi dimensioni potrebbero essere nascosti e visualizzati facilmente quando necessario. Forse potremmo anche avere blocchi di commenti che fanno parte della documentazione (non roba di tipo sandcastle, frammenti di documentazione leggibili dall'utente che sono stati incorporati nel codice, non solo le intestazioni del metodo)

Svantaggi: potrebbe fare in modo che i diff di origine sembrino cattivi se un gruppo di linee sembra che siano state modificate quando in realtà è stato modificato solo 1 (se l'editor ha salvato il file con le schede convertite in spazi). Oppure, se la scheda elastica è stata implementata con un singolo carattere (o più probabilmente, 2 schede), quindi la visualizzazione della tua fonte all'esterno dell'editor potrebbe avere un aspetto negativo.

Penso che mi piaccia l'idea, 'tab tab' alla fine di una riga elastica il blocco dei commenti e allinea tutti i commenti sulle righe successive (che hanno la spaziatura della doppia scheda) di conseguenza.


3

Ecco come lo vedo: se la maggior parte degli strumenti popolari già supportasse i tabstop elastici, molte persone li userebbero. Lo stesso è accaduto con la modalità di navigazione / modifica di vi, con l'evidenziazione della sintassi e successivamente con Intellisense. In ogni caso, la saggezza stabilita era che non era utile o non necessario, ma è stato implementato e decollato.

I tablet elastici hanno, ovviamente, un impatto relativamente basso. La maggior parte delle persone è sufficientemente soddisfatta dello status quo e quindi non importa. Un ragionamento simile viene applicato a molte situazioni in cui alcune persone sono semplicemente felici di ciò che hanno e non vedono alcun motivo per passare a qualcosa di più avanzato. In altre parole, il problema più grande con i tabstops elastici è lo stesso di quasi tutte le altre buone idee: deve guadagnare trazione.

Ciò non significa che la funzionalità non possa essere adottata in modo incrementale. Ogni singolo linguaggio di programmazione è stato adottato in modo incrementale, anche se un intero team richiede un nuovo compilatore e un nuovo IDE per iniziare a usarlo. Lo stesso vale per ogni singola architettura hardware e molti altri esempi. Non è inoltre il caso che la mancanza di integrazione con gli strumenti esistenti sia un ostacolo: lo stesso vale, ad esempio, per il "formato unificato-diff", che ha sostituito in modo incrementale un formato precedente meno leggibile che era comunque compreso dagli strumenti automatizzati (come patch). Tali strumenti sono stati aggiornati nel tempo.

Apprezzo le questioni di interoperabilità che altri hanno menzionato, ma nonostante ciò, ci saranno sicuramente squadre (come la mia) che lo adotteranno senza esitazione, nella nostra interezza. Strumenti esterni come diffing, fusione, ecc. Inizialmente non lo supporteranno, ma faremo la nostra parte per incoraggiare i fornitori a includere la funzione. Ecco come sono sempre stati fatti progressi. Richiede alcuni dolori per un periodo transitorio temporaneo, ma alla fine ne vale la pena.


L'argomento C vs C ++ appare un po 'fuorviante. Mentre può essere vero che questo è il caso di "alcune persone" (come giustamente hai detto), ci sono ovvi motivi per attenersi al C o favorire il C ++ a seconda della situazione. La dimensione del runtime C ++ è una di queste, in un'impostazione predefinita.
Hayylem,

Sono con haylem. Il tuo punto sarebbe più sonoro senza il confronto C-contro-C ++. Sono lingue abbastanza diverse. A mio avviso, C è per la programmazione di sistemi e altri lavori di basso livello in cui è necessario molto controllo (una macchina virtuale, ad esempio). Il C ++ è più per le applicazioni di medio livello in cui l'astrazione è utile per gestire la complessità (spazi dei nomi, contenitori e algoritmi STL, modelli), ma le prestazioni sono ancora un problema (i giochi sono l'esempio più visibile).
Jon Purdy,

@haylem: grazie per il feedback. Ho rimosso il riferimento a C / C ++.
Timwi,

@JonPurdy: grazie per il feedback. Ho rimosso il riferimento a C / C ++.
Timwi,

2

Il problema più grande che avrei con esso è la spaziatura incoerente in tutta la documentazione. So che come programmatore mi sarei seccato di vedere un ciclo o un'istruzione if in un rientro "standard" e poi di notare in diversi rientri. So personalmente che mi piace vedere tutte le mie parentesi graffe allineate nella documentazione, non solo nel blocco di codice che sto guardando.

Nel complesso penso che sia comunque una buona idea, ma personalmente non mi piacerebbe.


1

Ho appena provato l'implementazione di jEdit di tabstops elastici, che funziona incredibilmente bene con i linguaggi di programmazione con cui ho familiarità (principalmente HTML / XML e linguaggi simil-C). Con il codice Python, tuttavia, ecco come viene eseguito il rendering (spazi utilizzati al posto delle schede per illustrare come le cose si allineano):

def foo(x):
             '''<1 tab before the docstring.
No tab       <tab
No tab       <tab
             <tab  <another tab
             <tab  <another tab
             <tab'''
             if 1 or 2:    #<Tab before this comment
                           yield True

Per un linguaggio come Python che si basa sulla spaziatura, questo è un rompicapo a meno che non si disabiliti la funzionalità fornita da tabstops elastici. Editor come Vim ed Emacs rendono semplice disabilitare la maggior parte dei tipi di funzionalità se si conosce il nome dell'opzione e come disabilitarlo, ma questa funzionalità dovrebbe essere disabilitata per il codice come sopra.

Detto questo, è ottimo per x86 ASM, C, C ++, Go, XML, HTML e altri che non fanno tanto affidamento sugli spazi bianchi:

import (
    "fmt"    // We love formatting functions.
    "io"     // Because I/O is useful.
    "os"     // Can't open a file without os.Open!
)

type Foo struct {
    Field1              int          // This is properly aligned
    ReallyLongField2    string       // with this.
    privateField        io.Reader    // Elastic tabstops are great for Go.
}

Dirò che i dialetti di Lisp come Scheme hanno le loro convenzioni che renderebbero anche il tab "elastico" il rendering di tabstops elastici. Se cambio le mie impostazioni tabstop in modo che corrispondano alla convenzione di 2 colonne e inserisco tabstop in punti insoliti (tra una funzione e i suoi argomenti):

(let loop ((n 1))
  (if  (> n 10)
        '()
        (cons  n
               (loop (+ n 1)))))

vs. il più leggibile:

(let loop ((n 1))
  (if (> n 10)
      '()
      (cons n
            (loop (+ n 1)))))

Certo, questo non è male come nell'esempio di Python, ma riduce decisamente la leggibilità del codice. Mentre mi piace molto la funzionalità quando scrivo in qualcosa come C # o C ++, detesto la funzionalità quando scrivo in un linguaggio come Python o Scheme in cui lo spazio bianco è funzionale e / o visivamente utile. I tabstops elastici sono stati creati appositamente per essere utili senza richiedere un'utilità di rientro separata, ma chiaramente non è pensata per tutti i linguaggi di programmazione.


0

Emacs gestisce già il rientro in presenza di parentesi non chiuse e allinea automaticamente wilma con fred . Non ho idea del perché Eclipse non faccia lo stesso. Ok, ho un'idea, ma è spiacevole.

Anche Emacs potrebbe allineare il commento senza troppi problemi, ma AFAIK non lo ha mai desiderato.


2
Posso solo interpretare la tua ultima frase come troll, dal momento che ovviamente almeno un altro ragazzo lo voleva dannatamente abbastanza male da creare una pagina ben argomentata, un'implementazione Java e una GIF per mostrare perché è buono. Se leggi le risposte, scoprirai che anche Nick non è solo. Oh aspetta, guarda anche qui .
Roman Starkov,

A proposito, Emacs rientra di nuovo wilmaquando si apportano modifiche, come cambiare la lunghezza del nome della funzione? In tal caso, è abbastanza vicino a ciò che fanno i tabstops elastici.
Roman Starkov,

@romkyns: non intendevo trollare, intendevo solo che non avevo mai visto quel tipo di commento rientrare in EMACS. Generalmente EMACS non rientra più righe durante la digitazione, ma potrebbe essere modificato anche.
Kevin Cline,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.