JavaScript에서 정수를 이진수로 변환하는 방법은 무엇입니까?


299

이진수로 양수 또는 음수의 정수를보고 싶습니다.

이 질문 보다는 JavaScript에 대한 것입니다.


2
a.toString (2) 예제는 -1에서 작동하지 않는 것 같습니다.
barlop

1
바이너리에서 십진수로 변환하는 것도 가능합니다 : stackoverflow.com/questions/11103487/…
Anderson Green

그리고 내가 "바이너리로"말할 때, 그것은 약간 모호 할 수 있습니다. 내부 비트 문자열 표현은 2를 보완하므로 양수는 밑이 2이고 앞에 0이 붙습니다 (음수는 빼기 기호 또는 부호 크기 표현으로 작성되지 않지만 긍정적 인 eqivalent의 기능)
barlop

답변:


498
function dec2bin(dec){
    return (dec >>> 0).toString(2);
}

dec2bin(1);    // 1
dec2bin(-1);   // 11111111111111111111111111111111
dec2bin(256);  // 100000000
dec2bin(-256); // 11111111111111111111111100000000

Number.toString(2)함수 를 사용할 수 있지만 음수를 나타낼 때 문제가 있습니다. 예를 들어 (-1).toString(2)출력은 "-1"입니다.

이 문제를 해결하려면 부호없는 오른쪽 시프트 비트 연산자 ( >>>)를 사용하여 숫자를 부호없는 정수로 강제 변환 할 수 있습니다.

실행 (-1 >>> 0).toString(2)하면 숫자 0 비트가 오른쪽으로 이동하여 숫자 자체는 변경되지 않지만 부호없는 정수로 표시됩니다. 위의 코드는 "11111111111111111111111111111111"올바르게 출력 됩니다.

이 질문 에는 추가 설명이 있습니다.

-3 >>> 0 (올바른 논리 이동)은 인수를 부호없는 정수로 강제 변환하므로 32 비트 2의 보수 -3을 얻습니다.



자바 스크립트를 시도했지만 여기에서 시도 한지 오래 되었습니다. w3schools.com/js/tryit.asp?filename=tryjs_output_alert 이 <script> window.alert ((-3 >>> 0) .toString (2)); </ script>
그렇습니다.

1
텍스트에서 입력을 받고 있기 때문에 toString (2)가 작동하지 않습니다. 이것을 사용하십시오 : function decToBase (dec, base) {return parseInt (dec) .toString (base); } alert (decToBase (dec, 2));
Magus

당신은 입력 텍스트라고 가정하고 있지만 대답에서 함수는 정수를 기대 ... 그래서, 입력 텍스트 그냥 정수로 변환 가짜의 bitshift를 사용하고 그것을 끝낼 경우
fernandosavio

@ 텍스트에서 입력을받는 사람은?
barlop 2018 년

207

시험

num.toString(2);

2는 기수이며 2와 36 사이의 모든 기저가 될 수 있습니다.

여기에 소스

최신 정보:

이것은 양수에만 적용되며 Javascript는 2의 보수 표기법으로 음의 이진 정수를 나타냅니다. 트릭을 수행 해야하는이 작은 기능을 만들었으므로 제대로 테스트하지 않았습니다.

function dec2Bin(dec)
{
    if(dec >= 0) {
        return dec.toString(2);
    }
    else {
        /* Here you could represent the number in 2s compliment but this is not what 
           JS uses as its not sure how many bits are in your number range. There are 
           some suggestions /programming/10936600/javascript-decimal-to-binary-64-bit 
        */
        return (~dec).toString(2);
    }
}

나는 여기 에서 도움을 받았다


-1에서는 작동하지 않습니다. a = -1; document.write (Number (a.toString (2))); 표시 -1
barlop

음수에 대해서는 업데이트가 여전히 작동하지 않는 것 같습니다 ( -3returns 1). 또한 나는 생각 dec > 0해야 dec >= 0하는해야 적어도 수정 0에 있기 때문에, dec2Bin(0)반환 10.
Adam Merrifield

위의 주석에서 두 경우 모두 내 크롬 콘솔에서 올바른 결과를 반환합니다. var a = -1; a.toString (2); "-1"var a = -3; a.toString (2); "-11"
Anmol Saraf

@AnmolSaraf 나는 당신이 의미하는 것을 보았습니다. 사람들이 10 진수 -5를 말할 때 구어체로 대답은 -5입니다. 이진수로 음수에 관해서는, 의미에서 네, 빼기 부호를 붙일 수 있습니다. 101과 -5는 -101이지만 컴퓨터는 빼기 부호를 저장하지 않기 때문에 1과 0 만 나타내므로 2 진수로 음수를 말할 때 1과 0에 음수 (빼기 부호 포함)를 넣는 것을 의미합니다. 몇 가지 방법으로는 1의 보수, 2의 보수 및 '부호 및 크기'가 있습니다. 따라서 -101010101 또는 -0101010은 사람들이 이진수로 음수로 의미하는 것이 아닙니다.
barlop

이 링크는 일부 stackoverflow.com/questions/12337360/ 에 관심이있을 수 있습니다. 어쨌든, 당신의 대답은 그 자체와 모순됩니다. "자바 스크립트는 2의 보수 표기법으로 음의 2 진 정수를 나타냅니다." 그리고 당신의 코드는 "여기서 2s 칭찬으로 숫자를 표현할 수 있지만 이것이 JS가 [논 센스 이유]로 사용하는 것은 아닙니다"라고 말합니다.
barlop

53

'이진으로 변환'의 이진은 세 가지 주요 사항을 나타낼 수 있습니다. 위치 숫자 시스템, 메모리의 이진 표현 또는 32 비트 비트 열 (64 비트 비트 스트링의 경우 Patrick Roberts의 답변 참조 )

1. 번호 시스템

(123456).toString(2)숫자를 기수 2 위치 숫자 시스템으로 변환합니다 . 이 시스템에서 음수는 10 진수처럼 마이너스 부호로 기록됩니다.

2. 내부 대표

숫자의 내부 표현은 64 비트 부동 소수점 이며이 답변 에서는 몇 가지 제한 사항에 대해 설명 합니다. 자바 스크립트에서 비트 문자열 표현을 만들거나 특정 비트에 액세스하는 쉬운 방법없습니다 .

3. 마스크 및 비트 연산자

MDN에는 비트 연산자의 작동 방식에 대한 개요 가 있습니다. 중요하게 :

비트 연산자는 피연산자를 32 비트 시퀀스 (0과 1)로 취급합니다.

연산이 적용되기 전에 64 비트 부동 소수점 숫자는 32 비트 부호있는 정수로 캐스트됩니다. 그들이 다시 회심 한 후.

다음은 숫자를 32 비트 문자열로 변환하기위한 MDN 예제 코드입니다.

function createBinaryString (nMask) {
  // nMask must be between -2147483648 and 2147483647
  for (var nFlag = 0, nShifted = nMask, sMask = ""; nFlag < 32;
       nFlag++, sMask += String(nShifted >>> 31), nShifted <<= 1);
  return sMask;
}

createBinaryString(0) //-> "00000000000000000000000000000000"
createBinaryString(123) //-> "00000000000000000000000001111011"
createBinaryString(-1) //-> "11111111111111111111111111111111"
createBinaryString(-1123456) //-> "11111111111011101101101110000000"
createBinaryString(0x7fffffff) //-> "01111111111111111111111111111111"

간단한 Number (num) .toString (2) 대신이 함수를 사용하면 어떤 이점이 있습니까?
Magus

5
@Magus 나는 숫자와 이진 문자열의 차이점을 적절히 설명한다고 생각합니다. 32 비트 이진 문자열은 항상 32 개의 문자이며 "1"과 "0"으로 구성됩니다. toString은 주어진 밑이있는 위치 숫자 시스템을 사용하여 표현 된 실제 숫자를 반환합니다 . 문자열을 원하는 이유에 따라 매우 다른 의미를 갖습니다.
AnnanFay

미안, 네 말이 맞아 나는 코드로 바로 뛰어 들었다.
Magus

1
다른 게시 된 방법 (특히이 번호 536870912에서 두 개의 선행 0이 제거됨)을 사용하여 선행 0에 문제가 있었지만이 솔루션은 올바르게 처리했습니다.
UberMouse

@UberMouse 네 >>>에는 0으로 이어지는 문제가 있습니다.
barlop

43

간단한 방법은 ...

Number(42).toString(2);

// "101010"

24
나는 선호합니다(42).toString(2)
Willem D' Haeseleer

33
더 짧은42..toString(2)
kapex

9
사람들은 이것으로 어려움을 겪고 있습니다. 대답은 입력 (42)을 정수로 캐스팅하고 해당 줄이 필요하기 때문에 정확합니다. 텍스트 입력에서 '숫자'를 가져 오면 toString (2)가 작동하지 않습니다.
Magus

4
@Kapep, 천재입니다. 그것에 대해 어떻게 알았습니까?
Pacerier

2
@BatuG. 숫자 구문을 사용하면 소수점 구분 기호 뒤에있는 부분을 생략 할 수 있습니다. 당신은 1.1.0거나 그냥 같은 것을 쓸 수 있습니다 1(그리고 마찬가지로 부분을 생략하고 .5대신 쓸 수도 있습니다 0.5). 따라서이 예에서 첫 번째 점은 숫자의 일부인 소수 구분 기호이고 두 번째 점은 해당 숫자에서 메서드를 호출하기위한 점 연산자입니다. 두 개의 점을 사용해야하거나 숫자를 괄호로 묶어야 42.toString(2)하며 파서는 점을 소수점 구분 기호로보고 도트 연산자가 누락되어 오류가 발생하기 때문에 쓸 수 없습니다 .
kapex

30

이 답변은 2147483648 10 (2 31 ) – 9007199254740991 10 (2 53 -1) 범위의 절대 값으로 입력을 처리하려고 시도합니다 .


JavaScript에서 숫자는 64 비트 부동 소수점 표현 으로 저장되지만 비트 연산2의 보수 형식 으로 32 비트 정수강제 변환 되므로 비트 연산을 사용하는 모든 접근 방식은 출력 범위를 -2147483648 10 (-2 31 )으로 제한합니다. – 2147483647 10 (2 31 ).

그러나 비트 연산을 피하고 수학 연산 만 사용하여 64 비트 부동 소수점 표현을 유지하는 경우 53 비트를 부호 확장하여 안전한 정수 를 64 비트 2의 보수 이진 표기법으로 안정적으로 변환 할 수 있습니다 twosComplement.

function toBinary (value) {
  if (!Number.isSafeInteger(value)) {
    throw new TypeError('value must be a safe integer');
  }

  const negative = value < 0;
  const twosComplement = negative ? Number.MAX_SAFE_INTEGER + value + 1 : value;
  const signExtend = negative ? '1' : '0';

  return twosComplement.toString(2).padStart(53, '0').padStart(64, signExtend);
}

function format (value) {
  console.log(value.toString().padStart(64));
  console.log(value.toString(2).padStart(64));
  console.log(toBinary(value));
}

format(8);
format(-8);
format(2**33-1);
format(-(2**33-1));
format(2**53-1);
format(-(2**53-1));
format(2**52);
format(-(2**52));
format(2**52+1);
format(-(2**52+1));
.as-console-wrapper{max-height:100%!important}

구형 브라우저의 경우 다음 기능 및 값에 대한 폴리 필이 존재합니다.

추가 보너스로 다음을 사용하여 ⌈64 / log 2 (radix) ⌉ 숫자의 음수에 대해 2의 보수 변환을 수행하면 모든 기수 (2–36)를 지원할 수 있습니다 BigInt.

function toRadix (value, radix) {
  if (!Number.isSafeInteger(value)) {
    throw new TypeError('value must be a safe integer');
  }

  const digits = Math.ceil(64 / Math.log2(radix));
  const twosComplement = value < 0
    ? BigInt(radix) ** BigInt(digits) + BigInt(value)
    : value;

  return twosComplement.toString(radix).padStart(digits, '0');
}

console.log(toRadix(0xcba9876543210, 2));
console.log(toRadix(-0xcba9876543210, 2));
console.log(toRadix(0xcba9876543210, 16));
console.log(toRadix(-0xcba9876543210, 16));
console.log(toRadix(0x1032547698bac, 2));
console.log(toRadix(-0x1032547698bac, 2));
console.log(toRadix(0x1032547698bac, 16));
console.log(toRadix(-0x1032547698bac, 16));
.as-console-wrapper{max-height:100%!important}

ArrayBuffera Float64Array와 a 사이의 결합을 만드는 데 사용한 이전 답변에 관심 Uint16Array이 있으시면이 답변의 개정 내역을 참조하십시오 .


감사합니다. 64 비트에서 작동하는 것이 좋습니다 .. annan의 답변보다이 답변의 장점을 알려주시겠습니까?
barlop

2
더 큰 범위? 그것은 annan의 대답 을 좋아 -(2**53)-1하는 2**53-1대신에 작동합니다 . -(2**31)2**31-1
Patrick Roberts

예, 그것은 큰 이점입니다. 저는 그것을 얻을 것입니다. 비록 그것이 훨씬 더 많은 코드이지만, 다른 의미가 있다면 궁금합니다.
barlop

1
2 ** 32 + 1부터 마지막 ​​(가장 오른쪽) 비트는 설정해야 할 때 지워집니다.
Lovro

1
행이 다음과 같은 경우에 작동합니다. var exponent = ((uint16 [3] & 0x7FF0) >> 4)-1023 + 1;
Lovro

15

32 비트에 적합한 솔루션은 developer.mozilla.org (MDN)에서 가져온이 답변의 끝 코드이지만 A) 서식 및 B)에 대한 일부 줄이 추가되어 있습니다. 숫자가 범위 안에 있습니다.

어떤 사람들은 x.toString(2)네거티브에 효과가없는 것을 제안 했지만, 거기에는 마이너스 부호를 붙이면 좋지 않습니다.

Fernando는 간단한 해결책은 (x>>>0).toString(2);음수에는 좋지만 x가 양수이면 약간의 문제가 있다고 언급했습니다 . 출력은 1로 시작하며 양수의 경우 2를 보완하지 않습니다.

0으로 시작하는 양수와 2의 보수에서 1을 갖는 음수의 사실을 이해하지 못하는 사람은 2s 보수의 SO QnA를 확인할 수 있습니다. “2의 보완”이란 무엇입니까?

해결책은 양수에 0을 붙이는 것을 포함 할 수 있습니다.이 답변의 이전 개정에서 수행했습니다. 때로는 33 비트 숫자를 받거나 변환 할 숫자가-(2 ^ 31) <= x <2 ^ 31-1 범위 내에 있는지 확인할 수 있습니다. 따라서 숫자는 항상 32 비트입니다. 그러나 그렇게하기보다는 mozilla.org 에서이 솔루션을 사용할 수 있습니다

Patrick의 답변과 코드는 길고 64 비트에서 작동하지만 주석 작성자가 발견 한 버그가 있고 주석자가 Patrick의 버그를 수정했지만 Patrick은 코드에 주석을 달지 않았고 가지고있는 "매직 번호"를 가지고 있습니다 잊고 패트릭은 더 이상 자신의 코드를 이해하지 못합니다 / 왜 작동하는지.

Annan은 부정확하고 불명확 한 용어를 사용했지만 developer.mozilla.org https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Bitwise_Operators 의 솔루션을 언급했습니다. 이 32 비트 숫자 작동합니다.

코드는 3 줄의 기능으로 매우 컴팩트합니다.

그러나 출력을 8 비트 그룹으로 포맷하기 위해 정규 표현식을 추가했습니다. 를 기반으로 자바 스크립트에서 천 단위 구분 기호로 쉼표와 숫자를 인쇄하는 방법 (난 그냥 그것을 그룹화에서 개정 3S 오른쪽에서 왼쪽 및 추가에 쉼표 로 그룹화에, 8S 오른쪽에서 왼쪽으로, 그리고 추가 공간 )

그리고 mozilla는 nMask (feeded number)의 크기에 대해 언급했지만 범위 내에 있어야하지만 숫자가 범위를 벗어 났을 때 테스트하거나 오류를 발생시키지 않았습니다. 추가했습니다.

왜 그들이 그들의 매개 변수를 'nMask'라고 명명했는지 잘 모르겠지만 그대로 두겠습니다.

참조 : https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Bitwise_Operators

function createBinaryString(nMask) {
  // nMask must be between -2147483648 and 2147483647
  if (nMask > 2**31-1) 
     throw "number too large. number shouldn't be > 2**31-1"; //added
  if (nMask < -1*(2**31))
     throw "number too far negative, number shouldn't be < 2**31" //added
  for (var nFlag = 0, nShifted = nMask, sMask = ''; nFlag < 32;
       nFlag++, sMask += String(nShifted >>> 31), nShifted <<= 1);
  sMask=sMask.replace(/\B(?=(.{8})+(?!.))/g, " ") // added
  return sMask;
}


console.log(createBinaryString(-1))    // "11111111 11111111 11111111 11111111"
console.log(createBinaryString(1024))  // "00000000 00000000 00000100 00000000"
console.log(createBinaryString(-2))    // "11111111 11111111 11111111 11111110"
console.log(createBinaryString(-1024)) // "11111111 11111111 11111100 00000000"


8

비트 배열을 반환하는 고유 한 함수를 작성할 수 있습니다. 숫자를 비트로 변환하는 방법의 예

제수 | 배당 | 비트 / 나머지

2 | 9 | 1

2 | 4 | 0

2 | 2 | 0

~ | 1 | ~

위 행의 예 : 2 * 4 = 8이고 나머지는 1이므로 9 = 1 0 1

function numToBit(num){
    var number = num
    var result = []
    while(number >= 1 ){
        result.unshift(Math.floor(number%2))
        number = number/2
    }
    return result
}

나머지를 아래에서 위로 읽으십시오. 가운데 1에서 숫자 1까지.


1
Btw, 왜 Math.floor(number%2)대신에 number = Math.floor(number/2)?
Pacerier

1
그 이유는 number % 2가 number / 2와 같지 않기 때문입니다. 우리는 몫이 아닌 나머지 에 관심이 있습니다.
supritshah1289

0

나는 다른 접근법을 사용하여 이것을하는 것을 생각해 냈습니다. 프로젝트에서이 코드를 사용하지 않기로 결정했지만 누군가에게 유용 할 수 있도록 관련 코드를 다른 곳에 두겠다고 생각했습니다.

  • 비트 시프 팅 또는 2의 보수 강제를 사용하지 않습니다.
  • 나오는 비트 수를 선택합니다 ( '8', '16', '32'의 유효한 값을 확인하지만 변경할 수 있다고 생각합니다)
  • 부호있는 정수 또는 부호없는 정수로 처리할지 여부를 선택합니다.
  • 부호 처리 / 부호없는 비트 수와 비트 수의 조합으로 범위 문제를 확인하지만 오류 처리를 향상 시키려고합니다.
  • 또한 비트를 int로 다시 변환하는 함수의 "역"버전이 있습니다. 이 출력을 해석 할 다른 것이 없기 때문에 필요합니다. : D

function intToBitString(input, size, unsigned) {
	if ([8, 16, 32].indexOf(size) == -1) {
		throw "invalid params";
	}
	var min = unsigned ? 0 : - (2 ** size / 2);
        var limit = unsigned ? 2 ** size : 2 ** size / 2;
	if (!Number.isInteger(input) || input < min || input >= limit) {
		throw "out of range or not an int";
	}
	if (!unsigned) {
		input += limit;
	}
	var binary = input.toString(2).replace(/^-/, '');
	return binary.padStart(size, '0');
}

function bitStringToInt(input, size, unsigned) {
	if ([8, 16, 32].indexOf(size) == -1) {
		throw "invalid params";
	}
	input = parseInt(input, 2);
	if (!unsigned) {
		input -= 2 ** size / 2;
	}
	return input;
}


// EXAMPLES

var res;
console.log("(uint8)10");
res = intToBitString(10, 8, true);
console.log("intToBitString(res, 8, true)");
console.log(res);
console.log("reverse:", bitStringToInt(res, 8, true));
console.log("---");

console.log("(uint8)127");
res = intToBitString(127, 8, true);
console.log("intToBitString(res, 8, true)");
console.log(res);
console.log("reverse:", bitStringToInt(res, 8, true));
console.log("---");

console.log("(int8)127");
res = intToBitString(127, 8, false);
console.log("intToBitString(res, 8, false)");
console.log(res);
console.log("reverse:", bitStringToInt(res, 8, false));
console.log("---");

console.log("(int8)-128");
res = intToBitString(-128, 8, false);
console.log("intToBitString(res, 8, true)");
console.log(res);
console.log("reverse:", bitStringToInt(res, 8, true));
console.log("---");

console.log("(uint16)5000");
res = intToBitString(5000, 16, true);
console.log("intToBitString(res, 16, true)");
console.log(res);
console.log("reverse:", bitStringToInt(res, 16, true));
console.log("---");

console.log("(uint32)5000");
res = intToBitString(5000, 32, true);
console.log("intToBitString(res, 32, true)");
console.log(res);
console.log("reverse:", bitStringToInt(res, 32, true));
console.log("---");


-1

하나 더 대안

const decToBin = dec => {
  let bin = '';
  let f = false;

  while (!f) {
    bin = bin + (dec % 2);    
    dec = Math.trunc(dec / 2);  

    if (dec === 0 ) f = true;
  }

  return bin.split("").reverse().join("");
}

console.log(decToBin(0));
console.log(decToBin(1));
console.log(decToBin(2));
console.log(decToBin(3));
console.log(decToBin(4));
console.log(decToBin(5));
console.log(decToBin(6));

Vincent의 답변과 이에 대한 의견을 참조하십시오. 게시에 적용될 것입니다
barlop

이것은 자신의 답변에 대해 의견 불일치없이 의견에 게시 된 내용이며, 다른 사람들과의 동의를 얻어서 "컴퓨터 과학을 연구하여 수동으로 수행하는 방법을 알아 보는 것이 도움이 될 수 있습니다. 수동으로 휠을 수동으로 재발 명하려는 경우, 최소한 효율 향상의 이점이나 대처할 수있는 값의 크기 증가와 같은 이점이 있어야합니다. "그러한 장점을 언급 한 토론이 있습니다."
barlop

또한, 솔루션이 완전히 실패는 양수가 1로 시작하고 완전히 음수 실패하고 내 질문에 긍정적 또는 부정적 언급한다
barlop을

따라서 많은 답변에서 "답변"이 잘못되었습니다. 그리고 답변을 게시하기 전에 항상 다른 답변을 검토해야합니다
barlop

-2

이것은 내 코드입니다.

var x = prompt("enter number", "7");
var i = 0;
var binaryvar = " ";

function add(n) {
    if (n == 0) {
        binaryvar = "0" + binaryvar; 
    }
    else {
        binaryvar = "1" + binaryvar;
    }
}

function binary() {
    while (i < 1) {
        if (x == 1) {
            add(1);
            document.write(binaryvar);
            break;
        }
        else {
            if (x % 2 == 0) {
                x = x / 2;
                add(0);
            }
            else {
                x = (x - 1) / 2;
                add(1);
            }
        }
    }
}

binary();

3
그것은 컴퓨터 과학을 배우는 데 도움이 될 수 있습니다. 수동으로 수행하는 방법을 보아서 스스로 가르치는 것이지만, 그것은 내가 요구하는 것이 아닙니다! 휠을 수동으로 그렇게하는 것을 재발행하려는 경우, 최소한 효율 향상의 이점 또는 대처할 수있는 값의 크기 증가와 같은 이점이 있어야합니다. 나는 거기에서 그러한 이점을 언급하는 당신의 토론을 보지 못했습니다.
barlop

-3

이것이 해결책입니다. 사실은 아주 간단합니다

function binaries(num1){ 
        var str = num1.toString(2)
        return(console.log('The binary form of ' + num1 + ' is: ' + str))
     }
     binaries(3

)

        /*
         According to MDN, Number.prototype.toString() overrides 
         Object.prototype.toString() with the useful distinction that you can 
         pass in a single integer argument. This argument is an optional radix, 
         numbers 2 to 36 allowed.So in the example above, we’re passing in 2 to 
         get a string representation of the binary for the base 10 number 100, 
         i.e. 1100100.
        */

1
이 솔루션은 이미 여러 번 제안되었으며 OP가 3 월 30 '12 일 9:01에 이미 언급했듯이 음수에는 작동하지 않습니다.
애드리안여

@AdrianW 나는 이것을 downvoting하는 것이 좋습니다. 당신이하지 않은 것을 알 수 있습니다. 그러면 답을 내리는 데 무엇이 필요합니까?!
barlop
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.