Dlaczego typeof NaN zwraca „liczbę”?


166

Z czystej ciekawości.

Nie wydaje się logiczne, że typeof NaNjest to liczba. Nawiasem mówiąc, tak jak NaN === NaNlub NaN == NaNzwracając fałsz. Czy jest to jedna z cech javascript, czy może byłby tego powód?

Edycja: dzięki za odpowiedzi. Nie jest jednak łatwo przekonać kogoś do siebie. Czytając odpowiedzi i wiki zrozumiałem więcej, ale nadal, zdanie takie jak

Porównanie z NaN zawsze zwraca nieuporządkowany wynik, nawet w porównaniu z samym sobą. Predykaty porównania są albo sygnalizujące, albo nie sygnalizujące, wersje sygnalizacyjne sygnalizują nieważny wyjątek dla takich porównań. Predykaty równości i nierówności nie sygnalizują, więc x = x zwracające fałsz może być użyte do sprawdzenia, czy x jest cichym NaN.

tylko kręci mi w głowie. Gdyby ktoś mógł to przetłumaczyć na ludzki (w przeciwieństwie do, powiedzmy, matematyka) czytelny język, byłbym wdzięczny.


17
+1: „NaN jest liczbą, ale nie jest liczbą. Hmm… co ?!”
ere

11
Dla dodatkowej zabawy; (NaN! == NaN) == true
Alex K.

1
Jeszcze bardziej zabawne (ale zrozumiałe, gdy się nad tym zastanowić, isNaN zwraca wartość logiczną): isNaN (parseInt ('nodice')) === isNaN (parseInt ('someOtherNaN')) === true;
KooiInc

1
Jeśli korzystam z jQuery, wolę isNumericod sprawdzania typu: $.isNumeric(NaN); zwraca false, gdzie as $.type(NaN);zwraca liczbę. api.jquery.com/jQuery.isNumeric
Justin,

3
Jako zawodowy matematyk muszę powiedzieć, że zdanie ma niewiele wspólnego z precyzyjnym językiem matematyki.
Dmitri Zaitsev

Odpowiedzi:


53

To znaczy nie jest liczbą. Nie jest to osobliwość javascript, ale powszechna zasada informatyki.

Z http://en.wikipedia.org/wiki/NaN :

Istnieją trzy rodzaje operacji, które zwracają NaN:

Operacje z NaN jako co najmniej jednym operandem

Formy nieokreślone

  • Podziały 0/0, ∞ / ∞, ∞ / −∞, −∞ / ∞ i −∞ / −∞
  • Mnożenia 0 × ∞ i 0 × −∞
  • Moc 1 ^ ∞
  • Dodatki ∞ + (−∞), (−∞) + ∞ i równoważne odejmowania.

Prawdziwe operacje ze złożonymi wynikami:

  • Pierwiastek kwadratowy z liczby ujemnej
  • Logarytm liczby ujemnej
  • Styczna nieparzystej wielokrotności 90 stopni (lub π / 2 radianów)
  • Odwrotność sinusa lub cosinusa liczby, która jest mniejsza niż -1 lub większa niż +1.

Wszystkie te wartości mogą nie być takie same. Prosty test na NaN polega na tym, że test value == valuejest fałszywy.


46
Jeszcze prostszym testem jestisNaN(value)
Alsciende

4
@Alsciende to jednak nie jest równoważne. isNaN(undefined)zwraca true, ale undefined == undefinedjest również prawdziwe. To samo dotyczy wszystkich innych typów nieliczbowych, z wyjątkiem null.
Andy

7
Innymi słowy, value !== valuejest to prawdopodobnie najkrótszy sposób sprawdzenia, czy tak valuejest NaN.
Andy

1
Wygląda na to, że masz rację, @Andy. To jest osobliwość.
Alsciende

2
Wyrażenie „te wartości mogą nie być takie same” nie ma znaczenia, ponieważ te wartości nie istnieją.
Dmitri Zaitsev

103

Cóż, NaNnadal jest typem numerycznym , mimo że faktycznie oznacza Not-A-Number :-)

NaNoznacza po prostu, że określona wartość nie może być reprezentowana w ramach ograniczeń typu liczbowego (chociaż można to powiedzieć o wszystkich liczbach, które muszą zostać zaokrąglone w celu dopasowania, ale NaNjest to przypadek specjalny).

Określony NaNnie jest uważany za równy drugiemu, NaNponieważ mogą mieć różne wartości. Jednak NaNnadal jest typem liczbowym, podobnie jak 2718 lub 31415.


Co do zaktualizowanego pytania, aby wyjaśnić w kategoriach laika:

Porównanie z NaN zawsze zwraca nieuporządkowany wynik, nawet w porównaniu z samym sobą. Predykaty porównania są albo sygnalizujące, albo nie sygnalizujące, wersje sygnalizacyjne sygnalizują nieważny wyjątek dla takich porównań. Predykaty równości i nierówności nie sygnalizują, więc x = x zwracające fałsz może być użyte do sprawdzenia, czy x jest cichym NaN.

Wszystko to oznacza (podzielone na części):

Porównanie z NaN zawsze zwraca nieuporządkowany wynik, nawet w porównaniu z samym sobą.

Zasadniczo a NaNnie jest równe żadnej innej liczbie, w tym innej NaN, a nawet samej sobie .

Predykaty porównania są albo sygnalizujące, albo nie sygnalizujące, wersje sygnalizacyjne sygnalizują nieważny wyjątek dla takich porównań.

Próba wykonania operacji porównania (mniej niż, większe niż itd.) Między a NaNi inną liczbą może spowodować zgłoszenie wyjątku (sygnalizacja) lub po prostu uzyskanie wyniku fałszywego (brak sygnalizacji lub cichy).

Predykaty równości i nierówności nie sygnalizują, więc x = x zwracające fałsz może być użyte do sprawdzenia, czy x jest cichym NaN.

Testy równości (równe, nie równe) nigdy nie sygnalizują, więc ich użycie nie spowoduje wyjątku. Jeśli masz zwykły numer x, x == xzawsze będzie prawdziwy. Jeśli xjest NaN, to x == xzawsze będzie fałszem. Daje ci sposób na NaNłatwe (ciche) wykrycie .


1
dobre wyjaśnienie, chociaż nie zgadzam się w dwóch ostatnich zdaniach: lepszym sposobem sprawdzenia, czy x jest NaN, jest użycie funkcji isNaN ()
Carlos Barcelona,

@DominicRodger tak o tym myślę: typeof a === 'number'oznacza „a jest przechowywany wewnętrznie jako pływak IEEE 754”
Andy

Dlaczego Infinity === Infinityzwraca, trueskoro an Infinitymożna wygenerować przez różne wartości: 1,0 / 0,0 lub 2,0 / 0,0?
Hashem Qolami

1
@Hashem, całkiem prawdopodobne, ponieważ są uważane za tę samą nieskończoność. Traktując dzielenie jako wielokrotne odejmowanie, nie ma znaczenia, czy zaczniesz od dwóch, czy od jednego, jest to taka sama liczba kroków, jaka jest wymagana do osiągnięcia (a dokładniej: nie osiągnięcia) zera. Rozumiem, że guru matematyki mają różne klasy nieskończoności, ale (1) podejrzewam 1/0i 2/0leżę w tej samej klasie i (2) w IEEE754 jest tylko jedna klasa nieskończoności (inna niż +/-oczywiście).
paxdiablo

1
Nie znam żadnego sposobu, aby zdefiniować te wyjątkowe „rzeczywiste liczby” w jakikolwiek sensowny sposób. W matematyce log i pierwiastek liczb ujemnych można uzyskać tylko przez rozszerzenie liczb rzeczywistych na liczby zespolone, gdzie obliczane są na wiele wartości i 0/0nie są definiowane w żaden znaczący sposób, poza stwierdzeniem, że jego „wartością” jest cały zbiór liczb. A nawet jeśli zostały zdefiniowane, Math.log(-1) == Math.log(-1)nadal ocenia się do false. Zatem nie tylko nie ma innych „rzeczywistych liczb”, NaNale nawet gdyby istniały, nie były one używane do porównań.
Dmitri Zaitsev

20

Standard ECMAScript (JavaScript) określa, że Numberssą to zmiennoprzecinkowe IEEE 754 , które zawierają NaNjako możliwą wartość.

ECMA 262 5e sekcja 4.3.19 : Wartość

wartość pierwotna odpowiadająca wartości podwójnej precyzji w 64-bitowym formacie binarnym IEEE 754.

ECMA 262 5e Sekcja 4.3.23 : NaN

Wartość liczbowa, która jest wartością IEEE 754 „Not-a-Number”.

IEEE 754 w Wikipedii

Standard IEEE dla arytmetyki zmiennoprzecinkowej jest standardem technicznym ustanowionym przez Instytut Inżynierów Elektryków i Elektroników i najczęściej stosowanym standardem dla obliczeń zmiennoprzecinkowych [...]

Norma definiuje

  • formaty arytmetyczne : zbiory binarnych i dziesiętnych danych zmiennoprzecinkowych, które składają się z liczb skończonych (w tym ze znakiem zer i liczb podnormalnych), nieskończoności i specjalnych wartości „niebędących liczbą” (NaN)

[…]


8

typeof NaNzwraca, 'number'ponieważ:

  • Specyfikacja ECMAScript mówi, że typ liczby zawiera NaN:

    4.3.20 Rodzaj numeru

    zbiór wszystkich możliwych wartości Number, w tym specjalne wartości „Not-a-Number” (NaN), dodatnia nieskończoność i ujemna nieskończoność

  • Więc typeofzwraca odpowiednio:

    11.4.3 Typ Operatora

    Produkcja UnaryExpression : typeof UnaryExpression jest oceniany w następujący sposób:

    1. Niech val będzie wynikiem obliczania UnaryExpression .
    2. Jeśli Type ( val ) to Reference , to
      1. Jeśli IsUnresolvableReference ( val ) jest true , return"undefined" .
      2. Niech val będzie GetValue ( val ).
    3. Zwrócić łańcuch zależy od typu ( Val ) według Tabeli 20.

                    Table 20 — typeof Operator Results
    ==================================================================
    |        Type of val         |              Result               |
    ==================================================================
    | Undefined                  | "undefined"                       |
    |----------------------------------------------------------------|
    | Null                       | "object"                          |
    |----------------------------------------------------------------|
    | Boolean                    | "boolean"                         |
    |----------------------------------------------------------------|
    | Number                     | "number"                          |
    |----------------------------------------------------------------|
    | String                     | "string"                          |
    |----------------------------------------------------------------|
    | Object (native and does    | "object"                          |
    | not implement [[Call]])    |                                   |
    |----------------------------------------------------------------|
    | Object (native or host and | "function"                        |
    | does implement [[Call]])   |                                   |
    |----------------------------------------------------------------|
    | Object (host and does not  | Implementation-defined except may |
    | implement [[Call]])        | not be "undefined", "boolean",    |
    |                            | "number", or "string".            |
    ------------------------------------------------------------------

To zachowanie jest zgodne ze standardem IEEE dla arytmetyki zmiennoprzecinkowej (IEEE 754) :

4.3.19 Wartość liczbowa

wartość pierwotna odpowiadająca wartości podwójnej precyzji w 64-bitowym formacie binarnym IEEE 754

4.3.23 NaN

wartość liczbowa, która jest wartością „Not-a-Number” w standardzie IEEE 754

8.5 Typ liczb

Typ numer ma dokładnie 18437736874454810627 (czyli 2 53 -2 64 +3) wartości, reprezentujący 64-bitowy format IEEE 754 wartości podwójnej precyzji, jak określono w standardzie IEEE dla Binary arytmetyki zmiennoprzecinkowej, chyba że 9007199254740990 ( to znaczy 2 53 −2) odrębne wartości „Not-a-Number” normy IEEE są reprezentowane w ECMAScript jako pojedyncza specjalna wartość NaN . (Zauważ, że wartość NaN jest tworzona przez wyrażenie programu NaN).


5

NaN to poprawna wartość zmiennoprzecinkowa ( http://en.wikipedia.org/wiki/NaN )

a NaN === NaN jest fałszem, ponieważ niekoniecznie są one tą samą liczbą nieliczną


1
Przepraszam, ale muszę powiedzieć, że to nie jest dobry sposób, aby o tym myśleć. „niekoniecznie ta sama liczba nie jest liczbą” nie oznacza, że ​​są one zawsze różne i porównywanie ich powinno dawać fałszywe wyniki. Najlepiej nie określać ilości NaN i po prostu myśleć o tym jako o dziwactwie w naszej bazie wiedzy.
Dave,

1
Dlaczego więc wszystkie Infinitysą w jakiś sposób identyczne? jakieś pomysły?
Hashem Qolami

5

NaN != NaNponieważ nie są one potrzebne TEN SAM numer. Dlatego ma to dużo sensu ... Również dlaczego zmiennoprzecinkowe mają zarówno +0,00, jak i -0,00, które nie są takie same. Zaokrąglanie może sprawić, że w rzeczywistości nie są one zerowe.

Jeśli chodzi o typ, to zależy od języka. A większość języków powie, że NaN jest liczbą zmiennoprzecinkową, podwójną lub liczbą, w zależności od tego, jak ją sklasyfikują ... Nie znam żadnych języków, które powie, że jest to nieznany typ lub zerowy.


1
ehr, rozważ: var x = parseInt ('no dice'), y = x; Teraz powiedziałbym, że oba NaN są dokładnie takie same? Ale nie, x === y również zwraca fałsz.
KooiInc

tak, ale nie możesz być PEWNY, a zatem nie są one tym samym. Jest to ta sama logika, co logika NULLable w bazie danych. Chociaż wielu ludzi myśli o nich jako o zerowych wskaźnikach z innych języków programowania, w rzeczywistości mają one zupełnie inną semantykę. Są „NIEZNANE” i dlatego jedna wartość NULL w porównaniu z inną jest zawsze fałszywa. Wykonywanie obliczeń na wartości NULL kończy się wynikiem NULL. Spróbuj spojrzeć na to z perspektywy wartości nazywanej NIEZNANA
Cine

A jest typu number, NaNjest prymitywny i stąd jednoznacznie wyznaczona przez jego wartość.
Dmitri Zaitsev

4

NaNoznacza Not a Number . Jest to wartość liczbowych typów danych (zwykle typów zmiennoprzecinkowych, ale nie zawsze), która reprezentuje wynik nieprawidłowej operacji, takiej jak dzielenie przez zero.

Chociaż jego nazwa mówi, że nie jest to liczba, typ danych używany do jej przechowywania jest typem liczbowym. Tak więc w JavaScript pytanie o typ danych NaNzwróci number(jak alert(typeof(NaN))wyraźnie widać).


Faktycznie dzielenie przez zero ocenia się jako InfinitynieNaN
Dmitri Zaitsev

2

Javascript używa NaN do reprezentowania wszystkiego, co napotka, czego nie można przedstawić w żaden inny sposób w jego specyfikacjach. Nie oznacza to, że to nie jest liczba. To po prostu najłatwiejszy sposób opisania spotkania. NaN oznacza, że ​​to samo lub obiekt, który się do niego odwołuje, nie może być reprezentowane w żaden inny sposób przez JavaScript. Ze wszystkich praktycznych względów jest „nieznane”. Będąc „nieznanym”, nie jest w stanie powiedzieć, czym jest, ani nawet czy jest sobą. Nie jest to nawet obiekt, do którego jest przypisany. Może tylko powiedzieć, czym nie jest, a nie-istnienie lub nicość można opisać matematycznie tylko w języku programowania. Ponieważ matematyka dotyczy liczb, javascript reprezentuje nicość jako NaN. To nie znaczy, że to nie jest liczba. Oznacza to, że nie możemy tego czytać w żaden inny sposób, który ma sens. Dlatego może nie dorównuje sobie. Ponieważ tak nie jest.


2

Lepsza nazwa NaN, opisująca jego znaczenie dokładniej i mniej myląco, byłaby liczbowym wyjątkiem . Jest to naprawdę inny rodzaj obiektu wyjątku przebranego za posiadający typ pierwotny (zgodnie z projektem języka), podczas gdy jednocześnie nie jest traktowany jako prymitywny w swoim fałszywym porównywaniu siebie. Skąd zamieszanie. Tak długo, jak język „nie podejmie decyzji”, aby dokonać wyboru między właściwym przedmiotem wyjątku a prymitywną liczbą , zamieszanie pozostanie.

Niesławna nierówność NaNsamego siebie, zarówno ==i ===jest przejawem zagmatwanego projektu, który zmusza ten wyjątkowy obiekt do bycia typem prymitywnym. Łamie to podstawową zasadę, że prymityw jest wyjątkowo określony przez swoją wartość . Jeśli NaNwolisz być postrzegany jako wyjątek (którego mogą być różne rodzaje), to nie powinien być „sprzedawany” jako prymitywny. A jeśli ma być prymitywny, musi obowiązywać ta zasada. Dopóki jest zepsuty, tak jak w JavaScript, i nie możemy tak naprawdę zdecydować między nimi, zamieszanie prowadzące do niepotrzebnego obciążenia poznawczego dla wszystkich zaangażowanych pozostanie. Co jednak jest naprawdę łatwe do naprawienia, po prostu dokonując wyboru między nimi:

  • albo utworzyć NaNspecjalny obiekt wyjątku zawierający przydatne informacje o tym, jak powstał wyjątek, w przeciwieństwie do odrzucania tych informacji jako tego, co jest obecnie zaimplementowane, co prowadzi do trudniejszego do debugowania kodu;
  • lub uczynić NaNjednostkę typu pierwotnego number(która mogłaby być mniej myląco nazywana „numeryczną”), w którym to przypadku powinna być sobie równa i nie może zawierać żadnych innych informacji; ten ostatni jest zdecydowanie gorszym wyborem.

Jedyną zaletą pomyślenia zmuszając NaNdo numbertypu jest w stanie wyrzucić go z powrotem do dowolnego wyrażenia numerycznego. Co jednak sprawia, że ​​wybór jest trudny, ponieważ wynik dowolnego wyrażenia liczbowego zawierającego NaNalbo będzie NaN, albo prowadził do nieprzewidywalnych wyników, takich jak NaN < 0obliczanie do false, czyli zwracanie booleanzamiast zachowania wyjątku.

I nawet jeśli „rzeczy są takie, jakie są”, nic nie stoi na przeszkodzie, abyśmy dokonali tego wyraźnego rozróżnienia dla siebie, aby nasz kod był bardziej przewidywalny i łatwiejszy do debugowania. W praktyce oznacza to identyfikowanie tych wyjątków i traktowanie ich jako wyjątków. Co niestety oznacza więcej kodu, ale miejmy nadzieję, że zostanie to złagodzone przez narzędzia takie jak TypeScript of Flowtype.

A potem mamy niechlujne, ciche i hałaśliwe, czyli NaNrozróżnienie sygnalizacyjne . To naprawdę dotyczy tego, jak obsługiwane są wyjątki, a nie same wyjątki i nic nie różni się od innych wyjątków.

Podobnie Infinityi +Infinitysą elementami typu numerycznego powstającymi w przedłużeniu prostej rzeczywistej, ale nie są to liczby rzeczywiste. Matematycznie można je przedstawić za pomocą sekwencji liczb rzeczywistych zbiegających się do albo +lub -Infinity.


1

Dzieje się tak po prostu dlatego, że NaNjest to właściwość obiektu Number w JS, nie ma to nic wspólnego z tym, że jest liczbą.


Jak każdy inny obiekt, Number może mieć dowolny typ własności. Number.fu = "bar"; alert(typeof Number.fu);
Alsciende

NaNnie jest przechowywaną wartością Number.NaN, cokolwiek by to nie było. NaNjest wartością pierwotną typu Number. I dodatkowo wartość Number.NaNjest NaN, ale to nie ma związku.
Oriol

1

Najlepszym sposobem myślenia o NAN jest to, że nie jest to znana liczba. Dlatego NAN! = NAN, ponieważ każda wartość NAN reprezentuje jakąś niepowtarzalną nieznaną liczbę. Sieci NAN są niezbędne, ponieważ liczby zmiennoprzecinkowe mają ograniczony zakres wartości. W niektórych przypadkach dochodzi do zaokrąglania, gdy niższe bity są tracone, co prowadzi do czegoś, co wydaje się być nonsensem, na przykład 1,0 / 11 * 11! = 1,0. Naprawdę duże wartości, które są większe, to NAN, a nieskończoność jest doskonałym przykładem.

Biorąc pod uwagę, że mamy tylko dziesięć palców, każda próba pokazania wartości większych niż 10 jest niemożliwa, co oznacza, że ​​takie wartości muszą być wartościami NAN, ponieważ utraciliśmy prawdziwą wartość tej wartości większej niż 10. To samo dotyczy wartości zmiennoprzecinkowych, gdzie wartość przekracza granice tego, co może być przechowywane w zmiennej zmiennoprzecinkowej.


Nieskończoność nie jest reprezentowana przez NaN. Próba przedstawienia liczby spoza zakresu byłaby zaokrąglana w dół (do max / -inf) lub w górę (do min / + inf).
OrangeDog


1

NaNjest liczbą z punktu widzenia typu, ale nie jest zwykłą liczbą, taką jak 1, 2 lub 329131. Nazwa „Not A Number” odnosi się do faktu, że reprezentowana wartość jest specjalna i dotyczy dziedziny specyfikacji formatu IEEE, a nie domena języka javascript.


1

Jeśli korzystam z jQuery, wolę isNumericod sprawdzania typu:

console.log($.isNumeric(NaN));  // returns false
console.log($.type(NaN));       // returns number

http://api.jquery.com/jQuery.isNumeric/


Dzięki. Miałem problemy z isNumberod utilpakietu maszynopis. Dobrze, że nadal używamy jQueryw naszym projekcie, więc zamiast tego skorzystaj z Twojej sugestii.
Ashok MA

Dla rec, isNumberfrom utilof maszynopis również zwraca się truepo NaN.
Ashok MA

0

Javascript ma tylko jeden liczbowy typ danych, czyli standardowy 64-bitowy zmiennoprzecinkowy o podwójnej precyzji. Wszystko jest podwójne. NaN to specjalna wartość podwójna, ale mimo to jest podwójna.

Wszystko, co parseIntrobi, to „rzutowanie” łańcucha na numeryczny typ danych, więc wynikiem jest zawsze „liczba”; tylko jeśli oryginalny łańcuch nie był analizowalny, jego wartością będzie NaN.


0

NaN nadal jest typem liczbowym, ale reprezentuje wartość, która nie może reprezentować prawidłowej liczby.


0

Moglibyśmy argumentować, że NaN jest obiektem szczególnym. W tym przypadku obiekt NaN reprezentuje liczbę, która nie ma żadnego matematycznego sensu. W matematyce jest kilka innych obiektów specjalnych, takich jak INFINITE i tak dalej.

Nadal możesz z nim wykonać pewne obliczenia, ale spowoduje to dziwne zachowania.

Więcej informacji tutaj: http://www.concentric.net/~ttwang/tech/javafloat.htm (oparty na Javie, nie javascript)


0

Musisz pokochać Javascript. Ma kilka interesujących drobiazgów.

http://wtfjs.com/page/13

Większość z tych dziwactw można wytłumaczyć, jeśli przestaniesz je logicznie rozwiązywać lub jeśli wiesz trochę o teorii liczb, ale mimo to mogą cię złapać, jeśli o nich nie wiesz.

Swoją drogą, polecam przeczytanie pozostałej części http://wtfjs.com/ - można znaleźć o wiele więcej ciekawych dziwactw niż ten!


0

Wartość NaN to tak naprawdę liczba, więc gdy zapytasz, czy jest to liczba, powie tak. Zrobiłeś właściwą rzecz, używając wywołania isNaN ().

Dla informacji, NaN można również zwrócić przez operacje na liczbach, które nie są zdefiniowane, jak dzielenie przez zero lub pierwiastek kwadratowy liczby ujemnej.


W jakim sensie jest to „wartość”? NaN == Number.NaNocenia się na false!
Dmitri Zaitsev

@DmitriZaitsev Czy czytałeś wątek? A czy próbowałeś (parseInt ("nan") == Number.NaN)? Spróbuj także! = I zobacz, co ci powie.
Rob

Przepraszam, zapomniałem o głupiej NaN==NaNistocie false, musiał to być sadysta, który to wymyślił, żeby wszyscy cierpieli.
Dmitri Zaitsev

0

Przykład

Wyobraź sobie, że zamieniamy ciąg na liczbę:

Number("string"); // returns NaN

Zmieniliśmy typ danych na numer, ale jego wartość nie jest liczbą!


Wydaje się, że przegapiłeś sedno pytania. NaNjest typu liczbowego . Pytanie brzmi: dlaczego.
Quentin,

@Quentin wyjaśniłem w ostatniej linijce.
Amir Fo

-1

Jest to specjalna wartość typu Liczba jako POSITIVE_INFINITY

Czemu? Przez projekt

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.