Asembler jako pierwszy język programowania? [Zamknięte]


12

Jak myślisz, jak dobrym pomysłem byłoby nauczenie ludzi asemblera (jakiegoś wariantu) jako pierwszego języka programowania? Wymagałoby to o wiele więcej wysiłku niż nauka na przykład Java lub Python, ale można by dobrze zrozumieć maszynę mniej więcej od „pierwszego dnia programowania” (przynajmniej w porównaniu z wieloma językami wyższego poziomu). Co myślisz? Czy to realistyczny pomysł, przynajmniej dla tych, którzy są gotowi podjąć dodatkowy wysiłek? Zalety i wady?

Uwaga: nie jestem nauczycielem, jestem tylko ciekawy


5
Myślę, że lepiej nadaje się dla osób studiujących informatykę, a nie inżynierię / programowanie
Imran Omar Bukhsh,

1
@Imran Zgadzam się co do zasady, ale każdy program na poziomie uczelni, o którym myślę, ma stopnie informatyczne, które są zarabiane przez ludzi, którzy w większości kontynuują pracę w inżynierii oprogramowania. (Zakładam, że to pytanie dotyczy poważnej podstawy kariery programistycznej, a nie np. Liceum)
G__

7
@Imran - uznałem to za nieco zaskakujące. Informatyka z pewnością bardziej skłania się ku matematyce i teorii? Bardziej zainteresowany zestawami, abstrakcyjnymi algebrami i asymptotyczną notacją niż zbijaniem bitów i pisaniem niekończących się powtórzeń ruchów od bla do bla.
Steve314,

2
Informatyka z pewnością ma tematy abstrakcyjne, ale pod pewnymi względami jest bardzo „bliska sprzętowi”. Byłem kiedyś na konferencji LICS, informatycznej. Pamiętam, że miał artykuły na temat lokalizacji danych różnych algorytmów sortowania, które, jak sądzę, dają teoretyczne podstawy do badania praktycznej wydajności algorytmów. Jeśli chodzi o montaż, osobiście uważam, że ma pewne podobieństwo do niektórych teoretycznych modeli obliczeniowych (maszyny Turinga, maszyny
liczące

1
Każdy programista powinien przynajmniej przeczytać o tym, jak działa montaż, IMO. Dało mi to dużo wglądu i zazwyczaj jestem tak blisko chromu, jak tylko możesz. Krok po kroku asemblerowy montaż Jeffa Duntemanna to świetna lektura dla początkujących.
Erik Reppen

Odpowiedzi:


14

Trudno byłoby zainspirować nowego programistę kodem asemblera. Dynamiczne przywitanie, witryna użytkownika jest znacznie fajniejsza przy mniejszym wysiłku. Nie twierdzę, że podstawowe lekcje są takie same, ale kurs wprowadzający będzie miał dużą inspirującą treść, w przeciwnym razie nie będzie drugiego kursu.

Pamiętam, że moje wczesne kursy programowania były prowadzone w Schemacie i byłem głównie sfrustrowany, że nie mogłem łatwo po prostu skompilować do pliku .exe i „uruchomić” mój program (myślałem, że MS Visual Basic to koniec programowania). Dopiero po latach naprawdę zrozumiałem, jak potężnym narzędziem się bawiłem. Myślę, że bardziej doceniłbym to i lepiej skorzystałbym z tych lekcji, gdybym początkowo miał jakieś wczesne doświadczenie w czymś bardziej pragmatycznym.


20
Widziałem wielu uczniów, którzy byli znacznie bardziej zdumieni, gdy migali diodą LED i poruszali silnikiem.
whatsisname

1
@Whatsisname +1, byłoby to imponujące demo, o ile można tego dokonać bez angażowania się w elektronikę. Oczywiście można tego dokonać również w języku wyższego poziomu, tj. Hakowaniu Roomby, gdyby „kierowca” był czarną skrzynką dostarczaną przez instruktora.
G__

1
Wiele nowych programistów zostało zainspirowanych przez montaż na VIC20, C = 64 i podobnych maszynach.
Gaius

2
@Gaius Nie na początku! Włączasz te maszyny i jesteś w podstawowym tłumaczu. Zgromadzenie przychodzi po
sporej

1
@whatsisname, ale możesz użyć czegoś takiego jak Arduino, aby mrugać diodami LED i poruszać silnikami bez konieczności uczenia się montażu
Ken Liu

12

Myślę, że to okropny pomysł zarówno dla studentów inżynierii oprogramowania, jak i studentów CS i ogólnie bardziej zainteresowanych programowaniem niż elektroniką.

To może być zrobione, ale to nie znaczy, że powinno być zrobione. W tamtych czasach sposobem na naprawdę fajne rzeczy z komputerami domowymi było nauczenie się montażu. Stało się tak z powodu wczesnych ograniczeń sprzętowych - języki wyższego poziomu po prostu nie były wystarczająco mocne i szybkie. W dzisiejszych czasach możesz robić dużo fajniejsze rzeczy w krótszym czasie, używając języka wyższego poziomu.

Co brzmi ciekawiej, pisząc szybki prototyp dla prostej gry i bawiąc się wariacjami na temat algorytmu, lub walcząc z rejestrami i rzeczami niskiego poziomu?


3
Jako pianista z pewnością uważam, że ciekawiej jest wskoczyć do niektórych piosenek, ale aby stać się przyzwoitym, musisz ćwiczyć arpeggio, skale itp. A potem robić naprawdę przełomowe rzeczy (grać z „przygotowanymi pianinami” i itp.) musisz wiedzieć, jak działa pianino od wewnątrz. To wszystko, jak dobrze chcesz znać swoje rzemiosło.
Jan

10
@John w CashCommons: Zła analogia. Rozpoczęcie od asemblera jest jak uruchomienie młotków, klawiatury, obciążników i amortyzatorów. Następnie przechodzę do teorii muzyki (koło piątych), aby objaśnić sprawę czarnego i białego klucza. Następnie przejdź do jeszcze większej teorii muzyki, zanim zagrasz w skalę.
S.Lott,

3
@ S.Lott: Ehhhhh ... nie kupuj tego całkiem. Mogę napisać program typu „hello world” w assemblerze, nie martwiąc się o tranzystory. Nie trzeba być projektantem układów, aby być programistą. Wiedza, o której mówisz, byłaby podstawą do zbudowania lub naprawy fortepianu, co jest tylko kursorycznie związane z grą na fortepianie.
John

3
@John w CashCommons: „budowa lub naprawa fortepianu”. To analogia z asemblerem. Można napisać trywialny „witaj świat” w asemblerze , ale to tylko wywołania API systemu operacyjnego - w efekcie ignorując wszystkie przerażające szczegóły asemblera. Do pisania sterowników we / wy niezbędny jest asembler. W ten sam sposób młoty i amortyzatory dotyczą budowania i konserwacji, a nie działania.
S.Lott,

1
@ S.Lott: Hmmmm ... Chyba konkretny zestaw instrukcji zależy od układu, prawda? Słuszna uwaga.
Jan

7

Nie sądzę, że to okropny pomysł, ale jak skomplikowany program zamierzasz zapewnić tym studentom? Montaż zajmuje dużo więcej pracy. Może być w porządku, aby zacząć od bardzo podstawowych rzeczy, a następnie przenieść je do czegoś, w którym łatwiej jest pracować, gdy już docenią pracę na niższym poziomie. Po raz pierwszy uczniowie czasami wpadają na pomysł, że zakodują następną grę Halo, MS Office, AutoCAD lub coś w tym stylu, a kiedy zobaczą, ile pracy zajmuje prosty język asemblera, można się ich wystraszyć, więc wyjaśnij to że są lepsze rzeczy niż montaż, a następnie przenieś je do tego, gdy zobaczą koncepcje. Możesz także spróbować uczyć asemlby równolegle z czymś innym jak C.

Ponadto, który język asemblera? Nieco przypominam sobie, że MIPS był stosunkowo łatwy w obsłudze i myślę, że działa w emulatorze, więc nie ma niebezpieczeństwa powodowania problemów na prawdziwej maszynie, chociaż mogą być lepsze narzędzia niż teraz.

Może to działać dobrze, jeśli zostanie to wykonane poprawnie. Tylko bądź ostrożny...


+1 za złożoność problemu. Głosowałbym za zestawieniem kilku implementacji asemblera z implementacjami języka wyższego poziomu. I może użyj np. Asemblera 68000 w emulatorze zamiast x86 - nie wiem, jak ewoluował asembler x86 / amd64, ale 68000 był o wiele czystszy i łatwiejszy w obsłudze niż wtedy 8086. Warto również rozważyć - asembler maszyn wirtualnych, taki jak LLVM. Nie taki sam jak prawdziwy asembler, ale ma wiele podobnych zasad i prawdopodobnie jest bardziej odpowiedni.
Steve314,

Nauczanie ASM jednocześnie z C wydaje się całkiem dobrym pomysłem
Anto

@ Steve314: Nie jestem na asemblerze x86, ale wygląda na to, że stało się bardziej skomplikowane niż 8086.
David Thornley

@David - spodziewam się, że tak, ale może być nieco łatwiej. W ciągu 8086 dni zakres dostępnych trybów adresów zależał od konkretnego rejestru, którego używasz, a także od instrukcji. W 68000 istniały (dla większości celów) rejestry danych i rejestry adresowe, przy czym każdy typ był używany dość jednolicie, bez żadnych kłopotów z indeksem lub indeksem bazowym. Z czasem może to się zmieniło? 68000 miał także więcej rejestrów, co oszczędzało na przemieszczaniu się do pamięci. W każdym razie nie musisz uczyć się SIMD, aby uzyskać podstawowe zasady asemblera.
Steve314,

@David - Nie mogę uwierzyć, że zapomniałem (stłumiono) segmentowane adresowanie. To było wystarczająco złe w języku wysokiego poziomu. Adresowanie jest teraz podzielone na segmenty, ale jest inna sprawa związana z pamięcią wirtualną itp., O którą programiści na poziomie aplikacji nie powinni się martwić.
Steve314,

7

Montaż był pierwszym językiem, którego nauczyliśmy się w szkole elektronicznej (w latach 1900) i wydawało się, że to naturalny wybór. Przeszliśmy przez nasze kursy od elementów dyskretnych, przez logikę rezystor-tranzystor, bramki logiczne, układy scalone, procesory i programowanie w montażu. Wielu uczniów na tych zajęciach nigdy wcześniej nie programowało w żadnym języku i dobrze to zrozumieli.

Tak więc montaż może być dobrym wyborem dla pierwszego języka, jeśli uczeń ma odpowiednie podstawy. Uważam jednak, że dla każdego, kto chce być aplikacją lub programistą WWW, montaż jest prawdopodobnie zbyt niskim poziomem początkowym.


7

Jedno jest pewne, jeśli ludzie, najpierw ucząc się Zgromadzenia, zdążą, będą niesamowitymi programistami.

To przypomina mi, kiedy nauczyłem się prowadzić. Moja mama nalegała

Ucz się na automatycznym samochodzie, dopóki nie zyskasz pewności siebie, a potem będziesz mógł prowadzić nasze ręczne samochody.

Powodem jest to, że nie chciała, abym był rozproszony bardziej niż powinienem, naraz.

Zastosuj to do nauki programowania, czy konieczne jest rzucenie wszystkiego na ucznia naraz? Uczą się, czym jest zmienna, jednocześnie uczą się, ile danych mogą przechowywać w jakim rejestrze?

Ponad połowa mojej klasy zawiodła naszą klasę montażu, a była to grupa ludzi, którzy w tym czasie uważali się za znających się na programowaniu od ponad 2 lat.

Moją osobistą preferencją, gdybym musiał nauczyć się wszystkiego od nowa, byłoby zacząć od języka, który robi dla mnie jak najwięcej. Następnie, gdy się uczę, przejdź do języków niższego poziomu.


1
Myślę, że to dobra i solidna rada. W pewnym momencie ważne jest, aby zdawać sobie sprawę z bitów i bajtów oraz tego, co robi z nimi procesor, ale rozpoczynanie od nich jest bardzo marnotrawstwem, ponieważ mamy języki takie jak ruby ​​i python, które są idealne dla początkujących i zachęcają do doskonałych zasad inżynierii oprogramowania.
davidk01

1
Czy zastanawiałeś się nad możliwością, że instruktor wykonał mniej niż gwiazdorską pracę w nauczaniu asemblera?
John R. Strohm,

Myślę, że wykonał niesamowitą robotę.
CrazyPenguin,

3

Czy to realistyczny pomysł, przynajmniej dla tych, którzy są gotowi podjąć dodatkowy wysiłek?

Nie

ale można by dobrze zrozumieć maszynę

Dlaczego to jest korzystne? Czy możesz podać przykład lub podpowiedź, w jaki sposób może to mieć jakąkolwiek wartość?

Zalety i wady?

Zalety: brak.

Niedogodności:

  • Zbiór losowych ciekawostek na temat flag i stanów i rejestrów oraz złożonych schematów adresowania pamięci i urządzeń I / O oraz DMA oraz przerwań i cykli zegara i tym podobnych. Żaden z nich nie pomaga zrozumieć współczesnych języków opartych na maszynach wirtualnych i komputerów.

  • Odłączanie od faktycznego rozwiązywania problemów, do których faktycznie stosowane są komputery.

  • Rozwód od użytkowników końcowych oraz praktyczne problemy z danymi i przetwarzaniem, które muszą rozwiązać.

  • Niepotrzebna seria wyjaśnień maszyny i maszyny wirtualnej oraz kompilatora i interpretera oraz całego stosu żółwi trzymających świat.

  • Wiele szczegółowych „jest to fizyczna implementacja„ obiektu ”w języku wyższego poziomu, do którego ostatecznie dochodzą.

  • Wiele szczegółowych „w ten sposób wysyłane są funkcje metod” w języku wyższego poziomu, do którego w końcu dochodzą.

  • Wiele „nie dotyczy to 80386, ale dotyczy wyjaśnień mikroukładu 80586”.

  • Wiele niskopoziomowych wywołań API systemu operacyjnego, aby program ASM zrobił wszystko, co wydaje się być przydatne dla kogoś.

Celem pierwszego języka programowania nie jest opanowanie mikroukładu.

Celem pierwszego języka programowania jest

  1. Dowiedz się, jak myśleć o informatyce.

  2. Dowiedz się, jak wykonać przydatne przetwarzanie danych.

  3. Dowiedz się, jak coś zrobić. Projekt - kod - test.


1
@ S.Lott - Jasne, nie o to chodzi w moim pierwotnym pytaniu, ale warto mieć je przed przejściem na języki wyższego poziomu. Nie zrozum mnie źle, masz rację.
Anto

3
-1 Wiele waszych wad uważam za zalety. Lepiej wiedzieć, jak działa niski poziom, zanim użyjesz go z góry. Fundamenty są ważne.
Orbling

1
Asembler jako język programowania, znacznie lepiej eksponuje strukturę danych, logikę i więcej podstaw niższych poziomów niż języki wyższego poziomu. Oba mają swoje miejsce, asembler może być łatwiejszy do zrozumienia niż języki wyższego poziomu, pod warunkiem, że nie próbujesz osiągnąć niczego zbyt skomplikowanego. Ludzie nie powinni na początku próbować robić skomplikowanych rzeczy.
Orbling

4
Zaletą asemblera jest to, że pokazuje, jak działa prawdziwy komputer. Wiesz. Rzecz, na której właściwie wszystko działa .
Paul Nathan

1
@ S.Lott - Nie, ale to oznacza, że ​​możesz bardzo dobrze wykorzystać większość starej wiedzy, którą zgromadziłeś i z czasem wzbogacić ją. Spójrz, języki wysokiego poziomu, takie jak Python, pojawiają się z czasem z nowymi wersjami, ale stara wiedza jest nadal użyteczna (a właściwie Python zerwał wsteczną kompatybilność z v3)
Anto

3

Gdybym miał za zadanie zaprojektować program nauczania, miałbym dwa kursy prowadzone jednocześnie w pierwszym semestrze: asm + podstawowa organizacja / architektura komputerów oraz kurs oparty na SICP założony w Scheme. Drugi semestr byłby zorientowany na struktury danych i podstawowe algorytmy w schemacie.

Drugi rok byłby całorocznym projektem wykorzystującym jeden z Delphi, C ++ lub C #, skupiającym się na nowoczesnym projektowaniu oprogramowania (projektowanie OO, niektóre projekty funkcjonalne, inżynieria oprogramowania, kontrola wersji itp.).

Efektem powinno być intensywne ugruntowanie zarówno w formie abstrakcyjnej, jak i praktycznej, prowadząc do szczegółowych kursów w trzecim i czwartym roku.


3

Kiedyś chodziłam na wstępne zajęcia z informatyki i myślę, że to zły pomysł.

  1. Asembler używa zarówno logiki (jeśli to już ma), jak i bardzo trudnych tłumaczeń między pojęciami i liczbami. Wstęp CS studenci często zmagają się tylko z logiką (pętle, jeśli / inaczej, wyrażenia logiczne) i naprawdę muszą sobie z tym poradzić, zanim zaczną się martwić, które liczby oznaczają, jakie wyrażenia logiczne. Używanie języków wyższego poziomu wyodrębnia tę logikę dla studentów, którzy nie mieli wcześniej powodu, aby myśleć w ten sposób.
  2. Wstępne klasy CS niekoniecznie są podejmowane tylko przez kierunków CS, którzy będą kontynuować pracę z CS. Często są one również podejmowane przez inne kierunki inżynierskie i inne, które po prostu „zwiedzają” interesujący temat do wyboru. Asembler jest świetny jako podstawa dla twardych, zaangażowanych studentów CS, ale nie daje bardzo dobrego przeglądu tego, co programowanie często jest dla studentów rozważających specjalizację lub tych, którzy nigdy nie zamierzają podjąć specjalizacji, ale chcą wprowadzić się w tę dziedzinę ; nie jest też samodzielnie bardzo przydatny w większości dziedzin.
  3. Języki wyższego poziomu sprawiają, że rdzeń rzeczywistej pracy programistycznej jest bardziej przejrzysty. Asembler trafia na kilka podstawowych zagadnień - podstawowe koncepcje pamięci, podstawowe koncepcje wydajności itp. - ale tak naprawdę nie zajmuje się tworzeniem łatwego do utrzymania, czytelnego projektu, co jest obecnie ważniejsze, IMO. Wydaje się, że wcześni studenci często mają staroświeckie „Prawdziwi programiści piszą kod, z którym nikt inny nie potrafi sobie poradzić”, a nauczanie języka wyższego poziomu pomaga nauczyć, że kodowanie jest zadaniem współpracy, a nie tylko bycia genialnym.

Powiedziawszy to, uważam, że sprzęt montażowy / komputerowy powinien być bardzo wcześnie - najlepiej w pierwszym kwartale. Poproś uczniów, aby umieścili jeden język wysokiego poziomu za pasami, a następnie wskocz do sprzętu niskiego poziomu od razu przed przejściem do struktur danych - najlepiej w języku, który wymaga zarządzania pamięcią.


Bardzo dobrze powiedziane - zgadzam się. Pierwszy kurs musi przejść do sedna, wykazać przydatność zdobywanych umiejętności i uruchomić wyobraźnię: „O rany! Mogę programować? Co jeszcze mogę zrobić z tą nową umiejętnością…” Zgadzam się również, że najlepszy czas na język asemblera to jeden język wyższego poziomu. To motywuje do patrzenia „pod maską” na to, jak komputer rzeczywiście rozumie rzeczy wyższego poziomu. Po raz pierwszy zobaczenie języka asemblera po języku wyższego poziomu pozostawia kolejny potężny wpływ: uczeń napotyka elektronikę, układy scalone, czujniki itp.
Assad Ebrahim

3

Zgromadzenie było moim drugim językiem, zaraz po języku BASIC. Jednak kiedy się uczyłem, był inny czas. W moim Commodore 64 dostępne były inne języki, ale jeśli chcesz, aby coś wydawało się szybkie lub chcesz robić więcej niż jedną rzecz na raz, musisz nauczyć się języka asemblera i obsługi przerwań. System operacyjny środowiska graficznego (GEOS), który nadał Commodore system okienkowy, również został złożony. Był to ogólnie najlepszy interfejs API do montażu, jaki kiedykolwiek widziałem. Była to również jedyna platforma, z której korzystałem, w której można stylizować kod. Zgadza się, możesz użyć kursywy i różnych rozmiarów czcionek - coś, co okazało się przydatne do czytania komentarzy.

Wiele się nauczyłem o działaniu Commodore, ale układ Motorolla miał bardzo prosty zestaw kodów operacyjnych. Nietrudno jest oddzielić od siebie mniej niż 255 kodów. Byłem nie stanie przekształcić moje doświadczenie na Motorolla 6510 chipem do programowania dla Intel 8086. Chipsy i architektur systemowych są zbyt różne. Wyobrażam sobie, że miałbym takie same problemy z przejściem do układu Amolla Motorolla 68000.

Krótko mówiąc, muszę całym sercem nie zgodzić się z każdym, kto twierdzi, że Zgromadzenie powinno być dobrym pierwszym językiem. Dlatego:

  • Nie masz żadnej wewnętrznej struktury ani wspólnego sposobu na rozbicie funkcjonalności aplikacji. To właśnie sprawia, że ​​języki wyższego poziomu są tak przydatne.
  • Musisz wiedzieć bezużyteczne rzeczy, takie jak prawidłowe wywoływanie metody w bibliotece. Kiedy biblioteka została utworzona przez C, oznacza to manipulowanie stosem (lepiej uzyskać wszystko we właściwej kolejności), ale w innym języku może to oznaczać ustawienie rejestrów. To wszystko zajmuje się kompilatorem lub tłumaczem - i nie można ich optymalizować.
  • Twój kod nie może być użyty na innym chipie, i najprawdopodobniej zepsuje się na innej platformie sprzętowej.

Obecnie język asemblera jest używany do przyspieszenia niektórych skończonych akcji, w których ręcznie wykonany zestaw byłby szybszy niż zestaw generowany przez kompilator. Główna struktura aplikacji jest wykonywana w języku wyższego poziomu, takim jak C, C ++ itp. Oczywiście, programowanie asemblacyjne stałoby się bardzo ważne, jeśli zaczniesz pisać kompilatory. Ilu z nas to robi?


1

Wziąłem montaż w moim starszym roku liceum. Brałem już zajęcia w Javie, Pascalu, C i C ++, i nie byłem biegły w żadnym z nich, i naprawdę byłem do niczego przy Zgromadzeniu - byłem jedyną osobą, która brała udział w programie nauczania na odległość w college'u społecznościowym, zabrała mnie miesiąc czy dwa, zanim ktokolwiek zdoła uruchomić kompilator dla mnie.

Nie wydaje mi się, aby najpierw trzeba było się uczyć języka asemblera, ale mądrze jest nauczyć się tego, czego uczą się w pierwszych tygodniach montażu, o tym, jak działa procesor i niektórych sztuczkach debugowania. Te rzeczy uważałem za bardzo interesujące i pouczające jako neofita.


0

Nie rozumiem, dlaczego nie można tego zrobić, chociaż to, jak dobry jest ten pomysł, zależy od tłumu, którego byś go nauczył. Ktoś, kogo celem jest bycie programistą, prawdopodobnie się nudzi i może zrezygnuje, ponieważ nie dałoby im to natychmiastowej satysfakcji z tworzenia czegoś takiego, jak Python, Ruby itp. Jeśli chcą w końcu pracować na sprzęcie lub innych projektach niskiego poziomu, myślę, że byłby to dobry początek (pod warunkiem, że podasz wystarczającą ilość architektury komputera, aby miało to sens). Myślę, że może to pomóc ludziom w pisaniu lepszego kodu w przyszłości, chociaż myślę, że byłoby to trudniejsze niż nauka innych języków na początku.


0

Myślę, że język asemblera będzie miał sens tylko wtedy, gdy skupisz się na takich rzeczach jak:

  • Techniki zarządzania pamięcią
  • HW IO (zwłaszcza wyzwania związane z czasem i wydajnością)
  • Funkcje procesora - w szczególności funkcje bezpieczeństwa

Bez skupienia się na tym obszarze, jest to po prostu uproszczony język, który będzie uczył złych nawyków organizacyjnych. Kodowanie na poziomie maszyny dobrze jest mieć w zestawie narzędzi, aby wiedzieć, jak to działa, ale nie jest to dobry pierwszy język.

Zainteresowałbym kogoś językiem wyższego poziomu. Następnie naucz C ++; następnie asembler z naciskiem na to, jak kompilatory C ++ generują kod asemblera. Zrozumienie tabel v-v i innych funkcji językowych na wyższym poziomie znacznie pomoże deweloperowi pomyśleć o tym, jak naprawdę działają języki, niż po prostu zapisując informacje w „magii”.

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.