Base 64 kodlaması ne için kullanılır?


782

Orada "baz 64 kodlaması" hakkında konuştuğunu duydum. Ne için kullanılır?


1
Base64_encode () kılavuzundan : "Bu kodlama, ikili verilerin, posta gövdeleri gibi 8 bit temiz olmayan aktarım katmanları üzerinden aktarımı sürdürmesini sağlamak için tasarlanmıştır."
still_dreaming_1

Yanıtlar:


940

Bir ağ üzerinden göndermek istediğiniz bazı ikili verilere sahip olduğunuzda, genellikle sadece bitleri ve baytları kablo üzerinden ham biçimde akıtarak yapmazsınız. Neden? çünkü metin akışı için bazı ortamlar yapılır. Asla bilemezsiniz - bazı protokoller ikili verilerinizi kontrol karakterleri (modem gibi) olarak yorumlayabilir veya ikili verileriniz bozulabilir, çünkü alttaki protokol özel bir karakter kombinasyonu girdiğinizi düşünebilir (FTP'nin satırı nasıl çevirdiği gibi) uçları).

Bu nedenle, bunun üstesinden gelmek için insanlar ikili verileri karakterlere kodlar. Base64 bu tür kodlamalardan biridir.

Neden 64?
Çünkü genellikle birçok karakter kümesinde bulunan aynı 64 karaktere güvenebilirsiniz ve verilerinizin telin diğer tarafında bozulmayacağından emin olabilirsiniz.


104
(Teorik olarak base-80 kodlaması veya benzeri bir şey yapabilirsiniz, ancak bu daha zor olurdu. İkisinin güçleri ikili için doğal temellerdir.)
Jon Skeet

13
@yokees: Hiçbir garanti yoktur, sadece neredeyse her zaman güvende olan karakterlerdir . Bu yüzden Base-64'ün birden fazla formu vardır ( en.wikipedia.org/wiki/Base-64 ).

8
Bu, tüm ağ tipi veri geçişinin bir tür kodlama kullanması gerektiği anlamına mı geliyor?
Tanner Summers

6
Peki dize verilerini kodlamak için neden base64 yöntemi kullanılıyor? örn. Özel karakterler bir kullanım durumu olabilir, ancak neden bu durumda utf8 olmasın, eşdeğerler? Bununla ilgili herhangi bir kaynak çok takdir edilecektir.
partizanos

4
Başarısız olacak en azından bazı protokollerin bir listesi, eğer biri bilirse güzel olurdu.
Tadej

202

Temelde ASCII metninde rastgele ikili verileri kodlamanın bir yoludur. Her 3 bayt veri için 4 karakter ve sonunda potansiyel olarak biraz dolgu alır.

Esasen, girişin her 6 biti 64 karakterlik bir alfabe ile kodlanmıştır. "Standart" alfabe dolgu karakteri olarak = ile AZ, az, 0-9 ve + ve / kullanır. URL'de güvenli varyantlar var.

Wikipedia oldukça iyi bir bilgi kaynağıdır.


Php gibi bir langange, ikili veri gelecektir. Neredeyse her zaman metin olan dize verileriyle çalışırız.
Cholthi Paul Ttiopic

3
@CholthiPaulTtiopic: Şifreleme veya sıkıştırma veya ses / görüntü / video sonuçları.
Jon Skeet

1
@CholthiPaulTtiopic: Korkarım "depolama hakkında ne demek" ile ne demek istediğini bilmiyorum ama bu noktada biraz konu dışı olduğumuzu düşünüyorum.
Jon Skeet

2
@CholthiPaulTtiopic: "String binary" terimini düşünmekten kesinlikle kaçınırdım. İkili veri ikili veri olarak muamele edilmeli ve değil metin olarak tedavi. Kelimenin tam anlamıyla, bu ayrım üzerinde yeterince ilgilenmeyen insanlara kaybolan SO hakkında yüzlerce - muhtemelen binlerce - soru gördüm.
Jon Skeet

1
@ still_dreaming_1 PHP onları çağırır binary strings. (kaynak) php.net/manual/tr/function.pack.php
Cholthi Paul Ttiopic


116

Sonuçta ortaya çıkan metnin harfler, sayılar ve "+", "/" ve "=" sembollerinden başka bir şey olmadığı ikili verilerin metinsel olarak kodlanmasıdır. İkili verileri, özellikle metin verileri için kullanılan ortamlar üzerinde depolamanın / iletmenin uygun bir yoludur.

Peki ama neden Base-64? İkili verileri hemen akla gelen metne dönüştürmenin iki alternatifi:

  1. Ondalık: Her baytın ondalık değerini üç sayı olarak saklayın: 045 112 101 037 vb. Burada her baytın 3 bayt ile temsil edildiği. Veriler üç kez şişer.
  2. Onaltılık: baytları onaltılık çiftler halinde saklayın: AC 47 0D 1A vb. Her bir baytın 2 bayt ile temsil edildiği. Veriler iki kez şişer.

Base-64, 6 bitlik (6 x 4 = 24 bit) 4 karakterde 3 bayt (8 x 3 = 24 bit) eşler. Sonuç "TWFuIGlzIGRpc3Rpb ..." gibi bir şeye benziyor. Bu nedenle şişkinlik sadece orijinalin sadece 4/3 = 1,3333333 katıdır.


10
Doğru anlaşılıyor mu, 64 yazdırılabilir bir ASCII karakterine dönüştürülebilen iki en yüksek güç olduğu için en iyi seçimdir (95 tanesi var)?
voho

Her iki durumda da 24 bitlerse, şişkinlik 1: 1 değil mi? Veya 6 bitlik 4 karakter söylediğinizde, aslında karakter başına 8 bit olduğunu, ancak ilk ikisinin 0'lık yastıklı olduğunu mı kastediyorsunuz?
David Klempfner

1
@Backwards_Dave Her 6 bit 8 bit olarak ifade edilir. Dolayısıyla şişkinlik 8: 6 veya 4: 3'tür.
Ateş Goral

82

Daha önce söylenenlerin yanı sıra, listelenmemiş çok yaygın iki kullanım

Hash'ler:

Karmalar, bir bayt bloğunu 128bit veya 256bit (SHA / MD5) gibi sabit boyutlu başka bir bayt bloğuna dönüştüren tek yönlü işlevlerdir. Sonuçta elde edilen baytları Base64'e dönüştürmek, özellikle bütünlük için bir sağlama toplamı karşılaştırırken karmayı görüntülemeyi çok daha kolay hale getirir. Hashes, Base64'te o kadar sık ​​görülür ki, birçok kişi Base64'ün kendisini bir karma olarak karıştırır.

Kriptografi:

Bir şifreleme anahtarının metin değil, ham bayt olması gerektiğinden, bazen Base64'ün kullanışlı olduğu bir dosya veya veritabanında saklanması gerekir. Ortaya çıkan şifreli baytlarla aynı.

Base64'in kriptografide sıklıkla kullanılmasına rağmen bir güvenlik mekanizması olmadığını unutmayın. Herkes Base64 dizesini orijinal baytlarına geri dönüştürebilir, bu nedenle verileri korumak için bir araç olarak değil, yalnızca ham baytları daha kolay görüntüleme veya depolama biçimi olarak kullanılmalıdır.

Sertifikalar

PEM biçimindeki x509 sertifikaları temel 64 kodludur. http://how2ssl.com/articles/working_with_pem_files/


4
Birçok durumda baytları bayt olarak depolamak aslında işlemsel olarak daha kolaydır. Bir veritabanında ve özellikle bir dosyada bile (sabit uzunlukta kayıtlar kullanılıyorsa veya bayt tek içerikse). Base64 tipik olarak, bu baytların bir yere, özellikle bitleri kırabilecek veya bazı baytları kontrol kodları olarak yorumlayabilecek bir kanal üzerinden iletilmesi tasarlandığında kullanılır .
cHao

İmzasız 8 bit tam sayı, 0,1,255,36 ... olarak yazılmış bir karma görmedim ve UTF-8 veya başka bir kodlama ile göstermek mantıklı olmazdı, base64 dışında başka nasıl görüntüleyebilirdiniz? Şifreleme anahtarları ve şifreli veriler genellikle ham baytları depolayamayacağınız yapılandırma ve XML dosyalarında saklanır. Ham bayt olarak saklayabileceğinizi kabul ediyorum, ancak elbette, base64 yapamayacağınız durumlar içindir. Base64'ün iletmenin ötesinde birçok kullanımı vardır. Bunlar göreceğiniz iki yaygın senaryodur.
Despertar

1
Karma değerini ondalık değil onaltılık olarak görüntülersiniz. Hashler için, bu aslında base64'ten çok daha yaygındır.
cHao

@cHao Evet, bu da yaygın. Onaltılık basamaklar herhangi bir ikili veriyi temsil edebilir, ancak taban 64, daha fazla karakter kullandığından çok daha az yer kaplama avantajına sahiptir.
Despertar

45

Yıllar önce, postalama işlevselliği sunulduğunda, bu tamamen metin tabanlıydı, zaman geçtikçe, görüntü ve medya (ses, video vb.) Gibi eklere ihtiyaç duyuldu. Bu ekler internet üzerinden gönderildiğinde (temel olarak ikili veri biçimindedir), ikili verilerin bozulma olasılığı ham haliyle yüksektir. Böylece, bu sorunu çözmek için BASE64 ortaya çıktı.

İkili verilerdeki sorun, C, C ++ gibi bazı dillerde karakter dizesinin sonunu temsil eden null karakterler içermesidir, bu nedenle NULL baytları içeren ham formda ikili veri göndermek bir dosyanın tamamen okunmasını ve bozuk bir veriye yol açmasını durduracaktır.

Örneğin :

C ve C ++ 'da, bu "null" karakter bir dizenin sonunu gösterir. Yani "HELLO" şu şekilde saklanır:

MERHABA

72 69 76 76 79 00

00 "burada dur" diyor.

Şimdi BASE64 kodlamasının nasıl çalıştığına bakalım.

Dikkat edilmesi gereken nokta: Dizenin uzunluğu 3'ün katında olmalıdır.

Örnek 1 :

Kodlanacak dize: “ace”, Uzunluk = 3

1) Her karakteri ondalık sayıya dönüştürün.

a = 97, c = 99, e = 101

resim açıklamasını buraya girin

2) Her ondalık sayıyı 8 bit ikili gösterime değiştirin.

97 = 01100001, 99 = 01100011, 101 = 01100101

Kombine: 01100001 01100011 01100101

3) 6 bitlik bir grupta ayırın.

011000 010110 001101 100101

4) İkili ile ondalık arasındaki sayıları hesapla

011000 = 24, 010110 = 22, 001101 = 13, 100101 = 37

5) base64 grafiğini kullanarak ondalık karakterleri base64'e dönüştürün.

24 = Y, 22 = W, 13 = N, 37 = l

“Ace” => “YWNl”

resim açıklamasını buraya girin

Örnek 2:

Kodlanacak dize: “abcd” Uzunluk = 4, 3'ün katları değil. Dize uzunluğunu 3'ün katları yapmak için, uzunluk = 6 yapmak için 2 bit dolgu eklemeliyiz. Dolgu biti “=” işaretiyle temsil edilir.

Dikkat edilmesi gereken nokta: Bir dolgu biti iki sıfıra 00 eşittir, bu nedenle iki dolgu biti dört sıfıra eşittir 0000.

İşlemi başlatalım: -

1) Her karakteri ondalık sayıya dönüştürün.

a = 97, b = 98, c = 99, d = 100

2) Her ondalık sayıyı 8 bit ikili gösterime değiştirin.

97 = 01100001, 98 = 01100010, 99 = 01100011, 100 = 01100100

3) 6 bitlik bir grupta ayırın.

011000, 010110, 001001, 100011, 011001, 00

bu nedenle son 6 bit tamamlanmadığından, dört sıfır “0000” olan iki dolgu biti ekliyoruz.

011000, 010110, 001001, 100011, 011001, 000000 ==

Şimdi, eşit. Sonunda iki eşittir işareti 4 sıfırın eklendiğini gösterir (kod çözmede yardımcı olur).

4) İkili ile ondalık arasındaki sayıları hesaplayın.

011000 = 24, 010110 = 22, 001001 = 9, 100011 = 35, 011001 = 25, 000000 = 0 ==

5) base64 grafiğini kullanarak ondalık karakterleri base64'e dönüştürün.

24 = Y, 22 = W, 9 = j, 35 = j, 25 = Z, 0 = A ==

“Abcd” => “YWJjZA ==”


5
Bu gerçekten harika bir açıklama
maheshmnj

28

Bilgisayarların ilk günlerinde, telefon hattı sistemlerarası iletişimin özellikle güvenilir olmadığı durumlarda, veri bütünlüğünü doğrulamak için hızlı ve kirli bir yöntem kullanıldı: "bit paritesi". Bu yöntemde, iletilen her bayt 7 bit veriye sahip olacak ve 8'i 1 veya 0 olacak ve bayttaki toplam 1 bit sayısını eşit olmaya zorlayacaktır.

Bu nedenle 0x01, 0x81 olarak iletilir; 0x02, 0x82 olacaktır; 0x03, 0x03 vb. Olarak kalır.

Bu sistemi ilerletmek için ASCII karakter kümesi tanımlandığında, sadece 00-7F karakterleri atandı. (Bugün hala 80 FF aralığında ayarlanan tüm karakterler standart değildir)

Günün birçok yönlendiricisi, eşlik denetimi ve bayt çevirisini donanıma yerleştirerek, bağlı bilgisayarları 7 bitlik verilerle sıkı bir şekilde ilgilenmeye zorlar. Bu, e-posta eklerinin (ve diğer tüm verilerin, bu nedenle HTTP ve SMTP protokollerinin metin tabanlı olduğunu) salt metin biçimine dönüştürülmesini sağlar.

90'lı yıllardan az sayıda yönlendirici hayatta kaldı. Bunlardan herhangi birinin bugün kullanımda olduğundan şüpheliyim.


2
Bu mükemmel bir tartışma ve ilginç bir tarih dersi, teşekkürler.
Dan Bechard

26

Gönderen http://en.wikipedia.org/wiki/Base64

Base64 terimi, belirli bir MIME içerik aktarımı kodlamasına karşılık gelir. İkili verileri sayısal olarak işleyerek ve bir taban 64 gösterimine çevirerek kodlayan benzer herhangi bir kodlama şeması için genel bir terim olarak da kullanılır. Özel taban seçimi, karakter kümesi kodlamasının geçmişinden kaynaklanmaktadır: biri, alt kodun çoğu kodlama için ortak olan ve aynı zamanda yazdırılabilir olan 64 karakterlik bir grup seçebilir. Bu kombinasyon, geleneksel olarak 8 bitlik temiz olmayan e-posta gibi sistemlerden geçiş sırasında verilerin değiştirilmesine izin vermez.

Base64 çeşitli bağlamlarda kullanılabilir:

  • Evrim ve Thunderbird, e-posta şifrelerini gizlemek için Base64'ü kullanıyor [1]
  • Base64, sınırlayıcı çarpışmasına neden olabilecek metinleri iletmek ve depolamak için kullanılabilir
  • Base64 genellikle, kriptografik anahtar yönetiminin yükünü ödemeden sırları gizlemek için hızlı ama güvensiz bir kısayol olarak kullanılır

  • Spam gönderenler, Base64'ü çoğunlukla Base64 kodunu çözmeyen ve dolayısıyla kodlanmış iletilerdeki anahtar kelimeleri algılayamayan temel anti-spamming araçlarından kaçınmak için kullanır.

  • Base64, LDIF dosyalarındaki karakter dizelerini kodlamak için kullanılır
  • Base64 bazen ikili verileri bir XML dosyasına gömmek için kullanılır, örneğin ...... gibi Firefox'un bookmarks.html.
  • Base64 ayrıca, imza için makbuz karakterleri aktarırken gecikmeyi en aza indirmek için devlet Mali İmza baskı aygıtlarıyla (genellikle seri veya paralel bağlantı noktaları üzerinden) iletişim kurarken de kullanılır.
  • Base64, harici dosyalara bağlı kalmaktan kaçınmak için komut dosyaları içindeki görüntüler gibi ikili dosyaları kodlamak için kullanılır.
  • Ham görüntü verilerini arka plan görüntüsü gibi bir CSS özelliğine gömmek için kullanılabilir.

11

Bazı taşıma protokolleri yalnızca alfasayısal karakterlerin iletilmesine izin verir. Özel eylemleri tetiklemek için kontrol karakterlerinin kullanıldığı ve / veya karakter başına yalnızca sınırlı bir bit genişliğini destekleyen bir durum düşünün. Base64 yalnızca alfasayısal karakterler, kullanan bir kodlama herhangi bir giriş dönüştürür +, /ve =bir dolgu karakter olarak.


8

Burada tarif edeceğim Base64 kullanımı biraz hack. Yani hack'leri sevmiyorsanız, lütfen devam etmeyin.

MySQL'in utf8'inin 4 baytlık unicode karakterleri desteklemediğini fark ettiğimde belaya girdim çünkü utf8'in 3 baytlık bir sürümünü kullanıyor. Peki MySQL'in utf8 üzerinde tam 4 bayt unicode desteklemek için ne yaptım? Eh, veritabanına depolarken base64 dizeleri kodlarken ve alma sırasında base64 kodunu çözer.

Base64 kodlama ve kod çözme çok hızlı olduğundan, yukarıdakiler mükemmel çalıştı.

Dikkat etmeniz gereken aşağıdaki noktalar var:

  • Base64 kodlaması% 33 daha fazla depolama alanı kullanır

  • Veritabanında saklanan dizeler insan tarafından okunamayacak (Bunu bir özellik olarak veritabanı dizelerinin temel bir şifreleme biçimi kullandığını satabilirsiniz).

Unicode'u desteklemeyen herhangi bir depolama motoru için yukarıdaki yöntemi kullanabilirsiniz.


6
"Bunu veritabanı dizeleri temel bir şifreleme biçimi kullanmak bir özellik olarak satabilirsiniz" Stilinizi seviyorum: D
Ercan

7
"Bunu, veritabanı dizelerinin temel bir şifreleme biçimi kullandığını bir özellik olarak satabilirsiniz" demek ne korkunç bir şey: D
Alex

1
base64 kod çözme algoritması olmayan herkese karşı temel şifreleme biçimi rofl: D
Eladian

1
@Alex Hiç "söylemek korkunç bir şey" değil. İkinci derece hassas veriler, db yöneticileri tarafından okunamaz hale getirmek için base64 kodlu olabilir. Her veri parçası için en yüksek seviyede şifrelemeye sahip olmak her zaman gerekli değildir. Örneğin, bir db yöneticisinden "yorumları" gizlemek istiyorsanız, base64 iş için uygundur. Gratcias!
Basil Musa

1
MySQL'in artık tüm Unicode için desteğe sahip olduğunu belirtmek gerekir, ancak geriye dönük uyumluluk amacıyla, utf8türleri hala sadece üç bayttır; Eğer gerçek bir şey istiyorsanız, kullanın utf8mb4. Nice hack, ama artık gerekli değil.
TRiG

7

Rasgele ikili verileri ASCII metnine dönüştürmek için kullanılır.

Örneğin, e-posta ekleri bu şekilde gönderilir.


7

Büyük ikili nesneleri (görüntüler) web servisleri üzerinden aktardığımızda pratik anlamda kullanıyorum. Yani bir python komut dosyası kullanarak bir C # web hizmeti test ederken, ikili nesne biraz büyü ile yeniden oluşturulabilir.

[Python'da]

import base64
imageAsBytes = base64.b64decode( dataFromWS )

1
Veriler daha hızlı seyahat ediyor mu?
FelipeM

6

“Base64 kodlama şemaları, metinsel verilerle başa çıkmak üzere tasarlanmış ortamlar üzerinde depolanması ve aktarılması gereken ikili verilerin kodlanması gerektiğinde yaygın olarak kullanılır. Bu, taşıma sırasında değişiklik yapılmadan verilerin bozulmadan kalmasını sağlamak içindir ”(Wiki, 2017)

Örnek olarak şunlar verilebilir: yalnızca ASCII karakterlerini kabul eden bir web hizmetiniz var. Kullanıcı verilerini kaydetmek ve daha sonra başka bir konuma (API) aktarmak istiyorsunuz ancak alıcı el değmemiş veri almak istiyor. Base64 bunun içindir. . . Tek dezavantajı, base64 kodlamasının normal dizelerden yaklaşık% 33 daha fazla alan gerektirmesidir.

Başka Örneği :: uenc = url kodlanmış = aHR0cDovL2xvYy5tYWdlbnRvLmNvbS9hc2ljcy1tZW4tcy1nZWwta2F5YW5vLXhpaS5odG1s = http://loc.querytip.com/asics-men-s-gel-kayano-xii.html .

Gördüğünüz gibi, son ziyaret edilen URL'yi parametre olarak göndermek istiyorsak char / / karakterini koyamayız çünkü “MOD yeniden yazma” - GET parametresi için öznitelik / değer kuralını kıracağız.

Bunun tam bir örneği: “ http://loc.querytip.com/checkout/cart/add/uenc/http://loc.magento.com/asics-men-s-gel-kayano-xii.html/product / 93 /


4

Çoğunlukla, ikili verileri yalnızca ascii veya basit karakter kümelerini işleyebilecek bağlamlarda kodlamak için kullanıldığını gördüm.


3

Brad'in söylediklerini biraz genişletmek için: e-posta ve Usenet için birçok taşıma mekanizması ve diğer veri taşıma yolları "8 bit temiz" değildir, bu da standart ascii karakter setinin dışındaki karakterlerin transit olarak yönetilebileceği anlamına gelir - örneğin, 0x0D, satır başı olarak görülebilir ve satır başı ve satır beslemesine dönüştürülebilir. Base 64, tüm ikili karakterleri çeşitli standart ascii harfleri ve sayıları ve noktalama işaretleri ile eşleştirir, böylece bu şekilde karıştırılmazlar.


2

Base64

Base64, ikili verileri sayısal olarak işleyip bir temel 64 gösterimine çevirerek kodlayan bir dizi benzer kodlama şeması için genel bir terimdir. Base64 terimi belirli bir MIME içerik aktarımı kodlamasından kaynaklanır.

Base64 kodlama şemaları, metinsel verilerle başa çıkmak üzere tasarlanmış ortamlar üzerinde depolanması ve aktarılması gereken ikili verilerin kodlanması gerektiğinde yaygın olarak kullanılır. Bu, verilerin taşıma sırasında herhangi bir değişiklik yapılmadan bozulmadan kalmasını sağlamak içindir. Base64, MIME yoluyla e-posta ve karmaşık verilerin XML'de depolanması dahil olmak üzere birçok uygulamada yaygın olarak kullanılır.


0

Base64 birçok amaç için kullanılabilir.

Birincil neden, ikili verileri geçilebilir bir şeye dönüştürmektir.

Bazen JSON verilerini bir siteden diğerine aktarmak, bir kullanıcı hakkındaki çerezlerde bilgi depolamak için kullanıyorum.

Not: Şifreleme için "kullanabilirsiniz" - İnsanların neden yapamayacağınızı söylediklerini ve şifreleme olmadığını kolayca anlayabiliyorum, ancak kolayca kırılabilir ve kaşlarını çattı. Şifreleme, bir veri dizisini daha sonra şifresinin çözülebileceği veya çözülemeyeceği başka bir veri dizisine dönüştürmekten başka bir şey ifade etmez ve base64 bunu yapar.



2
Sen "şifreleme" tanımını yorumluyorsun kadar fazla ciddiye. Kelime, kökeninden biraz daha belirgin bir şeye dönüştü.
Dan Bechard

0

Bir onaltılık basamak bir kırıntıdan (4 bit) oluşur. İki nibble, 1 bit olarak da adlandırılan 8 bit yapar.

MD5, 32 onaltılık basamak dizisi kullanılarak temsil edilen 128-bitlik bir çıktı üretir ve bu da 32 * 4 = 128 bittir. 128 bit 16 bayt oluşturur (1 bayt 8 bit olduğu için).

Her Base64 karakteri 6 bit kodlar (2, 4 veya 6 bit kodlayabilen son ped olmayan karakter ve varsa son pad karakterleri hariç). Bu nedenle, Base64 kodlaması için, 128 bitlik bir karma en az ⌈128 / 6⌉ = 22 karakter ve varsa varsa ped gerektirir.

Base64 kullanarak, istenilen uzunlukta (6, 8 veya 10) kodlanmış çıktı üretebiliriz. 8 karakter uzunluğundaki çıkışa karar vermeyi seçersek, yalnızca 8 bayt kaplar, 128 bitlik karma çıkış için 16 bayt kaplar.

Bu nedenle, güvenliğe ek olarak, tüketilen alanı azaltmak için base64 kodlaması da kullanılır.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.