Підрахунок випадків цілого числа [закрито]


13

На основі запитання Скільки натуральних чисел <1 000 000 містять цифру 2? . Я шукаю найбільш креативне рішення для підрахунку всіх цілих літрів Xдо Yвмісту цілого числа Z. Zможе бути від 0 до Y.

Кожен знайдений цілий число рахується лише один раз, навіть якщо ціле число Zз’являється частіше. Наприклад:

Z = 2
123 counts 1
22222 also counts 1

Почну з дійсно простого алгоритму, написаного на Java (тому що він улюблений всіма):

public class Count {
    public static void main(String[] args) {
        int count = 0;
        for (int i = Integer.parseInt(args[0]); i <= Integer.parseInt(args[1]); i++) {
            if (Integer.toString(i).contains(args[2])) {
                count++;
            }
        }
        System.out.println(count);
    }
}

якщо це запустити

java -jar Count.jar 0 1000000 2

Ви отримуєте це як результат:

468559

Оскільки цю проблему не важко вирішити, це просто на . Виграє найбільш актуальна відповідь, опублікована 28 лютого!


Це не зовсім зрозуміло з вашого допису, але я думаю, що Z може бути від 0 до інф? Або просто між 0 і 9?
mmumboss

Z може бути від 0 до Y. Немає сенсу, що Z може бути більшим за Y.
Обл Тобл

@OblTobl Ви дійсно хочете явно виключити випадок Z> Y? Чому б просто не очікували, що вихід у такому випадку буде 0?
Cruncher

@Cruncher я не проти! але я думаю, це трохи марно ;-)
Обл Тобл

Чи означає це, що це Nможе бути, 123і воно відповідатиме лише тоді, коли існує підряд 123?
Populus

Відповіді:


26

баш (20)

seq $1 $2|grep -c $3

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

$ bash count.sh 0 1000000 2
468559

10
смішно, якщо виклик довший, ніж сама програма ;-)
Obl Tobl

11

Функсітон

Як завжди, оскільки висота рядка, додана StackExchange, розбиває рядки, розгляньте запуск $('pre').css('line-height',1)у консолі браузера, щоб виправити це.

На відміну від інших моїх відповідей Funciton, цей не використовує жодних оголошень функції. Це просто програма. Однак він використовує лямбда-вираз - особливість, яку я додав до Funciton у грудні :)

Очікує введення у вигляді трьох десяткових цілих чисел (можуть бути негативними), розділених пробілами (тобто x y z). Насправді це zможе бути будь-який рядок; наприклад, може бути лише знак мінус ( , U + 2212) підрахувати кількість від’ємних чисел в інтервалі :)

           ┌───╖
     ┌───┬─┤ ♯ ╟──────────┐
     │   │ ╘═══╝ ╔════╗ ┌─┴─╖             ┌────╖ ╔═══╗
   ┌─┴─╖ └────┐  ║ 21 ║ │ × ╟─────────────┤ >> ╟─╢   ║
 ┌─┤ ʃ ╟───┐  │  ╚══╤═╝ ╘═╤═╝             ╘═╤══╝ ╚═══╝
 │ ╘═╤═╝   │  └──┐  └─────┘   ┌───────────┐ │
 │ ╔═╧═╗ ┌─┴─╖ ┌─┴─╖ ╔════╗ ┌─┴─╖   ┌───╖ ├─┴────────┐
 │ ║   ╟─┤ · ╟─┤ ʘ ╟─╢ 32 ╟─┤ · ╟───┤ ʘ ╟─┘          │
 │ ╚═══╝ ╘═╤═╝ ╘═══╝ ╚════╝ ╘═╤═╝   ╘═╤═╝ ┌─────┐    │
 │         └───────┐  ╔═══╗ ┌─┴─╖     │ ┌─┴─╖   │    │
 │ ┌───────────┐   └──╢ 0 ╟─┤ ʃ ╟─┐   │ │ ♯ ║   │    │
 │ │   ┌───╖ ┌─┴─╖    ╚═══╝ ╘═╤═╝ │   │ ╘═╤═╝ ┌─┴─╖  │
 │ │ ┌─┤ ♯ ╟─┤   ╟─┬─┐ ╔════╗ │ ┌─┴─╖ │   │ ┌─┤ × ║  │
 │ │ │ ╘═══╝ └─┬─╜ └─┘ ║ −1 ║ └─┤ · ╟─┴───┘ │ ╘═╤═╝  │
 │ │ │    ┌────┴────┐  ╚══╤═╝   ╘═╤═╝       │ ╔═╧══╗ │
 │ │ │    │ ┌───╖ ┌─┴─╖ ┌─┴─╖ ┌───┴─────╖   │ ║ 21 ║ │
 │ │ │    └─┤ ♯ ╟─┤ ? ╟─┤ = ║ │ str→int ║   │ ╚════╝ │
 │ │ │      ╘═══╝ ╘═╤═╝ ╘═╤═╝ ╘═╤═══════╝   │ ┌────╖ │
 │ │ │      ╔═══╗ ┌─┴─╖   └─┐ ┌─┴─╖         └─┤ >> ╟─┘
 │ │ │      ║ 0 ╟─┤ ? ╟─┐   └─┤ · ╟───┐       ╘═╤══╝
 │ │ │      ╚═══╝ ╘═╤═╝ └─┐   ╘═╤═╝   └───┐   ┌─┴─╖
 │ │ │            ┌─┴─╖   └─┐ ┌─┴─╖       └───┤ ʘ ║
 │ │ └────────────┤ · ╟─┐   └─┤ ≤ ║           ╘═╤═╝
 │ │              ╘═╤═╝ │     ╘═╤═╝ ┌─────────╖ │
 │ │        ╔═══╗ ╔═╧═╕ │       └─┬─┤ int→str ╟─┘
 │ │        ║ 0 ╟─╢   ├─┤         │ ╘═════════╝
 │ │        ╚═══╝ ╚═╤═╛ └─────────┘
 │ └────────────────┴─┐              │
 │    ┌─────────╖   ┌─┴─╖ ┌─┐   ┌────┴────╖
 └────┤ str→int ╟───┤   ╟─┴─┘   │ int→str ║
      ╘═════════╝   └─┬─╜       ╘════╤════╝
                      └──────────────┘

1
Це дуже круто! Використовуючи мову, яку ви зробили самі
pcnThird

2
@pcnThird: Я думаю, що Тімві проводить весь свій час або на гольф, або на створення мов, на яких займається гольфом (див. також Сліптінг)!
Гейб

10

C #

public class Program
{
    public static void Main(string[] args)
    {
        Console.WriteLine(Enumerable.Range(Convert.ToInt32(args[0]), (Convert.ToInt32(args[1]) + 1) - Convert.ToInt32(args[0])).Count(x => x.ToString().Contains(args[2])));
    }
}

Приклад

count.exe 0 1000000 2
468559

розумне рішення! мені подобається, що ти це робив без петлі.
Obl Tobl

@OblTobl без видимого циклу.
Джастін

звичайно, приємно все
одно

1
Він має помилку, .Rangeприймає (int start, int count), ні (start, end). Я завжди сам потрапляю в цю пастку :)
Grozz

Служить мені правильно, щоб швидко збити це в Блокноті ... Я перетворив код, так що тепер це правильно!
Пн

5

APL (29)

{+/∨/¨(⍕⍺)∘⍷¨⍕¨⊃{⍺+0,⍳⍵-⍺}/⍵}

Це функція, яка приймає Zяк лівий аргумент і інтервал [X,Y]як правий аргумент:

      2 {+/∨/¨(⍕⍺)∘⍷¨⍕¨⊃{⍺+0,⍳⍵-⍺}/⍵} 0 1e6
468559
      0 {+/∨/¨(⍕⍺)∘⍷¨⍕¨⊃{⍺+0,⍳⍵-⍺}/⍵} 0 1e6
402131
      42 {+/∨/¨(⍕⍺)∘⍷¨⍕¨⊃{⍺+0,⍳⍵-⍺}/⍵} 0 1e6
49401

не дуже зрозуміло ... але дійсно круто!
Obl Tobl

4

Python 2.7

Жага швидкості

Пояснення

введіть тут опис зображення

Впровадження

def Count(lo,hi,key):
    if hi == 0: return 0
    # Count(lo,hi,key) = Count(0,hi,key) - Count(0,lo - 1,key)
    if lo != 0: return Count(0, hi, key) - Count(0, lo - 1, key)
    # Calculate no of digits in the number to search
    # LOG10(hi) may be a descent trick but because of float approximation
    # this would not be reliable
    n = len(str(hi)) - 1
    # find the most significant digit
    a_n = hi/10**n
    if a_n < key:
        count = a_n*(10**n - 9**n)
    elif a_n > key:
        count = (a_n - 1)*(10**n - 9**n) + 10**n
    else:
        count = a_n*(10**n - 9**n) + 1
    if hi % 10**n != 0:
        if a_n != key:
            return count + Count(0, hi%10**n, key)
        else:
            return count + hi%10**n
    else:
        return count

Демо

In [2]: %timeit Count(0,123456789987654321,2)
100000 loops, best of 3: 13.2 us per loop

Порівняння

@Dennis

$ \time -f%e bash count.sh 0 1234567 2
585029
11.45

@arshajii

In [6]: %timeit count(0,1234567,2)
1 loops, best of 3: 550 ms per loop

Це, звичайно, набагато швидше, але воно не відповідає вимогам питання. keyможе бути будь-яке ціле число , а не цифра, між loі hi.
Денніс

Математичне рішення все ще є, хоча воно буде ще довше ...
Red Alert

3

Python 2.7

Рішення з використанням регулярних виразів:

>>> from re import findall as f
>>> count=lambda x,y,z:len(f('\d*%d\d*'%z,str(range(x,y+1))))
>>>
>>> count(0,1000000,2)
468559

Ви можете використовувати re.findallв одній лайнері, виконуючи це__import__('re').findall('\d...
SimonT

3

баш - 32 31 17 14 символів + довжина X, Y і Z

Дякуємо devnull за пропозицію seq!

seq [X] [Y]|grep -c [Z]

наприклад X = 100, Y = 200, Z = 20

$ seq 100 200|grep -c 20
2

наприклад X = 100, Y = 200, Z = 10

$ seq 100 200|grep -c 10
11

наприклад X = 0, Y = 1000000, Z = 2

$ seq 0 1000000|grep -c 2
468559

приємний і зрозумілий!
Obl Tobl

Навіщо використовувати, echoколи ви могли використовувати seqта зменшити довжину на 4 символи? (1 для тривалості команди, 2 за можливість пропускати фігурні дужки і 1 для заміни ..на один пробіл)
розгорнутий

@devnull - дякую, а також можна позбутися xargsі wc- і він також працює набагато швидше!

3

PHP

Нічого оригінального, просто святкуючи тут моє перше повідомлення.

<?php

    $x = $argv[1];
    $y = $argv[2];
    $z = $argv[3];
    $count = 0;

    do
    {
        if (!(strpos($x, $z) === false))
            $count++;
        $x++;
    } while ($x <= $y);

    echo $count;

?>

Вхідні дані

php script.php 0 1000000 2

Вихідні дані

468559


2

Рубін

Це чудовий приклад використання скорочення!

puts (ARGV[0]..ARGV[1]).reduce(0) { |c, n| n.to_s.include?(ARGV[2].to_s) ? c + 1 : c }

Вхід:

ruby script.rb 0 1000000 2

Вихід:

468559

2

Пітон гольф - 61

f=lambda x,y,z:len([i for i in range(x,y)if str(z)in str(i)])

Python не гольф

def f(x, y, z):
    c = 0
    for i in range(x, y):
        c += str(z) in str(i)
    return c

2

Java8

Використовуючи новий матеріал IntStream, він, по суті, стає одним вкладишем, якщо ви ігноруєте обов'язкові речі Java Framework:

import java.util.stream.IntStream;
public class A{
  public static void main(String[] args){
    System.out.println(IntStream.rangeClosed(Integer.parseInt(args[0], Integer.parseInt(args[1])).filter(x -> ((Integer)x).toString().contains(args[2])).count());
  }
}

Він може працювати тут , хоча я повинен жорстко значення.


Дійсно цікаве рішення Java
Obl Tobl

2

F #

Це рішення використовує IndexOfдля пошуку рядка, а потім трохи невеликої кількості цифр для перетворення результату в 1, якщо його знайдено, і 0, якщо його не знайдено, то підсумовує результат:

let count x y (z : string) = 
    [ x .. y ] |> Seq.sumBy(fun n -> min 1 (n.ToString().IndexOf z + 1))

І це можна назвати так:

count 0 1000000 "2" // 468559

2

Регулярна виразність

Наступні будуть рахувати цифри від 1 до 49.

#!/bin/bash

echo "12313451231241241111111111111111111111111111111111111"  |\  
sed "s/[^1]//g;s/11111/5/g;s/1111/4/g;s/111/3/g;s/11/2/g;s/555555555/45/g;s/55555555/40/g;s/5555555/35/g;s/555555/30/g;s/55555/25/g;s/5555/20/g;s/555/15/g;s/55/10/g;s/54/9/g;s/53/8/g;s/52/7/g;s/51/6/g;s/50/5
/g;s/40/4/g;s/30/3/g;s/20/2/g;s/10/1/g"

2

R 23 25 27символів

Просто знайдіть потрібний інструмент для роботи. Просте використання грепу в R, нічого фантазійного.

Це те, що він робить: grepвсі екземпляри 2у векторі 0до 10e6та підраховують кількість використаних результатів length.

length(grep(2,0:100000,value=TRUE))

length(grep(2,0:10e6))

Результат: [1] 468559


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

count = function(x=0, y=1000000, z=2){
  length(grep(z,x:y))
}

Тепер ви можете зателефонувати countза допомогою x, y та z, якщо їх не встановлено (це за замовчуванням), значення для x, y та z відповідно 0, 1000000 та 2. Деякі приклади:

count()
[1] 468559

або

count(20, 222, 2)
[1] 59

або

count(0, 100, 10)
[1] 2

Деякі тут вважають, що час має важливе значення, оскільки використання цієї функції в R займає близько 1 секунди.

system.time(count())
user  system elapsed 
0.979   0.003   0.981

можливо, це занадто коротко ;-)
Obl Tobl

Ну, це все одно не код-гольф :) Я цікавлюсь: як виглядала б програма, якби вона мала приймати цифри як вхідні дані (а не жорстке кодування)?
Timwi

Створив функцію для
немислених

1

JavaScript (ES6), 63

f=(i,j,n)=>{for(c=0;i<=j;!~(''+i++).indexOf(n)?0:c++);return c}

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

f(0, 1e6, 2)
> 468559

Без гольфу:

f = (i,j,n) => {
  for(
    // Initialize the counter.
    c=0;
    // Iterate through all integers.
    i<=j;
    // Convert current number into string then increment it.
    // Check if the digit appears into the current number.
    !~(''+i++).indexOf(n)
      // Occurence not found.
      ? 0
      // Occurence found.
      // Add 1 to the counter.
      : c++
  );
  return c
}

1

Рубін

В основному я взяв відповідь Пабло і напівгольфував (38 знаків, якщо ви викинете непотрібний пробіл) в не дуже великий приклад використання select.

Він вибирає кожен індекс у діапазоні, (x .. y)який містить z. Цей проміжний результат, на жаль, зберігається в масиві, розмір якого потім повертається.

x,y,z = $*
p (x..y).select{ |i| i[z] }.size

Це виглядає досить акуратно як синтаксично, так і семантично, хоча ця i[z]частина насправді не має сенсу.

Це працює , тому що xі на yсамому справі є рядки, а не числом! Таким чином, кожен iтакож є рядком, і i[z]звичайно перевіряє, чи zміститься рядок в i.

$ ruby count-digits.rb 100 200 20
2
$ ruby count-digits.rb 0 1000000 2
468559

1

Пітон 2,7, 70 знаків

f = lambda x,y,z: sum(map(lambda x: str(z) in str(x), range(0, y+1)))

>>> f(0, 1000000, 2)
468559

Коротше, 65 ознак

g = lambda x, y, z: sum(str(z) in str(i) for i in range(0, y+1))
>>> g(0, 1000000, 2)
468559

Я не думаю, що тобі потрібно, range(0,y+1)якщо range(y+1)робить те саме. Крім того, ви можете прибрати більшість цих просторів, якщо займаєтесь гольфом ...
SimonT

1

Використання Ruby's Enumerable#grep:

start, stop, target = $*
p (start..stop).grep(Regexp.new target).size

1

T-SQL

Якщо я можу припустити , змінні @X, @Yі @Zдоступні:

Маючи (довільно велику;) таблицю чисел - 65

select count(*)from n where n>=@X and n<=@Y and n like '%'+@Z+'%'

З рекурсивним СТЕ - 127

with n(n)as(select @X union all select n+1 from n where n<@Y)select count(*)from n where n like'%'+@Z+'%'option(MAXRECURSION 0)

Якщо змінні потрібно чітко визначити:

До обох відповідей додайте 58 - Таблиця чисел: 123, Рекурсивна CTE: 185

declare @X int=0;declare @Y int=100;declare @Z varchar(30)='2';

Я поняття не маю, скільки пам’яті може використовувати рекурсивний CTE, але це, звичайно, не виграє жодних швидкісних змагань. Приклад пошуку від 2 до 0 до 1000000 у моїй системі займає 8 секунд.

Ось SQL Fiddle, якщо хтось хоче пограти з ним. Запит на 1000000 займає 30+ секунд.


не швидко, але дуже креативно!
Obl Tobl

1

Rebol

; version 1 (simple loop counting)

count: func [x [integer!] y [integer!] z [integer!] /local total] [
    total: 0
    for n x y 1 [if found? find to-string n z [++ total]]
    total
]


; version 2 (build series/list and get length)

count: func [x [integer!] y [integer!] z [integer!]] [
    length? collect [for n x y 1 [if find to-string n z [keep true]]]
]

Приклад використання в консолі Rebol (REPL):

>> count 0 1000000 2
== 468559

1

PowerShell

Два рішення, обидва 40 37 символів.

Для всіх версій PowerShell:

$a,$b,$c=$args;($a..$b-match$c).count

PowerShell V3 і вище мають slsпсевдонім для Select-String. Для цього @потрібно змусити масив, якщо через конвеєр проходить лише одне значення.

$a,$b,$c=$args;@($a..$b|sls $c).count

1

Пакетна

@setLocal enableDelayedExpansion&@set a=0&@for /L %%a in (%1,1,%2) do @set b=%%a&@if "!b:%3=!" NEQ "!b!" @set/aa+=1
@echo !a!

H:\uprof>count 0 1000000 2
468559

H:\uprof>count 1 2 3
0

Трохи легше читати -

@setLocal enableDelayedExpansion
@set a=0
@for /L %%a in (%1,1,%2) do (
    @set b=%%a
    @if "!b:%3=!" NEQ "!b!" @set/aa+=1
)
@echo !a!

Приємно і просто. Використовує маніпуляцію з рядком, щоб перевірити, чи змінна !b!та ж сама, що і сама без третього вводу користувача, %3( !b:%3=!).


1

Математика

Перший спосіб: струни

x, y, zперетворюються на рядки. Якщо рядкове ціле число не вільне z, воно підраховується.

f[{x_,y_},z_] :=Length[Select[ToString/@Range[Max[x, z], y], !StringFreeQ[#, ToString@z] &]]

Приклади

f[{22, 1000}, 23]
f[{0, 10^6}, 2]

20
468559


Другий спосіб: списки цифр

g[{x_,y_},z_]:=(t=Sequence@@ IntegerDigits@z;Length@Cases[IntegerDigits@Range[190], 
{s___,t,e___}])

Приклади

g[{22, 1000}, 23]
g[{0, 10^6}, 2]

20
468559


Математика завжди захоплююча навіть для простих проблем
Обл Тобл

1

GolfScript

Я намагався вдосконалити свої навички GolfScript, тому подумав, що я спробую це зробити. Ось що я придумав:

`@@0\{.3$>}{.`4$?-1>@+\(}while@;;\;

Це можна розбити так:

0 1000000 2    # parameters

`@@            # convert Z to string and put at bottom of stack
0\             # init counter and swap
{.3$>}         # loop condition: Y > X
{              # loop body
  .`           # convert to string
  4$?          # search for substring
  -1>@+        # if found add to counter
  \(           # decrement Y
}              # end loop body
while          # perform loop
@;;\;          # cleanup

Незважаючи на те, що це GolfScript, метою було скоріше спробувати зробити його відносно ефективнішим, а не компактним, тому я впевнений, що хтось може вказати на різні способи цього можна покращити.

Демонстрація : Зауважте, що я зменшив Y у демонстраційній версії, щоб він міг завершитись за <5 секунд.


1

PHP - 112

Ніяких видимих ​​циклів, але трохи важких для пам’яті!

<?=count(array_filter(range($argv[1],$argv[2]),function($i)use($argv){return strpos($i,$argv[3].'')!==false;}));

Використання php script.php 0 1000000 2


1

ECMAScript 3 до 6

(javascript, JScript тощо)

за допомогою регулярного вираження:

function f(x,y,z,r){for(r=0,z=RegExp(z);x<y;r+=+z.test(''+x++));return r}

зламатися:

function f(x,y,z,r){        // note argument `r`, eliminating the need for `var `
  for( r=0, z=RegExp(z)     // omitting `new` since ES will add it if omitted
     ; x<y                  // 
     ; r+=+z.test(''+x++)   // `x++` == post increment
                            // `''+Number` == convert Number to string
                            // `test` gives true | false
                            // `+Boolean` converts boolean to 1 | 0
                            // `r+=Number` incrementing r (were Number is always 1 or 0)
     );                     // no body thus semicolon is mandatory!
  return r;                 // returning r
}

використовуючи indexOf:

function f(x,y,z,r){for(r=0;x<y;r+=+!!~(''+x++).indexOf(z));return r}

зламатися:

function f(x,y,z,r){                // note argument `r`, eliminating the need for `var `
  for( r=0                          // omitting `new` since ES will add it if omitted
     ; x<y                          // 
     ; r+=+!!~(''+x++).indexOf(z)   // `x++` == post increment
                                    // `''+Number` == convert Number to string
                                    // `indexOf` returns index or `-1` when not found
                                    // `!!~ indexOf` converts sentinel value to boolean
                                    // `+Boolean` converts boolean to 1 | 0
                                    // `r+=Number` incrementing r (were Number is 1 or 0)
     );                             // no body thus semicolon is mandatory!
  return r;                         // returning r
}

це функціональне тіло на один знак менше, ніж флорентійське, тому при використанні позначення =>функції ES6 загальна сума складе 62 знаки

Приклад виклику: f(0,1e6,2)
Приклад використання:alert( f(0,1e6,2) );

JSFiddle тут

PS: обидві функції вище повертають свою локальну змінну r.
Тож, просочуючи змінну результату rв глобальну область, можна знову зберегти 10 символів:

function f(x,y,z){for(r=0;i<=j;r+=+!!~(''+i++).indexOf(z));}

Приклад використання: alert( f(0,1e6,2)||r );


1

Delphi - 120

Трохи набагато на мій смак, збираюся подивитися, чи можу я відмовитись.

var x,y,z,i,c:int16;begin readLn(x,y,z);for i:=x to y do if inttostr(i).contains(inttostr(z))then inc(c);writeln(c);end.

не заперечуйте над довжиною, я люблю бачити рішення delphi ;-)
Obl Tobl

@ OblTobl Чудово, але його так весело спробувати зробити його коротким: P
Teun Pronk

1

Python 2.7 - 50 символів

Трохи економії на існуючих відповідях Python.

lambda x,y,z:sum(1for n in range(y-x)if`z+x`in`n`)

Використовуючи наступні хитрощі:

  • Сума може бути застосована до генератора, на відміну від len, тому використовуйте sum (1 ...) замість len ([n ...])
  • Використовуйте `` замість str (), що також дозволяє ...
  • Убийте всі пробіли - див. "1для" та "якщо z+xв n"
  • Видаліть аргумент першого діапазону (), починаючи з 0 і перевіряючи зміщення (насправді ... нічого не економить, але мені подобається вигляд цього краще :))

Дія:

In [694]: (lambda x,y,z:sum(1for n in range(y-x)if`z+x`in`n`))(0,1000000,2)
Out[694]: 468559

1

k [28 символів]

{+/($x+!y)like"*",$:[z],"*"}

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

{+/($x+!y)like"*",$:[z],"*"}[0;1000000;2]
468559

1
Ви можете зберегти персонаж, замінивши $:[z]на ($z).
mollmerx

Однак верхня межа вашого рішення неправильна. Він перераховує від x до x + y-1, а не від x до y.
mollmerx
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.