piątek, 21 października 2011

How to set a bit(s) [AVR programming]

We want to set pins 0,2,5 to low and 1,3,4,6,7 to high.

How?
  • Binary number (works only on certain gcc compilers)
    PORTD = 0b11011010;
  • Hexadecimal number
    PORTD = 0xDA;
Changing a value of a specific bit to high. Let’s assume, our register looks like PORTD: 11011010 and we want only to change the value of the 2nd bit to one. We can use Boolean algebra disjunction like
PORTD |= (1 << bit_number);
In this case:
// set second bit high
PORTD |= (1 << 2);
11011010
00000100 |
11011110 (result)

We can also change several bits at the same time:
// sets pin 4 and 5 to logical one
PORTD |= (1 << 4) | (1 << 5);
Changing a value of a specific bit to low. It works almost the same as in the example above, except that logical conjunction and negation is used. When changing 3rd bit of PORTD to zero, the pattern looks like:
PORTD &= ~(1 << bit_number);
So: 
//sets third bit low
PORTD &= ~(1 << 3);
11011010
11110111 &
11010010 (result)

To change more than one bit, we use:
// sets pins 6 and 7 to logical zero
PORTD &= ~((1 << 6) | (1 << 7));

How to read a bit state? [AVR programming]

You can accomplish this in two simple ways - by using special functions like bit_is_set(Register,Bit number) / bit_is_clear(Register, Bit number) or by using some basic boolean algebra. First function  examines whether a bit is set, it returns a non-zero value if true. Second, works quite similar – it returns  zero when a bit is set, other values if it has been deleted. When using Boolean algebra, a basic knowledge of ANSI C programming is needed. This way is highly recommend, because any external library isn’t required – just regular C syntax.

Take a look at those examples:
// Check if a third bit of PORTD register is high 
//(instruction below return true if so)
bit_is_set(PORTD,3); // first option
PORTD & (1 << 3); // second option 
How does it works?
Let’s assume that PORTD looks like 11011010. There is high state on pins 1,3,4,6,7 and low on the rest.  If we want to check if pin 3 is active (high state) we must perform left bit shifting like 1 << 3 and examine the logical conjunction of those two.  

    11011010
& 00001000
    00001000

Which equals to decimal 8 (non-zero) – that means the third bit is set.

wtorek, 19 lipca 2011

Jaki jest twój japoński adres?

Ostatnio dowiedziałem się o fakcie, który nieźle zamieszał mi w głowie... 

Wyobraźmy sobie dwie sytuacje.

Sytuacja 1.

Stoisz przed Galerią Centrum na ulicy Marszałkowskiej w Warszawie i czekasz na znajomego. ­W pewnym momencie podchodzi do ciebie Japończyk i pyta się "Jaki jest numer tego kwartału?" (czerwony znak zapytania).


Nieco zmieszany, prosisz go, aby powtórzył pytanie, bo nie do końca zrozumiałeś o co chodzi. Azjata powtarza i wyjaśnia, że chciałby poznać adres miejsca w którym razem teraz stoicie. Załapałeś o co chodzi i kompleksowo zaczynasz mu opisywać - "Znajdujesz się przed budynkiem Galerii Centrum Wars-Sawa, który ograniczony jest przez ulicę Marszałkowską, Złotą i Chmielną..." Japończyk przerywa ci z miną wyrażającą nieporozumienie i prosi o powtórne wyjaśnienie. Zaczynasz się trochę irytować, ale powtarzasz to samo co powiedziałeś przed chwilą. Widzisz jednak, że turysta dalej nie ma pojęcia o co chodzi, ale odchodzi, nie chcąc sprawiać ci dalszego kłopotu.

Czy powiedziałeś coś nie tak?

Sytuacja 2.

Zgubiłeś się w Tokio. Jesteś na skrzyżowaniu (w punkcie oznaczonym czerwoną kropką) i pytasz się pierwszego przechodnia o swoje położenie, żebyś mógł je wpisać do mapy, którą masz w telefonie.



Pierwszy napotkany mieszkaniec, uśmiecha się i grzecznie odpowiada, że znajdujesz się w okręgu 5, między kwartałami 16, 17, 21 i 14.  Otwierasz szeroko oczy nie wiedząc co powiedzieć. Mieszkaniec widząc to zdziwienie powtarza to co powiedział, a następnie widząc twoje zmieszanie oferuje pomoc we wprowadzeniu lokalizacji do telefonu. Zerkasz na wyświetlacz... Faktycznie, działa ...

Ale co za cyferki, o których gadał ten skośnooki?

Dlaczego?

Japoński system adresowy różni się od zachodniego. Nazwy ulic są praktycznie nieużywane( z wyjątkiem starych części miast i słabo zaludnionych wiosek).  Adres zapisuje się stopniowo, od największej jednostki geograficznej (prefektury) do najmniejszej (numeru mieszkania).

Prefektury są jednostkami administracyjnymi, czymś w rodzaju polskich województw. Są większe niż powiaty, miasta i wsie. Każdą z nich rządzi gubernator i jednoizbowy parlament. Japonia składa się z 47 j.a. (43 prefektur, 1 metropolii - Tokio, 1 dystryktu - Hokkaido, 2 prefektur miejskich - Osaka i Kioto).
Po prefekturze w adresie wymienia się miejscowość lub dzielnice które posiadają status miasta. Następną częścią adresu jest lokalizacja w ramach miejscowości - dzielnice.

Ostatnie trzy części adresu to numer okręgu miejskiego, kwartału i w końcu domu. Dwa pierwsze numery przydzielane są w zależności od oddalenia od centrum miejscowości. Ostatni (numer domu) zgodnie z ruchem wskazówek zegara wewnątrz kwartału w którym się znajduje.

Mnemotechnicznie:
Prefektura -> miasto -> dzielnica -> nr okręgu -> nr kwartału -> nr domu

Przykład.


Tokyo Central Post Office
2-7-2 Marunouchi, Chiyoda-ku
Tokyo 100-8799.


W tym adresie Tokyo to prefektura, Chiyoda-ku jeden z okręgów. Marunouchi (numer 2) jest nazwą okręgu miejskiego. Ostatnie dwie cyfry (7-2) symbolizują kwartał i numer domu. W ostatnim wierszu mamy podany kod pocztowy składający się z trzech cyfr dywiz i 4 indywidualnych cyfry przydzielanych urzędowi pocztowemu.

Amazing, huh? :)

wtorek, 5 lipca 2011

Jak tworzyć klasy w języku JavaScript?

JavaScript nie stosuje rozwiązań znanych z popularnych języków umożliwiających programowanie obiektowe jak C++, Java czy PHP. Niewiele osób wie, że dzięki sprytnemu wykorzystaniu funkcji i zmiennych stworzymy implementację klasy, zawierającą konstruktor, składowe i metody, które mogą być publiczne, prywatne bądź też statyczne.

Jest to możliwe, ponieważ funkcje w języku JavaScript mają status obiektów pierwszej klasy, co oznacza, że funkcja traktowana jest równorzędnie z innymi typami danych (dzięki czemu może być zapisana w zmiennej lokalnej, przekazywana jako argument do innej funkcji czy zwracana jako jej wynik). 

Oto przykład przypisania zdefiniowanej funkcji do zmiennej, a następnie jej wywołanie:
// Przypisanie funkcji DisplayGreeting(hour) 
// do zmiennej display
var display = function DisplayGreeting(hour) {
 if (hour >= 22 || hour <= 5)
  document.write("Czas spac!");
 else
  document.write("Pracuj dalej!")
}

// Wywolanie funkcji DisplayGreeting() 
// poprzez zmienna display
display(10);
Jeśli decydujemy się przechowywać fragment kodu w zmiennej, warto rozważyć stworzenie "funkcji anonimowej", czyli bez nazwy. Tworzy się ją poprzez usunięcie nazwy z definicji.
var display = function (hour) {
...
}

display(10);
Funkcje anonimowe wykorzystuje się do przekazywania do ciała funkcji, w postaci argumentu, fragmentów kodu niewykorzystywanego w innym miejscu programu.

Wiedząc już, że funkcja będzie pełniła rolę obiektu zacznijmy od stworzenia konstruktora.

Konstruktor
Konstruktor to funkcja zdefiniowana wewnątrz klasy, która inicjuje obiekt w chwili jego tworzenia. Wywoływana jest ona automatycznie w chwili inicjacji obiektu za pomocą operatora new.
var myHello = new showHelloWorld();
Próba powołania instancji klasy (czyli tutaj obiektu myHello) skutkuje wywołaniem kodu zapisanego w funkcji, zupełnie tak, jakby nastąpiło jej bezpośrednie wywołanie.

W klasycznych językach programowania konstruktor jest specjalną publiczną metodą wewnątrz klasy. Nie zwraca ona żadnego wyniku, oraz jest uruchamiana w momencie tworzenia obiektu.

W języku JavaScript rolę konstruktora pełni kod funkcji będącej odpowiednikiem klasy
. Argumenty takiej funkcji są zatem parametrami konstruktora.

Zobaczmy przykład:
function helloWorld(hour) {
 // Konstruktor klasy inicjuje pole hour
 this.hour = (hour) ? hour : (new Date()).getHours();
 
 // Definicja funkcji wyswietlajacej pozdrowienie
 this.DisplayGreetings = function() {
  if (this.hour >= 22 || this.hour <= 5) 
   document.write("Czas spac!");
  else 
   document.write("Pracuj dalej!")
 }
}

var myHello = new helloWorld();
myHello.DisplayGreetings();

Tworzony jest obiekt klasy helloWorld. Klasa to posiada jedną publiczną składową - hour, która jeśli została podana, przyjmuje zadaną wartość, a jeśli nie - sprawdza aktualną godzinę w systemie. Obiekt ten posiada także jedną publiczną metodę (funkcję anonimową) o nazwie DisplayGreetings(), której zadaniem jest wyświetlenie komunikatu w zależności od godziny zapisanej w składowej.

Publiczne i prywatne składowe
W przykładzie wyżej klasa miała pola publiczne. Oznacza to, że każdy mógł odczytać bądź zmienić dane, odwołując się do nich np. w następujący sposób:
alert(myHello.hour); // wyswietla aktualną godzinę
Słowo this to odwołuje się do obiektu, na którym konstruktor jest wywoływany. Sposób ten pozwala na tworzenie publicznych zmiennych.
function Tablica(wiersze, kolumny) {
 // Składowe publiczne
 this.wiersze = wiersze;
 this.kolumny = kolumny;
}

var tab1 = new Tablica(2,4);
// wyświetla "2 4"
document.write(tab1.wiersze +  " " +  tab1.kolumny); 
Aby stworzyć prywatnego uczestnika klasy, będziemy musieli zadeklarować zmienną wewnątrz funkcji. Odbywa się to dzięki poprzedzeniu nazwy zmiennej deklaracją var (co znaczy tyle, że zmienna ma zasięg lokalny). Stworzone w ten sposób składowe są niewidoczne z poziomu instancji funkcji, w naszym przypadku możemy powiedzieć, że są to prywatne zmienne.
function Tablica(wiersze, kolumny) {
 // Składowe prywatne
 var wiersze = wiersze;
 var kolumny = kolumny;
}

var tab2 = new Tablica(5,2);
// wyświetla "undefined undefined"
document.write(tab2.wiersze + " " + tab2.kolumny);
Zmienne wiersze i kolumny obiektu tab2 nie są dostępne spoza ciała funkcji. Dzieje się tak, ponieważ składowe osiągane za pomocą słowa kluczowego this oraz deklarowane poprzez var przechowywane są w różnych miejscach pamięci. Wyjątkiem jest kontekst globalny, w którym nie wprowadza się podziału na zmienne (czyli składowe prywatne) i właściwości (składowe publiczne) obiektu.

Metody
Utwórzmy klasę Tablica, z publicznymi składowymi oraz z publiczną metodą zwracającą ilość komórek:
function Tablica(wiersze, kolumny) {
 // Składowe publiczne
 this.wiersze = wiersze;
 this.kolumny = kolumny;
 
 // Metody publiczne
 this.getLiczbaKomorek = function() {
  return this.wiersze * this.kolumny;
 }
}

var tab3 = new Tablica(1,5);
// wyświetla 5
document.write(tab3.getLiczbaKomorek());
Sposób jest intuicyjny i działa poprawnie, ale nie jest najlepszym rozwiązaniem. Kod zapisany w takiej formie, w chwili zainicjowania obiektu, stworzy nowe zmienne zawierające liczbę wierszy oraz kolumn, ale stworzy także nową kopię metody getLiczbaKomorek(), której nie potrzebujemy. Problem ten nazywany jest "niewystarczającym modelem obiektowym JavaScript". Wyobraźmy sobie, utworzenie kilku tysięcy obiektów klasy Tablica. Każda taka instancja zawierała będzie kod metody w niej zadeklarowanej. Takie praktyki nie najlepiej świadczą o roztropności programisty, ponieważ nie dba on o pamięć zużywaną przez jego aplikację. Stan obiektu musi być inny dla każdego z nich, ale metody klas mogą być wspólne. Jak tego dokonać? Wystarczy odwołać się do funkcji zewnętrznych...
function Tablica(wiersze, kolumny) {
 // Składowe publiczne
 this.wiersze = wiersze;
 this.kolumny = kolumny;
 
 // Metody publiczne
 this.getLiczbaKomorek = getLiczbaKomorek;
}

function getLiczbaKomorek() {
 return this.wiersze * this.kolumny;
}

var tab4 = new Tablica(3,15);
// wyświetla 45
document.write(tab4.getLiczbaKomorek());
To co zrobiliśmy to utworzenie referencji do zewnętrznej funkcji. Teraz wszystkie obiekty klasy Tablica będą korzystać z tej samej funkcji. Takie rozwiązanie jest znacznym ulepszeniem, ponieważ oszczędza moc obliczeniową i pamięć komputera.

Istnieje jeszcze jeden sposób na utworzenie publicznej metody. Ten sam efekt uzyskamy używając "prototypów".

Czym są prototypy?
Są to narzędzia JavaScriptu pozwalające przyłączać lub przypisywać metody do "planu" funkcji. Metody dodane do klasy (funkcji) prototypowej nie powielają się w czasie tworzenia obiektów tej klasy. Metody i właściwości dodane do klasy za pośrednictwem prototypu są automatycznie udostępniane wszystkim jej instancjom.
  • Każda funkcja w języku JavaScript ma właściwość prototype, która jest jednocześnie niezależnym obiektem.
  • Aby dodać uczestników do funkcji prototypowej należy dodać ich do właściwości prototype tej funkcji.
  • Każdy obiekt typu prototype dysponuje właściwością constructor, która przechowuje wskaźnik do funkcji konstruktora.
  • Funkcje i zmienne tworzące konstruktor nie są dostępne z poziomu funkcji dodanych do jego prototypu.
  • Dodanie nowego uczestnika do prototypu sprawia, że staje się on natychmiast dostępny dla wszystkich obiektów (nawet dla tych, które już istnieją)
  • Funkcja prototypu może zyskać nowych uczestników dopiero po zdefiniowaniu jej ciała
Utwórzmy analogiczną klasę wykorzystując właściwość prototype.
function Tablica(wiersze, kolumny) {
 // Składowe publiczne
 this.wiersze = wiersze;
 this.kolumny = kolumny;
}

Tablica.prototype.getLiczbaKomorek = function () {
 return this.wiersze * this.kolumny;
}

var tab5 = new Tablica(31,15);
document.write(tab5.getLiczbaKomorek());
Są to dwa sposoby na tworzenie publicznych metod, które to mogą być wykonywane z dowolnego miejsca w kodzie.

Zajmijmy się teraz prywatnymi metodami. W przypadku zmiennych prywatnych użycie referencji do metody nie będzie możliwe, ponieważ działają one tylko w obrębie funkcji, w której zostały zadeklarowane. W takim przypadku mamy do wyboru dwie opcje. Pierwsza to funkcja inline zdefiniowana w konstruktorze, a druga to funkcja przypisana do zmiennej z deklaracją var. Obie działają tylko w zakresie swojej klasy.
function Tablica(wiersze, kolumny) {
 // Składowe prywatne
 var _wiersze = wiersze;
 var _kolumny = kolumny;

 // Prywatne metody
 
 // OPCJA 1
 function _zwrocKomorki() {
  return _wiersze * _kolumny;
 }
 // OPCJA 2
 var _zwrocKomorki1 = function() {
  return _wiersze * _kolumny;
 }

 // obie funkcje zwraca 465 
 document.write(_zwrocKomorki());
 document.write(_zwrocKomorki1());
}

var tab5 = new Tablica(31,15);

// blad: tab5._zwrocKomorki is not a function
document.write(tab5._zwrocKomorki());
Próba odwołania się do funkcji z zewnątrz klasy, zwraca do konsoli błąd tab5._zwrockKomorki is not a function.

W przypadku klasy z polami publicznymi, aby prywatne metody poprawnie działały musimy przypisać wartości do tymczasowych zmiennych.
function Tablica(wiersze, kolumny) {
 // Składowe publiczne
 this.wiersze = wiersze;
 this.kolumny = kolumny;

 // Prywatne metody
 // Stwórz tymczasowe zmienne
var zm1 = this.wiersze;
var zm2 = this.kolumny;

// OPCJA 1
function _zwrocKomorki() {
return zm1 * zm2;
}
// OPCJA 2
var _zwrocKomorki1 = function() {
return zm1 * zm2;
}

// obie funkcje zwraca 465 
document.write(_zwrocKomorki());
document.write(_zwrocKomorki1());
}

var tab5 = new Tablica(31,15);

// zwraca undefined
document.write(tab5.zm1);
// zwraca 31
document.write(tab5.wiersze);

Zmienne statyczne
Zmienne statyczne w danym bloku programu posiadają dokładnie jedną instancję, niezależną od ilości utworzonych obiektów. Definiuje się je jako właściwości funkcji.
function Czlowiek(imie,kraj) {
 
 Czlowiek.populacja++;
 // lub
 // this.constructor.populacja++;
 
 this.imie = imie;
 this.kraj = kraj;
}

Czlowiek.populacja = 0;

czlowiek1 = new Czlowiek("Milena","Polska");
czlowiek2 = new Czlowiek("Kate","USA");
czlowiek3 = new Czlowiek("Sofia","Francja");

// wyswietla 3
document.write(Czlowiek.populacja);
W konstruktorze zadeklarowano instrukcję, która inkrementuje właściwość funkcji Człowiek o 1, przy każdym wywołaniu. Poza tą "klasą", zmiennej statycznej populacja przypisano początkową wartość równą zero. Po utworzeniu trzech obiektów, jej wartość automatycznie się zwiększa.

Podsumowanie
  • Zmienne publiczne
    Deklarowane: this.nazwaZmiennej
    Mogą być czytane i zmieniane poza klasą.
  • Zmienne prywatne
    Deklarowane: var nazwaZmiennej
    Dostęp do niej możliwy tylko wewnątrz danej funkcji.
  • Metody publiczne
    Deklarowane: nazwaKlasy.prototype.nazwaMetody = function() { .... }
    Deklarowane: this.nazwaMetody = nazwaMetody; (poza funkcją musi znajdować się kod funkcji nazwaMetody())
    Dostęp poza klasą i w klasie.
  • Metody prywatne
    Deklarowanie: funkcja inline w obrębie konstruktora,
    Deklarowanie: var nazwaMetody = function() { .. }
    Dostęp tylko w zakresie kodu funkcji (klasy).
  • Zmienne statyczne
    Deklaracja poza klasą: nazwaKlasy.nazwaZmiennej  = .... ;
    Zmiany wewnątrz klasy (np w konstruktorze).

poniedziałek, 27 czerwca 2011

Tworzenie aplikacji na Facebooka w PHP wykorzystując Graph API w praktyce.

Cel ćwiczenia: zapoznanie się z zasadą pobierania danych użytkownika za pomocą Graph API.

Opis: Zaprojektować system autoryzujący użytkownika, wyświetlający jego zdjęcie, imię, nazwisko, miejsce zamieszkania oraz polubione rzeczy.

Efekt finalny przedstawiono na zrzucie ekranu.


Cały proces podzielimy na trzy części. W pierwszej zaprojektujemy na lokalnym komputerze szkic witryny z wykorzystaniem elementów CSS3, a w drugiej rozbudujemy autoryzujący skrypt utworzony w tym poście, aby spełniał założenia zadania.W ostatniej scalimy ze sobą dwie pierwsze uzyskując ostateczną aplikację.

1. Projekt HTML

1.1 Wizualny schemat strony.
Przed przystąpieniem do zadania warto naszkicować sobie na kartce papieru schemat witryny i oznaczyć poszczególne divy. Ja zrobiłem to w ten sposób:
Sekcja #frame zawiera w sobie wszystkie elementy. Jej szerokość jest 10px mniejsza niż szerokość jaką daje nam okno iFrame Facebooka (760px). Wewnątrz mamy dwa większe kontenery - #topPanel i #mainArea. Pierwszy zawiera zdjęcie użytkownika, jego imię i nazwisko oraz miasto w którym aktualnie się znajduje. Drugi składa się ze stałego tekstu oraz pola #userLikes sformatowanego tak, by wyświetlał dane w trzech kolumnach.

1.2 Szkic w kodzie HTML
Kod HTML, zawierający te wszystkie elementy może wyglądać np tak:
<div id="frame">
 <div id="topPanel">
   <div id="photoDiv">
   </div>
   
   <div id="nameDiv">
   </div>
   
   <div id="cityDiv">
   </div>
 </div>
 <div id="mainArea">
  <p class="goText">Wiem co lubisz? Co powiesz na:</p>
  <hr />
  
  <div id="userLikes">
  </div>
 </div>
</div>

1.3 Wprowadzenie przykładowych danych.
Na razie nie mamy żadnego połączenia z Facebookiem, więc na potrzeby stylizacji wprowadzimy przykładowe dane. Kod może wyglądać tak:

<div id="frame">
 <div id="topPanel">
   <div id="photoDiv">
    <img id="userPhoto" src="http://graph.facebook.com/100000027824838/picture?type=normal" />
   </div>
   
   <div id="nameDiv">
    <p>Norbert</p>
    <p>Kozlowski</p>
   </div>
   
   <div id="cityDiv">
    <p>Aktualne miasto:</p>
    <p class="cityName">Wroclaw</p>
   </div>
 </div>
 <div id="mainArea">
  <p class="goText">Wiem co lubisz? Co powiesz na:</p>
  <hr />
  
  <div id="userLikes">
   Lorem ipsum dolor sit amet, consectetuer adipiscing elit.
 Nulla at turpis eget nibh ultricies dignissim. Duis luctus
 euismod turpis. Mauris augue. Aliquam facilisis semper elit.
 Pellentesque semper hendrerit arcu. Phasellus eleifend
 commodo justo. Aliquam orci urna, imperdiet sit amet,
 posuere in, lobortis et, risus. Integer interdum nonummy
 erat. Nullam tellus. Sed accumsan. Vestibulum orci ipsum,
 eleifend vitae, mollis vel, mollis sed, purus. Suspendisse
 mollis elit eu magna. Morbi egestas. Nunc leo ipsum, blandit
 ac, viverra quis, porttitor quis, dui. Vestibulum ante ipsum
 primis in faucibus orci luctus et ultrices posuere cubilia
 Curae; Vivamus scelerisque ipsum ut justo. Pellentesque et
 ligula eu massa sagittis rutrum. In urna nibh, eleifend vel,
 suscipit ut, sagittis id, nunc.
  </div>
 </div>
</div>

W kodzie użyto zdjęcia pobranego z Facebooka. Nazwę miasta wprowadzono w klasie .cityName by ułatwić proces stylizacji który odbędzie się w następnym kroku. Sekcję #userLikes wypełniłem przykładowym tekstem. Niżej aktualny podgląd strony w przeglądarce.

1.4 Dołączenie styli
W zasadzie moglibyśmy pominąć ten krok, bo nie jest on konieczny do osiągnięcia celu. Miło jest popatrzeć na coś ładnie się prezentującego, dlatego poświęcimy trochę czasu wklepując kod. Wykorzystałem tu dwa elementy standardu CSS3 - cienie napisów oraz formatowanie tekstu w kolumnach. Internet Explorer nie obsługuje poprawnie tych możliwości.

p {
  padding:0;
  margin:0;
 }
 
 #frame {
  width:750px;
 }
 
 #topPanel {
  height:140px;
  background-color: #4aa0e8;
  padding-left:10px;
  padding-right:5px;
  border:1px solid #3e33ff;
 }
 
 #photoDiv {
  float:left;
  width:102px;
  padding-top:10px;
 }
 
 #nameDiv p {
  font-family: "Blackadder ITC";
  font-size:47px;
  
  text-shadow: 3px 3px 2px #808080;
  -moz-text-shadow: 3px 3px 2px #808080;
  -webkit-text-shadow: 3px 3px 2px #808080;
 }
 
 #nameDiv {
  float: left;
  padding-top:10px;
  padding-left:5px;
 }
 
 #cityDiv {
  float:right;
  text-align:right;
  line-height: 15px;
  margin-top:10px;
  margin-right:10px;
  font-family:"Calisto MT";
 }
 
 #cityDiv .cityName {
  text-transform: uppercase;
  font-weight:bold;
  margin-top:5px;
 }
 
 #userPhoto {
  border:1px solid white;
  height:80%;
 }
 
 #mainArea {
  margin-top:3px;
  background-color:#ff8040;
  border:1px solid #804000;
  padding:0 5px 5px 5px;
  text-align:justify;
 }
 
 #userLikes {
  font-family:Tahoma;
  font-size:12px;
  line-height:18px;
  
  -moz-column-count: 3;
  -moz-column-gap: 20px;
  
  -webkit-column-count: 3;
  -webkit-column-gap: 20px;
 }
 
 #mainArea .goText {
  margin-top:3px;
  margin-bottom:3px;
  width:100%;
  font-family:Tahoma;
  text-align:center;
 }

Opakujmy ten styl pomiędzy znacznik <style> i umieśćmy przed głównym kodem HTML. Jak prezentuje się strona w różnych przeglądarkach?

Firefox 5.0

Safari 5.0.5

Internet Explorer 9.0 64bit

Internet Explorer nie obsługuje cienia rzucanego przez imię i nazwisko, nie dzieli tekstu na trzy kolumny, oraz ma problemy z interpretacją źródła do obrazka. Trzeba to uwzględnić przy projektowaniu większych aplikacji. Nie jest naszym celem stworzenie teraz aplikacji, która będzie poprawnie obsługiwana przez wszystkie przeglądarki, ale pobieranie danych poprzez Facebook Graph API i na tym się skupimy.

Mając gotową stronę, możemy przejść do drugiego kroku, czyli do tworzenia ...

2. Skrypt PHP

1.1  Skrypt autoryzujący pobierający dodatkowe informacje

Korzystając z informacji w tym wpisie zalążkiem naszego skryptu będzie właśnie to co napisaliśmy. Zacznijmy od następującego kodu stopniowo go modyfikując.
<?php
 // Nr ID aplikacji
 $app_id = '179524192103712';
 // Adres canvas aplikacji
 $canvas_page = 'http://apps.facebook.com/khozzyaps/';
 // Tworzenie adresu url zgodnego ze standardem OAuth
 // Pobieramy dodatkowo takie informacje jak lubiane rzeczy oraz lokalizacje uzytkownika
 $auth_url = 'http://facebook.com/dialog/oauth?client_id=' . $app_id . '&redirect_uri=' . urlencode($canvas_page) 
 . '&scope=user_likes,user_location';
 // Odebranie danych i zapisanie jej do zmiennej
 $signed_request = $_REQUEST["signed_request"];
 // Dzielimy odebrane dane wzgledem kropki na dwie czesci
 list($encoded_sig,$payload) = explode('.',$signed_request,2);
 // Dekodujemy druga czecs odebranych danych i zapisujemy je do zmiennej
 $data = json_decode(base64_decode(strtr($payload,'_-',' /')), true);
 
 // Jezeli nie zautoryzowano uzytkownika, przenies go z powrotem na strone autoryzacji
 if (empty($data["user_id"])) {
  echo("<script> top.location.href='" . $auth_url . "'</script>");
 }
 // Jezli wszystko odbylo sie poprawnie mozemy kontynuowac
 else {
  
  // TU WLASCIWY KOD
 }
?>
Jak już wiadomo, odbywa się tu procedura autoryzacji użytkownika, w której prosimy także o udostępnienie informacji o jego lokalizacji i lubianych rzeczach. Jeśli uzyskano zgodę (tym samym zwrócony został obiekt signed_request zawierający wymagany access_token) możemy przejść do właściwego fragmentu kodu.

1.2 Tworzenie zapytań

Mając obiekt signed_request zapisany w zmiennej $data, wyłuskajmy z niego i zapiszmy ID użytkownika oraz wygenerowany klucz.
$user_id = $data['user_id'];
$access_token = $data['oauth_token'];
Ułatwi to nam konstruowanie zapytań do serwera Graph.

Aby pobrać informacje o imieniu, nazwisku i miejscu zamieszkania a następnie zapisać je, musimy stworzyć zapytanie w odpowiednim formacie. Wszystko opisałem w tym wpisie.
$graph_url = "https://graph.facebook.com/" . $user_id .
"?access_token=" . $access_token;
$response = file_get_contents($graph_url);
$user_info_response = json_decode($response,true);
Na początku tworzone jest ogólne zapytanie w którym argumentami są ID użytkownika i access_token zwrócony przez niego (abyśmy mogli dostać się do prywatnych zasobów). $graph_url jest adresem przechowującym obiekt tekstowy JSON. Pobierzmy te dane i zapiszmy do kolejnej zmiennej. Możemy użyć funkcji curl() (która w tym przypadku jest odrobinę zbyt skomplikowana) lub file_get_contents(). Używając tej drugiej kopiujemy zawartość pliku wskazanego przez $graph_url do zmiennej $response. Nadal jest to tekstowy obiekt JSON. Aby dekodować dane wykonujemy funkcję json_decode(). Drugi parametr true() powoduje, że  $user_info_response jest tablicą asocjacyjną (przechowującą informacje w formacie nazwa-wartość) przechowującą informacje o użytkowniku. Nie podanie tego parametru spowodowałoby utworzenie obiektu stdClass, a co za tym idzie  inny sposób odwoływania się do jej składowych.

Pobierzmy w ten sposób informacje o rzeczach lubianych przez użytkownika.
$likes_url = "https://graph.facebook.com/" . $user_id . 
"/likes?access_token=" . $access_token;
$likesResponse = file_get_contents($likes_url);
$likes_info_response = json_decode($likesResponse);
Dodajmy kod diagnostyczny, aby sprawdzić czy wszystko wygląda na pewno tak jak oczekujemy.
echo '<pre>';
print_r($user_info_response);
print_r($likes_info_response);
echo '</pre>';
Wynik działania przedstawiono na zrzucie ekranu.

Tak jak zakładaliśmy, zaznaczony fragment jest tablicą asocjacyjną przechowującą ogólne informacje o użytkowniku, a kod niżej jest klasą stdClass zawierającą tablicę data z jego ulubionymi rzeczami.

1.3 Wyłuskanie danych

Aby pobrać i zapisać imię, nazwisko i miasto, które są zapisane w tablicy wpisujemy po prostu:
$userName = $user_info_response['first_name'];
$userLastName = $user_info_response['last_name'];
$userCity = $user_info_response['location']['name'];
Jeśli dane te byłyby zapisane jako obiekt, odwołuje się do nich w analogiczny sposób:
$userName = $user_info_response->first_name;
$userLastName = $user_info_response->last_name;
$userCity = $user_info_response->location->name;
Tablica, zawierająca lubiane przedmioty:
$likesArray = $likes_info_response->data;
Którą możemy także wylistować:
for ($i = 0; $i < sizeof($likesArray); $i++) {
 echo $likesArray[$i]->name;
}
Pozostaje nam zapisanie adresu zdjęcia profilowego użytkownika:
$userPhotoAddress = "http://graph.facebook.com/ " . 
$user_id . "/picture?type=normal";

3. HTML + PHP

3.1 Dodanie szablonu strony do kodu PHP

Wykorzystując funkcję echo() wkleimy do skryptu PHP cały kod HTML który napisaliśmy w punkcie pierwszym.
else {
  $access_token = $data['oauth_token'];
  $user_id = $data['user_id'];
  
  // Pobranie info o uzytkowniku
  $graph_url = "https://graph.facebook.com/" . $user_id .
 "?access_token=" . $access_token;
  $response = file_get_contents($graph_url);
    $user_info_response = json_decode($response,true);
  
  // Pobranie info o lubionych przedmiotach
  $likes_url = "https://graph.facebook.com/" . $user_id . 
"/likes?access_token=" . $access_token;
  $likesResponse = file_get_contents($likes_url);
  $likes_info_response = json_decode($likesResponse);
  
  $userName = $user_info_response['first_name'];
  $userLastName = $user_info_response['last_name'];
  $userCity = $user_info_response['location']['name'];
  
  // Tablica z lubianymi przedmiotami
  $likesArray = $likes_info_response->data;
  
  // Adres ze zdjeciem profilowym
  $userPhotoAddress = "http://graph.facebook.com/ " 
. $user_id . "/picture?type=normal";
  
  echo '
   TU KOD HTML WITYRYNY
  ';

  //for ($i = 0; $i < sizeof($likesArray); $i  ) {
  // echo '<b>=> </b>' . $likesArray[$i]->name;
  //}
 }
Gdzie napisany przez nas kod witryny to:

<style>
 p {
  padding:0;
  margin:0;
 }
 
 #frame {
  width:750px;
 }
 
 #topPanel {
  height:140px;
  background-color: #4aa0e8;
  padding-left:10px;
  padding-right:5px;
  border:1px solid #3e33ff;
 }
 
 #photoDiv {
  float:left;
  width:102px;
  padding-top:10px;
 }
 
 #nameDiv p {
  font-family: "Blackadder ITC";
  font-size:47px;
  
  text-shadow: 3px 3px 2px #808080;
  -moz-text-shadow: 3px 3px 2px #808080;
  -webkit-text-shadow: 3px 3px 2px #808080;
 }
 
 #nameDiv {
  float: left;
  padding-top:10px;
  padding-left:5px;
 }
 
 #cityDiv {
  float:right;
  text-align:right;
  line-height: 15px;
  margin-top:10px;
  margin-right:10px;
  font-family:"Calisto MT";
 }
 
 #cityDiv .cityName {
  text-transform: uppercase;
  font-weight:bold;
  margin-top:5px;
 }
 
 #userPhoto {
  border:1px solid white;
  height:80%;
 }
 
 #mainArea {
  margin-top:3px;
  background-color:#ff8040;
  border:1px solid #804000;
  padding:0 5px 5px 5px;
  text-align:justify;
 }
 
 #userLikes {
  font-family:Tahoma;
  font-size:12px;
  line-height:18px;
  
  -moz-column-count: 3;
  -moz-column-gap: 20px;
  
  -webkit-column-count: 3;
  -webkit-column-gap: 20px;
 }
 
 #mainArea .goText {
  margin-top:3px;
  margin-bottom:3px;
  width:100%;
  font-family:Tahoma;
  text-align:center;
 }
</style>
<div id="frame">
 <div id="topPanel">
   <div id="photoDiv">
    <img id="userPhoto" src="http://graph.facebook.com/100000027824838/picture?type=normal" />
   </div>
   
   <div id="nameDiv">
    <p>Norbert</p>
    <p>Kozlowski</p>
   </div>
   
   <div id="cityDiv">
    <p>Aktualne miasto:</p>
    <p class="cityName">Wroclaw</p>
   </div>
 </div>
 <div id="mainArea">
  <p class="goText">Wiem co lubisz? Co powiesz na:</p>
  <hr />
  
  <div id="userLikes">
   Lorem ipsum dolor sit amet, consectetuer adipiscing elit.
 Nulla at turpis eget nibh ultricies dignissim. Duis luctus
 euismod turpis. Mauris augue. Aliquam facilisis semper elit.
 Pellentesque semper hendrerit arcu. Phasellus eleifend
 commodo justo. Aliquam orci urna, imperdiet sit amet,
 posuere in, lobortis et, risus. Integer interdum nonummy
 erat. Nullam tellus. Sed accumsan. Vestibulum orci ipsum,
 eleifend vitae, mollis vel, mollis sed, purus. Suspendisse
 mollis elit eu magna. Morbi egestas. Nunc leo ipsum, blandit
 ac, viverra quis, porttitor quis, dui. Vestibulum ante ipsum
 primis in faucibus orci luctus et ultrices posuere cubilia
 Curae; Vivamus scelerisque ipsum ut justo. Pellentesque et
 ligula eu massa sagittis rutrum. In urna nibh, eleifend vel,
 suscipit ut, sagittis id, nunc.
  </div>
 </div>
</div>
Należy zamienić takie miejsca jak:
  • #photoDiv
  • #nameDiv
  • #cityDiv
  • #userLikes
Aby poszczególne sekcje pobierały dane ze zmiennych, należy podmienić wpisane przykładowe wartości nazwami zmiennych. Więc:
<div id="photoDiv">
 <img id="userPhoto" src="' . $userPhotoAddress . '" />
</div>
Zamiana imienia i nazwiska:
<div id="nameDiv">
 <p>' . $userName . '</p>
 <p>' . $userLastName . '</p>
</div>
miasta:
<div id="cityDiv">
 <p>Aktualne miasto:</p>
 <p class="cityName">' . $userCity . '</p>
</div>
Wypisanie lubianych przedmiotów
<div id="userLikes">';

 for ($i = 0; $i < sizeof($likesArray); $i  ) {
  echo '<b>=> </b>' . $likesArray[$i]->name;
 }
  
echo ' 
</div>
Użyłem apostrofów, aby wyjść funkcji echo, wypisać całą zawartość tablicy, a potem znowu ją wywołać, aby pozamykać pozostałe sekcje. Warto też dodać znacznik nowej linii po każdym przedmiocie (tutaj był pomijany). Całość widać na zrzucie ekranu

Wnioski
Przykładowe screeny:

Napotkane problemy wymagające rozwiązania: kompatybilność z przeglądarkami (poprawne wyświetlanie zdjęcia), kodowanie polskich znaków.
Założony cel osiągnięty.

niedziela, 26 czerwca 2011

Czym jest Graph API?

Graph API jest filarem na którym opiera się działanie Facebooka jako portalu społecznościowego. Dokładnie jest to interfejs programistyczny wiążący wszystkie elementy występujące na stronie w spójną całość. Jest to możliwe, ponieważ każde zdjęcie, osoba, wydarzenie czy komentarz reprezentowana jest jako obiekt o określonych właściwościach. W zależności od ustawień prywatności i od tego czy uzyskamy pozwolenie możemy ich widzieć więcej lub mniej.

Aby możliwe było utworzenie powiązań (np. przypisanie albumu ze zdjęciami konkretnemu użytkownikowi) każdy obiekt posiada swój unikalny numer ID.

Aby pobrać informacje o takim obiekcie musimy zmodyfikować specjalny adres URL serwera, który je przechowuje. Zobaczmy kilka przykładów.

http://graph.facebook.com/ID
http://graph.facebook.com/username

Graf profilu Marka Zuckerberga, założyciela portalu (o numerze ID 68310606562), dostępny jest pod adresem http://graph.facebook.com/68310606562 i wygląda następująco:
{
   "id": "68310606562",
   "name": "Mark Zuckerberg",
   "picture": "http://profile.ak.fbcdn.net/hprofile-ak-snc4/
50270_68310606562_2720435_s.jpg",
   "link": "http://www.facebook.com/markzuckerberg",
   "likes": 4538132,
   "category": "Public figure",
   "website": "www.facebook.com",
   "username": "markzuckerberg",
   "personal_interests": "openness, making things that help
people connect and share what's important to them, 
revolutions, information flow, minimalism\n\n\n"
}
Zamiast numeru ID możemy przekazać nazwę username obiektu (czyli do wspomnianego wyżej przykładu dostaniemy się poprzez adres http://graph.facebook.com/markzuckerberg). Dla przykładu - graf mojego fanpage-u zrzeszającego ludzi, którym podoba się idea Facebookowym pieczątek (https://graph.facebook.com/PieczatkiLubieTo) wygląda w taki sposób:
{
   "id": "129613800426235",
   "name": "Piecz\u0105tki \"Lubisz to\"",
   "picture": "http://profile.ak.fbcdn.net/hprofile-ak-snc4
/41607_129613800426235_5059275_s.jpg",
   "link": "http://www.facebook.com/PieczatkiLubieTo",
   "likes": 1401,
   "category": "Product/service",
   "website": "www.polubisz-to.pl\nhttp://allegro.pl/
show_user_auctions.php?uid=1761089",
   "username": "PieczatkiLubieTo",
   "company_overview": "Ty te\u017c jeste\u015b Facebook-o-
-holikiem tudzie\u017c Facebook-o-holiczk\u0105? \n\nTe\u017c
 czasami a\u017c chcesz oznaczy\u0107 co\u015b swoim \"Lubi\u0119
 to\" w realu?\n\nTeraz masz tak\u0105 mo\u017cliwo\u015b\u0107...\n\n
Piecz\u0105tk\u0105 \"Lubisz to\" mo\u017cesz oznaczy\u0107 dos\u0142ownie 
wszystko. Tylko od Twojej kreatywno\u015bci i wyobra\u017ani zale\u017cy, 
co to b\u0119dzie. \n\nCzekamy na Twoje pomys\u0142y, zdj\u0119cia, filmy 
- poka\u017c \u015bwiatu, co naprawd\u0119 lubisz!",
   "products": "Kieszonkowe stemple Pocket Stamp z Twoim imieniem i nazwiskiem 
lub pseudonimem oraz znaczkiem \"lubisz to\""
}
Odpowiedzi te są obiektami JSON. Możemy je wygenerować dla wszystkich obiektów w portalu (m.in. dla zdjęć, albumów, zdjęć profilowych, grup, aplikacji, statusów, stron...). Jak widać zawierają tylko podstawowe i ogólnie dostępne informacje do których dostęp ma nawet osoba nie posiadająca konta na Facebooku. Informacje te są powszechnie dostępne.

Obiekty są ze sobą w jakiś sposób powiązane. Dzieje się tak kiedy np. użytkownik lubi pewną stronę, uczestniczy w wydarzeniu, jest w związku z innym użytkownikiem, bądź po prostu ma go w znajomych. W omawianym "socjalnym grafie" relacja ta nazwana jest  połączeniem. Możemy badać takie "połączenia" elementu z numerem ID z innymi elementami jak np:
  • znajomymi
    https://graph.facebook.com/ID/friends?access_token=...
  • najnowszą aktywnością znajomych (news feed)
    https://graph.facebook.com/ID/home?access_token=...
  • wpisami na ścianie
    https://graph.facebook.com/ID/feed?access_token=...
  • lubianymi rzeczami
    https://graph.facebook.com/
    ID/likes?access_token=...
  • filmami
    https://graph.facebook.com/ID/videos/uploaded?access_token=...
  • muzyką
    https://graph.facebook.com/
    ID/music?access_token=...
  • książkami
    https://graph.facebook.com/ID/books?access_token=...
  • notatkami
    https://graph.facebook.com/
    ID/notes?access_token=...
  • znacznikami na zdjęciach
    https://graph.facebook.com/
    ID/photos?access_token=...
  • albumami
    https://graph.facebook.com/ID/albums?access_token=...
  • wydarzeniami
    https://graph.facebook.com/ID/events?access_token=...
  • grupami
    https://graph.facebook.com/ID/groups?access_token=...
  • .....
Informacje te są już jednak bardziej poufne i trzeba się nieco postarać aby uzyskać do nich dostęp. Sam użytkownik musi "pozwolić" nam je przeczytać. Robi to poprzez przekazanie nam parametru access_token, który podajemy jako argument w takim adresie URL. Jest on poufny, dlatego też połączenie musi odbywać się poprzez bezpieczny kanał (konieczny przedrostek https!). Aby uzyskać ten ciąg znaków należy przeprowadzić proces autoryzacji, który opisałem w tym wpisie. Jeśli użytkownik nie zgodzi się udostępnić nam swoich prywatnych danych, nie zostanie nam przydzielony access_token - nie uzyskamy dostępu do bardziej szczegółowych danych więc będziemy mogli korzystać tylko z zasobów, które zostały przez niego sklasyfikowane jako publiczne.

Zdjęcia

W łatwy sposób możemy także generować zdjęcia (np. profilowe, wydarzeń, grup, stron, aplikacji...). Wystarczy stworzyć zapytanie zgodne ze schematem

http://graph.facebook.com/ID/picture
http://graph.facebook.com/username/picure

Zdjęcia możemy sobie renderować według wymagań dzięki parametrowi type. Domyślnie jest to kwadrat (square) o boku 50px. Możemy wybierać między small (50px szerokość, wysokość zmienna), normal (100px szerokość, wysokość zmienna) oraz large (200px szerokość, wysokość zmienna).

Przykład:

Jeśli chcemy, aby zdjęcie było zwrócone bezpiecznym protokołem SSL, dodajemy argument return_ssl_resources.

Przykład:


Zapytania

Możemy tworzyć bardziej zaawansowane zapytania, które nie będą zwracały wszystkich informacji o obiekcie, tylko te o które sami poprosimy. Robi się to dodając argument fields z nazwami pól oddzielonymi przecinkami, które chcemy otrzymać.


Zwróci:
{
   "id": "68310606562",
   "name": "Mark Zuckerberg",
   "category": "Public figure"
}
Do jednego zapytania możemy dołączyć prośbę o inne obiekty. Służy do tego argument ids. Przykład niżej zwróci publiczne informacje o Marku Zuckerbergu i o fanpage-u 50 centa.


Warto wiedzieć także o identyfikatorze me, który zwraca informacje o aktywnym użytkowniku.


Wyszukiwanie i filtrowanie

Tworząc zapytania, możemy ograniczać liczbę zwracanych wyników. Służą do tego zmienne limit i offset

https://graph.facebook.com/me/likes?access_token=...&limit=3

Zapytanie to zwróci trzy ostatnio polubione przez nas rzeczy. Aby odnieść się do kolejnych trzech należy dodać offset czyli przesunięcie.

https://graph.facebook.com/me/likes?access_token=...&limit=3&offset=6
Bardzo ciekawą opcją jest wyszukiwarka. Zwraca ona wszystkie obiekty, które zawierają w sobie wyszukiwaną frazę. Wyszukiwanie ogranicza się przedziałami czasowymi (za pomocą argumentów since i until po którym podany jest czas zgodny z funkcją strtotime()) a szukaną frazę podaje się za argumentem q (ang. query).

http://graph.facebook.com/search?until=yesterday&q=gruby

To zapytanie wyświetli wszystko umieszczone przez użytkowników na portalu (np jako statusy, komentarze pod zdjęciami, nazwy filmów...) które zawiera w sobie słowo 'gruby' i zostało umieszczone nie wcześniej niż wczoraj.

Na każdej zwróconej przez wyszukiwarkę stronie umieszczone jest 25 obiektów, przeglądając je dochodzimy do linijek umożliwiających dalsze przeglądanie
"paging": {
      "previous": "https://graph.facebook.com/search?q=gruby&access_token=...
&paging=next&limit=25&since=1308956406",
      "next": "https://graph.facebook.com/search?q=gruby&access_token=...
&paging=next&limit=25&until=1308285693"
   }
Są to pola obiektu JSON więc implementacja w kodzie nie jest problemem.

Możemy także sprecyzować jakiego typu wyniki nas interesują. Służy do tego parametr type, który aktualnie obsługuje takie wyniki jak posty (post), użytkownicy (user), strony (page), wydarzenia (event), grupy (group), miejsca (place). Przykładowe zapytanie wyszukujące użytkownika nazywającego się Norbert

https://graph.facebook.com/search?q=norbert&type=user

sobota, 18 czerwca 2011

4 algebraiczne sposoby badania stabilności układu automatycznej regulacji

Napisany przeze mnie poradnik, oparty na założeniu "praktyka czyni mistrza". Każdy podrozdział zawiera, krótki wstęp do danego kryterium, praktyczne wskazówki pomocne przy rachunkach, kilka rozwiązanych i omówionych przykładów oraz wyciągnięte wnioski.

Omówione kryteria algebraiczne:
  • kryterium biegunów,
  • kryterium odpowiedzi na skok jednostkowy i impulsowy,
  • kryterium Hurwitza,
  • kryterium Routha-Hurwitza.

Plik do pobrania stąd.

Dystrybucja w celach komercyjnych zakazana.
Wykorzystywanie fragmentów bez mojej wiedzy sprawi, że się obrażę.

Jak przebiega autoryzacja aplikacji na Facebooku? Krok po kroku.

Aby uzyskać autoryzację dla aplikacji Facebookowej developerzy zalecają korzystanie z protokołu OAuth 2.0 Dialog (jest to standard pozwalający dzielić się swoimi prywatnymi materiałami z innymi). Do wykorzystania są także popularne biblioteki JS SDK lub PHP SDK ułatwiające pracę. Tu jednak poruszone zostanie klasyczne rozwiązanie.

Autoryzację OAuth w Facebooku wykonujemy przekierowując użytkownika na adres URL, stworzony według schematu: 
  
https://www.facebook.com/dialog/oauth?
client_id=YOUR_APP_ID
&redirect_uri=YOUR_CANVAS_PAGE


Gdzie YOUR_APP_ID jest identyfikatorem aplikacji , a YOUR_CANVAS_PAGE ścieżką URL do naszego  serwera który ją przechowuje. Domyślnie adres ten uzyskuje dostęp do podstawowych informacji o użytkowniku. Aby pobrać więcej danych, musimy wymienić żądane informacje, po parametrze scope. Poniższy przykład pokazuje jak uzyskać dostęp do adresu e-mail oraz pola news feed (czyli informacji o aktywności znajomych) 

https://www.facebook.com/dialog/oauth?
client_id=YOUR_APP_ID  
&redirect_uri=YOUR_CANVAS_PAGE 
&scope=email,user_status,user_location 

Pełna lista informacji jakie możemy pobrać dostępna jest na tej stronie. Istnieje pewna zależność pomiędzy ilością zbieranych danych, a liczbą użytkowników zezwalających na ich udostępnianie. Mianowicie, im więcej danych żądamy, mniej użytkowników będzie korzystało z naszej aplikacji.

W przypadku gdy użytkownik odmówi udostępnienia informacji, przeglądarka przekieruje go na adres wygenerowany na podstawie podanego wcześniej redirect_uri, zwracając błędy:

http://YOUR_CANVAS_PAGE?
error_reason=user_denied
&error=access_denied
&error_description=The+user+denied+your+request.

 
W przypadku, gdy użytkownik zezwala na udostępnianie informacji o które został poproszony, aplikacja przekierowuje go na adres podany w redirect_uri ustawiając parametr signed_request. Parametr ten jest połączeniem funkcji hashującej HMAC SHA-256, znaku ‘.’ oraz obiektu JSON zakodowanego algorytmem base64url. Może wyglądać np. tak (bez znaków nowej linii)
vlXgu64BQGFSQrY0ZcJBZASMvYvTHu9GQ0YM9rjPSso.
eyJhbGdvcml0aG0iOiJITUFDLVNIQTI1NiIsIjAiOiJwYXlsb2FkIn0 
Sygnatura HMAC zapewnia, że przesyłane dane pochodzą z serwisu Facebook (dzięki kodowaniu przez tajny kod App Secret znany tylko twórcy aplikacji).

Dalej zakodowany jest obiekt JSON. Jest to format tekstowy używany przy wymianie danych przez skrypty. Często używa się go przy okazji wykorzystania technologii AJAX. Obsługa odebranego ciągu znaków ogranicza się do zastosowania na nim funkcji eval() (JS). Zamienia ona dane JSON na dane w formacie tablicy. Dostęp do nich uzyskujemy poprzez nazwę i indeksy pól. Na przykład odebranaDana.tytul lub odebranaDana.tresc.

W przypadku języka PHP, wystarczy na tablicy danych zastosować funkcję json_encode(), aby zamienić je na format JSON. Dekodowanie wykonujemy analogicznie wykorzystując funkcję json_decode().

Obiekt signed_request zawiera następujące pola:

·         user
Tablica JSON zawierająca takie informacje jak kraj z którego pochodzi użytkownik, zakres wieku w jakim się plasuje, locale (czyli ustawienia zmiennych środowiskowych).
·         algorithm
Ciąg znaków JSON zawierający nazwę algorytmu użytego do zakodowania żądania.
·         issued_at
Liczba JSON w formacie POSIX, informująca kiedy żądanie zostało zrealizowane.
·         user_id
Ciąg znaków JSON zawierający identyfikator bieżącego użytkownika (UID).
·         oauth_token
Ciąg znaków JSON wykorzystywany przy korzystaniu z Graph API.
·         expires
Liczba JSON zawierająca czas w formacie POSIX, którego data wyznacza okres wygaśnięcia oauth_token.

Poniższy kod PHP demonstruje zasadę działania procesu autoryzacji oraz wyświetla zawartość zmiennej signed_request w formacie przyjaznym użytkownikowi.
<?php
 # Nr ID aplikacji
 $app_id = '179524192103712';
 # Adres canvas aplikacji
 $canvas_page = 'http://apps.facebook.com/khozzyaps/';
 # Tworzenie adresu url zgodnego ze standardem OAuth
 # Pobieramy dodatkowo takie informacje jak email, status oraz lokalizacje uzytkownika
 $auth_url = 'http://facebook.com/dialog/oauth?client_id=' . $app_id . '&redirect_uri=' . urlencode($canvas_page) 
 . '&scope=email,user_status,user_location';
 # Odebranie danych i zapisanie jej do zmiennej
 $signed_request = $_REQUEST["signed_request"];
 # Dzielimy odebrane dane wzgledem kropki na dwie czesci
 list($encoded_sig,$payload) = explode('.',$signed_request,2);
 # Dekodujemy druga czecs odebranych danych i zapisujemy je do zmiennej
 $data = json_decode(base64_decode(strtr($payload,'_-',' /')), true);
 
 # Jezeli nie zautoryzowano uzytkownika, przenies go z powrotem na strone autoryzacji
 if (empty($data["user_id"])) {
  echo("<script> top.location.href='" . $auth_url . "'</script>");
 }
 # Jezli wszystko odbylo sie poprawnie wyswietl zawartosc zmiennej $data w formie przyjaznej uzytkownikowi
 else {
  echo "<pre>";
  echo print_r($data); 
  echo "</pre>";
 }
 
?>

Oraz zrzut ekranu prezentujący działanie aplikacji:


poniedziałek, 30 maja 2011

6 sprawdzonych sposobów, aby użytkownik szybko opuścił twoją stronę internetową.

Zaintrygowany artykułem "What Makes You Leave A Website" opublikowanym na blogu www.smartpassiveincome.com postanowiłem zebrać większość powodów jakie pojawiły się w komentarzach pod wpisem. Dane te są szczególnie cenne ponieważ jasno określają preferencje użytkowników. 

Nie stosując się do poniższych rad, stworzymy witrynę przyjazną dla czytelnika/klienta, zwiększając prawdopodobieństwo na jej powtórne odwiedzenie.

Jak odstraszyć użytkownika? 

1.Przedstaw mu na powitanie ofertę sprzedaży.

Ludzie nie lubią być sterowani ani manipulowani. Chcą by przedstawiono im korzyści płynące z posiadania oferowanych dóbr. Jeśli zostaną one ukazane w sposób nienachalny (niekoniecznie moralny) istnieje większa szansa na pozytywny odbiór naszej oferty. Daje to lepszy efekt niż wykorzystanie prymitywnej sugestii w stylu "Niesamowita okazja! Kup teraz, taka oferta więcej się nie powtórzy". Dajmy im czas na przemyślenia i podjęcie słusznej decyzji.

2. Nie aktualizuj strony.

Jeśli użytkownik poszukujący informacji odwiedzi stronę/bloga na której ostatni post umieszczony był kilka lat temu, nie będzie usatysfakcjonowany i prawdopodobnie nie wróci tam  po raz drugi. Chcemy być na bieżąco, chcemy mieć poczucie, że wpisując adres dostaniemy jakiegoś świeżego i interesującego newsa. Wymaga to ciągłego zaangażowania i pracy autora.

3. Nie informuj jakie treści znajdują się na stronie.

W czytelnym miejscu należy umieścić informację ze słowami kluczowymi, które pomogą we wstępnej orientacji na naszej witrynie. Powinno to być miejsce na którym skupia się wzrok zaraz po załadowaniu strony. Nie utrudniaj życia internaucie, tylko kilka kliknięć dzieli go od konkurencji. Dobry tytuł także może dużo pomóc.

Warto także pamiętać, że każdy szuka jakiejś informacji i nie ma zamiaru czytać wypracowań aby ją znaleźć. Pamiętaj o krótkich paragrafach (maksymalnie 10 linijek), rysunkach, diagramach. Pisz poprawnie, gramatycznie, bez slangu. Wszystkie te "drobiazgi" mają znaczenie.

4. Strona musi zawierać wszystkie możliwe kolory w palecie barw oraz gadżety.

Aby zatrzymać internautę na stronie musimy zadbać o przejrzystość i intuicyjną nawigację na naszej witrynie. Warto zainteresować się odpowiednim tagowaniem treści, formatowaniem obrazów, właściwym doborem kolorów, podstawami designu. Użytkownik musi w przeciągu kilku sekund odnaleźć szukaną informację. 

Należy także usunąć wszystkie gadżety i skrypty, które nie zwiększają użyteczności strony. Prostota w tym przypadku jest najbardziej elegancka i pożądana.

Tworząc projekt witryny warto opierać się na statystykach odwiedzin (np. Google Analytics). Każda grupa odbiorców inaczej postrzega rzeczywistość. Strona będzie miała inny layout i inne kolory, gdy skierowana zostanie do młodzieży, a inny dla lekarzy.

5. Niech inni automatycznie poznają twoje gusta muzyczne.

To była jedna z najczęściej wymienianych skarg. Jeśli chcesz, aby użytkownik w mgnieniu oka skierował kursor w prawy górny, róg ekranu powitaj go automatycznie uruchamiającą się muzyką lub klipem wideo. Nic bardziej nie irytuje, niż kłopoty ze znalezieniem guzika wyłączającego dźwięku. Znajdź inny sposób oddziałania na ten zmysł, ponieważ nieumiejętnie wykorzystany w ogromnej większości przypadków zadziała na twoją niekorzyść.

6. Reklama jest dźwignią handlu. Biegnij po trupach do celu.

Umieszczając interesujący content, zwiększamy ruch na stronie. Naturalną rzeczą jest chęć czerpania korzyści finansowych z dobrze wykonywanej pracy. Pamiętajmy jednak jak uciążliwe są wyskakujące okienka pop-up lub pop-under. U wielu osób ich występowanie determinuje dalsze wizyty na stronie.

Warto zadbać o wyraźne oddzielenie sekcji z reklamami na naszej stronie, kierując się zasadą, że nigdy nie powinny one zajmować więcej niż 30% ekranu oraz nie przeszkadzać w płynnym przeglądaniu witryny. Unikajmy też reklam o charakterze soft-porn, gdyż część internautów jest uczulona na tego typu marketing.

Z pozoru banalne i oczywiste, jednak większość błędów jest stale popełniania. Prostym sposobem jest zmiana sposobu myślenia - wyobraź sobie, że to ty odwiedzasz po raz pierwszy stronę. Jak się czujesz? Czy od samego początku szukana treść jest łatwo dostępna? Czy strona zachęca cię wizualnie do dłuższego pozostania?