Dlaczego ostatnia zmiana na usuwanie / pomijanie średników w Javascript?


79

Wydaje się, że ostatnio modne jest pomijanie średników w Javascript. Kilka lat temu był post na blogu , w którym podkreślono, że w JavaScript średniki są opcjonalne, a sedno tego wpisu wydawało się, że nie powinieneś się nimi przejmować, ponieważ są niepotrzebne. Powszechnie cytowany post nie daje żadnych istotnych powodów, aby ich nie używać, tylko to, że ich pominięcie ma kilka skutków ubocznych.

Nawet GitHub wskoczył na modę bez średnika, wymagając ich pominięcia w dowolnym wewnętrznie opracowanym kodzie, a niedawne zatwierdzenie projektu zepto.js przez jego opiekuna usunęło wszystkie średniki z bazy kodu. Jego główne uzasadnienia to:

  • jest to kwestia preferencji dla jego zespołu;
  • mniej pisania

Czy istnieją inne powody, aby je pominąć?

Szczerze mówiąc, nie widzę powodu, aby je pomijać, a na pewno nie ma powodu, aby cofać się po kodzie, aby je usunąć. To samo odnosi się przeciwko ( lat ) Zalecaną praktyką , która tak naprawdę nie kupić „kulty cargo” argument. Dlaczego więc cała ostatnia nienawiść do średnika? Czy zbliża się niedobór? Czy to tylko najnowsza moda na Javascript?


2
„lata zalecanych praktyk” odnoszą się do pytania o czarną listę sondaży SO, która raczej nie czyni wiarygodnego poparcia dla jakiejkolwiek opinii
skomentuj

24
@gnat tylko dlatego, że ludzie nienawidzą tego pytania na SO, nie czyni go mniej wiarygodnym źródłem opinii ludzi.
Ryathal

3
@gnat Pytania „oficjalnie uważane za nieodpowiednie w StackOverflow” są czasami uważane przez społeczność ekspertów za bardzo autorytatywne. Smutne ale prawdziwe.
MarkJ

4
@gnat Na czarnej liście znajduje się kilka interesujących przykładów, dlaczego pominięcie ;może złamać kod. Powiedziałbym więc, że jest to przydatne odniesienie do tego pytania.
Andres F.

1
Może to być związane z rosnącą popularnością biodrówek na początku 2010 roku.
Alex

Odpowiedzi:


61

Przypuszczam, że mój powód jest najsłabszy: programuję jednocześnie w zbyt wielu różnych językach (Java, JavaScript, PHP) - które wymagają ';' więc zamiast trenować moje palce i oczy, aby „;” nie jest potrzebny w javascript, po prostu zawsze dodam ';'

Innym powodem jest dokumentacja: poprzez dodanie „;” Mówię wprost, gdzie spodziewam się końca tego oświadczenia. Potem znowu używam {} cały czas.

Cały argument liczby bajtów uważam za irytujący i bezcelowy:

1) w przypadku popularnych bibliotek, takich jak jquery: użyj Google CDN, a biblioteka prawdopodobnie będzie już w pamięci podręcznej przeglądarki

2) zaktualizuj własne biblioteki i ustaw je tak, aby były buforowane na zawsze.

3) gzip i zminimalizuj, jeśli naprawdę, naprawdę konieczne.

Ale tak naprawdę, ile stron ma największe wąskie gardło prędkości pobierania javascript? Jeśli pracujesz dla 100 najlepszych witryn, takich jak Twitter, Google, Yahoo itp., Może. Reszta z nas powinna martwić się o jakość kodu, a nie o wojny religijne średnikowe.


3
Myślę, że może być również odwrotnie. Ponieważ Python staje się coraz bardziej popularny w Internecie, łatwiej jest JS przypominać Python.
Ben DeMott

4
Spróbuj, ale wtedy ten sam bajtowy wojownik będzie za mną za niepotrzebne białe znaki na początku linii. (Miałbym również błędy w Javascript, ponieważ polegałbym na zasadzie wcięcia Pythona, zamiast używać {}
Pat

6
Jeśli zmniejszenie liczby bajtów jest ważne, będziesz mieć coś, co zminimalizuje pliki w jak największym stopniu. Jeśli nie warto jeszcze używać minimalizatora, nie warto martwić się usunięciem ';' aby zaoszczędzić na liczbie bajtów.
Lawtonfogle,

3
liczba bajtów niekoniecznie musi być zmniejszona, w rzeczywistości można ją zwiększyć, ponieważ nowa linia to często (nie zawsze) dwa znaki (nowa linia, po której następuje powrót karetki), więc w najbardziej oszczędnej przestrzeni nowa postać wiersz będzie miał jeden znak taki sam, jak jednoznakowy średnik (jeśli skompresujesz cały kod JS w jednym wierszu, co często jest wykonywane dla wdrożonego kodu JS, a nie kodu źródłowego programowania).
ALXGTV

Ludzie potrzebują wcięcia, aby zrozumieć głębokie zagnieżdżanie, które wymaga więcej bajtów niż średników. Jednak średniki odwracają uwagę od nacisków klawiszy.
Cees Timmerman,

39

Ułatwia to łączenie metod i czyszczenie różnic

Powiedzmy, że o to pytam i mam

$('some fancy selector')
  .addClass()
  .attr();

Jeśli chcę dodać coś i utrzymywać małą różnicę zatwierdzeń w wierszu , muszę dodać ją powyżej atrybutu. To jedna myśl dłuższa niż „dodaj na końcu”. A kto chce myśleć? =)

$('some fancy selector')
  .addClass()
  // new method calls must go here
  .attr();

Ale kiedy upuszczam średniki, mogę po prostu dołączyć i nazwać to dniem

  $('some fancy selector')
    .addClass()
    .attr()
+   .animate()
+   .click()

Ponadto, jeśli zdecyduję się zrezygnować z ostatniej metody, nie muszę ponownie przypisywać średnika i ponownie zanieczyszczać mojego zatwierdzenia.

  $('some fancy selector')
    .addClass()
    .attr()
    .animate()
-   .click()

W porównaniu z uggo

  $('some fancy selector')
    .addClass()
    .attr()
+   .animate();
-   .animate()
-   .click();

37
Jest to niszowy przypadek użycia IMO.
JBRWilkinson

9
Niemniej jednak interesujące.
Jonathan

8
Na końcu możesz umieścić średnik na nowej linii wciętej jako linię początkową. Następnie kopiujesz i porządkujesz wszystko tak, jak chcesz. To także ładnie zamyka łańcuch.
Nux

11
Czy to tylko ja zastanawiam się, dlaczego ktokolwiek miałby dbać o to, jak schludne są różnice w ich zobowiązaniach? z reguły ludzie czytają kod, a nie diffs.
Jules

11
@Jules, czystsze różnice oznaczają, że połączenia są bardziej prawdopodobne.
joeytwiddle

22

średniki w JavaScript są opcjonalne

Moim osobistym powodem nieużywania średników jest OCD.

Kiedy używam średników, zapominam 2% z nich i muszę ciągle sprawdzać / dodawać je z powrotem.

Kiedy nie używam średników, nigdy nie wkładam ich przypadkowo, więc nigdy nie muszę ich sprawdzać / usuwać.


3
Dobry. Zostałem wypalony linią lub średnikami bez średnika w pliku, który w przeciwnym razie byłby prawidłowo średnikowy.
Jonathan

3
Istnieją parsery (np. GeSHi), które nie będą poprawnie parsowały twojego kodu, jeśli nie będą obecne średniki. Można powiedzieć, że ludzie nie popełniają takich błędów ... Ale tak na poważnie - jeśli zdarzy się, że cały twój zespół zdoła sobie przypomnieć, gdzie absolutnie konieczne jest umieszczenie średników, czy naprawdę sądzisz, że zapamiętają to bez porannej kawy? I będą kodować w wielu stanach umysłów. Bądź tego pewien.
Nux

16

Niedawno napisałem analizator składni / analizatora JavaScript, w którym musiałem pieczołowicie wdrożyć ASI, a także mam swoją kopię kodu Crockford JavaScript: The Good Parts na mojej półce z książkami, która zaleca stosowanie zawsze średników. Intencja była dobra, ale nie zawsze pomaga w praktyce.

Oczywiście ludzie piszący frameworki takie jak jQuery, zepto itp. Są mistrzami składni JavaScript, a zatem znają różnicę między:

return
{
    status: true
};

i

return {
    status: true
};

JavaScript, choć potężny, jest także językiem dla początkujących i powodzenia w wyjaśnianiu tego komuś, kto dopiero się uczy, czym jest forpętla. Podobnie jak zapoznanie większości ludzi z nową umiejętnością, istnieją pewne bardziej złożone rzeczy, których nie chcesz od razu wyjaśniać, więc zamiast tego zdecydujesz się zaszczepić wiarę w „kult kultu” w pewne rzeczy, aby po prostu zrzucić je z ziemi. Masz więc dwie możliwości uczenia początkującego, jak pisać JavaScript:

  1. Powiedz im, „przestrzegaj tej jednej zasady i nie pytaj dlaczego”, mówiąc im, aby na końcu każdej linii umieszczali zawsze średnik. Niestety nie pomaga to w powyższym przykładzie ani w żadnym innym przykładzie, w którym ASI przeszkadza. I początkujący programista zostaje zamroczony, gdy powyższy kod zawiedzie.
  2. Powiedz im: „przestrzegaj tych dwóch zasad i nie pytaj dlaczego”, mówiąc im, aby nie zawracali sobie głowy średnikami na końcu każdej linii, i zamiast tego zawsze a) Postępuj zgodnie returnz a {, i b) Gdy linia zaczyna się od (, poprzedzaj to z ;.

Wybranie opcji 2 to lepszy zestaw zasad „kultu ładunku”, których należy przestrzegać (spowoduje to bardzo niewiele błędów związanych z ASI), a nawet jeśli dobrze zrozumiesz temat, masz mniej niepotrzebnych postaci na ekranie.


8
W porządku, ugryzę. Pomóż mi zrozumieć różnicę w składni między dwoma powyższymi przykładami. Moje niedoświadczone oko widzi tylko różnicę w formatowaniu.
Jesse C. Slicer

9
Z drugiej strony natknąłem się na odpowiedź przez przypadek. W pierwszym przykładzie returnjest uważana za pojedynczą instrukcję, a koniec linii jest odpowiednikiem średnika. Drugi przykład faktycznie zwraca obiekt. Chytry.
Jesse C. Slicer

9
Nie sądzę, że mogę zgodzić się z opinią, że JavaScript jest językiem dla początkujących, w JavaScript jest mnóstwo niespójności i zaskakujących efektów, które nie mają prostych wyjaśnień. IMO nie byłby takim językiem dla początkujących, nazwałbym JavaScript językiem pośrednim.
Ryathal

2
@Ryathal Rozumiem, do czego zmierzasz, ale nazwanie go językiem pośrednim sprawia, że ​​zastanawiam się, w jakich językach pośredniczy. Sprawiasz, że brzmi to tak, jakby to był krok w podróż do czegoś innego, a nie cel sam w sobie.
Racheet

9
Wyjaśnienie: returnprzykład jest w rzeczywistości wyjątkiem od normalnego zachowania JS, które polega na próbie pociągnięcia linii razem, gdy pominięto średnik. return, breaki continuewszystkie wykazują to wyjątkowe zachowanie, w którym końcowy znak nowej linii jest zawsze interpretowany jako koniec wyrażenia. (Źródło to „JavaScript: The Definitive Guide” Flanagana str. 25–26). Osobiście dążę do idei „kodu najmniejszego zaskoczenia”. Pozostawienie średników na ogół powoduje więcej niespodzianek niż cokolwiek innego (generalnie trzymam też nawiasy klamrowe nawet dla prostych stwierdzeń).
Kyle

16

Nie ma czegoś takiego jak przeciążenie informacji, tylko zły projekt.

- Edward Tufte

Jest to ogólna zasada w projektowaniu graficznym , aby pominąć niepotrzebne elementy i ozdoby do zmniejszenia hałasu.

Mniej elementów wizualnych na ekranie oznacza mniej pracy dla naszych mózgów w analizowaniu rzeczywistych użytecznych informacji.

let foo = 1

vs.

let /* variable */ foo = 1; // EOL

Przesadzony przykład, ale ilustruje ogólną zasadę: dodatkowe elementy wizualne należy dodawać tylko wtedy, gdy służą celowi. Czy średniki służą temu celowi?

Historyczne powody używania średników w JavaScript:

  • Zachowaj podobieństwo do C / Java
  • Unikaj problemów ze zgodnością ze źle napisanymi przeglądarkami i narzędziami
  • Pomaganie ludziom i maszynom w wykrywaniu błędów kodu
  • Automatyczne wstawianie średnika powoduje obniżenie wydajności

Problemy ze zgodnością są dziś praktycznie bez problemu. Nowoczesne lintery potrafią równie dobrze wykrywać wszelkie błędy kodu bez średników. Podobieństwo do C / Java / PHP może nadal być brane pod uwagę (patrz zaakceptowana odpowiedź Pat), ale to, że inne języki zawierają zbędne elementy składniowe, nie oznacza, że ​​powinniśmy trzymać je w JavaScript, zwłaszcza, że ​​wiele innych języków (Coffeescript, Python, Ruby, Scala, Lua) nie wymagają ich.

Zrobiłem szybki test, aby sprawdzić, czy w wersji V8 występuje spadek wydajności. To jest Io.js parsujący plik JavaScript 41 MB (Lodash powtórzył 100 razy) z średnikami, a następnie z usuniętymi średnikami:

$ time node lodashx100.js
node lodashx100.js  2.34s user 1.30s system 99% cpu 3.664 total
$ time node lodashx100s.js
node lodashx100s.js  2.34s user 1.15s system 99% cpu 3.521 total

Każdy musi zdecydować o swoim preferowanym stylu kodowania dla swoich projektów, ale nie widzę już żadnej wymiernej korzyści z używania średników, więc aby zmniejszyć szum wizualny, przestałem.


Chciałbym przeciwstawić się temu argumentowi polegającemu na pozostawieniu niepotrzebnych elementów w obciążeniu, które umysł musi teraz zrobić, aby dodać z powrotem w opcjonalnej składni. Teraz średnik nie jest dużym obciążeniem umysłowym, jeśli zostanie pominięty. To jest problem, którego doświadczyłem w Ruby i Scali. Kiedy staje się łańcuchem połączeń z połączeniami wewnątrz połączeń i wszystkie pominęły wszystkie paren, rozrywanie jest ciężkie.
Seamus

8

Wybór konwencji programowania jest faktycznie taki sam, jak wybór podzbioru języka docelowego. Wszyscy robimy to z typowych powodów: czytelność kodu, łatwość konserwacji, stabilność, przenośność itp. - potencjalnie poświęcając elastyczność. Te powody to prawdziwe powody biznesowe.

Powody, takie jak „oszczędzanie naciśnięć klawiszy” i „programiści powinni nauczyć się reguł JavaScript” są marginalnymi względami biznesowymi, dlatego mają niewielką wagę praktyczną.

W moim przypadku musiałem bardzo szybko dostosować JavaScript, więc skorzystanie z ograniczonego podzbioru języka było dla mnie korzystne. Wybrałem więc podzbiór JSLint JavaScript, włączyłem aplikację Rockstar JSLinter w Eclipse do najbardziej restrykcyjnych ustawień, jakie mogłem znieść, i nie oglądałem się za siebie.

Jestem wdzięczny, że mogę uniknąć szczegółów różnicy między „==” i „===”, lub szczegółów wstawiania średnika, ponieważ mam już listę zadań o wysokości mili i te szczegóły nie będą pomóż wykonać te prace o sekundę wcześniej.

Oczywiście najważniejszą rzeczą w konwencji jest konsekwencja, a myślenie o niej jako podzbiorze językowym pomaga wzmocnić ten imperatyw. I chociaż może to nie pomóc odpowiedzieć na pytanie PO, myślę, że może to pomóc w praktycznym sformułowaniu tego.


5

Zupełnie stare pytanie, ale jestem zaskoczony, że nikt nie wspomniał:

Minifikacja: jeśli zdarzyło Ci się zminimalizować fragment kodu JavaScript, który nie kończy jawnie znaków średnikiem, możesz mieć trudności z ustaleniem, co jest nie tak z fragmentem, który działał przed minimalizacją i teraz nie działa.

Dwuznaczność: Średniki są opcjonalne, prawda, jednak eliminując je z kodu źródłowego, można pozostawić parserowi dwuznaczne scenariusze, aby samodzielnie zdecydować. Jeśli piszesz 100 linii kodu dla sklepu internetowego, tak, może to nie ma znaczenia, ale poważniejsze zadania wymagałyby 100% przejrzystości.

Dawno temu czytałem bardzo ładną analogię o czymś innym, ale jest to również bardzo prawdziwe w tym przypadku: (W naszym przypadku) Eliminowanie średników jest jak przejście na czerwonym świetle. W końcu możesz być w porządku lub zostać potrąconym przez ciężarówkę.

Dlaczego w dzisiejszych czasach jest coraz bardziej popularny?

Osobiście uważam, że uruchomienie JavaScript po stronie serwera miało duży wpływ na samą społeczność JavaScript. W naszym przypadku oczywiście nikt nie zamierza zminimalizować JavaScript po stronie serwera (ponieważ kod źródłowy nie powinien być wysyłany do przeglądarki internetowej klienta), więc brak średników wygląda o wiele bezpieczniej, co jest prawdą; Jednak inni programiści, którzy uczą się na podstawie tych książek, artykułów i filmów, niestety odrzucają fakt, że JavaScript po stronie serwera nie jest dokładnie taki sam jak JavaScript po stronie klienta.


Minifikatory mogą wychodzić z linii nowego znaku lub wstawiać średniki, gdy średniki nie są obecne bez ograniczenia rozmiaru. Nie wiem, które (jeśli w ogóle) minifikatory to robią. Niebezpieczeństwo wciąż istnieje w co najmniej niektórych z nich, więc twój punkt nadal obowiązuje w praktyce.
poza

3

Istnieją dobre powody, aby je zatrzymać.

Nie są tak naprawdę opcjonalne, JS może dodać je z powrotem z automatycznym wstawianiem średników, gdy ich brakuje, ale to nie to samo.

JavaScript Douglasa Crockforda: The Good Parts dwa razy mówi, że to zły pomysł. Automatyczne wstawianie średnika może ukrywać błędy w programie i powodować niejednoznaczność.

JSLint nie zatwierdza.


3

JavaScript od ponad dekady nie potrzebuje średników do kończenia instrukcji. Jest tak, ponieważ znaki nowego wiersza są uważane za terminatory instrukcji (uważam, że jest to również wspomniane we wczesnych specyfikacjach ECMAScript). To naprawdę ma sens, tym bardziej, że naprawdę nie ma dobrego powodu, dla którego JavaScript wymaga częstego używania średników, ale nie innych interpretowanych języków deklaratywnych, takich jak Ruby czy Python.

Wymaganie średników może ułatwić napisanie parsera dla języka, ale jeśli każdy tłumacz interpretuje pominięcie średnika, o co właściwie chodzi?

Sprowadza się to do poziomu wiedzy programisty: jeśli wiesz, że możesz pominąć dwukropek, możesz to zrobić, wiedząc, że może to być konsekwencja. Ludzie są maszynami do podejmowania decyzji i prawie wszystkie decyzje wymagają kompromisu lub kompromisu. Kompromisem po prostu rzucanie średnikami dookoła twojego kodu (nawet w miejscach, gdzie nie są one potrzebne) jest to, że twój kod staje się mniej czytelny (w zależności od tego, kogo pytasz), a JSLint nie będzie narzekał (kogo to obchodzi ). Z drugiej strony, kompromis polegający na pomijaniu średników polega na tym, że 90% programistów JavaScript karci cię za to, ale z tego powodu możesz bardziej cieszyć się pisaniem JavaScript.

Co brzmi dla ciebie lepiej; podejmowanie świadomych decyzji lub ślepe podejmowanie decyzji / mentalność stada?


Byłbym zainteresowany, aby dowiedzieć się, dlaczego otrzymano opinie negatywne. JavaScript nie potrzebuje średników do zakończenia instrukcji; z pewnością może z nich korzystać, ale w żadnym wypadku nie są wymogiem. Gdyby były potrzebne, wyjaśnienia innych osób nie działałyby. Dowodzi tego fakt (tak, fakt), że można napisać całą aplikację JavaScript z kilkoma średnikami lub bez nich. Poza tym nie rozumiem, w jaki sposób zrozumienie, jak działa narzędzie i wykorzystanie własnego rozumowania do podejmowania decyzji, jest w jakiś sposób budzące zastrzeżenia w przeciwieństwie do „po prostu zrób to”. To się nazywa religia.
Ravenstine

Nie głosowałem za tym, ale problem może być taki, że nie jest to zgodne z prawdą, jak napisano. Newlines nie są uważane za terminatory instrukcji w javascript. Możesz zrezygnować ze średników ze względu na funkcję zwaną automatycznym wstawianiem średników, która pozwala automatycznie naprawić błędy analizy w określonych okolicznościach. Ludzie, którzy opowiadają się za średnikami, twierdzą, że wielu programistów javascript wydaje się źle rozumieć tę zasadę. Twój post wydaje się być argumentem na ich korzyść w tym świetle. (Mówiąc uczciwie, w większości zgadzam się z twoją tezą, ale z różnych powodów)
Tim Seguine

@ TimSeguine Tak, napisałem to wcześniej, zanim lepiej zrozumiałem. Nadal nie uważam, aby obiektywnie nie stosować średników, o ile ludzie tak rozumieją, co dokładnie robią. Powinienem przerobić swój post, a może się go pozbyć, skoro wystarczająco dużo innych się o tym mówiło. Dzięki za grzeczną krytykę! :)
Ravenstine

2

Mam dwie teorie:

ZA)

Rzecz w tym wyborze polega na tym, że w czasach, gdy obowiązywała JSLint itp., Postanowiłeś poświęcić dużo czasu na łapanie niejasnych błędów składniowych lub rozsądną ilość czasu na egzekwowanie zasad kodowania.

Jednak w miarę zbliżania się do kodu kierowanego testem jednostkowym i ciągłej integracji, czas (i interakcja człowieka) wymagany do wykrycia błędu składniowego znacznie się zmniejszył. Informacje zwrotne z testów szybko wskażą, czy Twój kod działa zgodnie z oczekiwaniami, na długo przed zbliżeniem się do użytkownika końcowego, więc po co marnować czas na dodawanie opcjonalnej gadatliwości?

B)

Leniwi programiści zrobią wszystko, aby ułatwić sobie życie w krótkim okresie. Mniej pisania -> mniej wysiłku -> łatwiej. (również bez konieczności używania średnika pozwoli uniknąć nadwyrężenia prawego palca serdecznego, unikając RSIness).

(Uwaga: nie zgadzam się z pomysłem pominięcia czegoś, co ujednoznacznia stwierdzenie).


1
jshint jest nadal ważnym narzędziem.
Raynos

Jak ujednoznaczniania oświadczenie, zarówno \ni ;\nsą takie same
Raynos

2
@Raynos W rzeczywistości okazało się, że JSLint jest nieco bezużyteczny ze względu na złożoność kodu o dużej ilości szkieletów, z którym często pracuję. Ponadto; \ n i \ n nie są takie same we wszystkich okolicznościach , w przeciwnym razie nigdy nie byłoby potrzeby;;
Ed James

7
jslint jest bezużyteczny, jednak jshint jest innym narzędziem.
Raynos

0

Nie pomijam ich, ale zmieniam zasady, kiedy je wstawiać.

Zasady, z których korzysta większość ludzi

  • Przed zakończeniem każdej linii
  • Z wyjątkiem tego, że linia kończy }się instrukcją funkcji
  • Ale tylko instrukcja funkcji, a nie przypisanie do literału funkcji

Moja zasada brzmi: na początku każdej linii, zaczynając od otwierającego nawiasu klamrowego / nawiasu.

Mój jest prostszy, dlatego łatwiejszy do naśladowania i mniej podatny na błędy. Również mała liczba średników ułatwia znajdowanie błędów, które można pominąć.


Kolejnym argumentem jest to, że niesławny return\nvaluebłąd pochodzi z niewiedzy o ASI. Moja reguła zmusza cię do poznania ASI, więc ludzie używający mojej reguły rzadziej wpadają w pułapkę tego błędu.


0

Liczba bajtów. Widzicie, złośliwi ludzie zwykle próbują zmieścić się tak bardzo w jednym wierszu kodu. Technicznie rzecz biorąc, nie byłoby to możliwe bez średników. Przypuszczam, że jest to raczej środek bezpieczeństwa niż tylko wymóg programowy. Jakoś to znacznie zmniejszyłoby XSS, gdy staje się wymaganiem, a nie sugestią.

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.