Cocokkan string yang panjangnya adalah kekuatan keempat


28

Dalam lingkup pertanyaan ini, mari kita pertimbangkan hanya string yang terdiri dari karakter yang xdiulang beberapa kali secara sewenang-wenang.

Sebagai contoh:

<empty>
x
xx
xxxxxxxxxxxxxxxx

(Ya, sebenarnya tidak harus x- karakter apa pun boleh saja asalkan seluruh string hanya memiliki 1 jenis karakter)

Menulis regex di setiap rasa regex pilihan Anda untuk mencocokkan semua string yang panjangnya n 4 untuk beberapa bilangan bulat non-negatif n (n> = 0). Misalnya, string dengan panjang 0, 1, 16, 81, dll. Valid; sisanya tidak valid.

Karena keterbatasan teknis, nilai n yang lebih besar dari 128 sulit untuk diuji. Namun, regex Anda seharusnya bekerja secara logis dengan benar.

Perhatikan bahwa Anda tidak diizinkan untuk mengeksekusi kode arbitrer di regex Anda (untuk pengguna Perl). Sintaks lain (lihat-sekitar, referensi-belakang, dll.) Diizinkan.

Harap sertakan juga penjelasan singkat tentang pendekatan Anda terhadap masalah tersebut.

(Tolong jangan rekatkan penjelasan sintaksis regex yang dibuat secara otomatis, karena tidak berguna)


"xx" tidak valid, bukan?
Kendall Frey

@KendallFrey: Tidak. Itu tidak valid.
n̴̖̋h̷͉̃a̷̭̿h̸̡̅ẗ̵̨́d̷̰̀ĥ̷̳

@nhahtdh menurut Anda ada kemungkinan jawaban untuk itu?
xem

1
@ Timwi: Ya. Java, PCRE (mungkin Perl juga, tetapi tidak dapat menguji), .NET. Milik saya tidak bekerja di Ruby / JS.
n̴̖̋h̷͉̃a̷̭̿h̸̡̅ẗ̵̨́d̷̰̀ĥ̷̳

1
Pertanyaan ini telah ditambahkan ke FAQ Ekspresi Reguler Overflow Overflow , di bawah "Advanced Regex-Fu".
aliteralmind

Jawaban:


21

Ekspresi reguler (ir) ini tampaknya berhasil.

^((?(1)((?(2)\2((?(3)\3((?(4)\4x{24}|x{60}))|x{50}))|x{15}))|x))*$

Regex ini kompatibel dengan rasa PCRE, Perl, .NET.

Ini pada dasarnya mengikuti "pohon perbedaan" (tidak yakin apakah ada nama yang tepat untuk itu), yang memberi tahu regex berapa banyak x yang cocok dengan kekuatan keempat berikutnya:

1     16    81    256   625   1296  2401 ...
   15    65    175   369   671   1105 ...
      50    110   194   302   434 ...
         60    84    108   132 ...
            24    24    24 ...  # the differences level out to 24 on the 4th iteration

\2, \3, \4Toko dan update perbedaan seperti yang ditunjukkan pada tanggal 2, 3 dan baris 4, masing-masing.

Konstruk ini dapat dengan mudah diperpanjang untuk kekuatan yang lebih tinggi.

Tentu bukan solusi yang elegan, tetapi itu berhasil.


+1. Jawaban yang bagus Meskipun jawaban ini berbeda dari milik saya (menggunakan regex bersyarat, sedangkan jawaban saya tidak), ia memiliki semangat yang sama dengan solusi saya (mengeksploitasi pohon perbedaan dan memanfaatkan referensi-belakang yang dinyatakan maju dari beberapa mesin regex).
n̴̖̋h̷͉̃a̷̭̿h̸̡̅ẗ̵̨́d̷̰̀ĥ̷̳

ide yang bagus tentang pohon perbedaan. untuk kotak, pohonnya adalah 1 4 9 16 ... 3 5 7 ... 2 2 2, kan?
Sparr

@Sparr terima kasih, dan ya
Volatilitas

24

Solusi Lain

Menurut saya ini adalah salah satu masalah paling menarik di situs ini. Saya perlu berterima kasih pada deadcode karena menabraknya kembali ke atas.

^((^|xx)(^|\3\4\4)(^|\4x{12})(^x|\1))*$

39 byte , tanpa persyaratan atau pernyataan ... semacam. Alternatifnya, seperti yang sedang digunakan ( ^|), adalah jenis kondisional dalam suatu cara, untuk memilih antara "iterasi pertama," dan "bukan iterasi pertama."

Regex ini dapat dilihat berfungsi di sini: http://regex101.com/r/qA5pK3/1

Baik PCRE dan Python menginterpretasikan regex dengan benar, dan itu juga telah diuji dalam Perl hingga n = 128 , termasuk n 4 -1 , dan n 4 +1 .


Definisi

Teknik umum adalah sama seperti pada solusi lain sudah diposting: menentukan ekspresi diri-referensi yang pada setiap iterasi berikutnya sesuai panjang yang sama dengan istilah berikutnya fungsi perbedaan maju, D f , dengan quantifier terbatas ( *). Definisi formal fungsi perbedaan maju:

Definisi 1: fungsi perbedaan maju

Selain itu, fungsi perbedaan urutan yang lebih tinggi juga dapat didefinisikan:

Definisi 2: fungsi perbedaan maju kedua

Atau, lebih umum:

Definisi 3: fungsi perbedaan kth forward

Fungsi perbedaan maju memiliki banyak sifat menarik; itu adalah urutan apa turunannya untuk fungsi kontinu. Misalnya, D f dari n th rangka polinomial akan selalu menjadi n-1 th rangka polinomial, dan untuk setiap i , jika D f i = D f i + 1 , maka fungsi f adalah eksponensial, dalam banyak cara yang sama bahwa turunan dari e x sama dengan dirinya sendiri. Fungsi diskrit paling sederhana di mana f = D f adalah 2 n .


f (n) = n 2

Sebelum kita memeriksa solusi di atas, mari kita mulai dengan sesuatu yang sedikit lebih mudah: regex yang cocok dengan string yang panjangnya adalah kuadrat sempurna. Meneliti fungsi perbedaan maju:

FDF: n ^ 2

Artinya, iterasi pertama harus cocok dengan string dengan panjang 1 , yang kedua string dengan panjang 3 , yang ketiga string dengan panjang 5 , dll., Dan secara umum, setiap iterasi harus cocok dengan string yang dua lebih panjang dari sebelumnya. Regex yang sesuai mengikuti hampir secara langsung dari pernyataan ini:

^(^x|\1xx)*$

Dapat dilihat bahwa iterasi pertama hanya akan cocok dengan satu x, dan setiap iterasi berikutnya akan cocok dengan string dua lebih lama dari sebelumnya, persis seperti yang ditentukan. Ini juga menyiratkan tes kuadrat sempurna pendek luar biasa di perl:

(1x$_)=~/^(^1|11\1)*$/

Regex ini dapat digeneralisasikan lebih lanjut untuk mencocokkan dengan panjang n- gonal:

Angka segitiga:
^(^x|\1x{1})*$

Angka kuadrat:
^(^x|\1x{2})*$

Angka pentagonal:
^(^x|\1x{3})*$

Angka heksagonal:
^(^x|\1x{4})*$

dll.


f (n) = n 3

Pindah ke n 3 , sekali lagi memeriksa fungsi perbedaan maju:

FDF: n ^ 3

Mungkin tidak segera jelas cara mengimplementasikan ini, jadi kami memeriksa fungsi perbedaan kedua juga:

FDF ^ 2: n ^ 3

Jadi, fungsi perbedaan ke depan tidak meningkat dengan nilai konstan, melainkan nilai linier. Itu bagus bahwa ( 'awal -1 th') nilai D f 2 adalah nol, yang menyimpan sebuah inisialisasi pada iterasi kedua. Regex yang dihasilkan adalah sebagai berikut:

^((^|\2x{6})(^x|\1))*$

Iterasi pertama akan cocok dengan 1 , seperti sebelumnya, yang kedua akan cocok dengan string 6 lebih panjang ( 7 ), yang ketiga akan cocok dengan string 12 lebih lama ( 19 ), dll.


f (n) = n 4

Fungsi perbedaan maju untuk n 4 :

FDF: n ^ 4

Fungsi perbedaan maju kedua:

FDF ^ 2: n ^ 4

Fungsi perbedaan maju ketiga:

FDF ^ 3: n ^ 4

Nah, itu jelek. Nilai awal untuk D f 2 dan D f 3 keduanya bukan nol, 2 dan 12 masing-masing, yang perlu dipertanggungjawabkan. Anda mungkin sudah tahu sekarang bahwa regex akan mengikuti pola ini:

^((^|\2\3{b})(^|\3x{a})(^x|\1))*$

Karena D f 3 harus sesuai panjang 12 pada iterasi kedua, sebuah niscaya 12 . Tetapi karena ia bertambah 24 setiap istilah, sarang yang lebih dalam berikutnya harus menggunakan nilai sebelumnya dua kali, menyiratkan b = 2 . Hal terakhir yang perlu dilakukan adalah menginisialisasi D f 2 . Karena D f 2 pengaruh D f langsung, yang pada akhirnya apa yang kita ingin mencocokkan, nilainya dapat diinisialisasi dengan menyisipkan atom yang tepat langsung ke regex, dalam hal ini (^|xx). Regex terakhir kemudian menjadi:

^((^|xx)(^|\3\4{2})(^|\4x{12})(^x|\1))*$

Pesanan Tinggi

Polinomial urutan kelima dapat dicocokkan dengan regex berikut:
^((^|\2\3{c})(^|\3\4{b})(^|\4x{a})(^x|\1))*$

f (n) = n 5 adalah latihan yang cukup mudah, karena nilai awal untuk fungsi perbedaan maju kedua dan keempat adalah nol:

^((^|\2\3)(^|\3\4{4})(^|\4x{30})(^x|\1))*$

Untuk enam polinomial pesanan:
^((^|\2\3{d})(^|\3\4{c})(^|\4\5{b})(^|\5x{a})(^x|\1))*$

Untuk polinomial urutan ketujuh:
^((^|\2\3{e})(^|\3\4{d})(^|\4\5{c})(^|\5\6{b})(^|\6x{a})(^x|\1))*$

dll.

Perhatikan bahwa tidak semua polinomial dapat dicocokkan dengan cara ini, jika salah satu koefisien yang diperlukan adalah non-integer. Sebagai contoh, n 6 mensyaratkan bahwa a = 60 , b = 8 , dan c = 3/2 . Ini dapat diatasi, dalam hal ini:

^((^|xx)(^|\3\6\7{2})(^|\4\5)(^|\5\6{2})(^|\6\7{6})(^|\7x{60})(^x|\1))*$

Di sini saya telah mengubah b menjadi 6 , dan c menjadi 2 , yang memiliki produk yang sama dengan nilai yang dinyatakan di atas. Sangat penting bahwa produk tidak berubah, karena a · b · c · ... mengontrol fungsi perbedaan konstan, yang untuk polinomial urutan keenam adalah D f 6 . Ada dua atom inisialisasi hadir: satu untuk menginisialisasi D f ke 2 , seperti dengan n 4 , dan yang lainnya untuk menginisialisasi fungsi perbedaan kelima menjadi 360 , sementara pada saat yang sama menambahkan dua yang hilang dari b .


Di mesin mana Anda menguji ini?
n̴̖̋h̷͉̃a̷̭̿h̸̡̅ẗ̵̨́d̷̰̀ĥ̷̳

Saya akhirnya mengerti apa yang sedang terjadi. Memang satu-satunya yang dibutuhkan adalah dukungan untuk referensi ke depan. +1
n̴̖̋h̷͉̃a̷̭̿h̸̡̅ẗ̵̨́d̷̰̀ĥ̷̳

@nhahtdh ahh, kamu benar. Referensi ke depan tidak harus merupakan fitur universal juga.
primo

1
Luar biasa! Saya suka betapa pendek, sederhana, dan mudah dimengerti ini. Dengan sarangnya yang dangkal, mudah untuk menghitung dengan tangan bagaimana kelakuannya. Juga, ini sama cepatnya dengan solusi Volatilitas dan nhahtdh . Dan saya suka penjelasan rinci Anda, termasuk demonstrasi bahwa ini bahkan dapat diperluas ke polinomial. Saya akan memberikan poin bonus jika saya bisa.
Deadcode

@ Lynn terima kasih! Tidak mengharapkan itu ...
primo

13

Berikut ini adalah solusi yang tidak menggunakan conditional, dideklarasikan ke depan atau bersarang referensi, melihat di belakang, menyeimbangkan kelompok, atau rekursi regex. Ini hanya menggunakan lookahead dan referensi standar, yang sangat banyak didukung. Saya terinspirasi untuk beroperasi di bawah batasan ini karena Regex Golf , yang menggunakan mesin regex ECMAScript.

Cara regex 50 byte ini bekerja secara konseptual agak sederhana, dan sama sekali berbeda dari semua solusi yang diajukan untuk teka-teki ini. Mengejutkan ketika mengetahui bahwa jenis logika matematika ini dapat diekspresikan dalam suatu regex.

      \2                     \4  \5
^((?=(xx+?)\2+$)((?=\2+$)(?=(x+)(\4+)$)\5){4})*x?$

(Grup Tangkap diberi label di atas regex)

Regex dapat digeneralisasi ke daya apa pun hanya dengan mengganti 4in {4}dengan daya yang diinginkan.

Cobalah online!

Ia bekerja dengan berulang kali membagi kekuatan keempat terkecil dari sebuah prime yang nilai saat ini dapat dibagi. Dengan demikian hasil bagi pada setiap langkah selalu merupakan kekuatan keempat, jika nilai aslinya adalah kekuatan keempat. Hasil akhir akhir 1 menunjukkan bahwa nilai asli memang kekuatan keempat; ini menyelesaikan pertandingan. Nol juga cocok.

Pertama menggunakan kelompok penangkap malas \2untuk menangkap faktor terkecil nomor lebih besar dari 1. Dengan demikian, faktor ini dijamin prima. Misalnya, dengan 1296 (6 ^ 4) awalnya akan menangkap \2= 2.

Kemudian, pada awal loop yang diulang 4 kali, ia menguji untuk melihat apakah angka saat ini dapat dibagi dengan \2, dengan (?=\2+$). Pertama kali melalui loop ini, tes ini tidak berguna, tetapi tujuannya akan menjadi jelas nanti.

Berikutnya dalam loop batin ini, menggunakan kelompok capture serakah \4untuk menangkap faktor terbesar jumlah ini lebih kecil dari itu sendiri: (?=(x+)(\4+)$). Dalam efek ini membagi jumlah oleh faktor utama terkecil, \2; misalnya, 1296 awalnya akan ditangkap sebagai \4= 1296/2 = 648. Perhatikan bahwa pembagian angka saat \2ini secara implisit. Meskipun dimungkinkan untuk secara eksplisit membagi angka saat ini dengan angka yang terkandung dalam kelompok tangkap (yang baru saya temukan empat hari setelah memposting jawaban ini), melakukan hal ini akan membuat regex lebih lambat dan sulit dipahami, dan itu tidak diperlukan, karena faktor angka terkecil yang lebih besar dari 1 akan selalu cocok dengan faktor terbesarnya lebih kecil dari itu sendiri (sehingga produk mereka sama dengan angka itu sendiri).

Karena regex semacam ini hanya dapat "menggerogoti" dari string (membuatnya lebih kecil) dengan meninggalkan hasil di akhir string, kita perlu "memindahkan" hasil pembagian ke akhir string. Hal ini dilakukan dengan menangkap hasil pengurangan (jumlah saat ini dikurangi \4), ke dalam grup tangkap \5, dan kemudian, di luar lookahead, mencocokkan sebagian dari awal nomor saat ini sesuai dengan \5. Ini meninggalkan sisa string yang belum diproses pada akhirnya dengan \4panjang yang cocok .

Sekarang ia kembali ke permulaan loop batin, di mana menjadi jelas mengapa ada tes untuk dapat dibagi oleh faktor utama. Kami baru saja dibagi dengan faktor prima terkecil nomor itu; jika angka masih dapat dibagi oleh faktor itu, itu berarti angka asli mungkin dapat dibagi oleh kekuatan keempat dari faktor itu. Pertama kali tes ini dilakukan tidak berguna, tetapi 3 kali berikutnya, itu menentukan apakah hasil pembagian secara implisit \2masih dapat dibagi \2. Jika masih dapat dibagi dengan \2pada awal setiap iterasi dari loop, maka ini membuktikan bahwa setiap iterasi membagi angka dengan \2.

Dalam contoh kita, dengan input 1296, ini akan berulang sebagai berikut:

\2= 2
\4= 1296/2 = 648
\4= 648/2 = 324
\4= 324/2 = 162
\4= 162/2 = 81

Sekarang regex dapat kembali ke langkah pertama; inilah yang dilakukan final *. Dalam contoh ini, 81 akan menjadi nomor baru; loop selanjutnya akan seperti berikut:

\2= 3
\4= 81/3 = 27
\4= 27/3 = 9
\4= 9/3 = 3
\4= 3/3 = 1

Sekarang akan kembali ke langkah pertama lagi, dengan 1 sebagai nomor baru.

Angka 1 tidak dapat dibagi dengan bilangan prima apa pun, yang membuatnya menjadi tidak cocok dengan (?=(xx+?)\2+$), sehingga keluar dari loop tingkat atas (yang dengan *di akhir). Sekarang mencapai x?$. Ini hanya bisa cocok dengan nol atau satu. Angka saat ini pada titik ini adalah 0 atau 1 jika dan hanya jika angka aslinya adalah kekuatan keempat yang sempurna; jika 0 pada titik ini, itu berarti bahwa loop tingkat atas tidak pernah cocok dengan apa pun, dan jika itu adalah 1, itu berarti loop tingkat atas membagi kekuatan keempat yang sempurna ke bawah sampai tidak dapat dibagi oleh apa pun lagi (atau itu 1 di tempat pertama, yang berarti loop tingkat atas tidak pernah cocok dengan apa pun).

Dimungkinkan juga untuk menyelesaikan ini dalam 49 byte dengan melakukan pembagian eksplisit berulang (yang juga digeneralisasi untuk semua kekuatan - ganti daya yang diinginkan minus satu ke dalam {3}), tetapi metode ini jauh, jauh lebih lambat, dan penjelasan tentang algoritma yang digunakannya berada di luar cakupan Jawaban ini:

^((x+)((\2(x+))(?=(\4*)\2*$)\4*(?=\5$\6)){3})?x?$

Cobalah online!


Dari pengujian saya (hingga panjang 1024), tampaknya itu benar. Namun, regex terlalu lambat - butuh banyak waktu hanya untuk mencocokkan panjang 16 ^ 4, jadi sangat sulit untuk memverifikasi untuk jumlah besar. Tetapi karena kinerja tidak diperlukan, saya akan merasa kecewa ketika saya memahami regex Anda.
n̴̖̋h̷͉̃a̷̭̿h̸̡̅ẗ̵̨́d̷̰̀ĥ̷̳

1
Regex dan Volatilitas Anda luar biasa. Kecepatan dan singkatnya membuat saya kagum, keduanya cocok dengan 100000000 dalam 7,5 detik pada i7-2600k saya, jauh lebih cepat daripada yang saya harapkan dari regex. Solusi saya di sini adalah pada urutan besarnya yang sama sekali berbeda, karena dibutuhkan 12 detik untuk mencocokkan 50625. Tetapi tujuan dengan milik saya bukanlah kecepatan, melainkan menyelesaikan pekerjaan dalam panjang kode minimal menggunakan serangkaian operasi yang jauh lebih terbatas.
Deadcode

Jawaban kami cepat, karena mereka hampir tidak melakukan backtracking. Anda melakukan banyak backtracking ((((x+)\5+)\4+)\3+)\2+$. Milikmu juga luar biasa dengan caranya sendiri, karena aku bahkan tidak bisa memikirkan bagaimana mencocokkan angka kuadrat tanpa referensi-maju yang dinyatakan.
n̴̖̋h̷͉̃a̷̭̿h̸̡̅ẗ̵̨́d̷̰̀ĥ̷̳

Ngomong-ngomong, pertanyaan ini bukan kode-golf, tapi teka-teki. Saya tidak menilai solusi berdasarkan panjang kode.
n̴̖̋h̷͉̃a̷̭̿h̸̡̅ẗ̵̨́d̷̰̀ĥ̷̳

Oh Itu menjelaskan mengapa Anda menggunakan (?:). Jadi, haruskah saya mengedit jawaban saya untuk membuat versi yang dioptimalkan menjadi yang utama?
Deadcode

8

Larutan

^(?:(?=(^|(?<=^x)x|xx\1))(?=(^|\1\2))(^x|\3\2{12}xx))*$

Regex ini kompatibel dengan rasa Java, Perl, PCRE, dan .NET. Regex ini menggunakan cukup banyak fitur: lihat-depan, lihat-belakang dan referensi-maju yang dideklarasikan ke depan. Jenis back-reference yang dideklarasikan ke depan membatasi kompatibilitas regex ini untuk beberapa mesin.

Penjelasan

Solusi ini menggunakan derivasi berikut.

Dengan memperluas penjumlahan sepenuhnya, kami dapat membuktikan kesetaraan berikut:

\ jumlah \ limit_ {i = 1} ^ n (i + 1) ^ 4 - \ jumlah \ limit_ {i = 1} ^ ni ^ 4 = (n + 1) ^ 4 - 1
\ jumlah \ limit_ {i = 1} ^ ni ^ 4 - \ jumlah \ limit_ {i = 1} ^ n (i-1) ^ 4 = n ^ 4

Mari kita gabungkan penjumlahan di sisi kiri:

\ jumlah \ limit_ {i = 1} ^ n (4 (i + 1) ^ 3 - 6 (i + 1) ^ 2 + 4 (i + 1) - 1) = (n + 1) ^ 4 - 1
\ jumlah \ limit_ {i = 1} ^ n (4i ^ 3 - 6i ^ 2 + 4i - 1) = n ^ 4

Kurangi 2 persamaan (persamaan atas dikurangi persamaan bawah) lalu gabungkan penjumlahannya di sisi kiri, kemudian sederhanakan:

\ jumlah \ limit_ {i = 1} ^ n (12i ^ 2 + 2) = (n + 1) ^ 4 - n ^ 4 - 1

Kami mendapatkan perbedaan antara kekuatan keempat berturut-turut sebagai jumlah daya:

(n + 1) ^ 4 - n ^ 4 = \ jumlah \ limit_ {i = 1} ^ n (12i ^ 2 + 2) + 1

Ini berarti bahwa perbedaan antara kekuatan keempat berturut-turut akan meningkat sebesar (12n 2 + 2).

Untuk membuatnya lebih mudah untuk berpikir, merujuk pada pohon perbedaan dalam jawaban Volatility :

  • Sisi kanan dari persamaan terakhir adalah baris ke-2 di pohon perbedaan.
  • Kenaikan (12n 2 + 2) adalah baris ke-3 di pohon perbedaan.

Matematika yang cukup. Kembali ke solusi di atas:

  • The 1st menangkap kelompok mempertahankan serangkaian angka ganjil untuk menghitung i 2 seperti yang terlihat dalam persamaan.

    Secara tepat, panjang grup tangkapan pertama adalah 0 (tidak digunakan), 1, 3, 5, 7, ... sebagai pengulangan yang berulang.

    (?<=^x)xmenetapkan nilai awal untuk seri angka ganjil. Itu ^hanya ada untuk memungkinkan melihat-depan dipenuhi dalam iterasi pertama.

    xx\1 menambahkan 2 dan maju ke nomor ganjil berikutnya.

  • Grup tangkapan kedua mempertahankan seri nomor kuadrat untuk i 2 .

    Secara tepat, panjang dari grup penangkap ke-2 akan menjadi 0, 1, 4, 9, ... karena perulangannya berulang.

    ^di (^|\1\2)set nilai awal untuk seri angka kuadrat. Dan \1\2menambahkan nomor ganjil ke nomor kuadrat saat ini untuk memajukannya ke nomor kuadrat berikutnya.

  • Grup tangkapan ketiga (di luar pandangan ke depan dan benar-benar menggunakan teks) cocok dengan seluruh sisi kanan persamaan yang kami peroleh di atas.

    ^xdi (^x|\3\2{12}xx)set nilai awal, yang merupakan + 1sisi kanan dari persamaan.

    \3\2{12}xxmenambahkan peningkatan perbedaan (12n 2 + 2) menggunakan n 2 dari menangkap grup 2, dan mencocokkan perbedaan pada saat yang sama.

Pengaturan ini dimungkinkan karena jumlah teks yang cocok di setiap iterasi lebih dari atau sama dengan jumlah teks yang dibutuhkan untuk menjalankan tampilan-depan untuk membangun n 2 .

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.