Mật mã gia tăng


19

Nhiệm vụ này khá đơn giản và sử dụng ba ký tự "toán tử" riêng biệt. Nhiệm vụ của bạn là, với một chuỗi đơn giản của các chữ cái, thực hiện các nhiệm vụ sau đây để mã hóa nó sử dụng <, >, *. Bạn có thể chọn sử dụng chữ hoa hoặc chữ thường, bạn không phải xử lý cả hai.


Giải thích mật mã

Mật mã rất đơn giản, bạn đang sử dụng các thao tác tăng và giảm để duyệt từ chữ 1 đến chữ cuối, với *chức năng "gửi" của bạn. Toán tử cho "gia tăng" sẽ là >và "giảm" sẽ là <.

Một ví dụ sử dụng từ này adbc:

  • Bắt đầu với chữ cái đầu tiên của từ, xuất ra chữ cái đó. a
  • Tiếp theo, sử dụng ><(như brainfuck) để "điều hướng" thư hiện tại đến thư tiếp theo. a>sẽ dẫn đến việc 'nâng' alên 1 cho bức thư b. a<sẽ dẫn đến kết quả là zvì bạn hạ thấp chữ cái (nó kết thúc tốt đẹp, bạn phải luôn chọn hướng dẫn đến số lượng hoạt động HÀNG ĐẦU).
  • Sau khi xuất kết hợp tối thiểu hóa chính xác <>xuất ra a *để biểu thị rằng chúng tôi đã đạt được chữ cái tiếp theo.

Các bước để mã hóa adbcsẽ là:

a          # a
a>>>*      # ad
a>>>*<<*   # adb
a>>>*<<*>* # adbc

Ví dụ

Các bước để mã hóa azasẽ là:

a       # a
a<*     # az
a<*>*   # aza

Ví dụ khác:

"abcdef"    =  "a>*>*>*>*>*"
"zyaf"      =  "z<*>>*>>>>>*"
"zzzzzz"    =  "z*****"
"z"         =  "z"
"zm"        =  "z<<<<<<<<<<<<<*" or "z>>>>>>>>>>>>>*" (equidistant)
"zl"        =  "z>>>>>>>>>>>>*"
"alphabet"  =  "a>>>>>>>>>>>*>>>>*<<<<<<<<*<<<<<<<*>*>>>*<<<<<<<<<<<*"
"banana"    =  "b<*>>>>>>>>>>>>>*<<<<<<<<<<<<<*>>>>>>>>>>>>>*<<<<<<<<<<<<<*" OR "b<*<<<<<<<<<<<<<*>>>>>>>>>>>>>*<<<<<<<<<<<<<*>>>>>>>>>>>>>*"
"abcdefghijklmnopqrstuvwxyz" = "a>*>*>*>*>*>*>*>*>*>*>*>*>*>*>*>*>*>*>*>*>*>*>*>*>*"
"abcdefz"   =  "a>*>*>*>*>*<<<<<<*"

Quy tắc

  • Chúng tôi đang mã hóa không giải mã, vì vậy đừng gây rối.
  • Bạn có thể cho rằng tin nhắn sẽ chứa các chữ cái [A-Z]hoặc [a-z], sự lựa chọn của bạn.
  • Bạn có thể sử dụng bất kỳ ký tự không phải chữ cái / số / dành riêng để biểu thị *(EG $).
  • Bạn phải có kết thúc *, nó không ngầm định lặp lại.
  • Bạn có thể cho rằng không có chuỗi trống, nhưng một ký tự là có thể.
  • Nếu nó tương đương với một trong hai chữ cái tiếp theo, bạn có thể chọn một hướng.
  • Đây là , byte thấp nhất.

Hãy giải thích câu trả lời của bạn, nó giúp người khác học theo cách này.


Để rõ ràng, trường hợp thử nghiệm cuối cùng đại diện abcdefghijklmnopqrstuvwxyzvà không phải là đầu vào của chính nó?
Nick Clifford

1
@NickClifford có.
Bạch tuộc ma thuật Urn

Tôi nghĩ zlnên sử dụng >.
xnor

4
Bạn có thể vui lòng kiểm tra các ví dụ? alphabettheo ý kiến ​​của tôi a>>>>>>>>>>>*>>>>*<<<<<<<<*<<<<<<<*>*>>>*<<<<<<<<<<<*zlnên z>>>>>>>>>>>>*banananên tồn tại một giải pháp thứ haib<*<<<<<<<<<<<<<*>>>>>>>>>>>>>*<<<<<<<<<<<<<*>>>>>>>>>>>>>*
Jörg Hülsermann

@xnor đúng, là một lỗi đánh máy thủ công từ zm. @jorg bắt tốt, sửa tất cả chúng, là một nỗ lực thủ công.
Bạch tuộc ma thuật Urn

Câu trả lời:


2

Thạch , 17 byte

OIżN$ẋ"@€⁾><;€⁶ṭḢ

Sử dụng một ký tự khoảng trắng thay cho *(một khoảng trắng hoặc một dòng mới , lưu một byte trên ”*).

Làm việc với một trong hai chữ hoa-only hoặc nhập chữ thường-only.

Hãy thử trực tuyến! hoặc xem bộ kiểm tra (trong đó các không gian đó được thay thế bằng cách*đọc dễ dàng).

Làm sao?

OIżN$ẋ"@€⁾><;€⁶ṭḢ - Main link: string s          e.g. "adbc"
O                 - cast s to ordinals                [97,100,98,99]
 I                - incremental differences           [3,-2,1]
    $             - last two links as a monad:
   N              -     negate                        [-3,2,-1]
  ż               -     zip together                  [[3,-3],[-2,2],[1,-1]]
         ⁾><      - literal ['>','<']                 "><"
      "@€         - using reversed @arguments for €ach zip with("):
     ẋ            -     repeat (-n are like zeros)    [[">>>",""],["","<<"],[">",""]]
            ;€    - concatenate €ach with:
              ⁶   -     literal ' '                   [[">>>","",' '],["","<<",' '],[">","",' ']]
               ṭ  - tack to:
                Ḣ -     head of s (1st char)          [['a'],[">>>","",' '],["","<<",' '],[">","",' ']]
                  - implicit print   (" not printed:) "a>>> << > "

11

Mã máy 8086, 70 68 67 byte

00000000  be 82 00 bf 43 01 57 31  d2 ac 3c 0d 74 2c 89 d1  |....C.W1..<.t,..|
00000010  88 c2 aa e3 f4 4f 28 c1  9f 88 e7 79 02 f6 d9 83  |.....O(....y....|
00000020  f9 0d 9f 76 05 83 e9 1a  f6 d9 30 fc 9e b0 3c 78  |...v......0...<x|
00000030  02 b0 3e f3 aa b0 2a aa  eb cf c6 05 24 b4 09 5a  |..>...*.....$..Z|
00000040  cd 21 c3                                          |.!.|
00000043

Làm thế nào nó hoạt động:

            |   org 0x100
            |   use16
be 82 00    |       mov si, 0x82        ; source = command line arguments
bf 43 01    |       mov di, result      ; destination = result
57          |       push di
31 d2       |       xor dx, dx          ; clear dx
ac          |   n:  lodsb               ; al = *si++
3c 0d       |       cmp al, 0x0d        ; end of input reached? (newline)
74 2c       |       je q                ; jump to exit in that case
89 d1       |   @@: mov cx, dx          ; store last char in cl
88 c2       |       mov dl, al          ; and store the current char in dl
aa          |       stosb               ; *di++ = al
e3 f4       |       jcxz n              ; skip encoding this char if cx == 0 (only happens for the first char)
4f          |       dec di              ; move di pointer back
28 c1       |       sub cl, al          ; take the difference between this char and the last one
9f          |       lahf                ; store flags from last subtraction in bh
88 e7       |       mov bh, ah
79 02       |       jns @f
f6 d9       |       neg cl              ; make sure cl is positive
83 f9 0d    |   @@: cmp cl, 13          ; which way is shorter?
9f          |       lahf                ; also store these flags
76 05       |       jbe @f
83 e9 1a    |       sub cl, 26          ; invert cl if we're going backwards
f6 d9       |       neg cl
30 fc       |   @@: xor ah, bh          ; xor saved flags together
9e          |       sahf                ; load flags register with the result
b0 3c       |       mov al, '<'
78 02       |       js @f               ; now the sign flag tells us which operator to use
b0 3e       |       mov al, '>'
f3 aa       |   @@: rep stosb           ; while (cx--) *di++ = al
b0 2a       |       mov al, '*'         ; mark the end with an asterisk
aa          |       stosb
eb cf       |       jmp n               ; repeat
c6 05 24    |   q:  mov byte [di], '$'  ; mark end of string
b4 09       |       mov ah, 0x09        ; dos function: print string
5a          |       pop dx              ; dx = string pointer
cd 21       |       int 0x21            ; syscall
c3          |       ret
            |   result rb 0

Điều này. Điều này là vượt quá mát mẻ. Bạn đã làm điều này thực sự nhanh chóng quá, dang.
Bạch tuộc ma thuật Urn

Cảm ơn. Đó là khá nhiều giải pháp tầm thường mặc dù. Chỉ xảy ra khá ngắn vào năm 8086.
user5434231

10

Python 3 , 87 byte

r,*s=input();p=r
for c in s:d=(ord(p)-ord(c)-13)%26-13;r+='<'*d+'>'*-d+'*';p=c
print(r)

Hãy thử trực tuyến!

Hoạt động với chữ thường hoặc chữ hoa.

Chương trình xây dựng chuỗi đầu ra rkhi nó lặp qua các ký tự trong chuỗi đầu vào. Nó lưu trữ ký tự trước đó pvà tính toán thao tác tăng dần để pchuyển sang ký tự mới c.

Khoảng giữa các ký tự là ord(c)-ord(p)(ord(c)-ord(p)-13)%26-13lấy modulo 26 thành khoảng [-13..12]. Kết quả tiêu cực có nghĩa là bước xuống ngắn hơn và kết quả tích cực có nghĩa là bước lên. Điều này cần phải được chuyển đổi thành một chuỗi >hoặc <tùy thuộc vào dấu hiệu. Thay vì sử dụng abshoặc có điều kiện, chúng tôi tận dụng phép nhân chuỗi của Python s*nđể tạo chuỗi trống khi nâm. Trong biểu thức '<'*-d+'>'*d, phần ký sai không đóng góp.

Trạng thái ban đầu được xử lý bằng cách chia đầu vào thành ký tự đầu tiên và phần còn lại với phần giải nén của Python 3 r,*s=input(). Ký tự ban đầu được sử dụng để bắt đầu xây dựng chuỗi, cũng như char "trước" ban đầu.

Cảm ơn các ovs đã gợi ý chuyển sang Python 3 để thực hiện việc giải nén này.



3

JavaScript (ES6), 118 109 107 byte

Chuỗi đầu vào không phân biệt chữ hoa chữ thường.

s=>s.replace(/./g,(c,i)=>(d=~~s-(s=parseInt(c,36)),i)?'<><>'[k=d/13+2|0].repeat([d+26,-d,d,26-d][k])+'*':c)

Làm thế nào nó hoạt động

Không giống như Python, toán tử modulo JS trả về một số có cùng dấu với cổ tức thay vì số chia. Ngoài ra, repeat()phương thức JS đưa ra một lỗi khi được cung cấp một số âm, thay vì trả về một chuỗi trống (và dù sao nó cũng dài hơn đáng kể so với một đơn giản *).

Đây là những hành vi khá bất lợi cho thử thách này. Vì vậy, chúng tôi nên xác định tốt hơn trong trường hợp chính xác chúng tôi đang làm thay vì dựa vào các thủ thuật toán học. (Điều đó không có nghĩa là những mánh khóe đó không tồn tại, mà là tôi đã không tìm thấy chúng.)

Dưới đây là bảng mô tả 4 trường hợp sở hữu, trong đó dkhoảng cách được ký giữa ký tự hiện tại và ký tự trước đó:

d           | floor(d / 13) + 2 | direction | repeat
------------+-------------------+-----------+-------
-25 ... -14 |         0         |     <     | d + 26
-13 ... -1  |         1         |     >     | -d  
 +0 ... +12 |         2         |     <     | +d  
+13 ... +25 |         3         |     >     | 26 - d

Các trường hợp thử nghiệm


2

PHP, 127 byte

for($l=ord($r=($s=$argn)[0]);$x=ord($s[++$i]);$l=$x)$r.=str_pad("",($a=abs($n=$l-$x))<14?$a:26-$a,"><"[$n>0^$a>13])."*";echo$r;

Tủ thử

PHP, 137 byte

for($l=$r=($s=$argn)[0];$s[++$i];$l=$s[$i])$r.=str_pad("",$d=min($a=abs(ord($l)-ord($s[$i])),$b=26-$a),"><"[$d<$b^$l<$s[$i]])."*";echo$r;

Tủ thử


2

JavaScript (ES6), 111 103 byte

f=
s=>s.replace(/./g,(c,i)=>(p=(n+26-(n=parseInt(c,36)))%26,i?'<>'[p+3>>4].repeat(p>13?26-p:p)+'*':c),n=0)
<input oninput=o.textContent=f(this.value)><pre id=o>

s=>[...s].map(c=>(n=parseInt(c,36),p&&(p=(n+26-p)%26,s+='><'[p+3>>4].repeat(p>13?26-p:p)+'*'),p=n),s=s[p=0])&&s

Phiên bản ban đầu mất 111 byte trước khi tôi điều chỉnh thủ thuật cài đặt của @ Arnauld ntrong khi tính toán p, tôi nghĩ có lẽ có một mẹo khác sử dụng sthay vì nnhưng nó bị trễ nên tôi sẽ không làm phiền:


2

Haskell (lambdabot), 161 153 byte

w(s:n)=s:(join.snd$mapAccumL(ap(,).g)s n);g c n|q<-[c..'z']++['a'..c],(Just l,s)<-minimum$first(elemIndex n)<$>[(q,'>'),(reverse q,'<')]=(s<$[1..l])++"*"

Hãy thử trực tuyến!


Giải trình:

-- Encode a single letter
g c n | q          <- [c..'z']++['a'..c]        -- The alphabet starting from letter c, looping around
      , (Just l,s) <- minimum                   -- Choose the smallest of ..
                    $ first(elemIndex n)        -- the index of the letter n ..
                  <$> [(q,'>'),(reverse q,'<')] -- from the alphabet q and its reverse

      = (s<$[1..l]) -- Repeat < or > the same number of times as the index of n ..
     ++ "*"         -- and append *

-- Encode the whole string
w (s:n) = s                                -- Yield the first char of the input
        : ( join . snd                     -- Concatinate the result of ..
          $ mapAccumL (\a b->(b,g a b))s n -- executing the g function on each letter of the input string ..
                                           -- except the first, passing the previous letter as the 'c' ..
                                           -- argument on each iteration
          )

2

EXCEL VBA 130 byte

s="":p=Mid(s,1,1):For i=1 To Len(s)-1:b=Asc(Mid(s,i+1,1)):a=Asc(Mid(s,i,1)):p=p &String(abs(b-a),IIf(b>a,">","<"))&"*":Next:[a1]=p

Chạy nó từ cửa sổ Excel VBA ngay lập tức.

Giải trình:

Đơn giản cho vòng lặp có chức năng Chuỗi để lặp lại số lần ">" hoặc "<" n trong đó n là sự khác biệt ascii giữa chuỗi ký tự i và i + 1.


2

Java 7-, 232 byte

class C{static void main(String[]a)throws Exception{int i=System.in.read(),j,d,c;p(i);while((j=System.in.read())>10){d=(j-i+26)%26;c=d>13?-1:1;while(d%26>0){d-=c;p(61+c);}p(42);i=j;}}static void p(int k){System.out.print((char)k);}}

Khá nhiều giải pháp tầm thường. Ungolfed và bình luận:

class C {
    static void main(String[] a) throws Exception {
        int i = System.in.read(), j, d, c; // i is the last character. j is the current character. d is the difference. c is the direction (-1 is left, 1 is right)
        p(i); // print the starting character first
        while ((j = System.in.read()) > 10) { // keep going until a newline is hit (or an EOF/EOL for -1)
            d = (j - i + 26) % 26; // get the difference (always positive) by wrapping around
            c = d > 13 ? -1 : 1; // get the direction by finding which way is shorter, going right when it's a tie
            while (d % 26 > 0) { // keep going until the current character is reached
                d -= c; // reduce d in the right direction
                p(61 + c); // < is 60 = 61 + (-1), > is 62 = 61 - (-1)
            }
            p(42); // print an asterisk
            i = j; // set the current character to the new reference point
        }
    }

    static void p(int k) {
        System.out.print((char) k);
    }
}

2

C, 170 byte

e(c){putchar(c);}i;m(a,b){i=b-a?a>b?b-a<14?b-a:-(a+26-b):a-b<14?-(a-b):b+26-a:0;while(i>0)e(62),i--;while(i<0)e(60),i++;}f(char*l){e(*l);while(l[1])m(*l,l[1]),e(42),l++;}

Chi tiết trực tiếp

e(c){ putchar(c); } // encode

g(a,b) // obtain required transition
{
    return (b-a) // calculate distance

         ? (a > b // distance is non-zero

             // if b comes after a
             ? (b-a < 14 // if forward is a shorter path
                 ? b-a // go forward
                 : -(a+26-b)) // otherwise go backward

             // if b comes before a
             : (a-b < 14 // if backward is a shorter path
                 ? -(a-b) // go backward
                 : b+26-a)) // otherwise go forward

         : 0; // if distance is 0
}

// transition
i;m(a,b)
{
    // obtain required transition
    i=g(a,b);

    // encode forward transition
    while(i>0)e('>'), i--;

    // encode backward transition
    while(i<0)e('<'),i++;
}

// incremental cipher function
f(char*l)
{
    e(*l); // encode first character

    while(*(l+1)) // while next character is not END-OF-STRING
        m(*l,*(l+1)), // do transition from current to next character
        e('*'), // encode
        l++; // next
}

Dung dịch mát. Sau đây có lẽ dễ hiểu hơn, nhưng dài hơn 1 byte:#define x q<14?q:q+26 e(c){putchar(c);}i,q;m(a,b){q=b-a;i=q?(a>b?x:-x):0;while(i>0)e('>'),i--;while(i<0)e('<'),i++;}f(char*l){e(*l);while(*(l+1))m(*l,*(l+1)),e('*'),l++;}
Moreaki

1
@Moreaki Thx, nhưng đây là môn đánh gôn, vì vậy chúng tôi luôn hướng tới mục tiêu giảm số byte, dù sao tôi cũng đã thêm giải thích chi tiết về cách hoạt động của mã.
Khaled.K

2

JavaScript (ES6), 140 128 129 111 113 byte

Tôi đã đi một con đường khác đến các giải pháp JS khác nhưng nó không hoạt động tốt lắm - đây là những gì tôi có cho đến nay:

f=

([x,...s])=>x+s.map(y=>`<><>`[r=(d=y[c=`charCodeAt`]()-x[c](x=y))/13+2|0].repeat([d+26,-d,d,26-d][r])+`*`).join``

i.addEventListener("input",()=>o.innerText=i.value&&f(i.value))
console.log(f("adbc"))
console.log(f("aza"))
console.log(f("abcdef"))
console.log(f("zyaf"))
console.log(f("zzzzzz"))
console.log(f("z"))
console.log(f("zm"))
console.log(f("zl"))
console.log(f("alphabet"))
console.log(f("banana"))
console.log(f("abcdefghijklmnopqrstuvwxyz"))
console.log(f("abcdefz"))
<input id=i>
<pre id=o>

  • Đã lưu 12 byte nhờ một gợi ý từ Luke về việc phá hủy chuỗi.
  • Đã thêm 1 byte sửa lỗi đọc sai thử thách mà tôi nghĩ là cho phép một ký tự in cuối cùng ẩn.
  • Đã lưu thêm 18 byte nhờ viết lại rộng rãi bởi Luke.
  • Đã thêm 2 byte vì có vẻ như các số không phải là ký tự in hợp lệ.

Bản gốc, 131 byte


1
([x,...s])=>x+s.map(...)tiết kiệm 12 byte. Lưu ý rằng bạn cũng nên thêm một ký tự in vào cuối. Tôi đề nghị sử dụng một số, sẽ chỉ tốn 2 byte `1`+1thay vì `*`.
Luke

Cảm ơn, Luke; Tôi đã quên tôi có thể phá hủy một chuỗi đầu vào như thế. Tôi phải đọc sai thử thách đêm qua; Tôi có thể đã thề rằng nhân vật in cuối cùng ẩn. Thật không may, chỉ đơn giản là xử lý nó sau khi joinđã dẫn đến một đầu ra không hợp lệ cho các đầu vào chữ cái đơn. Tuy nhiên, di chuyển ký tự in trong mapphương thức chỉ tốn 1 byte.
Xù xì

1
([x,...s])=>x+s.map(y=>'<><>'[r=(d=y[c='charCodeAt']()-x[c](x=y))/13+2|0].repeat([d+26,-d,d,26-d][r])+0).join``cho 111 byte
Luke

Cảm ơn, một lần nữa, @Luke. Trước khi tôi chỉnh sửa nó, bạn có muốn đăng ở trên như câu trả lời của riêng bạn không? Tôi cảm thấy nó khác hoàn toàn với tôi (gần như là sự kết hợp giữa nó và Arnauld) để điều đó ổn.
Xù xì

Không, bạn có thể chỉnh sửa nó. Tôi đã thử chơi một reducegiải pháp, nhưng hóa ra là 115 byte.
Luke

2

C ++, 210 190 byte

Lần thử đầu tiên của tôi khi chơi gôn!

#include<iostream>
int g(char*a){char k,j,d;std::cout<<*a;a++;for(;*a;a++){for(j=*(a-1),d=j-*a,k=d>0?d>13?62:60:d<-13?60:62;j!=*a;j+=k-61,j=j<97?122:j>122?97:j)std::cout<<k;std::cout<<'*';}}

k lưu trữ <,> hoặc * để in. Trước tiên, nó chỉ cần in phần tử đầu tiên của mảng sau đó chạy một vòng lặp cho phần tử đầu tiên đến phần tử cuối cùng của mảng. j lưu phần tử trước đó và sau đó bằng cách so sánh nếu j gần hơn với * a bởi <hoặc> đặt k thành <,> tương ứng và sau đó in k rồi chạy vòng lặp này cho đến khi j trở thành bằng p. Sau đó, sau mỗi kết thúc của vòng lặp thứ hai in *.


2
Chào mừng đến với trang web! Nếu tôi nhớ lại chính xác *p!=0có thể được thay thế bằng *p. Tôi khá chắc chắn rằng không gian trong char *acũng không cần thiết. Bạn cũng sẽ cần #include <iostream>using namespace std;(mặc dù tôi nghĩ rằng có thể rẻ hơn nếu chỉ thêm std::) để làm cho câu trả lời này hoàn chỉnh.
Phù thủy lúa mì

2
Chào mừng đến với trang web! Tôi nghĩ bạn cần bao gồm std::hoặc using namespace std;có lẽ bạn cũng sẽ cần #include <iostream>số lượng byte của mình.
DJMcMayhem

+1, nhưng hãy sửa hai điều đã nói ở trên, chào mừng bạn đến với PPCG;). Kiểm tra một số ngôn ngữ xung quanh TIO Nexus ( tio.run/nexus ) khi bạn có cơ hội! Có lẽ giới thiệu bản thân với Dennis, anh ta là một anh chàng chủ chốt nổi xung quanh đây.
Bạch tuộc ma thuật Urn

Cảm ơn tất cả mọi người cho lời đề nghị và chỉ ra những sai lầm. Tôi sẽ cập nhật mã trong thời gian ngắn.
0x81915

1

05AB1E , 17 byte

¬sÇ¥v„<>y0›èyÄ×ðJ

Hãy thử trực tuyến!

Giải trình

Sử dụng >, <<space>để biểu thị tăng , sụt lần , nộp

¬                  # get the first letter of the input string
 sǥ               # push a list of delta's of the character codes in the input string
    v              # for each delta
     „<>           # push the string "<>"
        y0›        # check if the delta is positive
           è       # use this to index into the string
            yÄ×    # repeat it abs(delta) times
               ðJ  # join to string with a space

Và mất cái này sau 3 giờ.
Bạch tuộc ma thuật Urn

1

Haskell , 167 168 126 byte

f=fromEnum
r=replicate
a?b=mod(f a-f b-13)26-13
c#x=r(c?x)'<'++r(-c?x)'>'
s(c,s)x=(x,s++c#x++"*")
e(x:y)=x:snd(foldl s(x,[])y)

Bây giờ sử dụng giải pháp số học của xnor. Gọi với e strnơi str :: Stringlà chuỗi được mã hóa.


Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.