緊密な言葉


22

前書き

Puzzling SE のRand Al'Thorの投稿によると、緊密な単語とは、アルファベット順で3つの文字を(任意の順序で)含む単語です。

以下のような言葉の教育は霧笛キャバレーがすべてのような言葉に対して、緊密な言葉と考えられている学習クラクションをし、実行していない緊密な言葉です。

チャレンジ

課題は、単一の単語を入力として使用できるプログラムをコードゴルフすることです(すべての意図と目的のために小文字と仮定)。は、結び目の単語であり、結び目の単語でない場合は空の出力です。

Input: education
Output: cde

Input: foghorn
Output: fgh

Input: cabaret
Output: abc

Input: hijacking
Output: ghi, hij, ijk

Input: pneumonia
Output: mno, nop

Input: klaxon
Output: <<no output>>

Input: perform
Output: <<no output>>

Input: learning
Output: <<no output>>

ルール

  1. 入力は単一の小文字の単語であり、出力は小文字でなければならないのに対して、出力の性質はコーディング言語の選択によって異なります。チャレンジの性質、STDOUT、ファイル出力、配列などに最適な出力形式を選択してください。
  2. これはコードゴルフであるため、最も少ないバイト数が明確な勝者である場合になります。
  3. 愚かな抜け穴はありません
  4. アルファベット順ではない連続した文字を含む回答は受け付けません。したがって、たとえばcab、の適切な出力とはみなされませんcabaret
  5. 特別な注意、「トリプレット」は必ずしもアルファベット順である必要はありませんが、トリプレット内の文字は...でなければならないので、例えば「パフォーマンス」という単語の場合、出力mno,nopは受け入れられます。ようにnop,mno。単語「ハイジャック」の場合には、トリプレットのその6つの方法がありghihijそしてijkリストに配置することができ、すべての6つの順列は、出力として許容可能です。

それ以外に、あなたのマークで、ゴルフを始めましょう!


出力は、に3つの連続した文字の各セットを持つ2D char配列にできますか?
ルイスメンドー

@LuisMendo視覚化できるように例を挙げていただけますか?
WallyWest

ファイナルなしで私のコードを試してみてください!そして、別の言葉で、現在のものが同じ結果を与えるので:-)
ルイスメンドー

@LuisMendoはMATLカラムのメジャーですか?
マルティセン

1
出力はつまり、大丈夫タプルの配列の形式で出力されますpneumoniaすることができ[('m','n','o'),('n','o','p')])
R. Kap

回答:


8

05AB1E7 6 5バイト

コード:

3ãAŒÃ

説明:

3ã      # Cartesian product × 3 with input
  AŒ    # All substrings of the alphabet
    Ã   # Setwise intersection

CP-1252エンコードを使用します。オンラインでお試しください!


これは単なる天才です...この言語を限界まで押し上げるチャレンジを作成しなければなりません...;)
WallyWest

10

Python 3.5、68バイト

w=input()
a=0
while 1:s='%c'*3%(a,a+1,a+2);a+=1;{*s}-{*w}or print(s)

出力文字列を出力し、文字値が大きくなりすぎるとエラーで終了します。

3つの連続したすべての文字列を生成し、入力語のサブセットである文字列を出力します。


8

Pyth- 11 10 8 7バイト

スーパーブルートフォース法。

@^z3.:G

テストスイート

@            Setwise intersection, finds common strings between the two lists
 ^           Cartesian product
  z          Input
  3          Of length 3
 .:          Substrings. Without second input finds all substrings which is ok
  G          Lowercase aphabet

7

ゼリー、7 バイト

ØaẆfṗ3$

これは単項リンクです。オンラインでお試しください!

使い方

ØaẆfṗ3$  Monadic link. Argument: s (string)

Øa       Yield the lowercase alphabet, i.e., a := "abcdefghijklmnopqrstuvwxyz".
  Ẇ      Window; yields all substrings of a.
      $  Combine the two links to the left into a monadic chain.
    ṗ3   Take the third Cartesian power of s, yielding all combinations of three
         characters that can be formed from the letters in s.
   f     Filter; keep only those substrings of a that appear in the Cart. power.

7

JavaScript(ES6)、95 90バイト

f=
s=>[...s].map(c=>a[parseInt(c,36)]=c,a=[])&&a.map((c,i)=>c+a[i+1]+a[i+2]).filter(c=>!c[3])
;
<input oninput="o.textContent=f(this.value).join`, `"><div id=o>

欠損値はとして連結されるundefinedため、結果の文字列には3文字を超える文字が含まれます。!c[3]5バイトを節約するために@ETHproductionsからトリックを借りました。


2
偶然にもundefined密接に
結びついた

なぜparseInt(c,36)代わりにc.charCodeAt()
タイタス

@Titus違いはないと思いますが、私はparseIntコードゴルフでの使用に慣れています。
ニール

4

Python 3.5、78バイト

s={*input()}
for c in s:o=ord(c);a=chr(o-2);b=chr(o-1);s>{a,b}and print(a+b+c)

4

PHP、100バイト

for($a="abc",$i=98;$i<123;$a=substr($a,1).chr(++$i))if(strstr(count_chars($argv[1],3),$a))echo"$a,";

コマンドライン引数として入力を受け取ります。末尾のコンマを出力します。で実行し-rます。


1
for($s=join(range(Z,z));$a=substr($s,++$i,3);)$ aを作成するより短い方法です。句読点の束といくつかの2文字のシリーズも確認しますが、入力は小文字のみであり、3文字を検出する必要があるためです。
user59178

for($a="ab "、$ i = 98; $ i <123;)!strstr(count_chars($ argv [1]、3)、$ a = substr($ a、1).chr(++ $ i))?: print 。「$、」; `2つのバイトを保存し、非常に良い方法は、私はPHPで他の方法を試してみましたが、あなたのコードのバイト数に達することができないあなたは、カンマの後にスペースが必要な場合、私はわからない。
イェルクHülsermann

4

C、175 174バイト

main(_,a,m,n)char**a;{char*s=a[1],*t=s;while(*++s)while(s>t&&(n=s[-1])>=*s){m=(*s^n)?*s:0;*s=n;*--s=m;!*t&&++t;}for(;t[1]&t[2];++t)*t==t[1]-1&&*t==t[2]-2&&printf("%.3s ",t);}

インデント:

main(_,a,m,n)char**a;
{
  char*s=a[1],*t=s;
  while(*++s)
    while(s>t&&(n=s[-1])>=*s){
      m=(*s^n)?*s:0;
      *s=n;
      *--s=m;
      !*t&&++t;
    }
  for(;t[1]&t[2];++t)
    *t==t[1]-1&&*t==t[2]-2&&printf("%.3s ",t);
}

並べ替えを行うと、重複する値が0に置き換えられますが、これらの0は単語の先頭に並べ替えられます。連続した値を探すのは簡単です。


1
サイトへようこそ!
DJMcMayhem

1
はい、PPCGへようこそ!あなたの答えは素晴らしい仕事です。Cはゴルフをするのに最も簡単なものではありません。
WallyWest

3

MATL、13バイト

2Y23YCtjmAZ)!

オンラインでお試しください!

2Y2    % Push string of lowercase alphabet
3YC    % 2D char array with sliding blocks of size 3, each on a column
t      % Duplicate
j      % Take input
m      % Member function: true for elements of the 2D array that are in the input
A      % All: true for columns that consist of all true values
Z)     % Use as logical index into the columns of the 2D char array
!      % Transpose. Implicitly display

3

Haskell、48バイト

f w=filter(all(`elem`w))[take 3[c..]|c<-['a'..]]

3つの連続した文字のトリプルをすべて生成し、入力で文字のみを使用するトリプルを取得します。


53バイト:

f w=filter(all(`elem`w))[[pred$pred c..c]|c<-['c'..]]

リストに['c'..]は、'c'以降のすべてのUnicode文字が含まれます。リストの内包表記[[pred$pred c..c]|c<-['c'..]]により、3文字連続したすべての文字列になります"abc"。最高のユニコード文字の後継を取得する際のエラーを回避するために、[pred$pred c..c]前方にではなく後方にステップ[c..succ$succ c]します。

これらのトリプルは、入力に文字のみを使用するものに対してフィルターされます。


3

Perl、36バイト

+1を含む -n

STDINに入力を与えます。

perl -nE 'join("",a..z)=~/[$_]{3}(?{say$&})^/' <<< "hijacking"

コードだけ:

join("",a..z)=~/[$_]{3}(?{say$&})^/

3

T-SQL、153バイト

最後のTSQLの回答から長い時間が経過したことについて、WallyWestからのコメントに反応する必要がありました。回答は、ブライアンJの回答に一部影響を受けました

ゴルフ:

USE MASTER
DECLARE @ varchar(max)='hijacking'

;WITH C as(SELECT distinct ascii(substring(@,number,1))z FROM spt_values)SELECT CHAR(C.z)+CHAR(D.z)+CHAR(E.z)FROM C,C D,C E WHERE c.z+1=d.z and d.z=e.z-1

フィドル

ゴルフをしていない:

USE MASTER -- can be left out if the master database is already being used
DECLARE @ varchar(max)='hijacking'

;WITH C as
(
  SELECT distinct ascii(substring(@,number,1))z
  FROM spt_values
)
SELECT CHAR(C.z)+CHAR(D.z)+CHAR(E.z)
FROM C,C D,C E
WHERE c.z+1=d.z and d.z=e.z-1

1
それは賢いです!そのテーブルについてさえ知りませんでした。良いことは、2048文字以上の単語がないことです!
ブライアンJ

2

Haskell、63 60 52バイト

f w=[x|x<-take 3<$>scanr(:)"_"['a'..],all(`elem`w)x]

使用例:f "hijacking"-> ["ghi","hij","ijk"]

scanr(:)"_"['a'..]始まるすべてのUnicode文字のリストの尾を持つリストを作成'a'し、それがで終わることができ'_'、すなわち["abcde...\1114111_", "bcde...\1114111_", "cde...\1114111_", ..., "\1114109\1114110\1114111_", "\1114110\1114111_", "\1114111_", "_"]。次に、各文字列の最大3つの文字を取得し、にバインドしxます。すべてのx文字が入力パラメータ内にあるすべてを保持しますw

編集:@xnorは3 7バイトを保存しました。ありがとう!


リストの最初の3つの要素をa:b:c:_@パターンでキャプチャできるかどうかは誰にもわかりますか?
-nimi

@-パターンについては知りませんが、'z'上限を削除して、すべての文字を試すことができます。
xnor

これらの最初の3つの要素をキャプチャするのは本当に面倒です。take空の文字列を使用して削除するだけf w=[x|x<-init$take 3<$>scanr(:)""['a'..],all(`elem`w)x]
です。– xnor

@xnor:いいね。scanr「。」で始めることができます の代わりに""、を省略しinit$ます。
-nimi

2

T-SQL(SQL Server 2014)、217バイト

ゴルフ

declare @ table(a char)declare @i int=1while @i<=len(@a)begin insert into @ values(SUBSTRING(@a,@i,1))set @i+=1 end select distinct t.a+u.a+v.a from @ t,@ u,@ v where ASCII(t.a)+1=ASCII(u.a)and ASCII(u.a)+1=ASCII(v.a)

使用法

最初に変数@aをある種のcharとして宣言し、そのように入力を割り当てます

declare @a varchar(max) = 'pneumoultramicroscopicsilicovolcanoconiosis'

私はコードの一部として宣言をカウントしませんでしたが、入力用のsql標準が見つからなかったため、カウントを変更したいと思います

出力は、トリプルごとに1行になるか、単語が近いニットでない場合は行なしになります

非ゴルフ

declare @temp table ( letter char(1) ) -- table to hold each letter of the word

declare @i int = 1

while @i <= len(@input) -- split each letter, and each row in @temp will have one letter
begin
    insert into @temp values (SUBSTRING(@input, @i, 1))
    set @i = @i + 1
end

-- join the letters table to itself to get three letter triples, where the three are in adjacent increasing order
-- use distinct because there might be duplicates in the word
select distinct t1.letter + t2.letter + t3.letter
from @temp t1
cross apply @temp t2
cross apply @temp t3
where ASCII(t1.letter) + 1 = ASCII(t2.letter)
and ASCII(t2.letter) + 1 = ASCII(t3.letter)

このインスタンスで宣言後に必要な機能を実行するために必要なコードを扱っているため、宣言はカウントされません。チャレンジのためのSQLソリューションを見てきてからしばらく経ちました。すごい仕事!
WallyWest

私は、185文字にスクリプトのダウンをgolfedているここ ungolfedバージョンです。あなたは、チェックアウトすることが私の答えを、同様
t-clausen.dk

2

R、220バイト

私の解決策は非常に簡単です。可能な3文字の組み合わせをループし、入力された文字列の文字を3文字連続してループしてチェックし、文字列に追加します。文字列は、3文字が見つかった場合にのみ印刷されます(c == 4)。

f<-function(w){if(nchar(w)>2){for(i in 1:24){
c<-1
t<-""
for(k in 1:3){for(j in 1:nchar(w)){if(substr(w,j,j)==intToUtf8(95+k+i)&c<4){
t<-paste(t,substr(w,j,j),sep="")
c<-c+1
break
}}}
if(c==4){print(paste(t))}}}}

入出力

> f("education")
> [1] "cde"
> > f("foghorn")
> [1] "fgh"
> > f("cabaret")
> [1] "abc"
> > f("hijacking")
> [1] "ghi"
> [1] "hij"
> [1] "ijk"
> > f("pneumonia")
> [1] "mno"
> [1] "nop"
> > f("klaxon")
> > f("perform")
> > f("learning")
> > 

2

Python 3.5、114 111 88 80 79バイト:

lambda X,W=[*map(chr,range(65,91))]:[i*({*X}>={*i})for i in zip(W,W[1:],W[2:])]

匿名のラムダ関数。入力を大文字の文字列として受け取り、入力に表示される連続した文字のすべてのセットを表す3つの大文字で埋められたタプルの配列を出力3します。例えば、

[(), (), (), (), (), (), ('G', 'H', 'I'), ('H', 'I', 'J'), ('I', 'J', 'K'), (), (), (), (), (), (), (), (), (), (), (), (), (), ()]

inputの出力になりますHIJACKING。この出力形式は、OPで問題がないことが確認されています。したがって、唯一の大文字の入力形式があります。あなたが入力したい場合は、唯一の小文字、単純に置き換えるrange(65,91)range(97,123)、もう1バイト追加します。

すべてのテストケースでRepl.it!

説明:

基本的にここで何が起こっているのですか:

  1. リストはW、を使用して作成さW=[*map(chr,range(65,91))]れ、英語のアルファベットのすべての大文字が含まれます。このため、大文字の入力が常に必要です。

  2. iリスト内の各タプルに対して、3つの連続した文字タプルすべてUを含むを呼び出します。つまり、

    U=[('A','B','C'),('B','C','D'),('C','D','E'),...]
    

    によって作成されzip(W,W[1:],W[2:])、()のiセットバージョンのすべての要素が入力()のセットバージョンにある限り、つまり、のスーパーセットである限り、それぞれが出力リストに完全に追加されます。それ以外の場合、空のバージョンの()がリストに追加されます。i{*i}X{*X}{*X}>={*i}Xii()

  3. 一致が完全に追加された状態ですべてのタプルが処理されると、リストが最終出力として返されます。


2

Scala、59バイト

(s:Set[Char])=>'a'to'z'sliding 3 filter{_.toSet subsetOf s}

ゴルフをしていない:

(s:Set[Char]) => ('a' to 'z').sliding(3).filter{threeChars => threeChars.toSet.subsetOf(s)}

説明:

(s:Set[Char])=>             //define a function with a Set of Chars called s as an argument
'a' to 'z'                  //create a Range of characters 'a' to 'z'
sliding 3                   //create an Iterator(Seq(a, b, c), Seq(b, c, d), Seq(c, d, e), ... , Seq(x, y, z))
filter{_.toSet subSetOf s}  //keep only the triplets which are a subset of s

2

実際には、13バイト

ゴルフの提案を歓迎します。オンラインでお試しください!

S3@╧`εj`M3úV∩

アンゴルフ

                Implicit input string s.
S               sorted(s).
 3@╧            Push all length-3 combinations of s.
    `εj`M       Join all of those combinations into single strings.
         3úV    Push all slices of the lowercase alphabet of length 1 <= n <= b
            ∩   Push the intersection of the combinations and slices.
                Implicit return.

1

Java 7、230バイト

String c(char[]q){java.util.Arrays.sort(q);char a[]=new String(q).replaceAll("(.)\\1","$1").toCharArray(),c=97,i=2;String r="",z="",s;for(;c<'z';z+=c++);while(i<a.length)if(z.contains(s=""+a[i-2]+a[i-1]+a[i++]))r+=s+" ";return r;}

これはおそらくゴルフにかけることができますが、挑戦は私が当初Javaで考えていたよりもはるかに困難でした

未ゴルフ&テストケース:

ここで試してみてください。

class M{
  static String c(char[] q){
    java.util.Arrays.sort(q);
    char a[] = new String(q).replaceAll("(.)\\1", "$1").toCharArray(),
         c = 97,
         i = 2;
    String r = "",
           z = "",
           s;
    for(; c < 'z'; z += c++);
    while(i < a.length){
      if(z.contains(s = "" + a[i-2] + a[i-1] + a[i++])){
        r += s+" ";
      }
    }
    return r;
  }

  public static void main(String[] a){
    System.out.println(c("education".toCharArray()));
    System.out.println(c("foghorn".toCharArray()));
    System.out.println(c("cabaret".toCharArray()));
    System.out.println(c("hijacking".toCharArray()));
    System.out.println(c("pneumonia".toCharArray()));
    System.out.println(c("klaxon".toCharArray()));
    System.out.println(c("perform".toCharArray()));
    System.out.println(c("learning".toCharArray()));
    System.out.println(c("dblacghmeifjk".toCharArray()));
  }
}

出力:

cde 
fgh 
abc 
ghi hij ijk 
mno nop 



abc bcd cde def efg fgh ghi hij ijk jkl klm 

なぜJavaなのかを尋ねるだけですか?それは最もゴルフに適した言語ではありません...?もちろん努力のために+1 ...
WallyWest

1
@WallyWestまあ、私は日常生活のJava開発者です。そして、私はJavaがいかに冗長であるかに挑戦することは決してないことを知っていますが、Java imhoでコードゴルフをするのはまだ楽しいです。:)
ケビンクルーイッセン

1
あなたが参加するために近い将来にいくつかの創造的なコードの課題を考え出す必要があると思います:)それにもかかわらず良い仕事!
WallyWest

1

PowerShell v2 +、93バイト

param($n)97..120|%{-join[char[]]($_,++$_,++$_)}|?{(-join([char[]]$n|sort|select -u))-match$_}

必要以上に長く感じますが、それ以上ゴルフをすることはできません。

入力を受け取ります$n。以下からのループ97120、連続する3文字の文字列を構築する-まで、である|?、我々は持っているだろうabcbcdcdeパイプラインの上に、など。次に、Where-Object|?)を介してフィードされ、句が真である項目のみを引き出します。ここで、句は、1)入力文字列$n、-array としてキャストcharsortedおよびselect -unique'd、-joinedを文字列に戻す、2)-match3文字の文字列に対するed(つまり、正規表現の一致)です。一致する場合、3文字の文字列が単語に含まれているため、|?。結果はパイプラインに残り、出力は暗黙的です。

(ここでは、連結によって出力を文字列化しているため、出力はスペースで区切られていることに注意してください。)

PS C:\Tools\Scripts\golfing> 'education','foghorn','cabaret','hijacking','pneumonia','klaxon','perform','learning'|%{"$_ -> "+(.\close-knit-words.ps1 $_)}
education -> cde
foghorn -> fgh
cabaret -> abc
hijacking -> ghi hij ijk
pneumonia -> mno nop
klaxon -> 
perform -> 
learning -> 

素晴らしい説明。可能であれば、私はあなたに2票を与えます。
WallyWest

1

網膜、106 56バイト

D`.
O`.
^
abc¶
{`^(.*)¶.*\1.*
$0¶$1
}T`_l`l;`^.*
2`.*¶?

重複排除、並べ替え。追加しabcます。部分文字列が見つかったかどうかを調べ、見つかった場合は追加します。次のサブストリングに翻訳します。繰り返す。次に、最初の2行を削除します。

オンラインで試す


単純なソリューション:

D`.
O`.
!&`abc|bcd|cde|def|efg|fgh|ghi|hij|ijk|jkl|klm|lmn|mno|nop|opq|pqr|qrs|rst|stu|tuv|uvw|vwx|wxy|xyz

重複排除、並べ替え、3つの連続した文字の重複する一致を出力します。

オンラインで試す


ナイーブな解決策は非常に簡単に見えます...私はあなたのゴルフの解決策がより好きです...よくやった!
WallyWest

1

JavaScript(Firefox 48)、93バイト

x=>[for(c of a=[...new Set(x,i=0)].sort())if(parseInt(d=c+a[++i]+a[i+1],36)%1333==38&!d[3])d]

これは、96バイトのES6バージョンに役立ちます。

x=>[...new Set(x)].sort().map((c,i,a)=>c+a[i+1]+a[i+2]).filter(x=>!x[3]&parseInt(x,36)%1333==38)

使い方

関数の最初の主要な部分は次のとおりです。

[...new Set(x)].sort()

new Set(string)文字列内の各一意の文字の1つを含むSetオブジェクトを作成します。たとえば、new Set("foghorn")を返しSet ["f", "o", "g", "h", "r", "n"]ます。これをで配列に変換[... ]してから、組み込みでソートでき.sort()ます。このターン"foghorn"["f", "g", "h", "n", "o", "r"]

次のステップはこれです:

.map((c,i,a)=>c+a[i+1]+a[i+2])

これcにより、arrayの各haracterは、その後の2つのアイテムと連結されたキャラクターにマッピングされます。たとえば、["f", "g", "h", "n", "o", "r"] => ["fgh", "ghn", "hno", "nor", "orundefined", "rundefinedundefined"]。(undefined配列の存在しないメンバーにアクセスしようとすると、sがポップアップします。

最後のステップはフィルタリングです:

.filter(x=>!c[3]&parseInt(x,36)%1333==38)

まず、!c[3]&を含む文字列を除外しますundefined。これは、バグが原因で次のアルゴリズムがgmundefined連続したトリプレットなどとしてカウントされるためです。

3つの連続した文字列はすべて、ベース36の数値として解釈された場合、1333を法とする38です。次の計算でこれを計算しました。

  • 012(ベース36)= 38
  • 123(ベース36)= 1371
  • 1371-38 = 1333
  • 1371 mod 1333≡38 mod 1333≡38

したがって、3文字の文字列がbase-36で38 mod 1333の場合、3文字はアルファベットで連続しています。

テストスニペット


これは、次のような言葉で失敗したgemmage
ニール

だから、ヘキサトリゲジマル(ベース36)から逆変換したときのすべての連続した文字トリプレットは、1333に対してmod'dされたときは38であると言っているのです。
WallyWest

@Neilは6バイトのコストで修正されました。
ETHproductions

私はあなたの充当!c[3]ので、今、私もあなたのFirefox 30+答えをoutgolfingよ、あなたの前のES6応答の長さに私のES6の答えをダウンさせトリックを。ごめんなさい
ニール

@Neil気にしない:)
ETHproductions

1

ラケット237バイト

(define(f s)(let((lr(λ(l i)(list-ref l i)))(l(sort(map char->integer(string->list s))<)))(for((i(-(length l)2)))
(when(=(-(lr l(+ i 2))(lr l(+ i 1)))1(-(lr l(+ i 1))(lr l i)))(for((j 3))(display(string(integer->char(lr l(+ i j))))))))))

テスト:

(f "education")

出力:

cde

詳細バージョン:

(define(f2 s)
  (let ((lr (λ(l i)(list-ref l i)))
        (l (sort (map char->integer (string->list s)) <)))
  (for ((i (-(length l)2)))
    (when (=  (- (lr l (+ i 2)) (lr l (+ i 1)))
              1
              (- (lr l (+ i 1)) (lr l i)))
      (for((j 3))
        (display (string(integer->char (lr l (+ i j))))))))))

1

ルビー、50バイト

each_cons(3)アルファベットから長さ3のすべての連続したサブリストを取得し、setwise交差を使用してターゲット文字列にすべての文字が含まれるサブリストのみを選択?a..?zするe&s.chars==eために使用します。リストのリストを返します。

->s{(?a..?z).each_cons(3).select{|e|e&s.chars==e}}

オンラインでお試しください!


1

[R]、110バイト

 f=function(b){a=combn(sort(utf8ToInt(b)),3);apply(unique(t(a[,which(apply(diff(a),2,prod)==1)])),1,intToUtf8)}

私はまだゴルフができると確信しています


弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.