Знайдіть найбільшу кількість, яка прилягає до нуля


38

Виклик:

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

Технічні умови:

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

Тестові приклади:

1 4 3 6 0 3 7 0
7

9 4 9 0 9 0 9 15 -2
9

-4 -6 -2 0 -9
-2

-11 0 0 0 0 0 -12 10
0

0 20 
20

Удачі та щасливого гольфу!


Ви повинні додати тестовий випадок, як четвертий, але там, де результат негативний (у списку є позитивні цифри).
mbomb007

Я збирався спробувати це в Retina, але потім помітив, що є негативи. Сітківка ненавидить негативи.
mbomb007

2
Не дозволяйте сітківці диктувати, що ви можете, а чого не можете. Беріть на себе відповідальність, ви начальник!
Стюі Гріффін

Відповіді:



19

MATL , 10 байт

t~5BZ+g)X>

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

Пояснення

Візьмемо [-4 -6 -2 0 -9]приклад як приклад.

t     % Input array. Duplicate
      %   STACK: [-4 -6 -2 0 -9],  [-4 -6 -2 0 -9]
~     % Logical negate. Replaces zeros by logical 1, and nonzeros by logical 0
      %   STACK: [-4 -6 -2 0 -9],  [0 0 0 1 0]
5B    % Push logical array [1 0 1] (5 in binary)
      %   STACK: [-4 -6 -2 0 -9], [0 0 0 1 0], [1 0 1]
Z+    % Convolution, maintaining size. Gives nonzero (1 or 2) for neighbours of
      % zeros in the original array, and zero for the rest
      %   STACK: [-4 -6 -2 0 -9], [0 0 1 0 1]
g     % Convert to logical
      %   STACK: [-4 -6 -2 0 -9], [0 0 1 0 1]
)     % Use as index into original array
      %   STACK: [-2 -9]
X>    % Maximum of array.
      %   STACK: -2
      % Implicitly display

x(~~(dec2bin(5)-48)). Хто задумував це здійснити? Дуже розумно і корисно для логічних масивів! :) Приємна відповідь!
Стюі Гріффін

1
@WeeingIfFirst Спасибі! Я використовував dec2bin()-'0'сотні разів у MATLAB, тому знав, що треба бути в MATL :-)
Луїс Мендо

5
До речі, той факт, що ви включили вміст стеку після кожної операції, варто лише підняти нагоду. Це набагато простіше зрозуміти (і, можливо, навчитися) MATL =)
Гріффін

2
Скрути Скелі. +1
Suever

10

05AB1E , 9 байт

ü‚D€P_ÏOZ

Пояснення

ü‚         # pair up elements
  D        # duplicate
   €P      # product of each pair (0 if the pair contains a 0)
     _     # logical negate, turns 0 into 1 and everything else to 0
      Ï    # keep only the pairs containing at least 1 zero
       O   # sum the pairs
        Z  # take max

Не працює в Інтернеті, але працює в автономному режимі.


Це дивовижно ха-ха! Якраз вчасно: с.
Аднан

1
Щойно реалізований один із цих операторів чи? :)
Стюі Гріффін

1
@WeeingIfFirst: üдодали лише вчора :)
Емінья

2
Чи не повернеться це, 0якщо фактична відповідь буде негативною? Ви повинні викинути нулі, я думаю.
Лінн

1
@Lynn Приємний улов! Це можна легко виправити, замінивши ˜на O(суму).
Аднан

9

Haskell, 63 43 байт

f x=maximum[a+b|(a,b)<-tail>>=zip$x,a*b==0]

Дякуємо @MartinEnder за 4 байти!


Я думаю, ви можете використовувати a*b==0замість ||.
Мартін Ендер

Ви повинні повернутися до попередньої версії за допомогою zip. Тут і вже не є сусідніми
Дамієн

Тут вам не потрібен лямбдабот. Це "регулярний" Хаскелл
Дамієн

8

Піта, 12 11 10 байт

eSsM/#0,Vt

Формує пари, фільтрує за нульовим членом, сортує за сумою, повертає найбільше.


,Vt(неявно QQ) повертає ті самі пари .:Q2, що і з переліченими парами. Має працювати, хоча.
PurkkaKoodari

f}0Tє/#0
isaacg

7

JavaScript (ES6), 59 57 56 байт

let f =
    
l=>l.map((n,i)=>m=l[i-1]==0|l[i+1]==0&&n>m?n:m,m=-1/0)|m

console.log(f([1, 4, 3, 6, 0, 3, 7, 0]));       // 7
console.log(f([9, 4, 9, 0, 9, 0, 9, 15, -2]));  // 9
console.log(f([-4, -6, -2, 0, -9]));            // -2
console.log(f([-11, 0, 0, 0, 0, 0, -12, 10]));  // 0
console.log(f([3, 0, 5]));                      // 5
console.log(f([28, 0, 14, 0]));                 // 28

Редагувати: збережено 2 байти завдяки Huntro
Редагувати: збережено 1 байт завдяки ETHproductions


1
Ви можете зберегти два байти, скориставшись ==замість===
Huntro

1
Я ви можете зберегти кілька байт у кількох місцях:l=>l.map((n,i)=>m=l[i-1]*l[i+1]==0&n>m?n:m,m=-1/0)|m
ETHproductions

Помилка: {"message": "Помилка синтаксису", "ім'я файлу": " stacksnippets.net/js ", "lineno": 15, "colno": 3}
RosLuP

@RosLuP - для цього потрібен ES6 із підтримкою функції стрілок і не працюватиме у всіх браузерах (включаючи, але не обмежуючись ними: всі версії IE до Edge, всі версії Safari нижче версії 10 та ін.)
Arnauld,

6

JavaScript (ES6), 53 байти

a=>(m=-1/0,a.reduce((l,r)=>(m=l*r||l+r<m?m:l+r,r)),m)

Тому що я люблю використовувати reduce. Альтернативне рішення, також 53 байти:

a=>Math.max(...a.map((e,i)=>e*a[++i]==0?e+a[i]:-1/0))

5

Пітон, 49 байт

lambda a:max(sum(x)for x in zip(a,a[1:])if 0in x)

Тести на ideone

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


4

Рубі, 51 байт

->a{a.each_cons(2).map{|a,b|a*b!=0?-1.0/0:a+b}.max}

використання

f=->a{a.each_cons(2).map{|a,b|a*b!=0?-1.0/0:a+b}.max}
p f[gets.split.map(&:to_i)]

Я не думаю, що вам потрібні дужки навколо a+b.
Мартін Ендер

Відбувається помилка синтаксису @Martin Ender ... ideone.com/F6Ed4B
cia_rana

Він працює в Ruby 2.3. (доступне тут, наприклад: repl.it/languages/ruby )
Мартін Ендер

@Martin Ender Коли я використовую "! =" Замість "==", це працює. Дякую за вашу пораду! ideone.com/F6Ed4B
cia_rana

Там є помилка :(. -3 -2 0Возвращается 0. Я думаю, що заміни ...?0:...на ...?-1.0/0:...слід виправити, додавши 5 байт.
m-chrzan

4

PHP, 77 68 71 байт

-3 байти від анонімного, -4 та -2 від MartinEnder

preg_match_all("#(?<=\b0 )\S+|\S+(?= 0)#",$argv[1],$m);echo max($m[0]);

бігати з php -r '<code>' '<space separated values>'


2
використання \Kдля того, щоб відмовитись від сірника, поки що коротше, ніж використовувати ззаду.
користувач59178

2
Ви також можете використовувати розділення пробілу для введення, а потім використовувати \S+для узгодження підписаного цілого числа. Вам, ймовірно, доведеться користуватися, \b0,тому вам не доведеться додавати ,.
Мартін Ендер

1
Це працює для введення 4 0 0 5?
Тон Євангелія

@TonHospel Ні. \KНе працює з альтернативами? З незрозумілої причини друга альтернатива повертається 0 0, так що більше немає 0відповідника перед 5. Виправлено, спасибі.
Тит

Перегляньте інше рішення PHP з register_globals
Jörg Hülsermann,

4

Java 7, 118 105 106 байт

int d(int[]a){int i=0,m=1<<31,c;for(;++i<a.length;m=a[i]*a[i-1]==0&(c=a[i]+a[i-‌​1])>m?c:m);return m;}

13 байт збережено завдяки @cliffroot , використовуючи замість цього арифметичний підхід. 1 додатковий байт подяку @mrco після виявлення помилки (доданий тестовий випадок 2, 1, 0повернеться 2замість 1).

Невикористаний і тестовий код:

Спробуйте тут.

class M{
  static int c(int[] a){
    int i,
        m = a[i=0],
        c;
    for(; ++i < a.length; m = a[i] * a[i-1] == 0 & (c = a[i] + a[i - 1]) > m)
                           ? c
                           : m);
    return m;
  }

  public static void main(String[] a){
    System.out.println(c(new int[]{ 1, 4, 3, 6, 0, 3, 7, 0 }));
    System.out.println(c(new int[]{ 9, 4, 9, 0, 9, 0, 9, 15, -2 }));
    System.out.println(c(new int[]{ -4, -6, -2, 0, -9 }));
    System.out.println(c(new int[]{ -11, 0, 0, 0, 0, 0, -12, 10 }));
    System.out.println(c(new int[]{ 0, 20 }));
    System.out.println(c(new int[]{ 2, 1, 0 }));
  }
}

Вихід:

7
9
-2
0
20
1

1
Дещо інший підхід із використанням арифметики, здається, працюєint d(int[]a){int i,m=a[i=0],c;for(;++i<a.length;m=a[i]*a[i-1]==0&(c=a[i]+a[i-1])>m?c:m);return m;}
скеля

3
Вихід помилковий, коли перше число не суміжне з 0, але більше, ніж будь-яке число, що примикає до 0. Відтворюється тестовим випадком {2, 1, 0}. Ви можете це виправити, ініціалізуючи i з 0 безпосередньо та m з 1 << 31 (+1 загалом).
mrco


3

MATLAB з інструментом для обробки зображень, 32 байти

@(x)max(x(imdilate(~x,[1 0 1])))

Це анонімна функція. Приклад використання для тестових випадків:

>> f = @(x)max(x(imdilate(~x,[1 0 1])))
f =
  function_handle with value:
    @(x)max(x(imdilate(~x,[1,0,1])))

>> f([1 4 3 6 0 3 7 0])
ans =
     7

>> f([9 4 9 0 9 0 9 15 -2])
ans =
     9

>> f([-4 -6 -2 0 -9])
ans =
    -2

>> f([-11 0 0 0 0 0 -12 10])
ans =
     0

>> f([0 20])
ans =
    20

3

Діалог APL , 14 байт

⌈/∊2(+↑⍨0∊,)/⎕

⌈/ найбільший з

сплющений (" e nlisted"

2(... )/попарно

+ сума (нуль плюс щось є щось)

↑⍨ прийнято, якщо

0 нуль

є членом

, пара (освітлення з'єднання лівого і правого номера)

СпробуйтеAPL онлайн!


3

R, 48 47 байт

EDIT: Виправлено помилку завдяки @Vlo та змінив її для зчитування вхідних даних із stdins, зберегши один байт шляхом призначення wта пропуску парантезів.

function(v)sort(v[c(w<-which(v==0)-1,w+1)],T)[1]

v=scan();w=which(v==0);sort(v[c(w-1,w+1)],T)[1]

Необмежене пояснення

  1. Знайдіть індекси, для яких вектор vприймає значення 0:w <- which(v == 0)
  2. Створіть новий вектор, який містить показники +-1: w-1іw+1
  3. Витягуйте елементи, що відповідають індексам w-1іw+1
  4. Сортувати в порядку зменшення та витягнути кулаковий елемент

Зауважте, що якщо останній або перший елемент vдорівнює нулю, w+-1він фактично отримає індекс поза довжиною вектора, що означає, що v[length(v)+1]повертає NA. Це, як правило, не проблема, але max()функції незручно повертаються, NAякщо у векторі є якісь події, якщо в одному не вказано параметр na.rm=T. Таким чином, на 2 байти коротше сортувати та витягувати перший елемент, ніж використовувати max(), наприклад:

max(x,na.rm=T)
sort(x,T)[1]

1
Потрібна додаткова дужка, інакше не вдасться до всіх тестових випадків, коли максимум праворуч від 0, наприклад, c(1, 4, 3, 6, 0, 10, 7, 0) c((w<-which(v==0))-1,w+1)також трохи коротше, ніж скануванняsort((v<-scan())[c(w<-which(v==0)-1,w+1)],T)[1]
Vlo

@Vlo Дякую за вказівку на очевидну помилку +1. У своєму запропонованому рішенні ви ()теж забули ;). Оновлено код і призначив vпопередню маніпуляцію зараз.
Billywob

3

Математика, 46 43 байти

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

Max[Tr/@Partition[#,2,1]~Select~MemberQ@0]&

Анонімна функція. Приймає список цілих чисел як вхідне і повертає ціле число як вихід. Виходячи з розчину Ruby.


2

Perl, 42 байти

Включає +1 для -p

Дайте цифри в рядку на STDIN

largest0.pl <<< "8 4 0 0 5 1 2 6 9 0 6"

largest0.pl:

#!/usr/bin/perl -p
($_)=sort{$b-$a}/(?<=\b0 )\S+|\S+(?= 0)/g

2

Джулія, 56 55 байт

f(l)=max(map(sum,filter(t->0 in t,zip(l,l[2:end])))...)

Створіть кортежі для сусідніх значень, візьміть ті кортежі, що містять 0, підсумовуйте значення кортежу та знайдіть максимум


1

Пітон 2, 74 байти

def f(x):x=[9]+x;print max(x[i]for i in range(len(x)) if 0in x[i-1:i+2:2])

Проведіть цикл по кожному елементу, якщо він 0знаходиться в положенні зліва або справа від поточного елемента, включіть його в генератор, а потім запустіть його max. Нам потрібно прошивати список деяким 0номером. Він ніколи не буде включений, оскільки фрагмент [-1:2:2]нічого не буде містити.


1

T-SQL, 182 байти

Гольф:

DECLARE @x varchar(max)='1 5 4 3 6 1 3 17 1 -8 0 -7'

DECLARE @a INT, @b INT, @ INT WHILE @x>''SELECT @a=@b,@b=LEFT(@x,z),@x=STUFF(@x,1,z,''),@=IIF(@a=0,IIF(@b<@,@,@b),IIF(@b<>0 or @>@a,@,@a))FROM(SELECT charindex(' ',@x+' ')z)z PRINT @

Безголовки:

DECLARE @x varchar(max)='1 5 4 3 6 1 3 17 1 -8 0 -7'

DECLARE @a INT, @b INT, @ INT
WHILE @x>''
  SELECT 
   @a=@b,
   @b=LEFT(@x,z),
   @x=STUFF(@x,1,z,''),
   @=IIF(@a=0,IIF(@b<@,@,@b),IIF(@b<>0 or @>@a,@,@a))
  FROM(SELECT charindex(' ',@x+' ')z)z 
PRINT @

Скрипка


1

PowerShell v3 +, 62 байти

param($n)($n[(0..$n.count|?{0-in$n[$_-1],$n[$_+1]})]|sort)[-1]

Трохи довше, ніж інші відповіді, але витончений підхід.

Бере введення $n. Потім проходить цикл через індекси 0..$n.count, використовує Where-Object( |?{...}), щоб витягти ті індекси, де знаходиться попередній або наступний елемент у масиві 0, і подає їх назад у фрагмент масиву $n[...]. Ми тоді|sort ці елементи і беремо найбільші[-1] .

Приклади

PS C:\Tools\Scripts\golfing> @(1,4,3,6,0,3,7,0),@(9,4,9,0,9,0,9,15,-2),@(-4,-6,-2,0,-9),@(-11,0,0,0,0,0,-12,10)|%{""+$_+" --> "+(.\largest-number-beside-a-zero.ps1 $_)}
1 4 3 6 0 3 7 0 --> 7
9 4 9 0 9 0 9 15 -2 --> 9
-4 -6 -2 0 -9 --> -2
-11 0 0 0 0 0 -12 10 --> 0

PS C:\Tools\Scripts\golfing> @(0,20),@(20,0),@(0,7,20),@(7,0,20),@(7,0,6,20),@(20,0,6)|%{""+$_+" --> "+(.\largest-number-beside-a-zero.ps1 $_)}
0 20 --> 20
20 0 --> 20
0 7 20 --> 7
7 0 20 --> 20
7 0 6 20 --> 7
20 0 6 --> 20

1

q, 38 байт

{max x where 0 in'x,'(next x),'prev x}

Схоже, це не працює, коли максимум приходить після 0 . Крім того, я не знавець q, але, думаю, вам доведеться оточити свій код, {}щоб він став функціонувати.
Денніс

1

J, 18 байт

[:>./2(0&e.\#+/\)]

Пояснення

[:>./2(0&e.\#+/\)]  Input: array A
                 ]  Identity. Get A
     2              The constant 2
      (         )   Operate on 2 (LHS) and A (RHS)
               \    Get each subarray of size 2 from A and
             +/       Reduce it using addition
           \        Get each subarray of size 2 from A and
       0&e.           Test if 0 is a member of it
            #       Filter for the sums where 0 is contained
[:>./               Reduce using max and return

1

Perl 6 , 53 байти

{max map ->$/ {$1 if !$0|!$2},(1,|@_,1).rotor(3=>-2)}

Розширено:

# bare block lambda with implicit signature of (*@_)
{
  max

    map

      -> $/ {           # pointy lambda with parameter 「$/」
                        # ( 「$0」 is the same as 「$/[0]」 )
        $1 if !$0 | !$2 # return the middle value if either of the others is false
      },

      ( 1, |@_, 1 )     # list of inputs, with added non-zero terminals
      .rotor( 3 => -2 ) # grab 3, back-up 2, repeat until less than 3 remain
}

1

PHP, 66 байт

foreach($a=$argv as$k=>$v)$v||$m=max($m,$a[$k-1],$a[$k+1]);echo$m;

Досить прямо. Ітераціює над вхідними даними, і коли число є 0, воно встановлює $mнайбільшу кількість двох суміжних чисел і будь-яке попереднє значення$m .

Виконати так ( -dдодано лише для естетики):

php -d error_reporting=30709 -r 'foreach($a=$argv as$k=>$v)$v||$m=max($m,$a[$k-1],$a[$k+1]);echo$m;' -- -4 -6 -2 0 -9;echo

1

C # 76 74 байти

using System.Linq;i=>i.Zip(i.Skip(1),(a,b)=>a*b==0?1<<31:a+b).Max(‌​);

Пояснення:

Використовуйте zip, щоб приєднати масив до себе, але пропустивши перше значення у другій посилання, щоб нуль елемента приєднався до елемента першого. Помножте на рази b, якщо результат дорівнює нулю, один з них повинен дорівнювати нулю і виводити a + b. В іншому випадку виведіть на мові мінімальне можливе ціле число. Зважаючи на припущення, що у нас завжди буде нуль і не нуль, це мінімальне значення ніколи не виводиться як макс.

Використання:

[TestMethod]
public void LargestFriend()
{
    Assert.AreEqual(7, F(new int[] { 1, 4, 3, 6, 0, 3, 7, 0 }));
    Assert.AreEqual(9, F(new int[] { 9, 4, 9, 0, 9, 0, 9, 15, -2 }));
    Assert.AreEqual(-2, F(new int[] { -4, -6, -2, 0, -9 }));
    Assert.AreEqual(0, F(new int[] { -11, 0, 0, 0, 0, 0, -12, 10 }));
    Assert.AreEqual(20, F(new int[] { 0, 20 }));
}

Привіт. ви можете видалити простір у int[]i) {. Також я рахую 75 байт у вашому поточному коді (74, якщо ви видалите пробіл).
Кевін Кройсейсен

Я думаю, ви можете врятувати 4 байти, перевернувши тернари:a?b?i.Min()).Max():a:b
Тит

Плюс using System.Linq;, ні?
pinkfloydx33

Щоправда, але це питання просто задав метод, а не повну програму, а використання System.Linq;є частиною шаблону нового класу за замовчуванням.
Grax32

@Grax У будь-якому випадку вам потрібно включити usingвислів у свій рахунок байтів
TheLethalCoder

1

R, 48 54 байти

s=scan()

w=which;max(s[c(w(s==0)+1,w(s==0)-1)],na.rm=T)

Читає вектор з консольного введення, а потім приймає максимум над усіма значеннями, суміжними з 0.

Редагувати: ловить НС, що виробляються на кордоні, завдяки rturnbull!


Чи я це роблю неправильно? pastebin.com/0AA11xcw
манастирство

Це не вдається для таких випадків, як 20 0, тому що s[w(s==0)+1]повертає NA, а maxобробкою за замовчуванням, NAце повернути його. Ви можете виправити, додавши аргумент na.rm=Tабо переробити код для використання sort(див. Іншу відповідь R, розміщену вище).
rturnbull

Можна згустити все в одну лінію? Я не знаю, як кодувати R, але я припускаю, що ви можете.
клісмік

@ Qwerp-Derp: Не наскільки я знаю. scan () чекає, коли консольний вхід читається у векторі, вхідний потік закривається введенням порожнього рядка. Якби ви запустили два рядки як один, друга частина буде принаймні частково визнана введеною для вектора s.
Headcrash

0

Ракетка 183 байти

(λ(k)(let*((lr(λ(l i)(list-ref l i)))(l(append(list 1)k(list 1)))(m(for/list((i(range 1(sub1(length l))))
#:when(or(= 0(lr l(sub1 i)))(= 0(lr l(add1 i)))))(lr l i))))(apply max m)))

Детальна версія:

(define f
 (λ(k)
    (let* ((lr (λ(l i)(list-ref l i)))
           (l (append (list 1) k (list 1)))
           (m (for/list ((i (range 1 (sub1(length l))))
                         #:when (or (= 0 (lr l (sub1 i)))
                                    (= 0 (lr l (add1 i))) ))
                (lr l i) )))
      (apply max m) )))

Тестування:

(f (list 1 4 3 6 0 3 7 0))
(f (list 9 4 9 0 9 0 9 15 -2))
(f (list -4 -6 -2 0 -9))
(f (list -11 0 0 0 0 0 -12 10))
(f (list 0 20 ))

Вихід:

7
9
-2
0
20

0

C 132 байт

Виходи з використанням основного коду повернення:

int main(int a,char**_){int i,m=0;_[0]=_[a]="1";for(i=1;i<a;++i){m=(*_[i-1]-48||*_[i+1]-48?m>atoi(_[i])?m:atoi(_[i]):m);}return m;}

Я відчуваю, що мені вдасться зберегти кілька байт, врятувавши один із викликів atoi, але я не міг знайти ефективний спосіб. ( ,tплюс t=плюс ,плюс tдвічі занадто довго). Також це технічно використовує невизначене поведінку (встановлення _ [a] на "1"), але кожен компілятор, про який я знаю, дозволяє це за замовчуванням.

Стратегія: прокладіть початок і кінець масиву по 1, потім переведіть петлю на внутрішній розділ, перевіряючи кожного сусіда.


0

PHP 69 64 байт

Деякі байти увімкнено та вимкнено від Йорга Гюльсермана та Тіта. =(-5)

Потрібні register_globals увімкнено. Використання:http://localhost/notnull.php?i[]=9&i[]=-5i[]=...

$x=$_GET['i'];
$y=0;
foreach($x as $j){
if($y<abs($j)){
$y=$j;
}
}
echo $y;

Гольф:

$x=$_GET['i'];$y=0;foreach($x as $j)if($y<abs($j))$y=$j;echo $y;

Чому не використовуйте безпосередньо вхід як масив. Я не міг побачити причину json_encode.
Йорг Гюльсерманн

Для параметрів, що не знаходяться за замовчуванням, ви повинні додати повну довжину зміни налаштувань до кількості байтів. (див. meta.codegolf.stackexchange.com/q/4778#4778 ) У цьому випадку +21 байт для -d register_globals=1(або вкажіть версію, де register_globals включена за замовчуванням)
Titus

Але json_decodeце приємна ідея.
Тит

@Titus Що я маю на увазі, це ?id[]=1&id[]=2&id[]=3 потім $_GET["id"]повертає масив. З цієї причини json_decode не має для мене сенсу
Jörg Hülsermann,

@ JörgHülsermann Це коштує в байтах, але це все-таки хороша ідея.
Тит
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.