Mengurai daftar nomor unary yang ditandatangani


16

Angka-angka unary biasanya hanya mewakili bilangan bulat non-negatif, tetapi kita dapat memperluasnya untuk mewakili semua bilangan bulat sebagai berikut:

  • Bilangan bulat positif N direpresentasikan sebagai N 1:5 -> 11111
  • Integer negatif -N direpresentasikan sebagai 0diikuti oleh N 1's:-5 -> 011111
  • Nol direpresentasikan sebagai 0

Kami kemudian dapat mewakili daftar angka-angka ini dengan jelas jika kami gunakan 0sebagai pemisah:

3,-2,0,1
111,011,0,1
111 0 011 0 0 0 1
11100110001

Tugas Anda: ambil string yang mewakili daftar nomor yang belum ditandatangani, dan terjemahkan ke dalam daftar angka desimal.

Detail

Anda dapat berasumsi bahwa input adalah daftar lengkap nomor unary yang ditandatangani. Secara khusus, program Anda tidak perlu menangani 1) input kosong atau 2) input yang berakhir dengan pemisah.

Anda dapat mengasumsikan bahwa besarnya setiap angka tidak akan melebihi 127. Untuk bahasa dengan ukuran string atau daftar maksimum, Anda dapat mengasumsikan bahwa input dan output akan sesuai dengan struktur data bahasa Anda, tetapi algoritma Anda secara teoritis harus bekerja untuk daftar ukuran apapun.

Program atau fungsi Anda dapat melakukan I / O dengan salah satu cara standar . Input dapat berupa string atau daftar karakter, string karakter tunggal, bilangan bulat, atau boolean. Anda dapat menggunakan dua karakter apa saja untuk mewakili 1dan 0; jika Anda tidak menggunakan 1dan 0, tentukan karakter yang Anda gunakan.

Output harus angka desimal dalam format daftar yang masuk akal (khususnya, harus ada semacam pemisah antara angka). Angka negatif harus ditunjukkan dengan tanda minus, meskipun jika bahasa Anda memiliki format berbeda untuk bilangan bulat negatif, saya juga akan menerimanya. Nol dapat direpresentasikan dalam output sebagai 0atau -0.

Uji kasus

1 -> 1
0 -> 0 (or -0, and similarly for the other test cases)
011 -> -2
1101 -> 2,1
1100 -> 2,0
11001 -> 2,-1
110001 -> 2,0,1
11100110001 -> 3,-2,0,1
00000001 -> 0,0,0,-1
01111011111111001111111111111110111111111111111100111111111111111111111110111111111111111111111111111111111111111111 -> -4,8,-15,16,-23,42
01111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 -> -127

2
Nitpick: Karena ini mengandung '0's, itu secara teknis tidak unary. Tantangan bagus!
DJMcMayhem

4
@DJMcMayhem Nitpick ke nitpick: Secara teknis saya tidak pernah mengatakan itu unary. Ini adalah perpanjangan dari unary yang saya sebut "ditandatangani unary." ;)
DLosc

@DJMcMayhem IMO, tantangannya adalah secara khusus bahwa pemisah ( 0) dan awalan tanda negatif ( 0) adalah sama, meskipun masih tidak ambigu, karena Anda tidak dapat memiliki tanda-tanda negatif di tengah-tengah angka (apakah 182--693-1angka? Tidak, dan tidak ada 1111011000101111untuk alasan yang sama persis).
Erik the Outgolfer

Apakah boleh jika daftar yang dikeluarkan dalam urutan terbalik dari input?
DJMcMayhem

baik secara teknis desimal juga bukan desimal karena menggunakan simbol '-'
Unlambder

Jawaban:


10

Python 2 , 73 70 byte

Fungsi yang mengambil string sebagai input dan mengembalikan representasi string dari daftar Python. Nol dapat direpresentasikan baik oleh 0dan -0(saat datang terakhir):

lambda s:`map(len,s.split('0'))`.replace('0, ','-').replace('--','0,')

Penjelasan

  1. splitstring input spada nol.
  2. Ambil panjang setiap string dalam daftar yang dihasilkan (menggunakan map).

Itu membawa kita jauh. Nol adalah pemisah. Dan jumlahnya tidak jelas, sehingga lenmudah dikonversi menjadi desimal. Tapi sekarang kami telah mengacaukan semua penggunaan non-separator 0. Untungnya, semua penggunaan non-pemisah memimpin nol sehingga mereka datang setelah pemisah-nol dan memberi kami string panjang nol ( '00'.split('0') == ['', '', '']). String nol-panjang itu kemudian juga menjadi 0karena len.

  1. Ubah daftar menjadi string ( menggunakan "tanda kutip terbalik" ), sehingga kami dapat memperbaiki kekacauan dengan lebih mudah.
  2. replacesetiap nol yang mendahului nomor lain dengan tanda negatif pada nomor itu sebagai gantinya. Itu memperbaiki penggunaan 0sebagai tanda tetapi itu menghancurkan nol harfiah. Nol literal juga didahului oleh pemisah, jadi mereka sekarang menjadi pasangan tanda hubung ekstra pada nomor berikutnya.
  3. replacemasing-masing --kembali menjadi 0elemen dalam "daftar".

1
Selamat datang di PPCG!
Steadybox

Ini adalah pendekatan yang sangat kreatif! Anda mungkin ingin menambahkan penjelasan singkat sehingga mereka yang tidak berbicara Python dapat menghargai jawaban Anda juga.
DLosc

@Dosc, terima kasih, saya tidak tahu tentang backtick. Penjelasan yang luas juga ditambahkan.
Mercator

8

Retina , 23 21 byte

(.)0
$1 
01
-1
1+
$.&

Cobalah online!

Tahap pertama (.)0<newline>$1<space>cocok dengan karakter apa pun yang diikuti oleh a 0. Pertandingan digantikan oleh karakter pertama diikuti oleh spasi. Ini membagi string dalam angka individual.

Tahap kedua 01<newline>-1menggantikan 0's sebelum blok 1' s ke -tanda.

Tahap terakhir 1+<newline>$.&cocok dengan semua blok 1's dan menggantinya dengan panjang grup.

Berikut ini adalah contoh dengan output dari setiap tahapan.


Sangat bagus - semua ide saya sepertinya bekerja pada 24 byte ...
Neil

1
Bisakah Anda menambahkan penjelasan? Saya tidak bisa bahasa Retina.
Daniel

@Dopapp menambahkan penjelasan
ovs

7

Vim, 56 byte

:s/\v(0?1*)0?/\1\r/g|%s/0/-/|%s/1*$/\=len(submatch(0))
D

Cobalah online!

Saya belum memposting di vim untuk sementara waktu. Saya kebanyakan menggunakan vim karena V kadang terasa menyakitkan. Karena countperintah, yang sempurna untuk mendapatkan angka '1 di telepon akan menimpa angka' 0 di telepon, jadi kita tidak bisa meniadakannya setelah itu.

Penjelasan:

Ini adalah satu byte lebih pendek daripada cara langsung:

:s/\v(0?1*)0?/\1\r/g
:%s/0/-
:%s/1*$/\=len(submatch(0))
D

karena perintah chaining. Karena yang memisahkan perintah, saya akan menggunakannya untuk penjelasan.

:s/                     " Substitute
                        " Search for...
   \v                   "   Enable 'magic'. This determines whether certain atoms require a backslash or not.
                        "   Without it we would have: '\(0\?1*\)0\?', which is 2 bytes longer
      0?                "   An optional 0
        1*              "   Followed by any number of '1's
     (    )             "   (call that group 1)
           0?           "   Followed by another optional 0
             /          " Replace it with...
              \1        "   Subgroup 1
                \r      "   A newline
                  /g    " Do this for every match on the current line.

Sekarang, setiap nomor unary yang ditandatangani ada pada satu baris. Menggunakan '11100110001' sebagai contoh, pada titik ini kita akan memiliki:

111
011
0
1

:%s/0   " Replace every 0
     /- " With a dash  

:%s/1*$/                    " Replace every run of 1's at the end of a line
        \=len(submatch(0))  " With the length of said run

Karena kami menambahkan baris baru di akhir setiap pertandingan, kami memiliki garis kosong sebelum menjalankannya. Setelah menjalankan itu, kita akan memiliki '0' (karena cocok dengan menjalankan 0 '1). Jadi kami hanya menelepon Duntuk menghapus baris ini, membiarkannya kosong


Ugh. :%s/1+$/akan membuat Anda satu byte lebih pendek jika bukan karena kebutuhan untuk backslash +:(
NieDzejkob

@NieDzejkob Saya tidak mengerti mengapa itu akan lebih pendek. Dan juga, itu akan memberikan -bukannya 0atau-0
DJMcMayhem

Saya ingin menghilangkan baris terakhir seperti itu: P, sudahlah.
NieDzejkob

7

Haskell , 68 66 byte

f(x:r)|(a,b)<-span(>0)r=([(0-),(1+)]!!x$sum a):[z|_:t<-[b],z<-f t]

Cobalah online! Mengambil input sebagai daftar nol dan satu. Contoh penggunaan: f [0,0,0,1,1]hasil [0,-2].

Penjelasan:

Pola yang cocok di dalam f(x:r)|(a,b)<-span(>0)rmengikat xelemen pertama input, ake daftar (berpotensi kosong) dari 1s berikut , dan bke seluruh input. Diberikan input [0,1,1,1,0,0,1], kita dapatkan x=0, a=[1,1,1]dan b=[0,0,1].

Angka saat ini adalah jumlah dari anegasi jika x=0, atau jumlah aplus satu jika x=1. Hal ini dicapai dengan mengindeks dengan xmenjadi daftar yang berisi negasi dan peningkatan fungsi, dan menerapkan fungsi yang dihasilkan dengan jumlah dari a: [(0-),(1+)]!!x$sum a.

Daftar sisanya bkosong atau berisi nol yang memisahkan dan nomor berikutnya. Pemahaman daftar [z|_:t<-[b],z<-f t]mencoba untuk mencocokkan bpada pola _:t, yaitu melupakan elemen kepala dan mengikat sisa daftar t. Jika bkosong, kecocokan ini gagal dan pemahaman daftar akan dievaluasi [], yang merupakan kasus dasar untuk rekursi. Kalau tidak, fungsi fini diterapkan secara rekursif tdan pemahaman daftar mengevaluasi semua elemen zdari hasil f t.


3

Bahasa Wolfram (Mathematica) , 80 byte

StringCases[#<>"0",x_~~Shortest@y___~~"0":>(If[x=="0",-#,#+1]&)@StringLength@y]&

Cobalah online!

Menyalahgunakan mekanisme StringCases, karena tidak memeriksa pola yang tumpang tindih. Karena kita mencari dari kiri ke kanan, tanpa tumpang tindih, kita selalu mendapatkan hanya bilangan bulat yang kita butuhkan.

Penjelasan

#<>"0"

Tambahkan nol di bagian akhir

StringCases

Temukan semua pola berikut ...

x_~~Shortest@y___~~"0"

Satu karakter (sebut saja x), diikuti oleh senar nol panjang atau terpanjang yang mungkin (sebut saja y), diikuti oleh nol.

(If[x=="0",-#,#+1]&)@StringLength@y

Berlaku untuk pola yang cocok: ambil panjangnya y. Jika xnol, maka negasikan nilainya. Lain, tambah satu.

Ini mencakup 00juga, karena yakan menjadi string kosong, dan kami akan menghitung -0( == 0).


3

Brain-Flak , 94 (70?) Byte

([]){{}({(<()>)()}{}(<>)<>{<([{}]<>{})><>})
{{}<>([{}])(<>)}{}{}([])}{}<>([]){{}({}<>)<>([])}<>

Cobalah online!

Ini sebenarnya sangat singkat untuk brain-flak.

Ini adalah versi yang dikomentari / dibaca:

([])

{

    #Pop the Stack height
    {}

    (
        #If there isn't a leading 0, evaluate to 1...
        {
            (<()>)

            ()
        }

        #Pop the 0
        {}

        #Push a 0 onto the alternate stack
        (<>)
        <>

        #Run of '1's
        {
            #Decrement the alternate stack
            <([{}]<>{})>
            <>
        }

        #And push it here
    )

    #Was there a not leading 0?

    {
        {}

        #Invert the value on the alternate stack
        <>([{}])(<>)
    }

    #Pop 2 zeros
    {}{}


    ([])

}{}<>

#Push stack height
([])

#Reverse the stack
{

    {}

    ({}<>)

    <>([])

}<>

Jika hasilnya bisa terbalik, kita bisa melakukan ini untuk 70 sebagai gantinya:

([]){{}({(<()>)()}{}(<>)<>{<([{}]<>{})><>}){{}<>([{}])(<>)}{}{}([])}<>

Tip saya ini hampir sempurna untuk situasi ini. Tapi itu tidak berhasil karena kita harus menekan 0 sebelum melakukan operasi (menghitung '1), dan operasi terjadi dalam satu lingkaran. Cara terpendek yang dapat saya lakukan untuk menggunakan tip ini adalah:

([]){{}({(<()>)()}{}(<>)<>{<([{}]<>{})><>})
{{}<>([{}])(<>)}{}{}(<>())<>([])}{}<>{{}({}<>)<>}<>

yang juga 94 byte.



3

Sekam , 20 18 17 15 14 byte

Γ~:?Σṁ_Πȯ₀tΣġ/

Cobalah online!

Penjelasan

Γ~:?Σṁ_Πȯ₀tΣġ/  Input is a list, say x = [0,1,1,0,0,0,1,1]
            ġ   Group by
             /  division.
                This splits x right before each 0: [[0,1,1],[0],[0],[0,1,1]]
Γ               Deconstruct into head y = [0,1,1] and tail z = [[0],[0],[0,1,1]]
   ?Σṁ_Π        Apply to y:
       Π         Product: 0
   ?Σ            If that is nonzero, take sum of y,
     ṁ_          else take sum of negated elements of y: u = -2
        ȯ₀tΣ    Apply to z:
           Σ     Concatenate: [0,0,0,1,1]
          t      Drop first element: [0,0,1,1]
         ₀       Recurse: [0,2]
 ~:             Tack u to the front: [-2,0,2]

Pemisahannya bekerja seperti ini. ġ/memecah argumennya antara setiap pasangan elemen a,byang /a bpalsu. /a badalah pembagian dengan argumen terbalik, sehingga bdibagi dengan a. Nilai yang relevan dalam program ini adalah:

  • /1 1memberi 1(kebenaran).
  • /1 0memberi 0(falsy).
  • /0 1memberi Inf(infinity positif, kebenaran).
  • /0 0memberi Any(nilai seperti-NaN khusus, falsy).

3

Acc !! , 252 237 byte

N
Count i while _/48 {
Count n while 48/_ {
Write 45
50+N
}
_+49/_*50
Count u while _%50/49 {
_+100-_%50+N
}
_/50-1
Count h while _/200 {
Write _/200+48
_%200+1
}
Count t while _/20+_%2 {
Write _/20+48
_%20-_%2
}
Write _/2+48
Write 9
N
}

Penggunaan -0. Menghasilkan angka yang dipisahkan oleh karakter tab, dengan tab tambahan. Cobalah online!

Jumlah waktu menulis algoritma yang sebenarnya: 20 menit. Jumlah waktu debugging kode output desimal saya: 45 menit. : ^ P

Dengan komentar

Saya tidak tahu apakah komentar-komentar ini menjelaskan kode dengan sangat baik - mereka didasarkan pada catatan saya untuk diri saya sendiri ketika saya sedang menulisnya, jadi mereka menganggap beberapa pemahaman tentang bagaimana Acc !! bekerja. Jika ada yang butuh penjelasan lebih lanjut, beri tahu saya dan saya akan mencoba membuatnya lebih jelas.

# We partition the accumulator _ as [number][flag][nextchar]
# [flag] is a 2-value slot and [nextchar] a 50-value slot
# So [nextchar] is _%50, [flag] is _/50%2, [number] is _/100
# [flag] is 1 if we're in the middle of reading a number, 0 if we're between numbers
# It is also used for outputting as decimal (see below)
# Possible input characters are 0, 1, and newline, so [nextchar] is 48, 49, or 10

# Read the first character
N
# Loop while the character we just read is 0 or 1 and not newline
Count i while _/48 {
  # What we do in the loop depends on the combination of [flag] and [nextchar]:
  # 0,48 (start of number, read 0) => write minus sign, [flag] = 1, read another char
  # _,49 (read 1) => increment [number], [flag] = 1, read another char
  # 1,48 (middle of number, read 0) => write/clear [number], status = 0, read another
  #      char
  # 1,10 (middle of number, read <cr>) => ditto; the next read will be 0 for eof, which
  #      means the acc will be less than 48 and exit the loop

  # Process leading 0, if any
  Count n while 48/_ {
    # acc is 48: i.e. [number] is 0, [flag] is 0, [nextchar] is 48 (representing a 0)
    # Output minus sign
    Write 45
    # Set [flag] to 1 (thereby exiting loop) and read [nextchar]
    50+N
  }
  # If number starts with 1, then we didn't do the previous loop and [flag] is not set
  # In this case, acc is 49, so we add (50 if acc <= 49) to set [flag]
  _+49/_*50

  # Process a run of 1's
  Count u while _%50/49 {
    # [nextchar] is 49 (representing a 1)
    # Increment [number] and read another
    _+100-_%50+N
  }

  # At this stage, we know that we're at the end of a number, so write it as decimal
  # This is "easier" (ha) because the number has at most three digits
  # We shift our partitioning to [number][flag] and set [flag] to 0
  _/50-1

  # Output hundreds digit if nonzero
  # Since [number] is _/2, the hundreds digit is _/200
  Count h while _/200 {
    Write _/200+48
    # Mod 200 leaves only tens and units; also, set [flag] to 1
    _%200+1
  }
  # Output tens digit (_/20) if nonzero OR if there was a hundreds digit
  # In the latter case, [flag] is 1
  Count t while _/20+_%2 {
    Write _/20+48
    # Mod 20 leaves only units; clear [flag] if it was set
    _%20-_%2
  }
  # Write units unconditionally
  Write _/2+48

  # Write a tab for the separator
  Write 9
  # Read another character
  N
}

2

Python 2 , 96 92 byte

lambda s:[[len(t),-len(t)+1]['1'>t]for t in s.replace('10','1 ').replace('00','0 ').split()]

Cobalah online!

Thx to ovs dan DLosc untuk masing-masing 2 byte.


2

R , 119 byte

function(x){n=nchar
y=regmatches(x,regexec("(0?)(1*)0?([01]*)",x))[[1]]
cat((-1)^n(y[2])*n(y[3]),"")
if(y[4]>0)f(y[4])}

Cobalah online!

Kode menggunakan solusi ini dari stackoverflow untuk masalah terkait (Terima kasih kepada iri untuk idenya). Outputnya adalah string yang dipisahkan ruang yang dicetak ke stdout.


2

Jelly ,  19  18 byte

Pasti ada cara yang lebih baik ...

®ḢN$Ḣ©?ṄEȧ
ṣ0L€ÇL¿

Program lengkap mencetak setiap nomor diikuti dengan linefeed.

Cobalah online!

Bagaimana?

®ḢN$Ḣ©?ṄEȧ - Link 1, print first number and yield next input: list of numbers, X
           -                              e.g. [8,0,15,16,...] or [0,4,8,0,15,16,...]
      ?    - if...
    Ḣ      - condition: yield head and modify  8([0,15,16,...])   0([4,8,0,15,16,...])  
     ©     -            (copy to register)     8                  0
®          - then: recall from the register    8
   $       - else: last two links as a monad:
 Ḣ         -         yield head and modify                        4([8,0,15,16,...])
  N                  negate                                      -4
       Ṅ   - print that and yield it           8                 -4
        E  - all equal (to get 0 to be truthy) 1                  1
         ȧ - AND the (modified) input          [0,15,16,...]      [8,0,15,16,...]
           -   (ready to be the input for the next call to this link)

ṣ0L€ÇL¿ - Main link: list e.g. [0,1,0,0,0,0,1,1]
ṣ0      - split at zeros       [[],[1],[],[],[],[1,1]
  L€    - length of €ach       [0,1,0,0,0,2]
      ¿ - while...
     L  - condition: length                           1  1  1  0  ([0,1,0,0,0,2], [0,0,0,2], [0,2], [])
    Ç   - action: call the last link (1) as a monad  -1  0 -2     ( - 1            - 0        - 2)

1

QBasic, 88 86 byte

1u$=INPUT$(1)
z=u$<"1
IF n*z THEN?(1-2*s)*(n-s):s=0:n=0ELSE s=s-z:n=n+1
IF"!"<u$GOTO 1

Ini sangat menyenangkan. Berbagai revisi yang dimulai dari versi 107-byte menghasilkan salah satu bit QBasic yang paling dikaburkan yang saya pikir pernah saya tulis. (Sunting: Anehnya, saya bisa bermain golf 2 byte dengan membuat kode lebih jelas.)

Catatan: program ini membaca input pengguna satu karakter pada satu waktu tanpa menggemakannya ke layar (hasil dari menggunakan INPUT$(1)bukan INPUTpernyataan yang biasa ). Jadi saat Anda mengetik, Anda tidak akan melihat angka 1 dan 0, tetapi angka desimal akan muncul saat dihitung. Pastikan untuk menekan Enterdi akhir input untuk melihat nomor terakhir dan mengakhiri program.

Versi tidak disatukan

sign = 0
num = 0
DO
  digit$ = INPUT$(1)
  isZero = (digit$ < "1")
  IF num > 0 AND isZero THEN
    PRINT (1 - 2 * sign) * (num - sign)
    sign = 0
    num = 0
  ELSE
    IF isZero THEN sign = 1
    num = num + 1
  END IF
LOOP WHILE "!" < digit$

Penjelasan

(AKA "Apa ?? Itu masih tidak masuk akal!")

Strategi dasarnya adalah menjalankan loop yang mengambil satu karakter dari INPUT$(1)setiap kali, melakukan hal-hal dengannya, dan terus mengulang selama karakter tersebut memiliki nilai ASCII lebih besar dari itu !(yaitu, bukan baris baru).

Kami melacak angka yang sedang berlangsung menggunakan dua variabel. numadalah jumlah karakter dalam nomor unary yang ditandatangani saat ini (termasuk nol di depannya). signadalah 1jika angka memiliki nol di depan, 0jika tidak. Kedua hal ini perlu diinisialisasi 0, yang bagus untuk versi golf karena variabel numerik dalam QBasic secara otomatis diinisialisasi 0.

Setiap kali kita membaca karakter, hal pertama adalah menentukan apakah karakter itu 1atau bukan 0. Kami akan menggunakan hasil ini dua kali, jadi kami menyimpannya di isZero. Secara teknis, nama itu menyesatkan, karena nilainya juga akan benar jika karakternya adalah baris baru. Perhatikan bahwa kebenaran dalam QBasic adalah -1dan falsey adalah 0.

Sekarang, jika kita sedang membaca angka ( num > 0) dan kami menekan nol atau akhir input ( isZero), kita perlu menghitung angka mana yang sudah kita baca.

  • signmenyimpan 0untuk positif, 1untuk negatif. Untuk mendapatkan 1positif dan -1negatif, kita perlu 1-2*sign.
  • nummenyimpan besaran yang benar untuk positif tetapi satu lebih dari besarnya untuk negatif (karena itu termasuk penanda tanda). Jadi bisa kita gunakan num-signuntuk besarnya.

Lipat gandakan dan cetak; kemudian reset signdan numuntuk 0persiapan membaca nomor berikutnya.

Kalau tidak (jika kita belum mencapai nol, atau jika kita sudah mencapai nol di awal angka), kami memperbarui signdan numsebagai berikut:

  • signmenjadi 1jika kita melihat nol di depan; jika tidak, jika kita melihat satu, itu tetap apa pun yang sudah ada. Kode golf adalah s=s-z, yang sama dengan jumlah yang sama:
    • Jika ini adalah nol di depan, zadalah -1. Karena sdijamin 0(karena ini adalah awal dari nomor baru), s-zakan menjadi 1.
    • Jika ini satu, zadalah 0. Kemudian s-ztetap pada nilai berapa pun ssebelumnya.
  • num bertambah.

Itu dia!


0

JavaScript (ES6), 60 byte

Mengembalikan daftar bilangan bulat yang dipisahkan oleh ruang.

s=>(0+s).replace(/00?1*/g,s=>(l=s.length,+s[1]?l-1:2-l)+' ')

Uji kasus


0

Lua , 58 byte

(...):gsub("(0?)(1*)0?",function(s,n)print(#n-2*#s*#n)end)

Cobalah online!

Program penuh, mengambil input dari baris perintah dan mencetak angka ke stdout dipisahkan oleh baris baru.

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.