Cevabınızı kendi üzerinizden çıkarın


15

<code>...</code>Bu soruya verilen yanıtın ilk HTML bloğunun içeriğini , cevaplar oylara göre sıralandığında hemen sizinkinin üzerinde olan bir program yazın . Top!En iyi cevap sizseniz çıktı alın .

Olumsuz oy kullanan veya <code>...</code>etiketi olmayan cevapları yoksay . Programınızın kaynağı <code>...</code>yayınınızın ilk satırında görünmelidir . Bu bloklar otomatik olarak oluşturulur zaman use backticksveya

indent things with 4 spaces.

Bu kod golf, en az karakterle cevap kazanıyor.

Ek Kurallar (Güncellendi)

  • İstediğiniz programlama dilinde cevap verin, ancak birden fazla cevap verirseniz farklı diller kullanın.
  • Çıktınızı zor kodlayamayabilirsiniz. Programınızın düzgün çalışma yeteneği, oy sayısına veya yukarıdaki cevabın ne olduğuna bağlı olmamalıdır. Oy dağıtımı büyük ölçüde değiştiyse, programınızın yine de üstündeki cevabın kodunu doğru bir şekilde vermesi gerekir.
  • Sen olabilir veya cevabım doğrudan bağlantı (sadece tek bir cevabı varsa) sert kod program böyle adınız olarak cevap, bazı benzersiz özellik aracılığıyla (bu yüzden bir sonraki en yüksek bulmak için gibi) bu sayfada kendisi aramak için.
  • Eğer iki cevabın eşit oyu varsa yine de seninkinin hemen üstünde olanı kullanmalısın.
  • <code>...</code>Cevabınızda birden fazla blok olabilir, ancak birincisi programınızın kaynağını içermelidir.

1
Birden fazla sayfayı hesaba katmam gerekir mi?
Οurous

1
Evet, birden fazla sayfa için hesap vermelisiniz
Calvin'in Hobileri

4
Not inline code spanssadece vardır <code></code>, ancak uygun kod taşlarıdır <pre><code>stuff</code></pre>.
Kapı Tokmağı

3
@ Calvin'sHobbies Sanırım bağlı cevapların sırası (oylarla) rastgele. En azından SO, burada hakkında bir fikrim yok.
Martin Ender

4
Birden fazla sayfanın bakımının gereksiz olduğunu iddia ediyorum - eğer ilk sayfada değilseniz, yine de
KAZANMAZsınız

Yanıtlar:


5

Javascript + jQuery (92 86 64 karakter)

Test etmek için bu sayfadaki Geliştirici Araçlarını açın (genellikle F12) ve kodumu çalıştırın!

Bu Javscript'in bu sayfadan (ve sadece bu sayfadan) konsol kullanılarak çalıştırılması gerekir.

alert($("code",$("#answer-34767").prev().prev()).html()||"Top!")

Çok kısa, kaydırma çubuğuna bile gerek yok!

Temel olarak, cevabımı kimliğe göre bulur ve sonra iki düğümü öne çıkarır (bağlantı bağlantısını atlar). Eğer bu yoksa, zirvede olmalıyım. Sonra ilk codeöğeye iner ve onu alır .innerHTML.

Güzel şey SE varsayılan olarak jQuery kullanır, bu yüzden bile denemeden bu avantajı elde olduğunu.


2
Ben şahsen cevabınızı beğenmedim, çünkü biraz hile gibi ... Her neyse, bu kadar kısa olabilir alert($("code",$("#answer-34767").prev().prev()).html()||"Top!").
core1024

@ core1024: İyileştirme için teşekkürler! Tek bir açıklama yapmayı düşünmemiştim. Çok büyük bir avantajım olduğunu kabul ediyorum. Belki de 78MB'den büyük Firefox kodunu saymalıyım? Kurallar "İstediğiniz programlama dilinde cevap verin" der.
Robbie Wxyz

Firefox'un kodunu saymanıza gerek yok :) Avantajınız yorumlayıcıda değil, mevcut ortamda. Sanki herkes sayfanın kaynağını zaten bir "nesne" / "değişkenine" yüklemiş gibi.
İstismar

4
Eğer ikinci sayfanın üstündeyse "top" u uyarır, doğru davranış bu mudur?
William Barbosa

@WilliamBarbosa: Ben "lrn" ile birlikteyim. (OP'nin sorusu hakkındaki yorumuna bakınız).
Robbie Wxyz

6

PHP 666 611 593 588 580 Karakterler

Düzenleme: Daha önce tinyurl'den daha küçük url kullanıldı.

Düzenleme: Boolean yerine int kullanılan diğer cevap yorumdan sonra. Ayrıca belirgin olan ancak şimdi düzeltilen bir hatayı düzeltmek gerekiyordu.

İşte kodum

<?
$a=34727;$b=new DOMDocument();$b->loadHTMLFile("http://turl.no/t2u");$c=$b->saveHTML();$d=$e=1;$f='data-answerid="';$g=strpos($c,$f);$h=substr($c,0,$g);$c=substr($c,($g+15));while($d==1){$g=strpos($c,'"');$i=substr($c,0,$g);if($i==$a){$j=$h;$k=$e;}$g=strpos($c,'vote-count-post ">');$c=substr($c,($g+18));$g=strpos($c,'<');$l=substr($c,0,$g);$g=strpos($c,'data-answerid="');if($g){++$e;++$e;$h=substr($c,0,$g);$c=substr($c,($g+15));}else{$d=2;}}if($k==1){echo 'Top!';}else{$g=strpos($j,'><code>');$m=strpos($j,'</code></pre>');$n=$m-$g-7;$o=substr($j,($g+7),$n);echo nl2br($o);}

Bunun DOMXPath ve düğümler kullanılarak geliştirilebileceğinden eminim. Ancak bundan oldukça memnunum. Benim cevabımda ne yapacağımıza karar veremedim, ama tek nokta bu kadar göz ardı edildi. Ancak başka bir yanıt gönderildi, bu yüzden artık sorun değil.

Ayrıca URL'yi kısaltmak için tinyurl kullandım ve çok fazla karakter kazandım.

Umarım beğenmişsindir,

Paul.

PS Bu kod defterinde çalışmaz, bu yüzden bir keman gösteremez.

Düzenleme: php etiketleri değiştirilerek 5 tane daha kaydedildi

Burada şu anda kullanmadığım bir alanda çalıştığını görebilirsiniz (bu yüzden sadece gizli bir bağlantı denemiyorum). Bu kalıcı bir bağlantı değildir, ancak şu anda mevcuttur.


Daha da kısa bir urlshortener =) kullanarak daha da kısaltabilirsiniz, örneğin ➡.ws / .v
flawr

Tinyarrows.com bağlantısı ile denedim ama bağlantı gecikmesi sunucu zaman aşımına uğradı. Gerçi gerçekten küçük url'ler.
Paul Drewett

1
Bu sitede, kısaltılmış bir açılış etiketi kullanmak ( <?yerine inanıyorum <?php) ve kapanış etiketini bırakmak kabul edilebilir . Bu size birkaç karakter daha bırakmalıdır.
Justin,

1
turl.no bazı oldukça kısa bağlantılar yapar ve bir Norveç bağlantı kısaltması olduğundan, az sayıda kişi bunu uluslararası olarak fark etmiştir. İşte sizin için bir bağlantı: turl.no/t2u tinyurl.com bağlantınızla aynı sayfayı işaret eder ve 8 karakter kaydeder.
bilde2910

@ bilde2910 Teşekkür ederim, bu işe yaradı ve gerçekten çok küçük bir url. Çok takdir ve Turl.ca ilginç. .Ca alan adlarını seviyor değil :-)
Paul Drewett

4

Dart 412 403

import"dart:io";import"dart:convert";main(){new HttpClient().get("pi.vu",0,"BYga").then((v)=>v.close()).then((r)=>r.transform(UTF8.decoder).join()).then((s,[i,c="Top!"])=>new RegExp(r'<div id="answer-(\d+)[^]*?vote-count-post ">(\d+)[^]*?<table class="fw"').allMatches(s).forEach((m)=>m[1]=="34735"?print(c):m[2][0]!='-'&&(i=(s=m[0]).indexOf("<code>"))>0?c=s.substring(i+6,s.indexOf("</code>",i)):0));}

Ungolfed (yeni satırlar ve önde gelen boşluklarla)

import"dart:io";
import"dart:convert";
main(){
  new HttpClient().get("pi.vu",0,"BYga")
  .then((v)=>v.close())
  .then((r)=>r.transform(UTF8.decoder).join())
  .then((s,[i,c="Top!"])=>
      new RegExp(r'<div id="answer-(\d+)[^]*?vote-count-post ">(\d+)[^]*?<table class="fw"')
      .allMatches(s)
      .forEach((m)=>
          m[1]=="34735"?print(c)
                       :m[2][0]!='-'&&(i=(s=m[0]).indexOf("<code>"))>0
                           ?c=s.substring(i+6,s.indexOf("</code>",i)):0
  ));
}

4

Delphi (688 873885 848 840)

Hala bazı karakterleri tıraş etmeye çalışacağım ama bu işi yapacak :)

Düzenleme: kısaltmak yerine daha uzun yaptım: P
Olumsuz bir oy sayısı veya hiçbir kod blokları olduğunda cevapları görmezden eklemek eklemeyi unuttum.

Düzenleme sırasında sadece golf oynamayan sürümü güncelliyoruz.
8 karakter alan önerilen düzenlemeler için @manatwork'e teşekkürler.

Golf versiyonu:

uses IdHTTP,Classes,MSHTML;const u='http://codegolf.stackexchange.com/questions/34705/output-the-answer-above-yours/34718#34718';var g:TIdHTTP;m:TMemoryStream;l:TStringList;p,t,r,o:OleVariant;s,i,j:int32;c:boolean;begin L:=TStringList.Create;g:=TIdHTTP.Create(nil);m:=TMemoryStream.Create;g.Get(u,m);m.Position:=0;L.LoadFromStream(m);p:=coHTMLDocument.Create as IHTMLDocument2;p.write(l.Text);for I:=0to p.body.all.length-1do begin c:=0>1;t:=p.body.all.item(i);if(t.classname='answer')and(t.id='answer-34718')then if s=0 then writeln('Top!') else for j:=0to o.all.length-1do begin t:=o.all.item(j);if t.tagname='CODE'then writeln(t.innertext);end else if t.classname='answer'then begin for j:=0to t.all.length-1do begin r:=t.all.item(j);if r.tagname='CODE'then c:=1>0 else if c and(r.class='vote-count-post')and(r.innertext[1]<>'-')then begin o:=t;s:=1;end;end;end;end;end.

Ungolfed sürümü:

uses
  IdHTTP,Classes,MSHTML;
const
  u='http://codegolf.stackexchange.com/questions/34705/output-the-answer-above-yours/34718';
  a='answer';b='CODE';
var
  g:TIdHTTP;
  m:TMemoryStream;
  l:TStrings;
  p,t,r,o,z:OleVariant;
  s,i,j:int32;
  c:byte;
begin
  L:=TStringList.Create;
  g:=TIdHTTP.Create(nil);
  m:=TMemoryStream.Create;
  g.Get(u,m);
  m.Position:=0;
  L.LoadFromStream(m);
  p:=coHTMLDocument.Create as IHTMLDocument2;
  p.write(l.Text);
  z:=p.body.all;
  for I:=0to z.length-1do
  begin
    c:=0;
    t:=z.item(i);
    if(t.classname=a)and(t.id='answer-34718')then
      if s=0 then
        write('Top!')
      else
        for j:=0to o.all.length-1do
        begin
          t:=o.all.item(j);
          if t.tagname=b then
            write(t.innertext)
        end
    else if t.classname=a then
      for j:=0to t.all.length-1do
      begin
        r:=t.all.item(j);
        if r.tagname=b then
          c:=1
        else if(c=1)and(r.class='vote-count-post')and(r.innertext[1]<>'-')then
        begin
          o:=t;
          s:=1;
        end;
      end;
  end;
end.

http://codegolf.stackexchange.com/questions/34705/output-the-answer-above-yours/34718#34718olarak değiştirilebilir http://codegolf.stackexchange.com/q/34718, bu da biraz karakter tasarrufu sağlar.
Kapı Tokmağı

Teşekkürler, ne yazık ki olumsuz bir oy sayımı veya kod blokları ile cevapları görmezden gelmek zorunda kaldığım bölümü unuttuğumdan beri biraz eklemek zorunda kaldım: / .. çalışmıyor :( 301 kalıcı olarak taşındım
Teun Pronk

Daha önce önerildiği gibi, TStringsbunun yerine l bildirebilirsiniz . (Ama örnekleme ile devam et TStringList.)
manatwork

Bunun byteyerine c yapmayı denerdim boolean.
manatwork

3

Python - 280

import os, sys, cgi
os.system('wget http://codegolf.stackexchange.com/questions/34705/output-the-answer-above-yours.html -q -O a')
b=[ x[:-2] for x in open('a').read().split('code>') if x[-1]=='/']
for i, m in enumerate(b):
    if m == cgi.escape(open(sys.argv[0]).read()):
        print b[i-1]

Bu benim ilk codegolf, umarım bu golf-y yeterli!

Düzenleme: İpuçları için teşekkürler! Şimdi biraz daha golfçü görünüyor.


İlk denemede kötü görünmüyor! Eğer bağlantı için bir URL kısaltıcı kullanabilirsiniz ve orada (birkaç boşluk kurtulmak rağmen for i,m, m==openvs.).
Christoph Böhmwalder

@HackerCow Bence URL kısaltıcıları genellikle kaşlarını çattı, ama http://codegolf.stackexchange.com/q/34705/14509kesinlikle işe yarayacaktı.
undergroundmonorail

@KidElephant Kodunuzdan bir sürü boşluk kaldırdım. Ben ya da başka bir şey test etmedi ama berbat sürece (mantıksal olarak) aynı program olmalıdır. Dikkat et, ben burada gerekli değildir. ix.io/dsz Beyaz alanı çıkartmak birkaç bayt tasarruf edebilir :)
undergroundmonorail

Ayrıca, kod golf zorlukları için bir bayt sayısı eklemeniz gerekir. Burada sizin için bir tane düzenlerdim, ancak herhangi bir öneri kullanırsanız cevabınız muhtemelen değişecek, bu yüzden rahatsız etmeyeceğim. Bayt sayısını çalıştırarak bulabilirsiniz wc -c $filename. Editörünüz dosyalara sondaki bir yeni satır eklerse (büyük olasılıkla yapar) son puanınızı almak için bundan bir satır çıkarabilirsiniz.
undergroundmonorail

2

Mathematica - 159

Mathematica'da ilk kez ayrıştırma yapıyor

FirstCase[
 Cases[Import["http://bit.do/JGta1","XMLObject"],
 {__,a_,_,_,_,XMLElement[_, {_, "id""answer-34780",__},_],__}a,∞], 
 XMLElement["code",_,{c_}]c,"Top!",∞]

2

Yakut 283 + 17 = 300

Bu, cevapların ne kadar az oy aldığını ve ikinci (veya onbeşinci) cevap sayfası olsun ya da olmasın, başarılı olur. Veri API'sını kullanır.

d=34849
JSON.parse(Net::HTTP.get(URI("http://api.stackexchange.com/2.2/questions/34705/answers?site=codegolf&filter=8G3Ng9T*")))['items'].map{|a|abort$1.gsub(/&.+?;/){|g|g[?a]??&:g[?g]??>:?<}if !d&&a['score']>=0&&/<code>(.*?)<\/code>/m=~a['body']
d=p if a['answer_id']==d}
$><<'Top!'

ile çalıştırılmalıdır ruby -rnet/http -rjson(dolayısıyla +17)

ungolfed:

d = 34849 # this answer id
i = JSON.parse(Net::HTTP.get(URI("http://api.stackexchange.com/2.2/questions/34705/answers?site=codegolf&filter=8G3Ng9T*")))['items'] # stackexchange api answers for this question
i.map{ |a|
  # if we've already hit this answer, the score's above 0 and there's code...
  if !d && a['score']>=0 && /<code>(.*?)<\/code>/m=~a['body'] then
    # abort with html-unescaped code
    abort $1.gsub(/&.+?;/){ |g|
      # this turns &amp;, &gt; and &lt; into &, > and <, respectively
      g[?a] ? ?& : g[?g] ? ?> : ?<       
    }
  end
  # if we are at our answer, set d = nil
  if a['answer_id']==d then 
    d = p 
  end
}
# no abort. puts 'Top!'
$><<'Top!'

Değişiklikler

Sembol regex içinde 300 kaldırılmış parens

302 ilk taahhüt


Filtrenizi güvensiz hale getirerek bazı baytlar kaydedebilirsiniz
pppery

@ppperry lütfen açıklayınız?
Charles

Güvenli olmayan filtreler kullanmak, unescape'i manuel olarak HTML olarak kullanmak istediğiniz anlamına gelir. Filtre belgelerine
pppery

1

PHP 135

<?
preg_match_all('@(\d+?)"></a.*de>(.*)</c@Us',join('
',file('http://pi.vu/BYga')),$m);echo$m[2][array_search(34786,$m[1])-1]?:'Top!';

Düzenleme: lrn'ın URL kısaltıcısı en kısa URL'yi üretir :)

RegEx, her yanıttan önce (yanıt kimliğiyle birlikte) bağlantıyı ve ilk <code>etiketin içindeki içeriği eşleştirir . UBayrak tetikler Ungreedy modu ve sbayrak yapmak .yeni satırlar (çok avuç) eşleşir. Cevaplar kaçış gibi başka bir şeyle eşleşirse endişelenmiyorum, böylece kimse <sayfanın kaynağına değişmezi ekleyemez .

Tüm cevapları aldıktan sonra $m[2] ve kimliklerini , cevabı benimki gibi basmak için $m[1]kullanıyorumecho$m[2][array_search(34786,$m[1])-1] , ya da "Top!", Cevabım sonunda ilk alırsa :)

PHP'de üçlü operatörün kısa devre operatörü olarak kullanılabilmesini seviyorum ?:


Bu harika. Sadece test ettim ama aşağıda birinden kodu gösteriyor. Bunun hızlı bir düzeltme olacağından eminim ama bundan bahsedeceğim. İnanılmaz bir iş olsa da, PHP 135, hala tam olarak inanamıyorum ...
Paul Drewett

1
@PaulDrewett Bu sayfayı özel taramada açarken lütfen siparişe bakın. Giriş yaptığınız sıradan farklı.
core1024

Oh, bu şaşırtıcı. Nedenini merak ediyorum? Hatada bir hata olduğunu belirttiğim için üzgünüm. Benim hatam. Sizi yararlı bir cevap olarak değerlendirdim. Hala şaşırtıcı olduğunu düşünüyorum ...
Paul Drewett

1

Delphi, 461 bayt , 553 bayt

Artık birden fazla sayfayı da işliyor!

golfed:

uses IdHTTP,RegularExpressions;var T,S,O:String;K,V,C:Int32;begin repeat Inc(C);Str(C,S);S:=TIdHTTP.Create.Get('http://codegolf.stackexchange.com/questions/34705/output-the-answer-above-yours?page='+S);T:=T+S;until Pos('<span class="page-numbers next',S)=0;O:='Top!';for T in TRegEx.Split(T,'<a name="') do begin S:=T;Val(Copy(S,1,Pos('"',S)-1),K,C);if C=1then Continue;Delete(S,1,Pos('post ">',S)+6);Val(Copy(S,1,Pos('<',S)-1),V,C);C:=Pos('<code>',S);if(C=0)or(V<0)then Continue;if K=34844then Break;O:=Copy(S,C+6,Pos('</code>',S)-C-6);end;Write(O)end.

(hafifçe)

uses
  IdHTTP,RegularExpressions;
var
  T,S,O:String;
  K,V,C:Int32;
begin
  // download all pages in thread and concat them
  repeat
    Inc(C);
    Str(C,S);
    S:=TIdHTTP.Create.Get('http://codegolf.stackexchange.com/questions/34705/output-the-answer-above-yours?page='+S);
    T:=T+S;
  until Pos('<span class="page-numbers next',S)=0;
  O:='Top!'; // initialize code string to 'Top!'
  for T in TRegEx.Split(T,'<a name="') do begin
    S:=T;
    Val(Copy(S,1,Pos('"',S)-1),K,C); // try to extract user id
    if C=1then Continue; // if failed, continue loop
    Delete(S,1,Pos('post ">',S)+6); // prepare S for next parse
    Val(Copy(S,1,Pos('<',S)-1),V,C); // try to extract vote count
    C:=Pos('<code>',S); // check if <code> tag exists
    if(C=0)or(V<0)then Continue; // make sure vote count is positive and <code> tag exists
    if K=34844then Break; // if its our answer, break the loop
    O:=Copy(S,C+6,Pos('</code>',S)-C-6); // get string in <code> tag
  end;
  Write(O); // write <code> string
end.

Nasıl çalıştırılır:

app.exe > output.txt

güzel, html birimlerini kullanmak yerine bunu da yapmış olabilir .. utanç Bunu düşünmedim: P
Teun Pronk

Teşekkürler. Ayrıca, birden fazla sayfayı da işleyen (yalnızca değil) kodlardan biri.
Marko Paunovic

1

PHP - 412 - 422 - 416 - 252 - 248:

Halen devam etmekte olan bir çalışma, birden fazla sayfa ile ilgili hiçbir şey yapmadım (başka kimseye de sahip değil mi?)

Bir sürü ekstra dom keserek 200 karakter düşüşünü aldım, neden sadece konumlarını bulabildiğimde nesneleri aramalıyım?

Bu aynı zamanda benim ilk kod golf! 200'lerde ve dom yöntemleri kullanarak yaptığım için mutluyum. Yorumlar sayesinde, sadece 4 karakter daha traş ettim.

Dom çaprazlama konusunda jquery / jscript gibi bir şey yapmak istedim ve hala bu zayıflama üzerinde çalışıyorum. Belki de kullanıcı adım olarak "asi" aramaktan kaçabilirim?

Golf:

<? $d=new DOMDocument;$d->loadHTMLFile("http://bit.do/JGta");$x=new DOMXPath($d);$r=$x->query("//*[@class='answer']");$a=-1;while($f=$r->item(++$a))if(strpos($f->nodeValue,"Asitaka"))echo$x->query(".//pre//code",$r->item($a-1))->item(0)->nodeValue;

biçimlendirilmiş:

    <?php
$d = new DOMDocument();
$d->loadHTMLFile("http://bit.do/JGta");
$x = new DOMXPath($d);
$r = $x->query("//*[@class='answer']");
$a = -1;
while($f = $r->item(++$a))
        if ( stripos($f->nodeValue, "Asitaka")!= 0)
            echo $x->query(".//pre//code",$r->item($a-1))->item(0)->nodeValue;
?>

Şerefe


İçinde parantezler new DOMDocument()ve kapanış ?>PHP'de atlanabilir.
jimmy23013

Teşekkürler, 4 karakter daha kaybetti. Şu anda, farklı sınıflar kullanmadıkça, DOM erişimcilerinin pahalı olduğunu nasıl kısaltacağımı hayal edemiyorum.
Asitaka

Kullanıcı adınızı değiştirerek karakterleri kaydedin!
DavidG

Bence bu harika. Ben sadece DOMXPath sorgu bölümünü öğrenmeye çalışıyorum ama itiraf etmeliyim ki zor buluyorum. Bunun için denedim ama alamadım. Sizinkini test ettim, ancak doğrudan yukarıdaki değil, yukarıdaki iki tanesini bildiriyor gibi görünüyor. Hızlı bir düzeltme olduğundan eminim ama sadece ben söyleyebilirim düşündüm.
Paul Drewett

Bu bilgiyi takiben, "Bu sayfayı özel taramada açarken sıraya bakınız. Giriş yaptığınız sıradan farklıdır - core1024" farklı cevap yorumundan Aynı şeyin burada da olduğunu varsaymak zorundayım. Bunun için özür dilerim.
Paul Drewett

1

Python 3, 197 191 bayt

import urllib.request as u,gzip,json;p='Top!'
for r in json.loads(gzip.decompress(u.urlopen("http://bit.ly/2hN8TKV").read()).decode())["items"]:
 if r['answer_id']==82837:exit(p)
 p=r['body']

Kurallar, API'yi kullanamayacağımı ve bir URL kısaltıcısını kullanamayacağımı söylemiyor.

https://tinyurl.com/hdemk76Genişletir https://api.stackexchange.com/2.2/questions/34705/answers?order=desc&sort=votes&site=codegolf&filter=withbody&pagesize=100 Bu, yalnızca oylamaya göre sıralanmış en iyi 100 yanıt içindeyse çalışır.


-6 https://tinyurl.com/hdemk76ile değiştirirsenhttp://bit.ly/2hN8TKV
Taylor Scott
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.