Присудок числового ланцюга


27

Проблема:

Ваше завдання - визначити, чи в послідовності чисел кожне число містить хоча б одну з цифр числа, що передувало йому.

Наприклад, наступні дані повинні повертати:

[1, 12, 203, 0, 30]
             ^   ^ Contains a 0
        ^ Contains a 2
    ^ Contains a 1

Наступні повинні повернути фальси:

[1, 32, 23, 34]
    ^ Doesn't contain a 1, therefore false

Ваше подання може бути функцією або повноцінною програмою.

Вхід:

Введення може бути будь-яким розумним типом послідовності. Масив чисел, масив рядків, розділений рядок чисел тощо.

Порядок має значення, тому будь-яка структура, яку ви вирішите прийняти як вхід, очевидно, повинна мати певне впорядкування.

Введення можна сприймати через stdin або як аргумент.

Ви можете припустити:

  • всі числа будуть невід’ємними цілими числами

  • Вхід завжди буде містити принаймні 2 числа

  • цифри введення не почнуться з 0

Вихід:

Результатом буде значення "truthy" або "falsey" (як визначено вашою мовою), що представляє, чи відповідає вищезазначена специфікація чи ні.

Значення Truthy / Falsey не потрібно узгоджувати між тестами.

Він може бути виведений у stdout або повернутий.

Випробування:

True cases:
[1, 1, 1, 11, 111, 11, 1]
[12, 23, 34, 45, 56]
[65, 54, 43, 32, 21]
[123, 29, 9, 59, 55, 52, 2017, 2]
[1234567890, 19, 95, 5012, 23]

False cases:
[1, 2, 3, 4, 5, 1, 11] (2 doesn't contain a 1)
[12, 23, 33, 45] (45 doesn't contain a 3)
[98, 87, 76, 11, 12, 23] (11 doesn't contain a 7 or 6)

Це код-гольф, тому виграє найменша кількість байтів.

Відповіді:


7

Желе , 5 4 байти

f2\Ạ

Введення - це масив рядків.

Спробуйте в Інтернеті!

Як це працює

f2\Ạ  Main link. Argument: A (array of strings)

 2\   Pairwise reduce by:
f       Filter, yielding all chars in the left string that appear in the right one.
   Ạ  All; yield 1 if all strings are non-empty, 0 if not.


12

Сітківка , 25 20 байт

(.).*¶(?=.*\1)

^.+$

Спробуйте в Інтернеті!

Щоразу, коли ми знаходимо цифру, яка також зустрічається в наступному номері, ми видаляємо роздільник між цими числами (разом із цифрами в колишньому номері, починаючи з загального, але це не має значення). Вхід є дійсним, якщо в процесі були видалені всі роздільники, що ми перевіряємо, переконуючись, що рядок може відповідати як один рядок.


11

Брахілог , 9 байт

{⊇ᵐ=∧?t}ˡ

Спробуйте в Інтернеті!

Зауважте, що це працює не тільки зі списком цілих чисел, але й зі списком рядків або списком списків.

Пояснення

{      }ˡ       Left fold on the input:
 ⊇ᵐ=              It is possible to find a number which is a subset of both input numbers
    ∧             (and)
     ?t           The output is the second number (to continue the fold)

2
Круто. Здається ... декларативним? Читає так, як ви просто розмовляєте мовою специфікацію.
Carcigenicate

3
@Carcigenicate Brachylog дійсно декларативний, він заснований на декларативної логіці мови програмування Prolog .
Фаталізувати

2
Прологи фактично в моєму (все більш) довгому списку мов, які я повинен вивчити, коли отримую необмежений вільний час. Занадто багато класних мов!
Carcigenicate

8

JavaScript (ES6), 47 44 * 43 байт

Збережено байт завдяки @Neil

x=>x.every(y=>y.match(`[${p}]`,p=y),p=1/19)

Вводиться як список рядків.

Фрагмент тесту

* ( закреслено 44 все ще регулярно 44 )


Хто `[${p}]`не працює?
Ніл

@Neil Не для першого елемента кожного масиву.
ETHproductions

Ах, я бачу, ви знайшли вирішення. Я отримав так далеко a=>a.reduce((l,r)=>`${l}`.match(`[${r}]`)&&r)(що також працює для числового введення).
Ніл

Можливо, ви можете видалити, p&&якщо встановите p=1/19?
Ніл

@Neil Я, е ... ну ... Це геніально, дякую :-)
ETHproductions

6

05AB1E , 10 байт

ü‚vy`Så1åP

Спробуйте в Інтернеті! або як тестовий набір

Пояснення

ü‚          # map pairing over each pair in input
  v         # for each pair
   y`       # push as 2 separate elements on stack
     Så     # check each digit in 2nd number for membership in first
       1å   # check if any 1 exists in the resulting list
         P  # product of stack

€Sü.å- Я б хотів, щоб це працювало так, як я думав, що це буде.
Чарівний восьминога Урна

@carusocomputing: Так, це було б чудово. Або просто ü.åабо €Süå.
Емінья

Чому знов не працює парно з командними точками?
Чарівний восьминога Урна

1
@carusocomputing: реалізовано лише для того, щоб взяти наступний байт як команду. Він не враховує крапку.
Емінья

6

CJam , 18 15 14 байт

Збережено 4 байти завдяки Мартіну Ендеру

l~Afb_1>.&:,:*

Спробуйте в Інтернеті!

Пояснення

l~              e# Read and eval the input
  Afb           e# Convert each number to a list of digits
     _          e# Duplicate the array
      1>        e# Slice it after the first element
        .&      e# Vectorized set intersection; take the set intersection of corresponding 
                e#  elements of the two arrays
          :,    e# Get the length of each intersection
            :*  e# Take the product of the whole array. 
                e#  Will be 0 if any intersection was empty.

6

Хаскелл, 51 48 35 байт

-3 байти завдяки @NickHansen! Мені справді потрібно поправитись із тими операторами монади

-4 і -9 байт завдяки @Laikoni та @nimi відповідно!

and.(zipWith(any.flip elem)=<<tail)

Ця версія сприймає вхід як масив рядків, виключаючи необхідність show, але, наскільки я бачу, він працює майже так само, як і старіша версія:

all(\(x,y)->any(`elem`x)y).(zip=<<tail).map show

(Я цілком впевнений, що мені можна надіслати анонімну функцію на зразок цієї, але я виправлю її, якщо потрібно)

Спочатку числа перетворюються на рядки. Тоді магія монади zip=<<tailстворює функцію, яка формує список із собою, який з'єднує кожен запис із сусідом. Потім allнанесіть лямбда на кожну пару, яка перевіряє, чи містить один рядок символи від другої, і нарешті перевіряє, чи всі вони виходять True.

Стара версія, яка працює в основному так само:

f a=and$zipWith(\b->any(`elem`show b).show)a$tail a

Мені вдалося поголити байт за допомогою zip та деякої (->) монади хитрості: f (x, y) = будь-яка ('elem'x) y; g = all f. (Zip = << хвіст). . редагувати: елем повинен [сподіваємось очевидно] містити передумови, але це неможливо з форматуванням коментарів.
Нік Хансен

44 байти:and.(zipWith(any.flip elem)=<<tail).map show
Лайконі

Дозволяється сприймати введення як список рядків, наприклад ["1234567890", "19", "95", "5012", "23"], ви можете скинути це .map show.
німі

5

Mathematica 62 47 35 байт

З 12 байтами збережено завдяки MartinE.

FreeQ[#⋂#2&@@@Partition[#,2,1],{}]&

FreeQ[#⋂#2&@@@Partition[#,2,1],{}]&[{{1},{1,2},{2,0,3},{0},{3,1}}]

помилковий

FreeQ[#⋂#2&@@@Partition[#,2,1],{}]&[{{1},{1,2},{2,0,3},{0},{3,0}}]

Правда


4

Ruby, 49 48 байт

->x{x.each_cons(2){|z|x&&=z*' '=~/(.).* .*\1/};x}

Вихід є nilпомилковим, а "випадкове" ціле число - для істинного.


4

Java 8, 94 90 87 байт

Введення - це масив рядків, що представляють числа. Починаючи з другим рядком, вона виконує регулярні порівняння виразів в відношенні кожного попереднього рядка , щоб побачити , якщо вона містить будь-яку з її символів: .*[previous string].*.

Гольф:

a->{int r=1,i=0;while(++i<a.length)r*=a[i].matches(".*["+a[i-1]+"].*")?1:0;return r>0;}

Безголівки:

public class NumberChainingPredicate {

  public static void main(String[] args) {
    System.out.println("Expect true:");
    for (String[] input : new String[][] { { "1", "1", "1", "11", "111", "11", "1" }, { "12", "23", "34", "45", "56" },
        { "65", "54", "43", "32", "21" }, { "123", "29", "9", "59", "55", "52", "2017", "2" },
        { "1234567890", "19", "95", "5012", "23" } }) {
      System.out.println(java.util.Arrays.toString(input) + " = " + exec(f(), input));
    }

    System.out.println();
    System.out.println("Expect false:");
    for (String[] input : new String[][] { { "1", "2", "3", "4", "5", "1", "11" }, { "12", "23", "33", "45" },
        { "98", "87", "76", "11", "12", "23" } }) {
      System.out.println(java.util.Arrays.toString(input) + " = " + exec(f(), input));
    }
  }

  private static java.util.function.Function<String[], Boolean> f() {
    return a -> {
      int r = 1, i = 0;
      while (++i < a.length) {
        r *= a[i].matches(".*[" + a[i - 1] + "].*") ? 1 : 0;
      }
      return r > 0;
    };
  }

  private static boolean exec(java.util.function.Function<String[], Boolean> function, String[] input) {
    return function.apply(input);
  }

}

Приємно! Набагато коротше, ніж я збирався опублікувати. У будь-якому випадку, ви можете a->{for(int i=1;i<a.length;)if(!a[i].matches(".*["+a[i++-1]+"].*"))return 0>1;return 1>0;}
покатати

Я також гольфував до 90, але по-іншому:a->{int r=1;for(int i=0;++i<a.length;)r*=a[i].matches(".*["+a[i-1]+"].*")?1:0;return r>0;}
Ділова кішка

1
Не зважаючи, отримав це до 87:a->{int r=1,i=0;for(;++i<a.length;)r*=a[i].matches(".*["+a[i-1]+"].*")?1:0;return r>0;}
Ділова кішка

Дякую обом. Я думаю, що єдиний спосіб покращити це значною мірою зараз - це переглянути регекс.

4

Желе , 6 байт

Dµf"ḊẠ

Спробуйте в Інтернеті!

Пояснення

Dµf"ḊẠ
Dµ        Treat the first (i.e. only) input as a list of decimal digits
   "      For each pair of corresponding elements in {the input digits} and
    Ḋ     {the input digits} with the first element removed
  f       take all elements common to both sides
     Ạ    then return true if the result has no empty lists, false otherwise

Тут найбільш очевидно спробувати використовувати 2/, але це виконує функцію одинарного на всіх фрагментах розміру 2. "ḊЕфективно виконує бінарну функцію на всіх парах сусідніх елементів, а значить, ми можемо використовувати fбезпосередньо (а не потрібно перетворювати її в одинарну функціонувати як f/). Це в кінцевому підсумку залишає останній елемент вводу на місці, але, на щастя, навіть введення 0 не стає порожнім списком при перетворенні в десятковий, тому це не впливає на .




3

05AB1E , 5 байт

Код:

üÃõå_

Використовує кодування CP-1252 . Спробуйте в Інтернеті! або Перевірте всі тестові випадки! .

Пояснення:

üà         # Intersection on each pair
  õå       # Check if the empty string exists
    _      # Boolean negate

О, людина це працює! RüÃõå_було те, що я придумав самостійно. Мені честь бути настільки близьким до вашої найкращої відповіді, видаляючи мою. Чому вам це не потрібно R?
Чарівний восьминога Урна

1
@carusocomputing Hmmm, що Rтоді? : p
Аднан

2

PowerShell , 87 байт

param($n)(1..($a=$n.length-1)|?{[char[]]$n[($i=$_)-1]|?{$n[$i]-like"*$_*"}}).count-eq$a

Спробуйте в Інтернеті!

Не найкоротший за будь-якими заходами, але трохи інший підхід, ніж інші, і демонструє чудову |?{}функціональність.

Це сприймає вхід як масив рядків у $n, а потім циклів від 1до length-1. Ми використовуємо Where-Object( |?{...}), щоб витягти ті індекси, які є правдоподібними для певної умови. Ви можете подумати про це, як комбінований forцикл із ifпунктом.

Стаття тут є [char[]]$n[($i=$_)-1]|?{$n[$i]-like"*$_*"}. Тобто ми беремо поточний індекс $_, встановлюємо його $iі віднімаємо 1, і використовуємо його для індексації $n(тобто таким чином ми отримуємо попередній елемент у нашому вхідному масиві). Потім він charпередається у вигляді масиву і надсилається через іншу Where-Objectпроцедуру.

Внутрішній пункт $n[$i]-like"*$_*"вказує, що рядок у поточному індексі $iє -likeпоточним символом $_з попереднього індексу. Таким чином, виведені будь-які символи, спільні між двома елементами масиву. Таким чином, зовнішнє застереження буде трибунним лише за наявності спільного символу (оскільки порожній масив є фальсиєю в PowerShell), і тому індекс буде обраний лише за наявності спільних символів.

Потім ми збираємо всі індекси, які відповідали критеріям, і перевіряємо, чи не відповідає .countїх -eqдовжині вхідний масив. Булевий результат залишається на конвеєрі, а вихід неявний.



2

APL (Dyalog APL) , 9 байт

∧/×≢¨2∩/⎕

Спробуйте в Інтернеті!

∧/ всі вони в списку

× знаки

 підрахунку

¨ кожен з

2∩/ парних перехрестях

 вхід?


Я не впевнений, що означає "знаки", але ви можете припустити, що всі цифри будуть позитивними.
Carcigenicate

@Carcigenicate вони також можуть бути нульовими.
Адам

Так, вибачте. "Негативний".
Carcigenicate

2

PHP, 65 68

for(;null!==$a=$argv[++$i+1];)$r+=$a==strtr($a,$argv[$i],_);echo!$r;

повторіть усі цифри та видаліть усі цифри, що з’явились у попередньому. Порахуйте, наскільки часто воно дорівнює самому числу (жодна цифра не видаляється). Якби принаймні один дорівнював, у нас не було збігу в одній з пар.


Виправлена ​​помилка за допомогою triminsted of strtr. Завдяки @ JörgHülsermann


Вибачте. для даних тестів ваше рішення працює. ["filename",1,11,414]працює не так.
Йорг Гюльсерманн

@ JörgHülsermann впевнений, що trimпрацює лише для провідних та останніх знаків. Виправлено це.
Крістоф

Для PHP <7.1 ви можете використовувати a&замість null!==(-5 байт).
Тит

... але це буде працювати лише для першої цифри в $argv[$i], оскільки "Якщо з і мають різну довжину, зайві символи в більшій з двох ігноруються". (з посібника)
Тіт

2

PHP, 75 байт

for($b=3**39;--$argc;)preg_replace("#[$b]#","",$b=$argv[$argc])<$b?:die(1);

бере числа з аргументів командного рядка; виходить з 1фальшивим, з 0правдою.
Запустіть -rабо випробуйте його в Інтернеті .

  • починати з $b= числа, що містить усі цифри
  • цикл через аргументи
    • видалити всі $bаргументи з аргументу
    • копіювати аргумент в $b
    • якщо жодна цифра не була видалена, вийдіть за допомогою 1
  • неявно: вихід із 0

1

PHP, 77 байт

for($i=$t=1;++$i<$argc;)$t*=preg_match("#[{$argv[$i-1]}]#",$argv[$i]);echo$t;

1
Альтернативно:, foreach($argv as$k=>$v)$t=$k--?$t*preg_match("#[{$argv[$k]}]#",$v)):1;echo$t;77 байт (не перевірено).
Ісмаїл Мігель

1
@IsmaelMiguel Важка альтернатива Спочатку ви повинні змінити , $k--щоб --$kі впасти один) після цього ваш підхід повинен працювати , і ви повинні додати @ для попередження
Йорг Hülsermann

О так, не помітили марних дужок, які викликають синтаксичні помилки. І я не згоден з цим питанням $k--. Я спеціально використовував його так, що $ k все ще дорівнює 0 під час першого запуску. І попередження невідомі. Це означає, що код зараз становить 76 байт, але все ще не перевірений.
Ісмаель Мігель

Після редагування я можу підтвердити, що foreach($argv as$k=>$v)$t=$k--?$t*preg_match("#[{$argv[$k]}]#",$v):1;echo$t;працює як слід. Тестування з $argv = array(1, 12, 123, 3, 34, 45, 5, 5);дисплеями 1та тестування з $argv = array(1, 12, 123, 3, 34, 45, 5, 6);дисплеями 0, як очікувалося.
Ісмаїл Мігель

@IsmaelMiguel Ви забуваєте, що перший параметр у - це ім'я файлу.
Йорг Гюльсерманн

1

MATL , 14 байт

1&)"V@VX&nv@]x

Спробуйте в Інтернеті!

Дякуємо @LuisMendo за збереження байта. Пояснення:

1&)            % 'Pop' the first item from the input and push it on the stack.
   "       ]   % Main 'for' loop, to loop over the rest of the input.
    V            % Stringify previous (or first) iten from the input.
     @V          % Push current number, convert to string
       X&        % Intersect with stringified number already on the stack.
         nv      % Count the size of the intersection, and add it to the existing list of sizes.
           @     % Push the current number again for the intersection in the next loop. 
             x % Remove the number pushed by the last loop.
               % Else the program would end with the result on the second instead of the first position in the stack

Ви можете зберегти байт, замінивши 1)VGйого 1&)(і це дозволяє уникнути повторення першого номера)
Луїс Мендо

@LuisMendo Звичайно! Я смутно пам'ятав, що MATL має цю функціональність, але пошук "pop" (наприклад, у черзі чи стеку) у специфікації не дав жодних результатів, тому я подумав, що помилявся.
Санчіз

Так, насправді це окремий випадок референсної індексації. З двома виходами операція опорної індексації на зразок )дає вибрані значення як перший вихід, а потім інші значення як другий вихід
Луїс Мендо

@LuisMendo Clever. Вони повинні найняти вас, хлопці MATL, щоб покращити MATLAB ...
Санчіз

Ха-ха. Я іноді пропускаю деякі з цих функцій у MATLAB
Луїс Мендо

1

Clojure, 71 байт

(fn[n](every?(fn[[q w]](some q w))(partition 2 1(map #(set(str %))n))))

Анонімна функція, яка приймає послідовність чисел. Повернення true/ false.

Мені подобається, як це читається. Тут напевно є кілька областей, які можна вдосконалити. Мою функцію, яку передають, не mapможна легко змінити, щоб вона не вимагала макроса функції, а це означає, що вся функція не може використовувати макрос, який, ймовірно, додав кілька байтів. Було б також непогано, якби я міг придумати кращий спосіб розпакування значень у every?присудку.

(defn number-chain? [nums]
  (let [; Turn each number into a set of characters
        set-nums (map #(set (str %)) nums)

        ; Partition the sets into lists of neighbors
        ; [1 2 3 4] -> [[1 2] [2 3] [3 4]]
        partitioned (partition 2 1 set-nums)]

    ; Does every second neighbor contain some element of the first?
    (every?
      (fn [[l1 l2]]
        (some l1 l2))
      partitioned)))

1

SimpleTemplate, 124 байти

Ого, це було тренування!

{@eachargv asA keyK}{@ifK}{@setR"/[",O,"]/"}{@calljoin intoR"",R}{@ifA is notmatchesR}{@return}{@/}{@/}{@setO A}{@/}{@echo1}

Це "просто" робить регулярний вираз, використовуючи старий елемент, показуючи 1як істинне значення, або нічого іншого.


Безголівки:

{@each argv as number key K}
    {@if K}
        {@set regex "/[", old, "]/"}
        {@call join into regex "", regex}
        {@if number is not matches regex}
            {@return false}
        {@/}
    {@/}
    {@set old number}
{@/}
{@echo 1}

1

JavaScript (ES6), 37 байт

s=>/^(.*(.).*\n(?=.*\2))+.+$/.test(s)

Приймає введення як рядок розділених новим рядком чисел. На основі чудової відповіді Retina на @ MartinEnder ♦, але я робила весь тест в одному regexp, тому що в JavaScript це коротше.


1

Піп , 12 10 байт

$&B@X^_MPg

Вводить дані як ряд аргументів командного рядка. Вихідні дані - це порожній список для правди і порожній список для фальси. Спробуйте в Інтернеті або перевірте всі тестові випадки .

Пояснення

         g  List of all cmdline args
       MP   Map this function to consecutive pairs of items from that list:
     ^_      Split 1st item of pair into list of characters
    X        Convert to regex that matches any of those characters
  B@         Find all matches in 2nd item of pair
$&          Fold on logical AND--truthy if all items are truthy, falsey if one is falsey
            Print (implicit)

1

Рода , 45 35 байт

{[_=~`(\S*(\S)\S* (?=\S*\2))+\S+`]}

Спробуйте в Інтернеті!

Це схоже на рішення Perl 5, яке є портом рішення Retina від Мартіна Ендера. -10 байт завдяки @Neil.

Ось інше рішення ( 73 72 байти):

{[_/""]|{|x|{x|[0]()unless[not(_ in y)]else[1]}if tryPeek y}_|sum|[_=0]}

Це анонімна функція, яка витягує рядки з потоку і перевіряє, що послідовні рядки містять однакові символи. Пояснення:

{
    [_/""]|    /* split strings -> creates arrays of characters */
    {|x|       /* begin for loop over character arrays */
        {      /* begin if tryPeek(y) -> peeks the second item from the stream */
               /* x and y are now two consecutive character arrays */
            x| /* push characters in x to the stream */
            [0]()unless[not(_ in y)]else[1] /* pushes 0 to the stream */
                                            /* if y contains the character */
                                            /* in the stream, otherwise 1 */
        }if tryPeek y
    }_|        /* end for loop */
    sum|       /* sum all numbers in the stream */
    [_=0]      /* return true if the sum is zero */
}

Можливо, можна було б пограти в гольф більше ...


Чи допомогло б мати єдиний регулярний вираз, який робить весь тест за один раз? Щось подібне ^(\S*(\S)\S* (?=\S*\2))+\S+$.
Ніл

@Neil Це, здається, працює. Спасибі!
fergusq

1

Утиліти Bash + Unix, 71 69 байт

sed "s/\(.*\)/<<<\1 \&\&grepx[\1]/;1s/.*g/g/;\$s/ .*//"|tr 'x
' \ |sh

Спробуйте в Інтернеті!

Вводиться на stdin, по одному номеру на рядок.

Вихідний код у вихідному коді: 0 для трити, 1 для фальси.

Це, ймовірно, може бути більше гольфу.

Щоб код вище працював, у поточному каталозі не може бути жодного файлу, ім'я якого - одна цифра. Якщо це неприйнятно, замініть [\1]у програмі '[\1]'(ціною 2 додаткові байти).

Вибірка зразка (останній тестовий випадок, наданий у виклику):

$ echo '98
> 87
> 76
> 11
> 12
> 23' | ./digittest > /dev/null; echo $?
1

(1 тут - фальси.)


Як це працює:

Я продемонструю на зразку пробігу вище.

Команда sed перетворює вхід у:

grepx[98]
<<<87 &&grepx[87]
<<<76 &&grepx[76]
<<<11 &&grepx[11]
<<<12 &&grepx[12]
<<<23

Потім команда tr перетворює це в рядок:

grep [98] <<<87 &&grep [87] <<<76 &&grep [76] <<<11 &&grep [11] <<<12 &&grep [12] <<<23

Цей рядок є командою оболонки для виконання потрібної операції, тому я передаю це в sh і я закінчую.


Обмеження файлу добре, хоча це, безумовно, дивне обмеження.
Carcigenicate

1

Q, 57 байт

{r::();({r,::any(last x)in y;x,enlist y}\)($)0,x;all 1_r}
  1. Ініціалізує глобальний r.
  2. Перетворює вхід у масив рядків.
  3. Сканує масив, перевіряючи, чи є якийсь символ в останньому рядку в поточному рядку.
  4. Додає кожен результат до r.
  5. Повертає 1, якщо всі рядки задовольняють крок 3, інше повертає 0.

Примітка: 0 додано до запуску вхідного масиву в межах функції. Це було зроблено для того, щоб порівняння першого елемента було зафіксовано. В іншому випадку останній символ першого елемента схоплений для порівняння. Можливо, проте перевірити тип, який додає 7 байт над поточним числом.


Це схоже на аналогічний підхід до моєї відповіді Clojure. Акуратно виглядає мова.
Carcigenicate
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.