9桁の問題


8

見つけるためのプログラム書く1から9までの数字のそれぞれが一度だけ表示される9桁からなる番号を。この数は、これらの分割可能要件も満たしている必要があります。

  1. 数は9で割り切れる必要があります。
  2. 右端の数字を削除すると、残りの数字は8で割り切れます。
  3. 新しい番号の右端の桁を削除すると、残りの番号は7で割り切れるはずです。
  4. 以下同様に、1桁になるまで(これは必ず1で割り切れます)。

クレジットDávidNémeth


28
最初のルールは不要のようです。1から9までの数字で構成される数値は、それぞれ9で割り切れます
— Geobits

6
ここのコードアスペクトは何ですか?これはPuzzling
— Simon Forsbergに

11
それを「標準の抜け穴」と呼ぶつもりでも、一般にそれを構築できるコードよりも短い固定出力を生成するコードゴルフの課題は、通常は特に興味深いものではありません。
— Ry- 2014年

9
このような課題で私が抱えている問題は、ハードコーディングと数学的なプロパティの適用の境界が曖昧であることです。たとえば、5の分割可能性のルールでは、数値は0または5で終わる必要があります。その数字の選択肢を出力のハードコーディング部分の0および5に制限していますか?10桁の数値を扱う場合はさらに悪化します。
— user2357112は

4
@Sylwesterあなたがやったことは、あなたが抜け穴を破ることを恐れているので、問題を解決する唯一の方法があると仮定しています。「番号チェック要件のループ」。これは、興味深い例を完全に除外します。そして問題は、「どの言語がこれらのものをチェックし、最も少ない文字でループできるか」です。
— ランチャー2014年

回答:


9

CJam-26

1{;9,:)_mrs0@{_3$<i\%+}/}g

ランダム化されていますが、Javaインタープリターでかなり高速に動作します。それは取ることができますカップルと分のオンライン通訳を。

説明:

1pushs 1(後で説明します)
{…}gはdo-whileループで
;スタックから値を削除し(最初は1から始めました)
9,、配列[0 ... 8]
:)が配列要素をインクリメントし、[1 ... 9]
_配列複製
mrシャッフル配列の
s文字列に変換する
0@上で、アレイの他のコピーをもたらし、次にプッシュ0
{…}/(番号1 ... 9以上)のために、各ループである
_現在の数(レッツコールその「K」を複製し)
3$スタックから数値文字列をコピー
<iし、最初のk文字の部分文字列を取得してから、k
\%の他のコピーと整数スワップに変換し、残り(%k)を取得して
+、残りをスタックの前の値に追加します(最初は上から0) )
この時点で、スタックには数値文字列があり、数値がすべての要件に一致する場合(つまり、残りがすべて0の場合)は0、それ以外の場合は0以外の値が続きます。
スタックの一番上がdo-whileループ状態になります。ポップされ、条件がtrueの場合はループが続行されます。
解が見つかった場合、条件は0(false)であり、ループは終了し、スタックの残り(数値文字列)が出力されます。
それが解決策でない場合、条件は0以外の値(true)であり、ループはスタック上の文字列で続行されます。文字列は次の反復の開始時にポップされます(そのため、ループはスタック上の値を期待し、それが最初の1の理由です)。

コードをより短く複雑にしてくれたDennisに感謝します:p


いいね!あなたはダミーの値を使用することにより、1つの以上のバイトを保存することができます:0{;9,:)_mrsT@{_3$<i\%+}/}g
— デニス

7

JavaScript(E6)105125134

数の再帰的構築、各ステップは可分性をチェックします。
ランタイムは0秒近くです。
今回はI / Oがありません。OPがプログラムに番号を見つけるように要求したため、番号が見つかり、自動的にコンソールに記録されました。

MT0の好意でゴルフをした

(Q=(n,d,b)=>([(m=n+(s=[...b]).splice(i,1))%d||Q(m,d+1,s)for(i in b)],d>9&&(Q.z=n),Q.z))('',1,'123456789')

ゴルフ

(Q=(n='',d=1,b=[...'123456789'],i)=>{
for(i=0;s=[...b],m=n+s.splice(i,1),b[i];i++)m%d||Q(m,d+1,s);d>9&&(Q.z=n);return Q.z;
})()

醜い

(Q=(n='', d=1, b=[...'123456789'], i) => {
   for(i=0; s=[...b], m=n+s.splice(i,1), b[i]; i++)
     m % d || Q(m,d+1,s);
   d > 9 && (Q.z=n);
   return Q.z;
})()

ボーナス

3つの小さな変更で、同じ関数を使用して、base> 10を使用してより長い数を見つけることができます。たとえば、base 14で...

(Q=(n='',d=1,b=[...'123456789ABCD'],i)=>{
  for(i=0; s=[...b], m = n+s.splice(i,1), b[i]; i++)
    parseInt(m,14)%d || Q(m,d+1,s);
  d>13 && (Q.z=n);
  return Q.z;
})()

9C3A5476B812D

未ゴルフ

Q=(n,d,b,i,c,z)=>{ // i,c,z fake parameters instead of vars.
  for (i=0; b[i]; i++)
  {
    s=[...b];
    m = n + s.splice(i,1);
    if (m % d == 0)
      if (z = d<9 ? Q(m, d+1, s) : m) return z;
  }
}
Q('',1,[...'123456789'])

1
105文字:(Q=(n,d,b)=>([(m=n+(s=[...b]).splice(i,1))%d||Q(m,d+1,s)for(i in b)],d>9&&(Q.z=n),Q.z))('',1,'123456789')
— MT0 2014年

101文字:(Q=(n,d,b)=>Math.max(...[(m=n+(s=[...b]).splice(i,1))%d||Q(m,d+1,s)for(i in b)],n))('',1,'123456789')
— MT0 2014年

@ MT0すごい!配列の理解は反撃します。1つ目を取り上げます。正しい1つがない場合は、他の1つが間違った番号を見つける可能性があるためです(IEが9ではなく7まで数える)。
— edc65 2014年

5

Perl、56

使用法: perl -E '...'

{$s++;redo if grep{$s!~$_||substr($s,0,$_)%$_}1..9}say$s

出力: 381654729

このプログラムは本当に遅いです。3.5時間以上のように。

より楽しい演習として、私は非常に高速なアルゴリズムを開発することにしました。

my $set = [1..9];
for my $divisor (2..9) {
    my $newset = [];
    for my $element (@$set) {
        my $num = $element * 10;
        for (my $digit = $divisor - ($num % $divisor); $digit < 10; $digit += $divisor) {
            if (index($element, $digit) == -1) {
                push @$newset, $num + $digit;
            }
        }
    }
    $set = $newset;
}

print "@$set\n";

上記は.00095秒で実行され、この問題の解決策が1つしかないことを確認します。


5

Python3、 214、 199、 184、 176、 174、 171、 165、 150、146

from itertools import*
g=lambda i,d:d==1!=print(i)or int(i[9:])%d==0!=g(i[:-1],d-1)
for x in permutations("123456789"):g("".join(map(str,x))*2,9)

出力:

381654729

これは私の最初のゴルフ台本です。あなたはそれが好きだと思います:)


4

Pyth、33文字

=Y]kFkY~Yf>ql{TlT%vTlTm+k`dr1T)pk

これをテストするには、上記のコードを標準入力としてタイトルのリンクに挿入します。

Python 3.4にコンパイルした後:

k=''
T=10
Y=[k]
for k in Y:
 Y+=list(filter(lambda T:(len(set(T))==len(T))>(eval(T)%len(T)),
                map(lambda d:k+repr(d),range(1,T))))
print(k)

説明:

=Y]k:Y=['']

FkY:Fのkの場合:

~Y:Yに追加

f:フィルター

>ql{TlT:すべてのユニークな要素と

%vTlT:eval(要素)%len(要素)= 0

m+k` d k + repr(d)のリスト

r1T:dは1から9まで。

):ループの終了

pk:プリントk


4

ルビー、66歳 78 チャー

[*r=1..9].permutation{|i|r.all?{|x|eval(i[0,x]*"")%x<1}&&$><<i*""}

実行時間は約8秒です(出力は3秒後に印刷されます)。

これは最初の数値を見つけた後も止まらないため、技術的には基準を満たすすべての数値を出力しますが、そのような数値は1つしかないため、違いはありません。

Ruby 1.8、63

[*r=1..9].permutation{|i|r.all?{|x|eval(i[0,x]*"")%x<1}&&$><<i}

基本的に上記と同じソリューション。Ruby 1.8では、配列は暗黙的に呼び出さArray#joinれて文字列に変換されるため、その呼び出しを保存できます。興味深いことに、コードはRuby 1.8でも2.0よりはるかに高速に実行されます(合計実行時間4.5秒、出力は1.6秒後に印刷されます)。


3

GolfScript(35文字)

1,{{10*){.)}8*}%{`..&=},{.`,%!},}9*

オンラインデモ

これにより、条件を満たすプレフィックスが作成されます。

# Initial prefixes: [0]
1,
# Loop 9 times
{
    # Extend each prefix by digits 1 to 9
    {10*){.)}8*}%
    # Filter out ones which repeat a digit
    {`..&=},
    # Filter down to ones which are divisible by their length
    {.`,%!},
}9*

3

ハスケル 129 121

これが私の素人っぽいHaskellの試みです(提案/改善は大歓迎です)。最短ではないかもしれませんが、それだけで実行されます.19 私のシステムでFlonkが変更されてから0.65秒。

import Data.List;f=foldl1$(+).(*10);main=print$[f x|x<-permutations[1..9],f[mod(read.take y.show$f x)y|y<-[9,8..1]]<1]!!0

PPCG.SEへようこそ!<!-- language: lang-haskell -->構文を強調表示するために、コードの前に2行追加してください。
— フロンク2014年

そして、実際にさらに8文字を節約する方法を見つけました!それぞれの残りが0であるかどうかを確認する代わりに、それらすべてを合計して、それが同じくらい長いかどうかを確認することができます。foldl1ただし、を関数に分離することにより、sumまたはの代わりにそれを使用できますany。import Data.List;f=foldl1$(+).(*10);main=print$[f x|x<-permutations[1..9],f[mod(read.take y.show$f x)y|y<-[9,8..1]]<1]!!0
— フロンク2014年

末尾の改行を含めて文字を数えたようです。コードには128文字しかありません。
— Peter Taylor

@Flonk 余分なサイクルはパフォーマンスを大幅に妨げますが、foldl1の書き込みを回避するためfに、mod述語で関数を使用することは絶対に好きです。
— DrJPepper

@DrJPepper 0.65秒?ええ。さらに悪化させましょう!リストに項目が1つしかないため、!!0への呼び出しで置き換えることもできfます。順序は関係ないため、リスト[9,8..1]はで置き換えることもできxます。コードの再利用について話してください!
— フロンク2014年

2

JavaScript 75(終了)

ブルートフォースソリューション(超低速)

for(a=c=1;b=c&&++a;)for(c=9;~(a+'').search(c)&&b%c<1;)--c?b=b/10|0:alert(a)

この存続期間の結果を確認する場合は、初期値を次のように更新します a=c=38e7

JavaScript 70(非終了)

for(a=1;b=++a;)for(c=9;~(a+'').search(c)&&b%c<1;)--c?b=b/10|0:alert(a)

そして、ただ楽しむために、はるかに速く実行されるランダムな総当たり攻撃(ES6のみ)

for(a=i=[..."123456789"];b=c=i&&a.sort(x=>Math.random()*9-5|0).join('');)for(i=9;c%i<1;)--i?c=c/10|0:alert(b)

2

Python、 142、 139、 125、124

私が彼のコードを正しく理解していれば、基本的には@Venteroのソリューションと同じですが、Pythonで行われます(クレジットの多くは@Greg Hewgillに支払われます)。

from itertools import*;print[s for s in map(''.join,permutations('123456789'))if all(t(s[:i])%i==0 for i in range(1,9))][0]

あなたは置き換えることができるはずr(9,1,-1)でr(9)繰り返しの順序は本当に重要ではありませんので、。
— Ventero 2014年

エラーなr(1,9)ので使用する必要%0があります。
— グレッグヒューギル2014年

@GregHewgillああ、もちろんあなたは正しい、それが0で始まることに気づかなかった。私がPythonの専門家ではないことは明らかだと思う。:)
— Ventero 2014年

@Venteroヒントをありがとう、Gregはr(1, 9)Pythonで使用する必要があります。
— Ashwini Chaudhary 2014年

1
使用していてpermutations("123456789")、''.join(s[:i])おそらくあなたが持っているものよりも短い(そしてあなたは排除することができるr=range)
— Greg Hewgill

2

Scala(128文字)

これで私の刺し傷...

Seq(1,2,3,4,5,6,7,8,9).permutations.filter(p=>(2 to 8)forall{n=>(p.take(n).mkString.toLong%n==0)}).map(_.mkString.toLong).toList

(2 to 8)との間のスペースを削除すると、キャラクターを保存できますforall。
— ProgramFOX 2014年

@ProgramFOXわからなかった。ドットやスペースが必要だといつも思っていました。ありがとう、私は128文字まで編集しました。
— キースピンソン2014年

2

Perl、72

使用法: perl -M5.010 find-9-digits.pl

{$s=join'',sort{4-rand 8}1..9;redo if grep{substr($s,0,$_)%$_}2..9}say$s

出力: 381654729

このプログラムは遅いです。数字「123456789」をシャッフルするため、10秒以上かかる場合がありますが、シャッフルには欠陥があります。

未ゴルフ:

# Enter a block.
{
     # Shuffle the characters "123456789".
     $s = join('', sort({2 - rand(4)} 1..9));

     # Redo block if any divisiblity test fails; grep returns the
     # number of failing tests.
     redo if grep({
        # For each divisor $_ in 2..9, test if the first $_ digits of
        # of $s are divisible by $_.  The test fails if the remainder
        # is a true value (not zero).
        substr($s, 0, $_) % $_
     } 2..9);
}
say $s;

数字の配列1..9をシャッフルするコードを使用しました。

  • use List'Util shuffle;shuffle 1..9 (34文字)
  • sort{(-1,1)[rand 2]}1..9 (24文字)
  • sort{.5<=>rand}1..9 (19文字)
  • sort(2-rand 4}1..9 (18文字)
  • sort{4-rand 8}1..9 (18文字)

Perlは、ソートブロックが$ aと$ bを一貫した方法で比較することを期待しています。私の並べ替えブロックは$ aと$ bを決して見ません。それらはランダムな順序を返すため、並べ替えはシャッフルになります。

を使用するsort{.5<=>rand}1..9と、プログラムの実行速度が速くなります。これは、0.5と、1.0を除く0.0から1.0までのランダムな浮動小数を比較して、1/2の確率で$ a <$ b、ほぼ1/2の確率で$ a> $ bです。(注意:これは「Microsoftシャッフル」であり、公平なシャッフルではあり.5<=>randません。一貫した順序を提供しないため、これには偏りがあります。)

私が1つのキャラクターを離れてゴルフし、はるかに悪いものを使用するとしますsort(2-rand 4}1..9。Perlは、ソートブロックが整数を返すことを期待します2-rand 4が、浮動小数点です。これは、-2.0を除く-2.0から2.0までのランダムなフロートです。Perlはこの浮動小数点数をゼロに向かって切り捨て、次の結果になります。

  • $ a <$ bである1/4の確率、-2.0 <float <= -1.0から整数-1
  • $ a == $ bである確率の1/2近く、-1.0から整数0 <float <1.0
  • $ a> $ bである1/4確率に近い、1.0から整数1または2 <= float <= 2.0

$ == $ bの、Perlは十分にシャッフルされません。したがって、私のプログラムは、2-rand 4頻繁に0を返さない十分なシャッフルを取得するまで、より多くのシャッフルを実行します。プログラムの実行速度が非常に遅いため、1分以上かかる場合があります。

私はを使用sort{4-rand 8}1..9しているので、$ a == $ bである確率は1/4 であり、私のプログラムはシャッフルを少なくしています。


ニースの手巻きシャッフル
— ミラー

1

CJam、35バイト

0{)_`$A,1>s=!1$9,{9\m1$\%@+\A/}/;}g

約27分後、次の出力が生成されます。

381654729

使い方

0         " Push 0 (“n”).                                                      ";
{         "                                                                    ";
  )_`$    " Increment “N”, duplicate, stringify and sort the resulting string. ";
  A,1>s   " Push '123456789'.                                                  ";
  =!      " Push 0 if the strings are equal and 1 otherwise (“a”).             ";
  1$      " Copy “n”.                                                          ";
  9,{     " For each i in [ 0 1 2 3 4 5 6 7 8 ].                               ";
    9\m   " Calculate “9 - i”.                                                 ";
    1$\%  " Calculate “n % (9 - i)”.                                           ";
    @+    " Add the result to “a”.                                             ";
    \A/   " Swap “a” with “n” and calculate “n / 10”.                          ";
  }/      "                                                                    ";
  ;       " Discard “n”.                                                       ";
}g        " If “a > 0”, repeat the loop.                                       ";

印象的なサイズが、それはさらに遅い私よりようで、私はそれが正しいではありません疑う
— SEは悪であるため、aditsuが終了

完全にはわかりませんが、0を数字として受け入れているようです。また、いつ停止しますか?
— SEが悪魔であるためaditsuが辞任2014

1

Python 2(78)

x=1
while len(set(`10*x`))<=9+sum(x/10**i%(9-i)for i in range(9)):x+=1
print x

順列を生成する必要はありません。各数値を試し、その数字と0が異なるかどうかを確認してください。実行に時間がかかります。


1

SWI-Prolog 84

g([],O,_,O).
g(L,N,I,O):-nth1(_,L,D,R),M is N*10+D,J is I+1,0 is M mod J,g(R,M,J,O).

数字のリストをクエリで指定する必要があるため、これは少し不正です。

?- g([1,2,3,4,5,6,7,8,9],0,0,O).
O = 381654729 ;
false.

しかし、それがこのコードを面白くするものです。数字のリストの問題を解決できます。例えば:

?- g([1,2,3,4,5,6,7,8,9,0],0,0,O).
O = 3816547290 ;
false.

?- g([1,2,3,4,5,6,7,8],0,0,O).
O = 38165472 ;
false.

?- g([1,2,3,4,5,6,7],0,0,O).
false.

?- g([1,2,3,4,5,6],0,0,O).
O = 123654 ;
O = 321654 ;
false.

?- g([2,2,3,3,5,6,7,8,9],0,0,O).
O = 363258729 ;
O = 363258729 ;
O = 363258729 ;
O = 363258729 ;
O = 723258963 ;
O = 723258963 ;
O = 723258963 ;
O = 723258963 ;
false.

1

Python 2 – 114

最短のPythonソリューションでさえありませんが、とにかくそれを共有しています:

e=""
f=lambda s,n:[[n,e.join(f(s.replace(j,e),n+j)for j in s)][s>e],e][n>e>0<int(n)%len(n)]
print f("123456789",e)

1

Bash + coreutils、159バイト

l=`echo {1..8}`
for d in {2..8};{
l=$(printf "a=%s;if(!a%%$d)a\n" $(eval echo {${l// /,}}{1..8}|tr \  '
'|grep -Pv '(\d).*\1')|bc|paste -d\  -s -)
}
echo ${l}9

これは少し長いですが、これはおそらく0.1秒未満で実行される(通常は遅い)シェルスクリプトであることを考えると、アルゴリズムはおそらく最も高速なものの1つだと思います。

アルゴリズムは次のようになります。

  • 左端の数字(1-8)から始めます
  • 右側に次の数字を追加(1-8)
  • 数字が繰り返される数字を削除する(grep)
  • で生成された式$dを使用してbc、(桁数)で分割可能かどうかを確認しますprintf
  • 8桁の数字が得られるまで上記を繰り返します

いくつかのショートカットがありますが、これらは数学的には正しいと思います:

  • 左端の数字は1で割り切れる必要があります。これはすべて数字であるため、左端の数字の最初のセットを明示的にチェックしません。
  • 右端の数字は9でなければなりません(これが有効な仮定であるかどうかは、実際にはわかりません。少し考えなければなりません)。

1

C ++、187

私はこれをC ++で試さなければなりませんでした。明らかに、それは最短の解決策にはならないでしょうが、ここにそれがあります:

#include <algorithm>
using namespace std;bool c(int n,int d=9){return d<2||n%d==0&c(n/10,d-1);}int main(){for(char n[]="123456789";next_permutation(n,n+9);)if(c(atoi(n)))return atoi(n);}

一部の文字を保存するために出力する代わりに番号を返します(くそー)もちろん、POSIXシステムでは、これは8ビットの符号なしに変換されるため、正しくありません。ただし、プログラムは正しい数を計算します。

Ungolfed(C ++ 11が必要):

#include <iostream>
#include <algorithm>
using namespace std;

bool check(int n, int digit = 9)
{
  return (n % digit==0) && (digit == 1 || check(n/10,digit-1));
}

int main()
{
  string num {"123456789"};
  while (next_permutation(begin(num), end(num)))
    if (check(stoi(num))){
      cout << num << endl;
      break;
    }
}

1

T-SQL 2005以降-203

T-sqlは非常に競争の激しいゴルフ言語ではありません...

with A(n)as(select top 10 number from spt_values where'p'=type),R as(select \r,1l union all select r*10+n,l+1from R,A where n not in(select substring(str(r),n,1)from A)and(r*10+n)%l=0)select max(r)FROM R

masterデータベースで実行する必要があります。最初のCTEをこれに置き換えてデータベースに依存しないようにすることができますが、さらにいくつかの文字を使用します(2008が必要です)。

with A as(select*from(VALUES(1),(2),(3),(4),(5),(6),(7),(8),(9))f(n))

読みやすい編成:

 with A(n)as(select top 10 number from spt_values where'p'=type),
    R as(select \ r,1 l 
        union all 
        select r*10+n,l+1
        from R,A
        where n not in (
            select substring(str(r),n,1)
            from A
        )
        and(r*10+n)%l=0)
select max(r) FROM R

基本的rに、文字列でまだ表示されていない数字の後ろに数字を追加し続け、新しい文字列が現在のレベルのモジュロ0であることを確認します。Rをに初期化し\ます。これが実際にこのコードの唯一のトリックです。これは、moneyデータ型で0に設定するためのクレイジーな方法です。\通貨の代わりにタイプさせる方法を私は推測しています。 $T-SQLでも同じことを行いますが、$l存在しない疑似列を解釈しようとしてエラーをスローします。これにより、使用に関する心配を回避できますintこれにより、通常は10番目の連結でオーバーフローが発生し、実際にレベルをチェックする必要があります。編集:おもしろい事実2014年のT-sqlには、文字列を値のテーブルに変換する組み込みの方法がない(たとえば、split funcがない)ので、実際にAテーブルを2回再利用して、ストリング化されたR

T-Sql優先ルールは煩わしいので、文字列連結ではなく数値連結(* 10 + n)を使用する必要があります。


あなたは、5つのバイトを保存し、それをして最初の行を交換することにより、データベースのすべての種類の上で実行できるようにすることができます:with A as(select 1n union all select n+1 from A where n<9),
— comfortablydrei

いい視点ね。実際のコードでは、rCTEを使用してカウントすることは決してないので、試してみることもできませんでした。
— マイケルB

0

PHP、89バイト

ランダムバージョン、89バイト:

for($n=123456789;$n=str_shuffle($n);$d||die("$n"))for($d=10;--$d&&substr($n,0,$d)%$d<1;);

数字を含む文字列をシャッフルし、ループ内で可分性をテストします。

で実行し-nrます。


ブルートフォースループ、90バイト、非常に遅い:

for(;++$i<1e9;$d||die("$i"))for($d=10;--$d&&max(count_chars($i))<2&substr($i,0,$d)%$d<1;);

100000001からループし、内部ループの分割可能性をテストし、解が見つかると終了します。


再帰関数、94バイト、非常に高速:

function f($n="",$e=1){while($d++<9)strpos(_.$n,"$d")|($x=$n.$d)%$e||print$e>8?$x:f($x,$e+1);}

数値にまだ含まれていない1桁を追加します。長さによる分割が可能であれば、再帰(または出力)します。

これは、解決策が1つしかないことを利用しています。それがprint$e>8?$x:f($x,$e+1)なければ、print$e>8?"$x\n":f($x,$e+1)(+ 3バイト、すべてのソリューションを出力する)または($e>8?die("$x"):f($x,$e+1))(+4バイト、最初のソリューションで終了する)でなければならず、そうでない場合、ソリューションは区切り文字なしで出力されます。

と電話する f();

-

TiO

ブルートフォースバージョンには明らかな理由でTiOがありませんが、他の2つを試すことができます。

関数呼び出しのランタイムはインラインで測定されます(2〜4ミリ秒の間)。
合計実行時間はWebサイトによって測定されます(通常は50〜500ミリ秒)。

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