Pantera Śnieżna w Sierra Nevada

W ubiegłym tygodniu przytrafiła mi się sposobność aktualizowania systemu operacyjnego na iMacu. Na pierwszy rzut oka mogło by się wydawać, że zadanie jest trywialne i polega na kliknięciu jednego przycisku w AppStore, jednak czynnikiem podnoszącym poziom trudności okazała się różnica numerów wersji, którą trzeba było pokonać.

Na warsztacie:

  • iMac 27″ z końca 2009 roku (symbol iMac11,1)
  • zainstalowany system Mac OS X 10.6 Snow Leopard z 2011 roku
  • docelowy system macOS Sierra 10.12.6 z 2017 roku

Podejście pierwsze

Po wejściu do działu aktualizacji systemu w AppStore wyświetliła się propozycja automatycznej instalacji macOS Sierra. Niestety, próba jej uruchomienia zakończyła się komunikatem, że wymagane jest posiadanie co najmniej OS X w wersji 10.7.5 Lion. Nie było nigdzie jednak wyjaśnione, w jaki sposób podnieść 10.6 do 10.7.

Pomyślałem, że można by spróbować zdobyć obraz płyty instalacyjnej macOS Sierra, wystartować z niej komputer i zainstalować system „na czysto”. W odmętach internetu znalazłem plik w formacie PKG, niestety za nic w świecie nie dawał się rozpakować na 10.6, ani wbudowanym domyślnym archiwizatorem ani komendami w terminalu (pkgutil, xar, tar, zip).

Podejście drugie

Zdecydowałem się na pójść inną drogą i zacząć od instalacji OS X 10.7 Lion. Z nieoficjalnych źródeł w internecie pobrałem obraz płyty, która w przeciwieństwie do PKG z Sierrą pozwoliła się rozpakować i uruchomić. Niestety, w połowie wgrywania plików wyświetlił się błąd pakietu i aktualizacja została przerwana.

Należy tu nadmienić, że wewnątrz każdej aplikacji instalującej system znajduje się plik InstallESD.dmg, który jest obrazem dysku zawierającym samodzielny instalator z partycją startową EFI. Przy pomocy wbudowanego w 10.6 narzędzia dyskowego wgrałem plik DMG na pendrive i uruchomiłem iMaca z USB (klawisz Option podczas startu).

Ponownie, w połowie aktualizacji pojawił się błąd informujący o uszkodzonym pakiecie i proces kopiowania się zatrzymał. Po restarcie, uruchomił się co prawda stary system 10.6, jednakże ciężko go już było móc określać mianem stabilnego. W szczególności Finder wykazywał dziwne skłonności do zawieszania się co chwilę. W tym momencie wiadomo już było, że Pantera Śnieżna skrzyżowana z chorym Lwem nie wydała zdrowego potomstwa.

Podejście trzecie

Przesiadłem się na inny komputer z zainstalowanym Windows w celu znalezienia lepszego źródła 10.7. Jako, że i tak Lion miał być tylko krokiem przejściowym, potrzebowałem czegoś co się da zainstalować na chwilę i co pozwoli na pobranie oficjalnego instalatora 10.12 z AppStore.

Do trzech razy sztuka. Pobrałem nowy obraz dysku 10.7, wypakowałem z niego plik InstallESD.dmg i ze względu na to, że nie ufałem już systemowi działającemu na iMacu, startowy pendrive przygotowałem pod Windows przy pomocy programu TransMac (trial).

Po wystartowaniu iMaca z USB, sformatowaniu dysku twardego (przy okazji podzieliłem go na dwie partycje HFS+ i ExFAT) i czystej instalacji od zera, miałem w końcu dostęp do działającego OS X Lion.

Czas na Sierrę

To nie koniec problemów. Po wejściu do AppStore i uruchomieniu procesu pobierania macOS Sierra, znów wyświetlił się komunikat o braku odpowiedniej wersji systemu operacyjnego. Na szczęście chodziło tylko o różnicę w ostatniej cyfrze i dało się to naprawić pobierając 2GB aktualizacji od Apple.

Po kolejnym restarcie, wszystkie wymagania instalatora 10.12 zostały wreszcie spełnione.

Tym razem AppStore nie protestował i pobrał 5GB oficjalnej paczki z macOS Sierra, którą na wszelki wypadek skopiowałem sobie od razu na zewnętrzny dysk. Plan był taki, żeby przygotować nowy pendrive startowy i wgrać ostateczny system na czysty dysk, bez żadnych śladów po Lionie z nieoficjalnego źródła.

DMG jak damage

Niestety, narzędzie dyskowe z 10.7.5 nie potrafiło zapisać pliku InstallESD.dmg z 10.12 na USB.

Wyświetlał się komunikat o konieczności przeskanowania obrazu dysku, po czym po chwili występował „błąd wewnętrzny”.

Próba utworzenia dysku z poziomu terminala, przy pomocy zawartego w pakiecie programu „createinstallmedia” kończyła się dosłownie niczym, po wprowadzeniu hasła administratora system wracał bez słowa do znaku zachęty wiersza polecenia.

Nawet nagranie DMG przez TransMac z poziomu Windows nie dawało pozytywnych rezultatów. Przygotowany w ten sposób pendrive nie był widziany na liście dostępnych dysków startowych podczas uruchamiania iMaca.

Sierrę Lionem, Sierrę Sierrą

Pozostało pozwolić AppStore, żeby uruchomił instalator Sierry pod kontrolą Liona. Niespodziewanie, proces aktualizacji przebiegł bez najmniejszych problemów i po restarcie uruchomił się system w wersji 10.12.5.

To jednak nie wszystko. Ze względu na to, że na dysku wciąż znajdowały się pozostałości po 10.7, zdecydowałem się jeszcze raz spróbować utworzyć pendrive, by móc uruchomić z niego iMaca i wgrać 10.12 na sformatowaną partycję.

Naturalnie, cały pakiet instalacyjny został automatycznie usunięty od razu po aktualizacji, ale na szczęście miałem jego kopię na zewnętrznym dysku. Tutaj czekała na mnie kolejna niespodzianka, komenda „createinstallmedia” tym razem dała się uruchomić w terminalu i poprawnie wykonała swoje zadanie.

Dalej już było z górki. Restart z wciśniętym klawiszem Option, wybranie startowego dysku USB, format dysku, utworzenie partycji, instalacja systemu, restart, wstępna konfiguracja i gotowe.

Koniec?

Jaka była pierwsza rzecz, którą zgłosił macOS Sierra po uruchomieniu i podłączeniu do internetu? Że akurat tego dnia (20 lipca 2017) została wydana wersja 10.12.6 i należy uruchomić aktualizację…

Instalacja edytora Unity 3D w Linuxie

Pod koniec 2015 roku, Unity Technologies wydało pierwszą, testową wersję edytora Unity 3D dla systemu Linux. Od tamtego momentu minęło już trochę czasu i można powiedzieć, że większość początkowych problemów zostało już usuniętych, dzięki czemu aplikacja nadaje się do poważnej pracy.

W poniższym przykładzie zainstalujemy wersję 2017.2.0 Beta 2 na Ubuntu.

Przygotowania

Pierwszą rzeczą którą należy sprawdzić, to wersja OpenGL obsługiwana przez nasz system. Unity wymaga co najmniej OpenGL 3.2 i w przypadku jego braku będzie zamykane z błędem w momencie dodawania nowego obiektu do sceny albo w ogóle się nie uruchomi.

Wpisujemy w terminalu komendę „glxinfo -B” (pakiet Mesa 3D) i szukamy numerów wersji. W moim przypadku:

name of display: :1
display: :1  screen: 0
direct rendering: Yes
Extended renderer info (GLX_MESA_query_renderer):
    Vendor: Intel Open Source Technology Center (0x8086)
    Device: Mesa DRI Intel(R) Ivybridge Mobile  (0x166)
    Version: 17.1.2
    Accelerated: yes
    Video memory: 1536MB
    Unified memory: yes
    Preferred profile: core (0x1)
    Max core profile version: 4.2
    Max compat profile version: 3.0
    Max GLES1 profile version: 1.1
    Max GLES[23] profile version: 3.0
OpenGL vendor string: Intel Open Source Technology Center
OpenGL renderer string: Mesa DRI Intel(R) Ivybridge Mobile 
OpenGL core profile version string: 4.2 (Core Profile) Mesa 17.1.2
OpenGL core profile shading language version string: 4.20
OpenGL core profile context flags: (none)
OpenGL core profile profile mask: core profile
OpenGL version string: 3.0 Mesa 17.1.2
OpenGL shading language version string: 1.30
OpenGL context flags: (none)
OpenGL ES profile version string: OpenGL ES 3.0 Mesa 17.1.2
OpenGL ES profile shading language version string: OpenGL ES GLSL ES 3.00

Pomimo tego, że linia „OpenGL version” wskazuje na 3.0, Unity automatycznie wybierze profil „core” i uruchomi się w trybie 4.2.

Domyślnym edytorem kodów źródłowych w Unity jest MonoDevelop, które jest co prawda zawarte w pakiecie instalacyjnym, ale ze względu na lepszą integrację z systemem wygodniej jest używać wersji dostępnej w oficjalnym repozytorium. Uruchamiamy z poziomu administratora:

apt install mono-complete mono-reference-* monodevelop

Instalacja

Lista wszystkich dostępnych paczek znajduje się na forum Unity w wątku „Unity on Linux: Release Notes and Known Issues„. Znajdujemy interesujący nas Build #20170707 i pobieramy:

wget http://beta.unity3d.com/download/b6e0e521da90/unity-editor_amd64-2017.2.0b2.deb

Przy pomocy komendy „dpkg –info unity-editor_amd64-2017.2.0b2.deb” możemy sprawdzić, jakie dodatkowe pakiety będą potrzebne do uruchomienia programu:

Package: unity-editor
Version: 2017.2.0b2
Architecture: amd64
Maintainer: Linux Team <linux-team@unity3d.com>
Installed-Size: 7895832
Depends: debconf (>= 0.5) | debconf-2.0, gconf-service, lib32gcc1 (>= 1:4.1.1), lib32stdc++6 (>= 4.6), libasound2 (>= 1.0.23), libc6 (>> 2.15), libc6-i386 (>= 2.15), libcairo2 (>= 1.6.0), libcap2 (>= 2.10), libcups2 (>= 1.4.0), libdbus-1-3 (>= 1.2.14), libexpat1 (>= 1.95.8), libfontconfig1 (>= 2.8.0), libfreetype6 (>= 2.3.9), libgcc1 (>= 1:4.1.1), libgconf-2-4 (>= 2.31.1), libgdk-pixbuf2.0-0 (>= 2.22.0), libgl1-mesa-glx | libgl1, libglib2.0-0 (>= 2.31.8), libglu1-mesa | libglu1, libgtk2.0-0 (>= 2.24.0), libnspr4 (>= 1.8.0.10), libnss3 (>= 3.14.3), libpango1.0-0 (>= 1.22.0), libstdc++6 (>= 4.6), libx11-6 (>= 2:1.4.99.1), libxcomposite1 (>= 1:0.3-1), libxcursor1 (>> 1.1.2), libxdamage1 (>= 1:1.1), libxext6, libxfixes3, libxi6 (>= 2:1.2.99.4), libxrandr2 (>= 2:1.2.99.2), libxrender1, libxtst6, zlib1g (>= 1:1.1.4), libpng12-0 | libpng16-16, libpq5, lsb-release, xdg-utils, npm
Recommends: ffmpeg | libav-tools, nodejs, java6-runtime, gzip, monodevelop, java7-jdk | java7-sdk, mono-reference-assemblies-2.0, mono-reference-assemblies-3.5
Section: devel
Priority: optional
Homepage: http://unity3d.com

Instalacja pliku DEB przy pomocy dpkg nie bierze pod uwagę wymaganych zależności, trzeba ją więc uzupełnić o wywołanie komendy apt. Z poziomu administratora:

dpkg -i unity-editor_amd64-2017.2.0b2.deb
apt install -f

To wszystko, Unity zostało zainstalowane w katalogu /opt i jest gotowe do pracy.

Dodatkowe informacje na temat działania i ewentualnych problemów na które natrafili użytkownicy, znajdują się na forum w dziale „Linux Editor„.

Konfiguracja libGDX w IntelliJ IDEA

Utworzenie nowego projektu opartego na bibliotece libGDX i wczytanie go do IntelliJ IDEA nie sprawia większych problemów, jednak ze względu na integrację z Gradle oraz fakt, że na początku nie wszystko konfiguruje się automatycznie, należy pamiętać o wykonaniu wszystkich wymaganych kroków.

Poniższy przykład wykorzystuje:

  • IntelliJ IDEA w wersji 2017.1.4
  • libGDX w wersji 1.9.6
  • Android SDK z API 20 oraz Build Tools 23.0.1
  • system operacyjny Linux (Ubuntu)

Instalator libGDX

Zaczynamy od pobrania i uruchomienia najnowszej wersji instalatora libGDX ze strony www.

cd ~/Pobrane
wget https://libgdx.badlogicgames.com/nightlies/dist/gdx-setup.jar
java -jar gdx-setup.jar

Następnie podajemy instalatorowi kilka podstawowych informacji o projekcie:

Name: nazwa aplikacji (zostanie zapisana do pliku build.gradle jako allprojects.ext.appName oraz do android/res/values/strings.xml jako app_name)

Package: unikatowa nazwa pakietu dla aplikacji, zgodna ze standardem Java

Game class: główna klasa aplikacji, która będzie w zależności od platformy uruchamiana przez DesktopLauncher lub AndroidLauncher (zostanie utworzona w katalogu core/nazwa_pakietu)

Destination: docelowy katalog, w którym zostanie utworzony projekt

Android SDK: katalog z zainstalowanym Android SDK

Sub Projects: docelowe platformy, na które będziemy kompilować aplikację (w tym przypadku zostawiamy tylko Desktop i Android)

Extensions: opcjonalne biblioteki, z których będzie dodatkowo korzystać aplikacja (ten przykład nie wykorzystuje żadnej z nich)

Show Third Party Extensions: kolejna lista dodatkowych bibliotek, których na razie nie będziemy używać

Advanced: opcje zaawansowane, możemy zostawić je wyłączone

Przed kliknięciem przycisku Generate, warto się jeszcze upewnić, że mamy zainstalowany Android SDK w odpowiedniej wersji. Minimalne zalecane wersje można znaleźć na stronie libGDX:

Wersje zainstalowane w systemie sprawdzamy przy pomocy skryptu znajdującego się w katalogu Android SDK ($ANDROID_HOME/tools/bin):

$ANDROID_HOME/tools/bin/sdkmanager --list

W moim przypadku:

Installed packages:
  Path                        | Version | Description                       | Location                    
  -------                     | ------- | -------                           | -------                     
  build-tools;23.0.1          | 23.0.1  | Android SDK Build-Tools 23.0.1    | build-tools/23.0.1/         
  build-tools;25.0.2          | 25.0.2  | Android SDK Build-Tools 25.0.2    | build-tools/25.0.2/         
  build-tools;26.0.0          | 26.0.0  | Android SDK Build-Tools 26        | build-tools/26.0.0/         
  emulator                    | 26.0.3  | Android Emulator                  | emulator/                   
  extras;android;m2repository | 47.0.0  | Android Support Repository, re... | extras/android/m2repository/
  extras;google;m2repository  | 54      | Google Repository                 | extras/google/m2repository/ 
  patcher;v4                  | 1       | SDK Patch Applier v4              | patcher/v4/                 
  platform-tools              | 26.0.0  | Android SDK Platform-Tools        | platform-tools/             
  platforms;android-20        | 2       | Android SDK Platform 20, rev 2    | platforms/android-20/       
  platforms;android-25        | 3       | Android SDK Platform 25           | platforms/android-25/       
  sources;android-20          | 1       | Sources for Android 20            | sources/android-20/         
  sources;android-25          | 1       | Sources for Android 25            | sources/android-25/         
  tools                       | 26.0.2  | Android SDK Tools                 | tools/

Uruchamiamy generowanie projektu i czekamy na rozwój wydarzeń. Istnieje duże prawdopodobieństwo, że pojawi się nam ostrzeżenie:

Wybranie „No” spowoduje wymuszenie korzystania z narzędzi w wersji 23.0.1.

Analogicznie, kolejne pytanie będzie dotyczyło wersji API:

Wybranie „No” wymusi API 20.

W przypadku, gdy zdecydujemy się później na zmianę tych ustawień, wystarczy poprawić pliki w katalogu projektu:

android/AndroidManifest.xml:

<uses-sdk android:minSdkVersion="9" android:targetSdkVersion="20" />

android/build.gradle:

android {
    buildToolsVersion "23.0.1"
    compileSdkVersion 20

[...]

    defaultConfig {
        minSdkVersion 9
        targetSdkVersion 20

Parametr minSdkVersion oznacza minimalną wersję systemu Android, na którym będzie można uruchomić aplikację. W przypadku libGDX jest to API 9 czyli Android 2.3 GINGERBREAD.

Po chwili projekt powinien być gotowy:

Wczytanie do IntelliJ IDEA

Kierując się podpowiedzią z instalatora, w głównym oknie IntelliJ IDEA wybieramy „Open” i wskazujemy plik build.gradle.

Następnie potwierdzamy, że chcemy go otworzyć jako projekt.

W ustawieniach importu Gradle ważne jest odznaczenie opcji „Create separate module per source set”.

Wszystkie moduły zostawiamy włączone.

Teraz musimy poczekać, aż wszystkie pliki zostaną zindeksowane. Dymkami z informacjami nie musimy się na razie przejmować.

Na liście konfiguracji powinien pojawić się „android”. Cel „desktop” trzeba dodać ręcznie.

W edytorze konfiguracji klikamy zielony plus i wybieramy „Application”.

Jako „Main class” wskazujemy klasę DesktopLauncher.

Katalog „Working directory” jest wspólny dla obu platform i powinien wskazywać na „android/assets”. W „Use classpath of module” wybieramy moduł desktop.

W podobny sposób, możemy sobie dodać skróty do zadań zdefiniowanych w Gradle:

Zadanie „clean” usuwa wszystkie pliki powstałe podczas kompilacji projektu:

Analogicznie możemy dodać android -> assembleRelease tworzące plik APK dla Androida (przed opublikowaniem trzeba go jeszcze podpisać cyfrowo).

Zadanie desktop -> dist tworzy paczkę JAR zawierającą wszystkie elementy potrzebne do uruchomienia projektu na Linux/Windows/MacOS.

Tak ostatecznie wygląda przykładowa lista konfiguracji:

Uwagi

Plugin Gradle dołączany do libGDX nie jest najnowszy, więc prędzej czy później wyświetli się nam komunikat z propozycją aktualizacji. Wystarczy kliknąć Update i poczekać na zakończenie instalacji.

Jeżeli korzystamy z dodatku FindBugs, podczas weryfikowania projektu pojawi się ostrzeżenie o błędach w generowanym automatycznie pliku R.java. Jako, że nie mamy wpływu na jego zawartość, najlepiej dodać go do wyjątków.

Listy wykluczeń są zapisywane w formacie XML a ich położenie można znaleźć w konfiguracji dodatku FindBugs w zakładce Filter.

Przykładowy plik findbugs-android-exclude.xml:

<?xml version="1.0" encoding="UTF-8"?>
<FindBugsFilter>
    <Match>
        <Or>
            <Class name="~.*\.R\$.*"/>
            <Class name="~.*\.Manifest\$.*"/>
        </Or>
    </Match>
</FindBugsFilter>

To w zasadzie wszystko. Możemy rozpocząć pracę nad naszą aplikacją.

Polecane wtyczki do IntelliJ IDEA

Save Actions

Jedną z funkcjonalności, które są dostępne w Eclipse a których brakuje w IntelliJ IDEA, jest możliwość automatycznego wykonywania wybranych czynności przed zapisaniem pliku w edytorze. Tę niedoskonałość rozwiązuje plugin Save Actions.

Configure -> Plugins -> Browse repositories -> Save Actions:

W podstawowej konfiguracji, dodatek zatroszczy się o usunięcie nieużywanych importów oraz sformatowanie kodu zgodnie ze standardami ustawionymi w Settings -> Editor -> Code Style.

FindBugs

FindBugs to jeden z najlepszych darmowych analizatorów statycznych kodu źródłowego dla języka Java. Dzięki regularnie aktualizowanej liście reguł i zasad pozwala na wykrycie potencjalnych błędów w programie jeszcze przed jego uruchomieniem.

Configure -> Plugins -> Browse repositories -> FindBugs:

Po zainstalowaniu pluginu, aktywujemy dodatkowe źródła reguł w zakładce General -> Plugins:

Włączanie i wyłączanie pojedynczych reguł znajduje się w zakładce Detector:

Proponuję włączyć wszystkie i przeskanować swój kod a później ewentualnie zdecydować na jakie ustępstwa od narzuconych zasad się godzimy i dezaktywować tylko te wybrane.

Wstępna konfiguracja IntelliJ IDEA

Moją przygodę z programowaniem w Java zacząłem w środowisku Eclipse, jednak po tym jak w 2013 roku Google wydało Android Studio oparte na IntelliJ IDEA, zdecydowałem się na przesiadkę. Początkowo na nowej platformie brakowało mi kilku elementów z których korzystałem wcześniej, ale na szczęście dodatki dostępne w oficjalnym repozytorium rozwiązały te problemy.

Instalacja

Instalacja IntelliJ IDEA w systemie Linux nie sprawia większych problemów. Na początku musimy zadbać o dostępność środowiska Java. W przypadku Ubuntu, uruchamiamy z poziomu administratora:

apt install default-jre default-jdk

Następnym krokiem jest pobranie najnowszej wersji IntelliJ IDEA ze strony JetBrains (w moim przypadku 2017.1.4 Community Edition w formacie TAR.GZ) i rozpakowanie jej do docelowego katalogu.

cd /opt
wget https://download-cf.jetbrains.com/idea/ideaIC-2017.1.4.tar.gz
tar xvfz ideaIC-2017.1.4.tar.gz
mv idea-IC-171.4694.23 idea
chmod a+rX -R idea

Po przelogowaniu się na użytkownika ze standardowymi uprawnieniami, uruchamiamy program:

/opt/idea/bin/idea.sh

Pierwsze ekrany akceptujemy w zasadzie bez żadnych zmian (najodważniejsi oraz osoby o skłonnościach masochistycznych mogą sobie włączyć plugin emulujący edytor VIM). Konfigurator utworzy skrót do uruchamiania programu z poziomu systemowego menu, dzięki czemu później nie trzeba będzie pamiętać o położeniu pliku idea.sh.

Jeżeli wszystko pójdzie zgodnie z planem, zobaczymy ekran startowy:

Ustawienia

Na początku, proponuję wyłączyć opcję automatycznego otwierania ostatniego projektu po uruchomieniu programu. W przypadku, gdy planujemy utworzyć nowy projekt lub pracować na innym niż poprzednio, zaoszczędzi nam to trochę czasu.

Configure -> Settings -> Apperance & Behavior -> System Settings:

Każdy nowy plik źródłowy dodawany do projektu powinien zaczynać się od komentarza z informacjami na jego przeznaczenia, autora oraz warunków licencji. W ustawieniach IntelliJ IDEA możemy przygotować szablony takich bloków, które później będą wstawiane do kodu:

Configure -> Settings -> Editor -> Copyright-> Copyright Profiles:

Configure -> Settings -> Editor -> Copyright:

Konfiguracja SDK

Przed skompilowaniem i uruchomieniem pierwszego programu, należy skonfigurować SDK.

Configure -> Project Defaults -> Project Structure:

Z listy SDKs wybieramy JDK (Java Development Kit) i znajdujemy katalog na dysku z zainstalowanym środowiskiem.

W moim przypadku, ścieżką do najnowszej zainstalowanej Javy jest /usr/lib/jvm/default-java wskazującą na katalog OpenJDK w wersji 1.8.

Przy okazji możemy podpiąć SDK pozwalające na tworzenie aplikacji na Androida. Analogicznie jak wyżej, wybieramy Android SDK i wskazujemy katalog w którym znajdują się biblioteki (naturalnie wcześniej trzeba je zainstalować np. z Android Studio).

Build Target to wersja API dla której będą kompilowane aplikacje.

Na koniec, w polu Project SDK ustawiamy domyślne SDK które będzie wykorzystywane w naszych projektach.

Po tych krokach, IntelliJ IDEA jest gotowa do pracy.

Wirtualne zakupy dla naiwnych

Niedawno, przeglądając galerię coraz to bardziej wymyślnych bannerów reklamowych, trafiłem na stronę promującą kolejny rewolucyjny specyfik przeciwzmarszczkowy. Profesor, który firmuje go swoim nazwiskiem ma prawdopodobnie grubo ponad 100 lat, biorąc pod uwagę fakt, że dzięki swoim magicznym kremom na zdjęciu wygląda na 70-latka.

Nie to jednak zainteresowało mnie na jego stronie. Zgaduję, że dotychczasowe metody przekonywania potencjalnych klientów do złożenia zamówienia straciły na skuteczności i zwykłe wychwalanie produktu nie zdawało już egzaminu, dział marketingu zdecydował się więc na nowatorskie posunięcie. Na stronie umieszczony został popup, wyświetlający co chwilę informacje o rzekomych kolejnych zamówieniach. Co bowiem lepiej przekonuje do zakupu, niż świadomość że inni już się zdecydowali? Na dodatek, gdy zrobili to „przed chwilą”, bądź „minutę temu” a przeglądających witrynę jest aktualnie ponad 200 osób.

Sęk w tym, że po załadowaniu strona nie wykonuje już żadnych zapytań do serwera, skąd zatem ma nowe informacje na temat zamówień? Odpowiedzią jest skrypt odpowiedzialny za generowanie treści wyświetlanej w okienku, umieszczony bez najmniejszej żenady w nagłówku kodu strony. Oto jego fragment:

var locali_mian = new Array("Warszawa", "Kraków", "Poznań", "Szczecin", "Radom", "Gdańsk", "Giżycko", "Szczawnica", "Łódź", "Kielce", "Żywiec", "Zakopane", "Lublin", "Jelenie Góra" , "Szklarska Poręba", "Malbork" ,"Tarnów", "Bytom", "Pisz", "Ryn", "Brodnica", "Ełk", "Legnica");

var locali_dop = new Array("z Ciechanowa", "z Radomia", "z Mińska Maz.", "z Warki", "z Torunia", "z Przemyśla", "z Warszawy", "z Katowic", "z Wrocławia", "z Gdyni", "z Bydgoszczy", "z Sopotu", "z Łomży", "z Koszalina" , "z Suwałk", "z Legionowa", "z Zamościa", "z Rzeszowa" , "z Sanoka", "z Krosna" , "z Darłowa",
"z Warszawy", "z Krakowa", "z Poznania", "ze Szczecina", "z Radomia", "z Gdańska", "z Giżycka", "ze Szczawnicy", "z Łodzi", "z Kielc", "z Żywca", "z Zakopanego", "z Lublina", "z Jeleniej Góry" , "ze Szklarskiej Poręby", "z Malborka" ,"z Tarnowa", "z Bytomia",  "z Rynu", "z Brodnicy", "z Legnicy");

var locali_ppl2 = new Array("panią Anię", "panią Katarzynę", "panią Marię", "panią Mariannę", "panią Marzenę", "panią Ewę", "panią Grażynę", "panią Ludmiłę", "panią Weronikę", "panią Zofię", "panią Czesławę", "panią Alicję", "panią Paulinę", "panią Krystynę", "panią Ilonę", "panią Barbarę", "panią Bożenę",
"pana Mariana", "pana Henryka", "pana Miłosza", "pana Marka", "pana Dariusza", "pana Macieja", "pana Romana", "pana Wiesława", "pana Piotra", "pana Jana"
);

var locali_ppl = new Array(
"pani Ania", "pani Alicja", "pani Agata", "pani Agnieszka",
"pani Barbara", "pani Bożena",
"pani Czesława",
"pani Daria", "pani Danuta",
"pani Ewa", "pani Edyta", "pani Ewelina",
"pani Grażyna",
"pani Halina", "pani Hanna",
"pani Ilona", "pani Izabela", "pani Iwona",
"pani Krystyna", "pani Katarzyna",
"pani Ludmiła",
"pani Maria", "pani Marianna", "pani Marzena",
"pani Natalia",
"pani Paulina",
"pani Sonia",
"pani Teresa",
"pani Urszula",
"pani Weronika",
"pani Zofia", "pani Zuzanna",
"pan Adam", "pan Andrzej",
"pan Bartosz", "pan Bogusław",
"pan Dariusz",
"pan Edward",
"pan Henryk",
"pan Jan", "pan Janusz",
"pan Marian", "pan Miłosz", "pan Marek", "pan Maciej",
"pan Piotr", "pan Paweł",
"pan Roman",
"pan Wiesław"
);

var init_usrs = Math.floor((Math.random()*100)+200);
var buyers = new Array();

[...]

function genPpl()
{
  var peopl_diff = Math.floor((Math.random()*40));
  msg ="W tym momencie na stronie jest "+(init_usrs+peopl_diff)+' '+"użytkowników";
  $.pnotify({
      title: '',
      text: msg,
      animation: 'fade',
      type: 'success',
      addclass: "stack-bottomright",
      stack: stack_bottomright
    });
  setTimeout(genPpl, 60000);
}

function genBuy()
{
  //alert('smth');
  var where = Math.floor((Math.random()*locali_dop.length));
  var who = Math.floor((Math.random()*locali_ppl.length));
  var when = new Date().getTime();

  var temp_buy = new Array(when, who, where);
  buyers.push(temp_buy);
  showLast3Buyers();

  setTimeout(genBuy, Math.floor((Math.random()*30000)+15000));
}

function showLast3Buyers()
{
  var lastBuys='';
  var l = buyers.length;

  for(var i=0; i&lt;3; i++){
    if(l&gt;i)
    {
      var time = new Date().getTime() - buyers[l-i-1][0];
      var time_in_sec = Math.floor(time/1000);
      var time_str= '';
      if(time_in_sec&lt;3)
        time_str ="przed chwilą"
      else
      if(time_in_sec&gt;60)
      {
        var time_in_min = Math.floor(time_in_sec/60);
        time_in_sec -= time_in_min*60;
        time_str = time_in_min+ "min. "+time_in_sec+' '+"sekund temu"
      }
      else
        time_str = time_in_sec+' '+"sekund temu"
      lastBuys +=  time_str + ' '+ locali_ppl[buyers[l-i-1][1]]+' '+ locali_dop[buyers[l-i-1][2]]+" ";
    }
  }

  $.pnotify({
      title: "Ostatnio dokonane zakupy:",
      text: lastBuys,
      animation: 'fade',
      type: 'success',
      addclass: "stack-bottomright",
      stack: stack_bottomright
  });
  //setTimeout(showLast3Buyers, 30000);
}

Pogratulować pomysłowości.