Golf un numero più grande del numero di Loader


18

Come seguito al programma di abbreviazione più breve la cui dimensione di output supera il numero di Graham e Golf un numero maggiore di TREE (3) , presento una nuova sfida.

Il numero di Loader è un numero molto grande, che è un po 'difficile da spiegare (poiché era esso stesso il risultato di un esercizio di golf con un obiettivo flessibile). C'è una definizione e una spiegazione qui , ma ai fini dell'autocontenimento, cercherò di spiegarlo più avanti in questo post.

L'algoritmo utilizzato da Ralph Loader produce uno dei più grandi numeri di qualsiasi algoritmo (calcolabile) mai scritto! In effetti, il numero di Loader è il più grande numero "calcolabile" sul Wiki di Googology. (Per numero "calcolabile", significano un numero definito in termini di calcolo.) Ciò significa che se la risposta produce un numero maggiore del numero di Loader in un modo interessante (cioè non solo il numero di Loader + 1), si può scendere in Storia di googologia! Detto questo, i programmi che producono qualcosa come il numero di Loader + 1 sono sicuramente risposte valide e contendenti a questa domanda; non aspettarti nessuna fama.

Il tuo compito è creare un programma di terminazione che produca un numero maggiore del numero di Loader. Questo è , quindi vince il programma più corto!

  • Non puoi ricevere input.
  • Alla fine il programma deve terminare in modo deterministico, ma si può presumere che la macchina abbia una memoria infinita.
  • Puoi presumere che il tipo di numero della tua lingua possa contenere qualsiasi valore finito ma devi spiegare come funziona esattamente nella tua lingua (es: un float ha una precisione infinita?)
    • Gli infiniti non sono ammessi come output.
    • Underflow di un tipo di numero genera un'eccezione. Non si avvolge.
  • Devi fornire una spiegazione del perché il tuo numero è così grande e una versione non modificata del tuo codice per verificare se la tua soluzione è valida (poiché non esiste un computer con memoria sufficiente per memorizzare il numero di Loader).

Quindi, ecco una spiegazione del numero di Loader. Vedi http://googology.wikia.com/wiki/Loader%27s_number e i relativi collegamenti per dettagli più precisi. In particolare, contiene un programma che produce esattamente il numero di Loader (per definizione).

Il calcolo delle costruzioni è essenzialmente un linguaggio di programmazione con proprietà molto particolari.

Prima di tutto, ogni programma sintatticamente valido termina. Non ci sono loop infiniti. Questo sarà molto utile, perché significa che se eseguiamo un programma di calcolo arbitrario delle costruzioni, il nostro programma non si bloccherà. Il problema è che ciò implica che il calcolo delle costruzioni non è completo di Turing.

In secondo luogo, tra i linguaggi completi non turing, è uno dei più potenti. In sostanza, se puoi dimostrare che una macchina di Turing si fermerà su ogni input, puoi programmare una funzione nel calcolo delle costruzioni che la simulerà. (Questo non lo rende completo, perché ci sono macchine di arresto che non si possono dimostrare che stanno arrestando.)

Il numero di Loader è essenzialmente un numero di castori occupato per il calcolo delle costruzioni, che è possibile calcolare poiché tutti i programmi coc terminano.

In particolare, loader.c definisce una funzione chiamata D. Approssimativamente, D(x)scorre tutte le stringhe di bit in meno x, le interpreta come programmi coc, esegue quelli sintatticamente validi e concatena i risultati (che saranno anche stringhe di bit ). Restituisce questa concatenazione.

Il numero del caricatore è D(D(D(D(D(99))))).

Una copia più leggibile del codice dalla wiki di googolology

int r, a;

P(y,x){return y- ~y<<x;}

Z(x){return r = x % 2 ? 0 : 1 + Z (x / 2 );}

L(x){return x/2 >> Z(x);}

S(v,y,c,t){
   int f = L(t);         
   int x = r;
   return f-2 ? f>2 ? f-v ? t-(f>v)*c : y : P(f,P(S(v,y,c,L(x)), S(v+2,t=S(4,13,-4,y),c,Z(x)))) : A(S(v,y,c,L(x)),S(v,y,c,Z(x)));
}

A(y,x){return L(y)-1 ? 5<<P(y,x) : S(4,x,4,Z(r));}

D(x) 
{
   int f;
   int d;
   int c=0;
   int t=7;
   int u=14;
   while(x&&D(x-1),(x/=2)%2&&(1)){
      d = L(L(D(x))),
      f = L(r),
      x = L(r),
      c - r||(L(u)||L(r)-f||(x/=2)%2&&(u=S(4,d,4, r),t=A(t,d)),f/2&(x/=2)%2&&(c=P(d,c),t=S(4,13,-4,t),u=S(4,13,-4,u))),
      c&&(x/=2)%2&&(t=P(~u&2|(x/=2)%2&&(u=1<<P(L(c),u)),P(L(c),t)),c=r)
      u/2&(x/=2)%2&&(c=P(t,c),u=S(4,13,-4,t),t=9);
    }
    return a = P( P( t, P( u, P( x, c)) ),a);
}

main(){return D(D(D(D(D(99)))));}

6
Vorrei sconsigliare di sottovalutare questo per somiglianza con la domanda TREE (3): il numero di Loader è molto più grande di TREE (3) che sono richiesti approcci nuovi e interessanti.
lirtosiast,

2
@ fəˈnɛtɪk Bene, la stampa del numero di Caricatore + 1 è ancora interessante dal punto di vista del golf del codice (ad esempio, puoi battere i 512 byte originali?) Ci sono anche alcune generalizzazioni naturali del numero del caricatore che potrebbero essere più facili da implementare (ad esempio, usando ZFC anziché CoC). Inoltre, potrebbero essere utilizzate sequenze di cricche avide o giochi di promessa finita.
PyRulez il

2
Sfortunatamente, poiché non capisco la costruzione del numero di Loader e non sembrano esserci limiti superiori conosciuti in termini di gerarchia in rapida crescita, non posso dare nessuna buona risposta qui. Credo che la maggior parte delle risposte saranno estensioni del numero di Loader o cose come le avide sequenze di cricche e i giochi a promessa finita ...
Simply Beautiful Art

1
@SimplyBeautifulArt Oh ragazzo, se non lo capisci, non è di buon auspicio per questa sfida. : PI potrebbe provare a spiegartelo più dettagliatamente in chat, ma non conosco nemmeno i limiti superiori della gerarchia.
PyRulez,

1
@SimplyBeautifulArt In particolare, dato che la costante di Loader è stata appositamente scelta per cercare di essere il numero più grande generato da una certa quantità di codice (dove come il numero di Graham e TREE (3) a numeri matematicamente interessanti che sembrano così grandi), I pensa che la maggior parte delle risposte sarà solo il numero di Loader + 1.
PyRulez il

Risposte:


9

JavaScript, D ^ 6 (9) ( 508 501 495 492 487 485 481 byte)

_='r=a=0,PN,yEx-~x<<y,ZNEr=x%2?0:1+ZC>>1@LNEx/2>>ZC@S=Bt,f=Ht@x=rEf-2?f>2?f-v?t-(f>v)*c:y:Ff,FSO(v+2,t8y@c,ZCMM:A(AOBZC)GAN,yELC)-1?5<<PC,y):Iy,4,Z(rGDN,f,dQ=0,t=7,u=14Eeval("whileC&&DC-1@61Md=HHDC)Gf=Hr@x=Hr@c-r||(Hu)||Hr)-f||6u=Id,4,r@t=A(t,dGfJdQ@t8t@u8u)Gc&&6t=F~u&2|6u=1<<FHc@uGFHc@tGc=r@uJtQ@u8t@t=9);a=FFt,Fu,PCQ)Ga)"@KKK9MMM6C>>=1)%2&&(8=I13,-4,G)@@),B(v,yQ,N=COBLCGSC(xE)=>J/2&6c=FFP(HL(IS(4,KD(D(M))Q,c';for(Y of $='QMKIHFJECONB@G86')with(_.split(Y))_=join(pop());eval(_)

Questo è un codice codificato.

_='r=a=0,PN,yEx-~x<<y,ZNEr=x%2?0:1+ZC>>1@LNEx/2>>ZC@S=Bt,f=Ht@x=rEf-2?f>2?f-v?t-(f>v)*c:y:Ff,FSO(v+2,t8y@c,ZCMM:A(AOBZC)GAN,yELC)-1?5<<PC,y):Iy,4,Z(rGDN,f,dQ=0,t=7,u=14Eeval("whileC&&DC-1@61Md=HHDC)Gf=Hr@x=Hr@c-r||(Hu)||Hr)-f||6u=Id,4,r@t=A(t,dGfJdQ@t8t@u8u)Gc&&6t=F~u&2|6u=1<<FHc@uGFHc@tGc=r@uJtQ@u8t@t=9);a=FFt,Fu,PCQ)Ga)"@KKK9MMM6C>>=1)%2&&(8=I13,-4,G)@@),B(v,yQ,N=COBLCGSC(xE)=>J/2&6c=FFP(HL(IS(4,KD(D(M))Q,c'; //encoded code
for(Y of $='QMKIHFJECONB@G86')with(_.split(Y))_=join(pop()); //decoding algorithm
eval(_) //Evaluation of the string

Codice decodificato:

r=a=0,P=(x,y)=>x-~x<<y,Z=(x)=>r=x%2?0:1+Z(x>>1),L=(x)=>x/2>>Z(x),S=(v,y,c,t,f=L(t),x=r)=>f-2?f>2?f-v?t-(f>v)*c:y:P(f,P(S(v,y,c,L(x)),S(v+2,t=S(4,13,-4,y),c,Z(x)))):A(A(v,y,c,L(x)),S(v,y,c,Z(x))),A=(x,y)=>L(x)-1?5<<P(x,y):S(4,y,4,Z(r)),D=(x,f,d,c=0,t=7,u=14)=>eval("while(x&&D(x-1),(x>>=1)%2&&(1))d=L(L(D(x))),f=L(r),x=L(r),c-r||(L(u)||L(r)-f||(x>>=1)%2&&(u=S(4,d,4,r),t=A(t,d)),f/2&(x>>=1)%2&&(c=P(d,c),t=S(4,13,-4,t),u=S(4,13,-4,u))),c&&(x>>=1)%2&&(t=P(~u&2|(x>>=1)%2&&(u=1<<P(L(c),u)),P(L(c),t)),c=r),u/2&(x>>=1)%2&&(c=P(t,c),u=S(4,13,-4,t),t=9);a=P(P(t,P(u,P(x,c))),a)"),D(D(D(D(D(D(9))))))

Codice decodificato, non salvato (le condizioni e le cose sono conservate da loader.c):

var r=a=0;
function P(y,x){
  return y-~y<<x;
}
function Z(x){
  return r=x%2?0:1+Z(x>>1);
}
function L(x){
  return x/2>>Z(x);
}
function S(v,y,c,t){
  var f=L(t),x=r;
  return f-2?
           f>2?
             f-v?
               t-(f>v)*c
               :y
             :P(f,P(S(v,y,c,L(x)),S(v+2,t=S(4,13,-4,y),c,Z(x))))
           :A(S(v,y,c,L(x)),S(v,y,c,Z(x)))
}
function A(y,x){
  return L(y)-1?
         5<<P(y,x):
         S(4,x,4,Z(r));
}
function D(x){
  var f,
      d,
      c=0,
      t=7,
      u=14;
  while(x&&D(x-1),(x>>=1)%2&&(1))
    d=L(L(D(x))),
    f=L(r),
    x=L(r),
    c-r||(
      L(u)||L(r)-f||
      (x>>=1)%2&&(
        u=S(4,d,4,r),t=A(t,d)
      ),
      f/2&(x>>=1)%2&&(
        c=P(d,c),
        t=S(4,13,-4,t),
        u=S(4,13,-4,u)
      )
    ),
    c&&(x>>=1)%2&&(
      t=P(
        ~u&2|(x>>=1)%2&&(
          u=1<<P(L(c),u)
        ),
        P(L(c),t)
      ),
      c=r
    ),
    u/2&(x>>=1)%2&&(
      c=P(t,c),
      u=S(4,13,-4,t),
      t=9
    );
  return a=P(P(t,P(u,P(x,c))),a)
};
D(D(D(D(D(D(9))))))

In questo, si presume che sia:

  • Stack di chiamate infinito
  • Memoria infinita
  • Precisione infinita Number
  • Magnitudine infinita Number
  • Gli operatori bitmap e bit a bit lavorano su numeri interi a bit infiniti anziché a 53 bit. La negazione bit a bit nega ancora il bit del segno.

Algoritmo di codifica / decodifica:

La codifica viene eseguita come segue:

  • Prendi una stringa ripetuta, chiamala S.
  • Sostituisci tutte le S nel codice con una chiave K.
  • Metti K e S alla fine.
  • Crea un elenco di chiavi e inserisci anche l'algoritmo di decodifica in modo che il codice venga effettivamente eseguito.

L'algoritmo di decodifica:

  • Prendi l'elenco delle chiavi.
  • Prendi la prima chiave K.
  • Dividi la stringa per ogni K.
  • Poiché l'ultimo dell'array è ciò che sostituisce KS, lo pop e sostituisce tutto K unendo l'array con il valore spuntato S.

La compressione è stata eseguita con questo codice , selezionare solo l'ultima casella. Dal momento che questo codificherà per primo il salvataggio più grande, non è la compressione più efficiente, ma non so neanche come ridurlo.

JavaScript, (339 caratteri )

eval("_㴧爽愽〬偍ⱹ䕸⵾砼㱹ⱚ䵅爽砥㈿〺ㄫ婃㸾ㅀ䱍䕸⼲㸾婃䁓㵂琬昽䡴䁸㵲䕦ⴲ㽦㸲㽦⵶㽴⴨显瘩⩣㩹㩆昬䙓丨瘫㈬琸祀挬婃䭋㩁⡁乂婃⥇䅍ⱹ䕌䌩ⴱ㼵㰼偃ⱹ⤺匨㐬礬㐬娨片䑍ⱦⱤⱣ㴰ⱴ㴷Ⱶ㴱㑅敶慬⠢睨楬敃☦䑃ⴱ䀶ㅋ搽䡈䑃⥇昽䡲䁸㵈牀挭牼簨䡵⥼籈爩ⵦ籼㙵㵓⠴ⱤⰴⱲ䁴㵁⡴Ɽ䝦䥤Ᵽ䁴㡴䁵㡵⥇挦☶琽䙾甦㉼㙵㴱㰼䙈捀畇䙈捀瑇挽牀畉琬捀甸瑀琽㤩㭡㵆䙴ⱆ甬偃Ᵽ⥇愩≀䩊䨹䭋䬶䌾㸽ㄩ┲☦⠸㵓⠴ⰱ㌬ⴴⱇ⥀䀩ⱂ⡶ⱹⱣⱍ㵃乂䱃䝓䌨硅⤽㹉⼲☶挽䙆倨䡌⡊䐨䐨䬩⤧㭦潲⡙映␽❋䩈䙉䕃乍䉀䜸㘧⥷楴栨弮獰汩琨天⥟㵪潩渨灯瀨⤩㭥癡氨弩".split``.map(a=>(d=String.fromCharCode)((c=a.charCodeAt())>>8)+d(c&255)).join``.slice(1))

Questo codice prenderà la stringa a 16 bit come a, la convertirà in stringa a 8 bit con lo stesso binario (BE), e evallo farà .

Il codice decodificato è il codice codificato sopra.

Prova che D ^ 6 (9)> D ^ 5 (99)

Per questo, dovremmo confrontare D (9) e 99.

Eseguendo manualmente il codice, D (9) si trova uguale a (15*2^14849+1)*2^((15*2^14849+1)*2^((15*2^59+1)*2^((15*2^59+1)*2^((15*2^59+1)*2^((15*2^59+1)*2^((15*2^59+1)*2^((15*2^59+1)*2^((15*2^59+1)*2^((15*2^59+1)*2^((15*2^59+1)*2^((15*2^59+1)*2^((15*2^59+1)*2^((15*2^59+1)*2^((15*2^59+1)*2^((15*2^59+1)*2^((15*2^59+1)*2^((15*2^59+1)*2^((15*2^59+1)*2^((15*2^59+1)*2^((15*2^929+1)*2^((15*2^929+1)*2^((15*2^59+1)*2^((15*2^59+1)*2^((15*2^59+1)*2^((15*2^59+1)*2^((15*2^59+1)*2^((15*2^59+1)*2^((15*2^59+1)*2^((15*2^59+1)*2^((15*2^59+1)*2^((15*2^59+1)*2^(15*2^59+1)))))))))))))))))))))))))))))))), e anche D (0) è uguale a 8646911284551352321.

Quindi, D (9) >>> 99, e poiché D è strettamente crescente, D ^ 6 (9)> D ^ 5 (99).

  • 508B-> 501B, -7B
    • -1B per ... Non so perché. Sono passato D(D(D(D(D(99)))))a D(D(D(D(D(D(9)))))). Anche quello ha mescolato le lettere.
    • -6B per aggiungere nuovamente &&(1)per D(x)la condizione di loop.
  • 501B-> 495B, -6B
    • Risolto il problema con la maggior parte dei messaggi /2di posta >>1elettronica perchéNumber
    • 6 byte di salvataggio da qualche parte
    • Puoi vedere il mio tentativo in questo aggiornamento qui
  • 495-> 492B, -3B
    • Modificando il decodificatore da for...ina for...of.
  • 492-> 487B, -5B
    • Rimozione di incarichi non necessari
    • Modifica dei nomi degli argomenti
  • 487-> 485B, -2B
    • 1 byte dall'uso evalper D, la rimozione return.
    • Compressione da 1 byte che combina le parentesi chiuse con una virgola.
  • 485-> 481B, -4B
    • Comprimendo diverse sottostringhe.

Oppure passalo facilmente con uguale lunghezza sostituendo 99 con M9, il che rende il valore D ^ 6 (9).
Naruyoko,

0

Python 3, D ^ 6 (9) ( 608 600 599 byte)

_='r=a=0?CM:#y-~y<<x?H6@r=0.EB1+HI)#r?Fx):#xI>>H)?8t6@TtNr#A(U8HG).f==2BCf,CUS(v+2,/yNc,HGG.f<2Bt-(f>v)*c.f-vBy?A(M:#5<<CM.Fy)-1BOx,4,Z(rG?Jx6,a@f=d=c=0@VW7,14@while 1:@.x:Jx-1)X~E:breakKd,TFJxGNFrNFr)@.c-r:K.not(Fu)or(Fr)-fGQ.E:WOd,4,rRA(Vd)K.fIQ.Yd,cR/t);W/u)@.c:@!.EQ q=~u&2|EK .q:W1<<CFuNu)K  Vc=Cq and u,CFcNtG,rXuI&YVc);W/tR9@a=CCVCu,Cx,cGNa)#a\nprint(JJJJJJ9GGG)X\n!if !  x=xIK#@return . if /O13,-4,6):@global r8S(v,y,c,?\ndef Q:K! K@ @\n B else CP(YE:c=CEx%2Tf,x=FFL(U8FxG,G))HZ(xI>>1JD(My,x)N),OS(4,R);t=Vt,Wu='
for Y in 'WVRONMJIHGUFTEYCB@KQ?86/.#!X':_=_.split(Y);_=_.pop().join(_)
exec(_)

Questo è un codice codificato. estratto:

r=a=0
def P(y,x):
 return y-~y<<x
def Z(x):
 global r
 r=0 if x%2 else 1+Z(x>>1)
 return r
def L(x):
 return x>>1>>Z(x)
def S(v,y,c,t):
 global r
 f,x=L(t),r
 return A(S(v,y,c,L(x)),S(v,y,c,Z(x))) if f==2 else P(f,P(S(v,y,c,L(x)),S(v+2,S(4,13,-4,y),c,Z(x)))) if f<2 else t-(f>v)*c if f-v else y
def A(y,x):
 return 5<<P(y,x) if L(y)-1 else S(4,x,4,Z(r))
def D(x):
 global r,a
 f=d=c=0
 t,u=7,14
 while 1:
  if x:D(x-1)
  x=x>>1
  if ~x%2:break
  d,f,x=L(L(D(x))),L(r),L(r)
  if c-r:
   if not(L(u)or(L(r)-f)):
    x=x>>1
    if x%2:u=S(4,d,4,r);t=A(t,d)
   if f>>1:
    x=x>>1
    if x%2:c=P(d,c);t=S(4,13,-4,t);u=S(4,13,-4,u)
  if c:
   x=x>>1
   if x%2:
    x=x>>1
    q=~u&2|x%2
    if q:u=1<<P(L(u),u)
    t,c=P(q and u,P(L(c),t)),r
  x=x>>1
  if u>>1&x%2:c=P(t,c);u=S(4,13,-4,t);t=9
 a=P(P(t,P(u,P(x,c))),a)
 return a
print(D(D(D(D(D(D(9)))))))

In questo, si presume che sia:

  • Stack di chiamate infinito
  • Memoria infinita

Questa è sostanzialmente una porta della mia risposta JavaScript . Per maggiori dettagli, controlla quello.

La compressione è stata fatta con questo .

Non sono molto esperto in Python, quindi ci sono sicuramente posti dove salvare i byte. Penso che il sub-600 sia possibile. il sotto-600 è stato provato.

  • 608-> 600B, -8B
    • Raggruppati alcuni compiti
    • Condizioni inverse Sper ridurre la parentesi
  • 600-> 599B, ​​-1B
    • Cambiando u/2nell'ultima riga della definizione di Da u>>1, salvando un byte dalla compressione in un carattere con altri >>1s.

0

Ruby, D ^ 6 (9) (553 byte)

_='F=$a=0TEK#y-~yUx.Z@#F=x%2G1?0R1+Z(x/2).L@#x/2>>Z@.8t)VHt);x=F#fG2?A(8L@C8Z@IRf>2?fGv ?yRt-(f>v ?1R0)*cREf,E8L@CS(v+2,t6yCc,Z@I).A(K#Hy)G1?Mx,4,Z(FIR5UEK.D@;$>UxVd=c=0;t=7;u=14;while[xNOx-1CB>0][1];d=HHD@IVW;x=W;cGF&&[Hu)G0&&WGf&&![u=Md,4,FCt=A(t,d)],fJd,cCt6tCu6u)]];cNB&&[t=E~u&2|!(u=1UEHcCu)CEHcCt)Cc=F];uJt,cCu6tCt=9]Q#$a=EEt,Eu,Ex,cIC$a)Q;$>UOOOOOO9III!BN#;return .QT6=M13,-4,8S(v,y,c,@(x)B(x/=2)%2C),J/2&![c=EEP(F$rNG0||G==WHF)HL(I))Ky,x)MS(4,OD(Q;endR: T;def U<<V;f=VUTRQOMKIHWGNFEJCB@86.#!'.each_char{|Y|_=_.split(Y);_=_.join(_.pop())};eval(_)

Questo è un codice codificato. estratto:

$r=$a=0;def P(y,x);return y-~y<<x;end;def Z(x);return $r=x%2==1?0: 1+Z(x/2);end;def L(x);return x/2>>Z(x);end;def S(v,y,c,t);f=L(t);x=$r;return f==2?A(S(v,y,c,L(x)),S(v,y,c,Z(x))): f>2?f==v ?y: t-(f>v ?1: 0)*c: P(f,P(S(v,y,c,L(x)),S(v+2,t=S(4,13,-4,y),c,Z(x))));end;def A(y,x);return L(y)==1?S(4,x,4,Z($r)): 5<<P(y,x);end;def D(x);$><<x;f=d=c=0;t=7;u=14;while[x==0||D(x-1),(x/=2)%2>0][1];d=L(L(D(x)));f=L($r);x=L($r);c==$r&&[L(u)==0&&L($r)==f&&(x/=2)%2==0||[u=S(4,d,4,$r),t=A(t,d)],f/2&(x/=2)%2==0||[c=P(d,c),t=S(4,13,-4,t),u=S(4,13,-4,u)]];c==0||(x/=2)%2&&[t=P(~u&2|(x/=2)%2==0||(u=1<<P(L(c),u)),P(L(c),t)),c=$r];u/2&(x/=2)%2==0||[c=P(t,c),u=S(4,13,-4,t),t=9];end;return $a=P(P(t,P(u,P(x,c))),$a);end;$><<D(D(D(D(D(D(9))))))

Questo codice è invece il Numero del caricatore con D 6 (9).

In questo, si presume che sia:

  • Stack di chiamate infinito
  • Memoria infinita

Questa è sostanzialmente una porta della mia risposta JavaScript e della risposta Python 3 . Per maggiori dettagli, controlla quelli.

La compressione è stata fatta con questo (potrebbe apparire in quanto non esiste).

Sono un principiante al Ruby, quindi forse sotto i 512 è possibile, ma ne dubito.

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.