Вывести перевернутую палатку


27

Учитывая целое число, выведите перевернутую палатку.

Вход определяет как размер палатки (абсолютное значение), так и то, находится ли вход слева (отрицательные числа) или справа (положительные числа).

If input = -1:
____
\/_/

If input = -2:
________
\  /   /
 \/___/

If input = -3:
____________
\    /     /
 \  /     /
  \/_____/

If input = 1:
____
\_\/

If input = 2:
________
\   \  /
 \___\/

If input = 3:
____________
\     \    /
 \     \  /
  \_____\/

et cetera

Обратите внимание, что верхняя часть палатки (то есть последняя строка) имеет 2 * abs(input) - 1подчеркивание.

Там не может быть не ведущие пробелы, так что первая линия непосредственно начинается с символа подчеркивания.

Предположим, что ввода никогда не будет 0.

Ваш код должен быть максимально коротким.

Это испытание основано на мини-соревновании в чате от Helka Homba , которое разрешено использовать в реальных соревнованиях в соответствии с условиями общественной лицензии Calvin's Hobbies .


1
Конечные пробелы в порядке? Имеется в виду, можем ли мы вывести четыре строки длиной 12 (прямоугольник) для ввода, 3например?
AdmBorkBork

1
@TimmyD Они будут разрешены.
user48538

2
@TimmyD уверен, что кто-то, вероятно, тоже обманщик, я не совсем уверен, где начинается цепочка. Я просто думаю, что мы уже видели достаточно из них.
Натаниэль

5
Я не вижу, как вопросы даже отдаленно похожи. Конечно, это обе задачи ascii-art, которые принимают число и заставляют вас выводить n-ю итерацию чего-либо, но на этом сходство заканчивается. Если этого достаточно, чтобы закрыть глаза, мы не должны больше принимать вызовы ascii-art .
DJMcMayhem

2
@Nathaniel Нашим общепринятым принципом для двух задач, являющихся дубликатами, является вопрос о том, можно ли повторно использовать ответы одного (конкурентно) другого без каких-либо изменений или без изменений. Вопрос о том, принесут ли проблемы что-то новое, не является частью этого руководства. Пожалуйста, используйте отрицательные оценки для вызовов, которые вы хотите обескуражить, или просто игнорируйте их, если они не думают, что они интересны, и дайте возможность тем, кто действительно наслаждается ими.
Мартин Эндер

Ответы:


11

MATL , 55 53 52 51 байт

|95cy4*Y"DXytPEt0*yvG0>?P_]!'\/ 'w)95JG|G0<yEq:++&(

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

объяснение

Позвольте Nобозначить вход. Код продолжается в три этапа.

Во-первых , первая строка 4*Nподчеркивания строится как строка и отображается (что удаляет ее из стека).

Во-вторых , «каркас» палатки строится с использованием двух типов слешей. Для этого создается числовой двумерный массив, который содержит 1и 2соответствует двум типам слешей, а также 0для пространства.

Это делается путем объединения четырех матриц:

  1. Единичная матрица размера abs (N);
  2. Матрица того же размера, содержащая 2в антидиагонале;
  3. Нулевая матрица того же размера;
  4. Копия матрицы 2.

Конкатенация этих четырех матриц по вертикали дает N=3на примере следующую 4*N × Nматрицу:

1 0 0
0 1 0
0 0 1
0 0 2
0 2 0
2 0 0
0 0 0
0 0 0
0 0 0
0 0 2
0 2 0
2 0 0

(который, транспонированный, начинает выглядеть как палатка).

Теперь мы позаботимся о знаке ввода. Если оно положительное, мы просто перемещаем вышеуказанную матрицу и индексируем в строку '\/ '. Индексирование основано на 1 и является модульным, поэтому 1становится '\', 2становится '/'и 0становится ' ', создавая массив двумерных символов

\    /     /
 \  /     / 
  \/     /  

С другой стороны, если входной сигнал отрицательный, мы вертикально переворачиваем и арифметически отрицаем 4*N × Nматрицу, производя

-2  0  0
 0 -2  0
 0  0 -2
 0  0  0
 0  0  0
 0  0  0
-2  0  0
 0 -2  0
 0  0 -2
 0  0 -1
 0 -1  0
-1  0  0

Индекс -1теперь относится '/'и -2к '\'. Таким образом, два типа косых черт были заменены, как требуется. Снова транспонирование и индексирование в строку, '\/ 'таким образом, дает обратную палатку:

\     \    /
 \     \  / 
  \     \/  

В-третьих , подчеркивания необходимо заполнить частью последней строки двумерного массива символов. Горизонтальное положение этой линии зависит от знака ввода и его длины abs(N).

Как только соответствующие пробелы были заменены символами подчеркивания, результат неявно отображается ниже начальной строки символов подчеркивания, которая уже отображалась на первом этапе.


Разве эти подчеркивания в начале не должны быть пробелами?
DJMcMayhem

@DJMcMayhem Извините, что вы имеете в виду?
Луис Мендо

Когда я запускаю ваш код, первая строка подчеркивается. Вывод, который дал Зябин, не имеет этого.
DJMcMayhem

@DJMcMayhem Я не следую. Первая строка в тестовых случаях подчеркивает, не так ли? И другие ответы (не ваши) тоже это делают?
Луис Мендо

1
@DJMcMayhem :-D действительно странно. Попробуйте другой браузер?
Луис Мендо

9

Javascript (ES6), 139 байт

Строит палатку рекурсивно:

f=(N,n=N>0?N:-N,i=0,r=(j,i)=>' _'[i||0].repeat(j),a=`\\${r(i)}/`,b=r(n*2+i-1,+!i))=>n--?f(N,n,i+2)+`
`+r(n)+(N<0?a+b+'/':'\\'+b+a):r(i*2,1)

Разоблаченный и прокомментированный

f = (
  N,                                  // N is the original parameter (remains unchanged)
  n = N > 0 ? N : -N,                 // n is initialized to abs(N)
  i = 0,                              // i is the row counter (*2)
  r = (j, i) => ' _'[i||0].repeat(j), // helper function to repeat ' ' or '_' j times
  a = `\\${r(i)}/`,                   // a = '\ /' pattern
  b = r(n*2+i-1, +!i)                 // b = padding pattern filled with ' ' or '_'
) =>
  n-- ?                               // if we haven't made it yet to the top row:
    f(N, n, i+2) + `\n` +             //   - compute next row(s) / append line break
    r(n) +                            //   - append leading spaces
    (N < 0 ? a+b+'/' : '\\'+b+a)      //   - append a/b patterns according to N sign
  :                                   // else:
    r(i*2, 1)                         //   - return top row, made of '_' characters

Примеры

var f=(N,n=N>0?N:-N,i=0,r=(j,i)=>' _'[i||0].repeat(j),a=`\\${r(i)}/`,b=r(n*2+i-1,+!i))=>n--?f(N,n,i+2)+`
`+r(n)+(N<0?a+b+'/':'\\'+b+a):r(i*2,1)

console.log(f(3));
console.log(f(-4));


6

Python 2, 143, 141, 139, 138, 137 байт.

-2 байта благодаря @ Sp3000 (нет необходимости заключать в скобки exec в Python 2)
-1 байт благодаря @ Sp3000 (использовать cmp)

def f(n):d=cmp(n,0);a,b='\/'[::-d];s=n*d;x=2*s-1;y=4*s;print'_'*y;i=0;exec"print' '*i+(b+' '*(y-3-x-i-i)+a+'_ '[s-i>1]*x+a)[::d];i+=1;"*s

Проверьте это на Ideone

Сначала мы видим, nотрицательно d +1ли это, и делаем, если оно есть, и -1если нет.
Затем мы выбираем две косые черты aи b, используя так d, чтобы a='\', b='/'когда было nположительно, а a='/', b='\'когда было nотрицательно.
Далее мы устанавливаем, s=abs(n)что может быть достигнуто s=n*d.
Затем мы рассчитываем число _вверху (внизу рисунка), которое также является числом в стороне от палатки как x=2*s-1.
Затем мы рассчитываем количество _у основания палатки (вверху рисунка) и сохраняем его так, y=4*sкак оно будет использоваться в цикле для создания остальной части палатки.
Теперь мы печатаем основание палатки, используя print'_'*y.
Затем мы печатаем оставшуюся часть палатки, выполняя sоператоры печати с iинициализируемой переменной цикла, значение 0которой увеличивается 1для каждого оператора печати.
У остальной части палатки есть y-3-x-i-iпробелы в дверях и xпробелы в корпусе до тех пор, пока не будет достигнут верх, когда s-i>1оценивается как False, выбирая _from '_ '.
Для положительной палатки с левой дверью вся палатка, исключая ведущие пространства, находится спереди назад, поэтому она переворачивается, тогда как положительной палатки с правой дверью нет [::d].


@ Sp3000, к сожалению, cmp(0,0)возвращается0
Джонатан Аллан

5

Python 2, 121 байт

def f(n):i=k=abs(n);print'_'*k*4;exec"print' '*(k-i)+r'\\\%%s%\*%c%%*sc/'[n<0::2]%(' _'[i<2]*(2*k-1))%(2*i-1,47);i-=1;"*k

Просто много форматирования строк.


5

C #, 215 214 байт

string t(int N){var n=N<0;N=n?-N:N;var t=new string('_',4*N);for(int i=0;i<N;){string f=new string(i<N-1?' ':'_',2*N-1),p=new string(' ',2*N-2*i-2);t+='\n'+new string(' ',i++)+'\\'+(n?p+'/'+f:f+'\\'+p)+'/';}return t;}

Есть возможность сэкономить несколько байтов при использовании using s=string;заранее.

s t(int N){var n=N<0;N=n?-N:N;var t=new s('_',4*N);for(int i=0;i<N;){s f=new s(i<N-1?' ':'_',2*N-1),p=new s(' ',2*N-2*i-2);t+='\n'+new s(' ',i++)+'\\'+(n?p+'/'+f:f+'\\'+p)+'/';}return t;}

что будет 15 (с использованием) + 184 (метод) = 199 байт.


5
Добро пожаловать в PPCG, BackFromExile!
Эрик Outgolfer

Действительно, добро пожаловать в PPCG! Очень хороший первый ответ +1. Я пытался найти что-нибудь для гольфа (довольно давно, так как я программировал на C #), и в итоге смог найти только одну вещь для -1 байта: если вы измените первое varв цикле for на string, вы можете удалить второй var (включая место для сохранения байта). Так var fстановится string fи ;var p=становится ,p=.
Кевин Круйссен,

4

TSQL, 195 байт

Golfed:

DECLARE @ INT=-2
DECLARE @b INT=ABS(@),@i INT=0PRINT REPLICATE('_',4*@b)z:SET @i+=1PRINT SPACE(@i-1)+'\'+STUFF(REPLICATE(IIF(@i<@b,' ','_'),4*@b-2*@i),@b*2-IIF(@<0,@i*2-1,0),1,IIF(@<0,'/','\'))+'/'IF @i<@b GOTO z

Ungolfed:

DECLARE @ INT=-2

DECLARE @b INT=ABS(@),@i INT=0

PRINT REPLICATE('_',4*@b)
z:
  SET @i+=1
  PRINT 
    SPACE(@i-1)+'\'
    +STUFF(REPLICATE(IIF(@i<@b,' ','_'),
      4*@b-2*@i),@b*2-IIF(@<0,@i*2-1,0),1,IIF(@<0,'/','\'))
    +'/'
IF @i<@b GOTO z

скрипка


4

V , 66 байт

é /ä
"aDoÀñá_>ñ^hr\A\/ò^hÄX$2é_Ó_/ òÄÒ_ñ/-
ddÍܨ[ _]*©Ü¨ *©/ܲ¯±

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

Это довольно наивный подход, поэтому я постараюсь развить его чуть позже сегодня. Это решение содержит непечатаемые символы, поэтому вот hexdump:

0000000: e920 2fe4 0a22 6144 6f1b c0f1 e15f 3ef1  . /.."aDo...._>.
0000010: 5e68 725c 415c 2f1b f25e 68c4 5824 32e9  ^hr\A\/..^h.X$2.
0000020: 5fd3 5f2f 20f2 c4d2 5ff1 2f2d 0a64 64cd  _._/ ..._./-.dd.
0000030: dca8 5b20 5f5d 2aa9 dca8 202a a92f dcb2  ..[ _]*... *./..
0000040: afb1                                     ..

4

05AB1E , 52 байта

Ä©'_4®*×,FNð×'\®·<N>®Qi'_ëð}×®N>-·ð×®¹Qi'\ës'/}s'/J,

объяснение

                                                     # implicit input, call this A
Ä©                                                   # store abs(A) in register for later use
  '_4®*×,                                            # print 4*A underscores (tent floor)
         F                                           # for each non-floor section in range(N)
          Nð×'\                                      # push N spaces at the beginning of the 
                                                     # row followed by a backslash
                  N>®Qi'_ëð}                         # if we're on the last row push an
                                                     # underscore, else a space
               ®·<          ×                        # repeat that char abs(A)*2-1 times
                             ®N>-·ð×                 # push 2*(abs(A)-(N+1)) spaces
                                    ®¹Qi'\ës'/}      # if input is positive push backslash
                                                     # else push a slash
                                               s'/   # move that char between the 2 sections
                                                     # of spaces
                                                  J, # join the row and print

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


4

PowerShell v2 +, 217 205 190 187 184 байта

param($b)"_"*(($a=[math]::Abs($b))*4);$z,$y='/\'[($b=$b-lt0),!$b]
((($x=1..$a|%{($w=" "*($_-1))+$z+" "*(2*($a-$_))+$y+(' ','_')[$_-eq$a]*($a*2-1)+$y+$w})|%{-join$_[($a*4)..0]}),$x)[$b]

Принимает ввод $bкак целое число. Обратите внимание, что если $bоно отрицательное, вам нужно явно заключить его в скобки для правильного приведения (см. Примеры), иначе PowerShell будет думать, что это строка.

Независимо от того, в каком направлении стоит палатка, первая строка одна и та же, несколько подчеркиваний; 4*abs(input)на самом деле их точно много. Этот номер также сохраняется $aдля последующего использования. Кроме того, теперь, когда у нас есть абсолютное значение, $bсохраненное в $a, мы превращаемся $bв логическое значение для его знака и выбираем наши слэши, сохраненные в $yи $z.

Следующая строка - это построение и формулировка вывода, и это глупо, поэтому давайте разберем его.

Мы по существу индексируем в массив из двух элементов, (big long calculations saved into $x)или $x, на основе $b.

Расчеты, где строение палатки. Мы возвращаемся из 1..$a|%{...}. На каждой итерации мы строим линию тела палатки. Мы начинаем с количества пробелов, равных строке #, в которой мы находимся -1, так что это соответственно выровнено по левому краю. Это сохраняется $wдля последующего использования и объединяется с соответствующей косой чертой ($ z, на основе $b), затем количеством пробелов в дверной раме, затем другой косой чертой $y, либо подчеркиванием или пробелами в зависимости от того, находимся ли мы в нижней строке или нет, затем еще одна косая черта $yи, наконец, соответствующее количество конечных пробелов ( $w) для построения прямоугольной строки. Этот результирующий массив строк сохраняется в $x.

Если выбрана левая половина массива (то есть, $bэто , Falseтак как входной сигнал был положительным), то мы должны петли через $xи обратный каждый элемент строки - это где конечные пробелы вступают в игру; это позволяет нам просто повернуть линии, а не пересчитывать расстояния.

Если $bесть True, то $xвместо этого выбирается правая половина массива .

В любом случае, конвейер теперь содержит массив строк. Неявный вывод через Write-Outputпроисходит при завершении программы, с новой строкой по умолчанию между элементами.

Примеры

PS C:\Tools\Scripts\golfing> .\print-upside-down-tent.ps1 (-5)
____________________
\        /         /
 \      /         / 
  \    /         /  
   \  /         /   
    \/_________/    

PS C:\Tools\Scripts\golfing> .\print-upside-down-tent.ps1 (4)
________________
\       \      /
 \       \    / 
  \       \  /  
   \_______\/   

3

Haskell, 187 184 183 байта

f x=unlines$[(n*4)%'_']++((' '#)<$>[0..n-2])++['_'#(n-1)]where m#i=i%' '++'\\':m!i++"/";m!i|x>0=(2*n-1)%m++'\\':(2*(n-i-1))%' '|q<-2*(n-i-1)=q%' '++'/':(2*n-1)%m;n=abs x;m%c=c<$[1..m]

Я чувствую, что это не лучший результат для Haskell, поэтому любые идеи по улучшению приветствуются.

  • 3 байта сохранены благодаря @Myridium
  • 1 байт сохранен благодаря @nimi

Ungolfed

tent :: Int -> String
tent x = unlines $ [replicate (n*4) '_'] ++ (row ' '<$>[0..n-2]) ++ [row '_' (n-1)]
    where row m i = replicate i ' ' ++ "\\" ++ dir m i ++ "/"
          -- direction selector
          dir m i | x > 0 = side m ++ "\\" ++ entrance i ' '
                  | 1 > 0 = entrance i ' ' ++ "/" ++ side m
          side = replicate (2*n-1)
          entrance i = replicate (2*(n-i-1))
          n = abs x

Лучше, чем мои 290 байт, которые я собирался опубликовать ...
Myridium

Не следует ли добавить, mainчтобы он принимал в stdinкачестве входных данных?
Миридиум

Вы можете опубликовать одну функцию, если в вопросе не указано иное. Есть мета-поток для общих правил ответа, я постараюсь найти его для вас.
Sudee

1
Вы можете сохранить 2 байта, изменив место, где вы добавляете один символ для использования :символа. т.е. изменить "\\" ++ entrance...на '\\':entrance.
Миридиум

1
Не тратьте «иначе» охранника : вы можете изменить |1>0=(2*(n-i-1))%' 'на |q<-2*(n-i-1)=q%' '.
Ними,

2

C 240 207 193 байта

#define P putchar
a,j,l,m;g(x,y,z){for(m=y+z+1;m--;P(m^z?l?32:95:x));}f(n){g(32,(a=abs(n))*4,0);for(P(10),j=2*(l=a)-1;l--;){for(m=a;--m>l;P(32));P(92);m=n>0?g(92,j,l*2):g(47,l*2,j);puts("/");}}

На этот раз я оптимизировал функцию g (...), чтобы использовать один цикл for.

#define P putchar
a,j,l,m;g(x,y,z){for(;y--;P(l?32:95));for(P(x);z--;P(l?32:95));}f(n){g(32,(a=abs(n))*4,0);l=a;j=2*a-1;P(10);for(;l--;){for(m=a;--m>l;P(32));P(92);m=n>0?g(92,j,l*2):g(47,l*2,j);puts("/");}}

На этот раз макрос X лучше использовать как функцию g (...), и, поскольку y и z являются параметрами в новой области видимости, я могу просто уменьшить их в области видимости g.

#define P putchar
#define X(x,y,z){for(k=0;k++<y;P(l?32:95));P(x);for(k=0;k++<z;P(l?32:95));}
a,i,j,k,l,m;f(n){for(l=a=abs(n);i++<a*4;P(95));j=2*a-1;P(10);while(l--){for(m=a;--m>l;P(32));P(92);if(n>0)X(92,j,l*2)else X(47,l*2,j)puts("/");}}

Проверьте с этой основной функцией; Это должно упасть намного меньше.

main(c,v)char**v;
{
    f(atoi(v[1]));
}

2

C # 241 231 байт

Сохранено 10 байтов благодаря @Kevin Cruijssen

using s=System.String;s f(int N){var f=N<0;N=N>0?N:-N;var o=new s('_',N*4);for(int j=0,z;j<N;){z=-2*j+2*N-2;var O=j>N-2?'_':' ';o+='\n'+new s(' ',j)+'\\'+new s(' ',z)+(f?'/':O)+new s(O,j++*2)+(f?O:'\\')+new s(' ',z)+'/';}return o;}

Старая версия:

string f(int N){var f=N<0;N=N>0?N:-N;var o=new string('_',N*4);for(int j=0;j<N;){int z=-2*j+2*N-2;var O=j>N-2?'_':' ';o+='\n'+new string(' ',j)+'\\'+new string(' ',z)+(f?'/':O)+new string(O,j++*2)+(f?O:'\\')+new string(' ',z)+'/';}return o;}

Первоначально имел new string(...)как Func<char,int,string>сохраненный один байт, используя конструктор. Я хочу int-> charбыл неявным

Уверен, моя математика тоже может быть исправлена, но я ее не вижу


1
Вы можете играть в гольф еще немного. Прежде всего , вы можете удалить int перед тем z=, добавив его в обмен на петлю: int j=0,z. И так как вы используете stringдовольно много, вы можете присвоить ему псевдоним. using s=System.String;Таким образом, итоговое значение становится: using s=System.String;s f(int N){var f=N<0;N=N>0?N:-N;var o=new s('_',N*4);for(int j=0,z;j<N;){z=-2*j+2*N-2;var O=j>N-2?'_':' ';o+='\n'+new s(' ',j)+'\\'+new s(' ',z)+(f?'/':O)+new s(O,j++*2)+(f?O:'\\')+new s(' ',z)+'/';}return o;}( 231 байт )
Кевин Круйссен

1

Swift 2.2 421 байт

Ну ... Это была попытка.

Golfed:

let t={(s:String,n:Int)->String in return String(count:n,repeatedValue:Character(s))};let e={(n:Int)in var w=[String]();w.append(t("_",abs(n)*4));let c = abs(n);let d = n>0 ? "/": "\\";let f = n>0 ? "\\": "/";for var i in 0...abs(n)-1 {w.append(t(" ",i)+d+t(" ",c*2-2-(2*i))+f+(i<c-1 ?t(" ",2*c-1)+f:t("_",2*c-1)+f)+(n>0 ?t(" ",i):""));};w=n<0 ?w:w.map(){String($0.characters.reverse())};print(w.joinWithSeparator("\n"))}

UnGolfed:

let t={(s:String,n:Int) -> String in
    return String(count:n,repeatedValue:Character(s))
};
let e={(n:Int) in
    var w=[String]();
    w.append(t("_",abs(n)*4));
    let c = abs(n);
    let d = n>0 ? "/": "\\";
    let f = n>0 ? "\\": "/";
    for var i in 0...abs(n)-1 {
        w.append(t(" ",i)+d+t(" ",c*2-2-(2*i))+f+(i<c-1 ?t(" ",2*c-1)+f:t("_",2*c-1)+f)+(n>0 ?t(" ",i):""));
    };
    w=n<0 ?w:w.map(){String($0.characters.reverse())};
    print(w.joinWithSeparator("\n"))
}

1

PHP, 143 байта

$t=str_repeat;echo$t(_,4*$s=$k=abs($n=$argv[1]));for(;$k--;$p.=" "){$f=$t("  ",$k);$r=$t($k?" ":_,2*$s-1);echo"
$p\\",$n<0?"$f/$r/":"$r\\$f/";}

бежать с php -r '<code>' <parameter>

сломать

$t=str_repeat;  // function name to variable saves 10-1 bytes
echo$t(_,4*$s=$k=abs($n=$argv[1])); // print bottom
for(
    ;
    $k--;   // $k from abs($n-1) to 0
    $p.=" "                 // create padding
)
{
    $f=$t("  ",$k);         // create front
    $r=$t($k?" ":_,2*$s-1); // create side/roof
    echo"\n$p\\",$n<0
        ?"$f/$r/"   // print, entrance left
        :"$r\\$f/"  // print, entrance right
    ;
}

1

Пакетный, 289 байт

@echo off
set/pn=
set u=
for /l %%i in (2,1,%n:-=%)do call set u=_%%u%%_
echo _%u%__%u%_
set l=
set m=%u%/_%u%
if %n% gtr 0 set m=%u%_\%u%
set m=%m:_= %
for /l %%i in (2,1,%n:-=%)do call:l
set m=%m: =_%
:l
echo %l%\%m%/
set l= %l%
if %n% gtr 0 set m=  %m:~0,-2%
set m=%m:~2%

Принимает участие в STDIN. Начинается с создания строки 2*(abs(n)-1)подчеркивания. Затем это повторяется плюс еще 4 подчеркивания для основания палатки. Затем остальная часть палатки состоит из отступа (который увеличивается на 1 в каждой строке), а \, середины палатки и а /. Середина палатки начинается с 2*(abs(n)-1)пробелов, плюс либо \или /плюс пробел (который я не могу представить в Markdown), а также другие 2*(abs(n)-1)пробелы. Я повторно использую строку подчеркивания и заменяю их пробелами для удобства, но затем заменяю пробелы на подчеркивания для последней строки. Каждая строка удаляет два пробела с одной стороны от середины палатки, хотя немного сложнее, если нужно, сначала переместить два пробела к началу струны.


Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.