planes jocul copilăriei într-un format modernalaiba/pub/absolvire/2017 iarna/planes.pdf3...

53
UNIVERSITATEA „ALEXANDRU IOAN CUZA” IAŞI FACULTATEA DE INFORMATICĂ LUCRARE DE LICENŢĂ Planes – Jocul copilăriei într-un format modern propusă de Ionuț Mihai Burlacu Sesiunea: februarie, 2017 Coordonator ştiinţific Asist. Dr. Vasile Alaiba

Upload: others

Post on 22-Jan-2020

2 views

Category:

Documents


0 download

TRANSCRIPT

Page 1: Planes Jocul copilăriei într-un format modernalaiba/pub/absolvire/2017 iarna/Planes.pdf3 DECLARAŢIE DE CONSIMŢĂMÂNT Prin prezenta declar că sunt de acord ca Lucrarea de licență

UNIVERSITATEA „ALEXANDRU IOAN CUZA” IAŞI

FACULTATEA DE INFORMATICĂ

LUCRARE DE LICENŢĂ

Planes – Jocul copilăriei într-un

format modern

propusă de

Ionuț Mihai Burlacu

Sesiunea: februarie, 2017

Coordonator ştiinţific

Asist. Dr. Vasile Alaiba

Page 2: Planes Jocul copilăriei într-un format modernalaiba/pub/absolvire/2017 iarna/Planes.pdf3 DECLARAŢIE DE CONSIMŢĂMÂNT Prin prezenta declar că sunt de acord ca Lucrarea de licență

1

UNIVERSITATEA „ALEXANDRU IOAN CUZA” IAŞI

FACULTATEA DE INFORMATICĂ

Planes - Jocul copilăriei într-un

format modern

Ionuț Mihai Burlacu

Sesiunea: februarie, 2017

Coordonator ştiinţific

Asist. Dr. Vasile Alaiba

Page 3: Planes Jocul copilăriei într-un format modernalaiba/pub/absolvire/2017 iarna/Planes.pdf3 DECLARAŢIE DE CONSIMŢĂMÂNT Prin prezenta declar că sunt de acord ca Lucrarea de licență

2

DECLARAŢIE PRIVIND ORIGINALITATE ŞI RESPECTAREA

DREPTURILOR DE AUTOR

Prin prezenta declar că Lucrarea de licenţă cu titlul „Planes – Jocul copilăriei într-un

format modern” este scrisă de mine şi nu a mai fost prezentată niciodată la o altă facultate sau

instituţie de învăţământ superior din ţară sau străinătate. De asemenea, declar că toate sursele

utilizate, inclusiv cele preluate de pe Internet, sunt indicate în lucrare, cu respectarea regulilor

de evitare a plagiatului:

- toate fragmentele de text reproduse exact, chiar şi în traducere proprie din altă limbă,

sunt scrise între ghilimele şi deţin referinţa precisă a sursei;

- reformularea în cuvinte proprii a textelor scrise de către alţi autori deţine referinţa

precisă;

- codul sursă, imaginile etc. preluate din proiecte open-source sau alte surse sunt utilizate

cu respectarea drepturilor de autor şi deţin referinţe precise;

- rezumarea ideilor altor autori precizează referinţa precisă la textul original.

Iaşi, data

Absolvent Ionuț Mihai Burlacu

___________________________

Page 4: Planes Jocul copilăriei într-un format modernalaiba/pub/absolvire/2017 iarna/Planes.pdf3 DECLARAŢIE DE CONSIMŢĂMÂNT Prin prezenta declar că sunt de acord ca Lucrarea de licență

3

DECLARAŢIE DE CONSIMŢĂMÂNT

Prin prezenta declar că sunt de acord ca Lucrarea de licență cu titlul „Planes - Jocul

copilăriei într-un format modern”, codul sursă al programelor şi celelalte conţinuturi (grafice,

multimedia, date de test etc.) care însoţesc această lucrare să fie utilizate în cadrul Facultăţii de

Informatică.

De asemenea, sunt de acord ca Facultatea de Informatică de la Universitatea „Alexandru

Ioan Cuza” Iași să utilizeze, modifice, reproducă şi să distribuie în scopuri necomerciale

programele-calculator, format executabil şi sursă, realizate de mine în cadrul prezentei lucrări

de licenţă.

Iaşi, data

Absolvent Ionuț Mihai Burlacu

_________________________

Page 5: Planes Jocul copilăriei într-un format modernalaiba/pub/absolvire/2017 iarna/Planes.pdf3 DECLARAŢIE DE CONSIMŢĂMÂNT Prin prezenta declar că sunt de acord ca Lucrarea de licență

4

Cuprins

1. Introducere ................................................................................................................................ 6

1.1 Motivație ............................................................................................................................... 6

1.2 Context ................................................................................................................................. 6

1.3 Cerințe funcționale ............................................................................................................... 7

1.4 Abordare tehnică .................................................................................................................. 8

1.5 Contribuții ............................................................................................................................. 9

2. Dezvoltarea aplicației server .................................................................................................. 10

2.1 Sails.js .................................................................................................................................. 10

2.2 Socket.io ............................................................................................................................. 12

2.3 Configurarea proiectului .................................................................................................... 13

2.4 Cele 3 servere ..................................................................................................................... 16

2.5 MongoDB ............................................................................................................................ 17

2.6 isAuthorized ........................................................................................................................ 19

2.7 Multiple logins .................................................................................................................... 20

2.8 Lucrul cu imagini ................................................................................................................. 22

2.9 Push Notification ................................................................................................................ 23

2.10 Email Service ..................................................................................................................... 24

2.11 Main Service ...................................................................................................................... 25

3. Dezvoltarea aplicației client .................................................................................................... 27

3.1 AngularJS 2 .......................................................................................................................... 27

3.2 Ionic 2 .................................................................................................................................. 28

3.3 localStorage ......................................................................................................................... 30

3.4 ApiService ............................................................................................................................ 31

3.5 DataService .......................................................................................................................... 33

3.6 Push Notification ................................................................................................................. 34

3.7 Globals ................................................................................................................................. 35

Page 6: Planes Jocul copilăriei într-un format modernalaiba/pub/absolvire/2017 iarna/Planes.pdf3 DECLARAŢIE DE CONSIMŢĂMÂNT Prin prezenta declar că sunt de acord ca Lucrarea de licență

5

3.8 LoadingService ..................................................................................................................... 36

3.9 Electron ................................................................................................................................ 37

4. Descrierea aplicației ................................................................................................................ 39

4.1 Login .................................................................................................................................... 39

4.2 Register ............................................................................................................................... 40

4.3 Forgot Password ................................................................................................................. 41

4.4 Home .................................................................................................................................. 42

4.5 Side Menu ........................................................................................................................... 43

4.6 Game Invitations ................................................................................................................ 44

4.7 Profile ................................................................................................................................. 45

4.8 Update Info / Change Password ......................................................................................... 46

4.9 Friend List / Search Players ................................................................................................ 47

4.10 Friend Requests / Match History ...................................................................................... 48

4.11 Game Setup ...................................................................................................................... 49

4.12 Game ................................................................................................................................ 50

4.13 End Game ......................................................................................................................... 51

5. Bibliografie ............................................................................................................................... 52

Page 7: Planes Jocul copilăriei într-un format modernalaiba/pub/absolvire/2017 iarna/Planes.pdf3 DECLARAŢIE DE CONSIMŢĂMÂNT Prin prezenta declar că sunt de acord ca Lucrarea de licență

6

1. Introducere

1.1 Motivație

Majoritatea dintre noi cred că am jucat în pauzele de la liceu sau chiar de la facultate

jocul Avioane, însă cel mai mare impediment era faptul că la fiecare joc trebuiau trasate pe foi

cele două tabele necesare jocului, lucru care făcea ca jocul să se termine de obicei după o

singură rundă. Am ales să realizez o aplicație atât mobilă cât și desktop cu ajutorul căreia să se

poată juca Avioane fără a avea nevoie de hârtie și pix, fiind nevoie doar de conexiune la

internet și de un dispozitiv mobil sau de un desktop/laptop.

1.2 Context

Jocurile de strategie jucate în două persoane au apărut de foarte mult timp, primul joc

de acest gen fiind ”X și 0” care se presupune că își are originile în antichitate.

Jocul Avioane este o variantă alternativă a jocului Battleships1 care datează din timpul

primului război mondial. Avioane este un joc de strategie ce se joacă în două persoane. Pentru a

juca acest joc, fiecare jucător are nevoie de o foaie și un instrument de scris. La începutul

jocului, fiecare persoană trebuie să își amplaseze cele 3 avioane pe un chenar de 10x10 căsuțe.

După ce jocul a început, fiecare jucător trebuie să ghicească pe rând câte o căsuță în care se află

unul din avioanele inamicului. Jocul se termină atunci când unul din jucători a descoperit toate

cele 3 avioane ale jucătorului. Putem vedea mai jos un exemplu de chenar aparținând unuia

dintre jucători:

1 https://en.wikipedia.org/wiki/Battleship_(game)

Page 8: Planes Jocul copilăriei într-un format modernalaiba/pub/absolvire/2017 iarna/Planes.pdf3 DECLARAŢIE DE CONSIMŢĂMÂNT Prin prezenta declar că sunt de acord ca Lucrarea de licență

7

Figura 1 – Chenar 10x10 cu cele 3 avioane poziționate2

1.3 Cerințe funcționale

Posibilitatea de a juca jocul Avioane contra unei alte persoane aleasă de către

server care dorește să joace în același timp cu tine sau cu o persoană la alegere

din lista de prieteni;

Crearea de cont, fie direct din aplicație, fie prin intermediul rețelei de socializare

Facebook. Contul este necesar pentru a putea avea o listă de prieteni și pentru a

putea vedea istoricul meciurilor jucate. Jocul se va putea juca și fără

autentificare, însă utilizatorul nu va avea acces la lista de prieteni sau la istoricul

meciurilor, acesta numindu-se în joc “guest” (Oaspete);

Accesul la lista de prieteni, aceștia fiind adăugați în urma căutării după nume;

Accesul la istoricul meciurilor jucate unde se va putea vedea între cine și cine s-a

jucat meciul, cine a fost câștigătorul și în urmă cu cât timp s-a jucat fiecare meci;

În cazul în care unul dintre jucători părăsește jocul din greșeală sau din cauza

lipsei conexiunii la internet, aplicația va permite acestuia să revină în joc timp de

30 de secunde, în caz contrar celălalt jucător va fi ales învingător.

Invitarea altor persoane la joc se va putea realiza și pentru jucătorii care se află

în aplicație în acel moment, dar și pentru cei care nu se află în aplicație prin

intermediul notificărilor push.

2 https://ro.wikipedia.org/wiki/Avioane_(joc)

Page 9: Planes Jocul copilăriei într-un format modernalaiba/pub/absolvire/2017 iarna/Planes.pdf3 DECLARAŢIE DE CONSIMŢĂMÂNT Prin prezenta declar că sunt de acord ca Lucrarea de licență

8

Accesul la profilul utilizatorului unde acesta își va putea schimba imaginea de

profil, username-ul sau parola contului.

1.4 Abordare tehnică

Pentru partea de server (back-end) am folosit NodeJS împreună cu bibliotecile Sails.js și

Socket.IO. Baza de date este una de tip NoSQL realizată cu ajutorul arhitecturii MongoDB.

Comunicarea între aplicație și server se va realiza prin intermediul websocket-urilor în timpul

jocului propriu-zis și prin intermediul serviciilor web REST pentru restul funcționalităților.

Aplicația va fi de două feluri, pentru desktop și pentru mobil. Pentru aplicația de mobil

voi folosi biblioteca Ionic, iar pentru aplicația de desktop voi folosi biblioteca Electron. Datorită

tehnologiilor folosite aplicația de mobil va putea fi rulată pe Android, iOS și Windows Phone, iar

aplicația de desktop va putea fi rulată pe Windows, OS X și Ubuntu. Eu voi alege să prezint

aplicația doar pe Android în cazul celei pentru mobil și doar pe Windows în cazul celei pentru

desktop. Avantajul folosirii acestor tehnologii este faptul că aplicația este scrisă o singură dată,

iar apoi compilată pentru platforma dorită.

JavaScript este un limbaj de programare orientat obiect bazat pe conceptul

prototipurilor care a apărut în anul 1995 și care a fost dezvoltat inițial de către Brendan Eich.

Acest limbaj a fost inițial conceput pentru a putea adăuga funcționalități paginilor web care

până la acea vreme erau statice, însă mai târziu a început să fie utilizat și pentru crearea

serverelor web.

NodeJS este un mediu de programare bazat pe limbajul JavaScript, multiplatformă, cu

sursă deschisă, cu ajutorul căruia se pot realiza servere web. NodeJS oferă o arhitectură bazată

pe evenimente capabilă să realizeze transfer de date asincron. Aceasta permite realizarea de

aplicații web scalabile care conțin multe operații de intrare/ieșire, dar și realizarea de aplicații

care rulează în timp real (”real-time”) cum ar fi o aplicație de chat sau un joc.

Page 10: Planes Jocul copilăriei într-un format modernalaiba/pub/absolvire/2017 iarna/Planes.pdf3 DECLARAŢIE DE CONSIMŢĂMÂNT Prin prezenta declar că sunt de acord ca Lucrarea de licență

9

1.5 Contribuții

Prezenta lucrare este împărțită în trei capitole: Dezvoltarea aplicației server,

Dezvoltarea aplicației client și Descrierea aplicației.

Capitolele Dezvoltarea aplicației server și Dezvoltarea aplicației client prezintă în primul

rând tehnologiile folosite în dezvoltarea acestora, dar și unele funcționalități importante ce

merită a fi menționate. Ambele capitole au atașate secțiuni de cod relevante din ambele

aplicații, client și server.

Capitolul Descrierea aplicației prezintă succint fiecare ecran din aplicația client împreună

cu o scurtă descriere a funcționalităților acestora. Și aici avem atașate capturi de ecran realizate

pe un dispozitiv mobil ce rulează aplicația client.

Page 11: Planes Jocul copilăriei într-un format modernalaiba/pub/absolvire/2017 iarna/Planes.pdf3 DECLARAŢIE DE CONSIMŢĂMÂNT Prin prezenta declar că sunt de acord ca Lucrarea de licență

10

2. Dezvoltarea aplicației server

2.1 Sails.js

Sails.js este o bibliotecă cu sursă deschisă de tip MVC (Model-View-Controller) scrisă în

totalitate în limbajul JavaScript. Aceasta este una dintre cele mai populare biblioteci bazate pe

Node.js. Sails.js poate fi folosit pentru realizarea de aplicații de tip enterprise, dar mai cu seamă

pentru aplicații de tip chat sau jocuri multiplayer.

Figura 2: Structura de tip MVC3

Structura unui proiect bazat pe biblioteca Sails.js este una de tip modulară pentru a

permite o dezvoltare cât mai ușoară a aplicației. Împărțirea este realizată după funcționalitatea

pe care o are fiecare fișier în proiect.

Din structura proiectului merită menționate următoarele dosare/fișiere importante:

Dosarul /api conține toată logica aplicației server și are în componență următoarele dosare:

Dosarul /controllers conține toate clasele care manipulează datele definite în modele cu

ajutorul serviciilor;

Dosarul /models conține clasele ce ajută la reprezentarea datelor din baza de date;

Dosarul /policies conține politicile ce sunt aplicate în momentul realizării unei cereri

către server, dar înainte ca aceasta să ajungă în controller (ex. Verificarea că un

utilizator este autentificat atunci când face o cerere);

Dosarul /services conține clasele care realizează interogări în baza de date cu ajutorul

modelelor și apoi returnează răspunsul înapoi către controller.

Dosarul /config are în componență toate fișierele de configurare necesare funcționării

serverului cum ar fi: datele de conectare la baza de date, regulile de rutare, constante

folosite în clase, etc.;

3 https://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93controller

Page 12: Planes Jocul copilăriei într-un format modernalaiba/pub/absolvire/2017 iarna/Planes.pdf3 DECLARAŢIE DE CONSIMŢĂMÂNT Prin prezenta declar că sunt de acord ca Lucrarea de licență

11

Dosarul /node_modules conține toate librăriile externe ce au fost instalate în prealabil

utilizând comanda npm install nume_librărie ;

Fișierul app.js reprezintă nucleul serverului, el fiind cel care înglobează toate fișierele

descrise mai sus într-un singur proces;

Fisierul package.json este un fișier ce conține toate datele necesare instalării aplicației pe o

mașină ce rulează Node.js.

Figura 3: Structura aplicației server

Interacțiunea cu serverul se poate defini în câțiva pași:

1. Utilizatorul realizează o cerere către server printr-o anumită adresă definită în

fișierul routes.js;

2. Cererea trece mai întâi prin politicile definite pentru această rută dacă este

cazul, iar apoi ajunge în controller;

3. Controllerul apelează un serviciu pentru o interogare în baza de date;

4. Serviciul realizează interogarea cu ajutorul modelului definit pentru respectivul

tabel din baza de date și returnează un răspuns către controllerul care l-a apelat;

5. Controllerul preia răspunsul returnat de către serviciu și îl trimite înapoi către

utilizator.

Page 13: Planes Jocul copilăriei într-un format modernalaiba/pub/absolvire/2017 iarna/Planes.pdf3 DECLARAŢIE DE CONSIMŢĂMÂNT Prin prezenta declar că sunt de acord ca Lucrarea de licență

12

2.2 Socket.io

Socket.io este o bibliotecă cu sursă deschisă care permite comunicarea bidirecțională în

timp real între server și clienți. Comunicarea este bazată pe evenimente, iar protocolul de

comunicare este WebSocket.

Această bibliotecă este alcătuită din două părți: o librărie pentru partea de client ce

poate fi fie un browser, fie o aplicație pentru mobil și o librărie pentru partea de server.

Un scenariu simplu de interacțiune între client și server poate fi definit astfel:

1. Clientul apeleaza funcția connect() ce primește ca parametru un URL și un port

definit de către server;

2. Serverul acceptă cererea de conectare trimisă de către client, iar apoi ascultă pe

mai multe evenimente ce ar putea fi emise de către client;

3. Se realizează schimbul de date între client și server;

4. Clientul se deconectează de la server apelând funcția disconnect() sau prin

distrugerea obiectul în care era păstrată conexiunea.

Am ales să folosesc această bibliotecă pentru a asigura o experiență de joc cât mai

plăcută, toată acțiunea jocului petrecându-se în timp real.

Figura 4: Secțiune din codul unui server ce acceptă conexiuni de timp WebSocket

Page 14: Planes Jocul copilăriei într-un format modernalaiba/pub/absolvire/2017 iarna/Planes.pdf3 DECLARAŢIE DE CONSIMŢĂMÂNT Prin prezenta declar că sunt de acord ca Lucrarea de licență

13

2.3 Configurarea proiectului

În urma creării proiectului cu ajutorul comenzii sails new Planes-Backend au fost

generate în mod implicit fișierele de configurare pentru a putea rula aplicația server fără a face

nici o modificare în ele.

Pentru a asigura comunicarea dintre client și server, avem nevoie mai întâi să definim un

set de reguli de rutare pentru a asigna fiecărei metode din controller un URL prin care poate fi

apelată. Acest lucru se realizează în fișierul routes.js din dosarul /config. Mai jos avem

prezentată o secțiune din acest fișier de configurare:

Figura 5: Secțiune din fișierul /config/routes.js

Apoi, pentru setarea portului pe care va rula aplicația server, dar și pentru configurarea

modulului SSL am modificat în fișierul local.js din dosarul /config proprietatea port pentru a

defini portul și proprietatea ssl pentru configurarea modulului SSL.

Figura 6: Secțiune din fișierul /config/local.js

Cheia ca vine din engleză de la Certificate Authority și reprezintă un lanț de încredere ce

asigură browser-ul sau aplicația că certificatul folosit în cheia cert este unul valid. Acest lanț

este format din mai multe certificate ce sunt oferite de către companiile ce vând certificate SSL.

Cheia key reprezintă cheia de criptare cu care a fost realizat certificatul, iar cheia cert reprezintă

certificatul în sine. Acest modul asigură un protocol de comunicare sigur între client și server,

evitând astfel atacuri de timp man-in-the-middle de exemplu. Serviciile web sunt apelate

folosind protocolul https în loc de http cum este definit în mod implicit.

Page 15: Planes Jocul copilăriei într-un format modernalaiba/pub/absolvire/2017 iarna/Planes.pdf3 DECLARAŢIE DE CONSIMŢĂMÂNT Prin prezenta declar că sunt de acord ca Lucrarea de licență

14

Pentru comunicarea cu baza de date a trebuit să configurez în fișierul connections.js din

dosarul /config o conexiune oferind adresa, portul și credențialele serverului de tip MongoDB.

Inițial, la instalarea serverului de baze de date nu este configurat un utilizator cu care să se facă

conexiunea. Am configurat manual un utilizator pentru a nu lăsa serverul pe oricine să acceseze

datele din el.

Figura 7: Exemplu conexiune cu serverul MongoDB

Unele rute ce au fost definite în routes.js trebuie să poată fi accesate doar de către

utilizatorii ce s-au autentificat înainte. Acest lucru se poate face după ce am creat o politică ce

verifică dacă utilizatorul este autentificat, iar rutele ce folosesc această politică se configurează

în fișierul policies.js din dosarul /config astfel:

Figura 8: Definirea rutelor ce folosesc politici

Cheia * reprezintă faptul că toate metodele din acel controller vor folosi politica

isAuthorized, iar la MainController doar cele două metode vor folosi aceeași politică. În cazul

controllerului AuthController este setat valoarea true deoarece în acest caz nu avem nevoie de

nici o politică în metodele din acel controller.

Page 16: Planes Jocul copilăriei într-un format modernalaiba/pub/absolvire/2017 iarna/Planes.pdf3 DECLARAŢIE DE CONSIMŢĂMÂNT Prin prezenta declar că sunt de acord ca Lucrarea de licență

15

Ultima setare care merită menționată este făcută în fișierul cron.js din dosarul /config.

În acest fișier se definesc procesele de tip cron4 ce rulează în mod independent de serverul

propriu-zis la o anumită perioadă de timp definită în prealabil.

Figura 9: Exemplu configurare cron

Acest cron din exemplu rulează la fiecare cincisprezece secunde și are rolul de a verifica

utilizatorii care sunt online în aplicație în acel moment. Logica din spate este următoarea:

1. După ce un utilizator s-a autentificat în aplicație, aceste anunță serverul la fiecare trei

secunde printr-o cerere faptul că el este online;

2. În momentul în care serverul a primit o astfel de cerere, el marchează pentru acest

utilizator timestamp5-ul curent;

3. Atunci când cron-ul rulează, el va verifica pentru fiecare utilizator din lista celor online

diferența dintre timestamp-ul curent și cel al utilizatorului;

4. Dacă diferența este mai mare de zece secunde, înseamnă că acel utilizator nu a mai

anunțat serverul la fiecare trei secunde că este online, deci va fi marcat ca fiind offline.

Constantele folosite în aplicația server sunt definite tot în dosarul /config într-un fișier

creat de mine care este numit const.js. Folosirea constantelor asigură faptul că atunci când

dorim să schimbăm o valoare, această va fi schimbată automat în tot proiectul. Ele pot fi

accesate în proiect folosind variabila globală sails.config.const.NUME_CONST.

Figura 10: Exemplu definire constante

4 https://en.wikipedia.org/wiki/Cron 5 https://en.wikipedia.org/wiki/Timestamp

Page 17: Planes Jocul copilăriei într-un format modernalaiba/pub/absolvire/2017 iarna/Planes.pdf3 DECLARAŢIE DE CONSIMŢĂMÂNT Prin prezenta declar că sunt de acord ca Lucrarea de licență

16

2.4 Cele trei servere

În urma unei analize realizată înainte de începerea lucrului la aplicația server am ajuns la

concluzia că folosirea protocolului WebSocket pentru întreaga comunicare dintre client și server

nu este o soluție viabilă. Folosirea acestui protocol presupune menținerea unei conexiuni

permanente, iar acest lucru face ca nivelul de date consumate să crească, iar durata de viață a

bateriei dispozitivului mobil să scadă.

Așadar, am decis să împart aplicația server în trei părți:

1. Primul server este realizat pe bază de servicii web REST6 și se ocupă de toate

funcționalitățile aplicației mobile, înafară de ecranele Game Setup și Game, și

funcționalitatea Search For Opponent;

2. Al doilea server este realizat cu ajutorul bibliotecii Socket.io și se ocupă de toată

logica din spatele jocului propriu-zis. Conexiunea cu acest server începe în

momentul când utilizatorul a ajuns în ecranul Game Setup și se termină atunci

când revine în ecranul acasă.

3. Al treilea server este realizat tot cu ajutorul bibliotecii Socket.io și conține doar

logica din spatele funcționalității Search For Opponent. Conexiunea cu acest

server începe în momentul când utilizatorul apasă pe butonul Search for

Opponent și se termină atunci când acesta și-a găsit un adversar sau când a

renunțat la căutare.

În acest fel, împărțirea aceasta asigură comunicare în timp real între clienți și server

doar acolo unde este într-adevăr nevoie, iar bateria dispozitivelor mobile este păstrată în cel

mai bun mod posibil.

Mai merită menționat faptul că cele trei servere rulează pe trei porturi diferite însă

comunicarea cu serverul de baze de date MongoDB se realizează printr-o singură conexiune.

6 https://spring.io/understanding/REST

Page 18: Planes Jocul copilăriei într-un format modernalaiba/pub/absolvire/2017 iarna/Planes.pdf3 DECLARAŢIE DE CONSIMŢĂMÂNT Prin prezenta declar că sunt de acord ca Lucrarea de licență

17

2.5 MondoDB

Pentru a păstra datele utilizatorilor avem nevoie de o bază de date. Unul dintre

avantajele bibliotecii Sails.js este ușurința și flexibilitatea cu care poate comunica cu multe

tipuri de baze de date cum ar fi: Postgres, Oracle, MySQL, MongoDB, etc.

MongoDB este un program de baza de date cu sursă deschisă, multiplatformă orientat

pe obiecte. MongoDB este clasificat ca fiind NoSQL și folosește documente de tip JSON pentru

stocarea datelor. Acesta a fost lansat în anul 2009 de către compania MongoDB Inc. MongoDB

prezintă o soluție din ce în ce mai căutată pentru aplicațiile care au nevoie de acces rapid

asupra datelor.

Eu am ales să folosesc MongoDB datorită vitezei cu care poate extrage datele și a

scalabilității. Datele sunt stocate sub formă de documente, în format JSON, împăcându-se

foarte bine cu Node.js.

Pentru a defini un document în MongoDB avem nevoie de un model declarat în aplicația

server. Un model este ca o schemă pentru acel document deoarece în el se declară coloanele

din acel document și tipul acestora. Tipul datelor poate fi: string, integer, date, etc.

Figura 11: Exemplu Model GameInvitation

Page 19: Planes Jocul copilăriei într-un format modernalaiba/pub/absolvire/2017 iarna/Planes.pdf3 DECLARAŢIE DE CONSIMŢĂMÂNT Prin prezenta declar că sunt de acord ca Lucrarea de licență

18

În figura 11 mai putem vedea declarate și două relații de tip one-to-many7 între modelul

User și modelul GameInvitation. Aceste relații ușurează extragerea datelor din baza de date și

sporește viteza de lucru.

Manipularea datelor se realizează în totalitate cu ajutorul ORM8-ului numit Waterline.

Waterline este o colecție de API-uri ce face ca lucrul cu datele din baza de date să fie unul

foarte curat și ușor de înțeles, indiferent de tipul de baze de date folosit.

Figura 12: Exemplu de interogare ce returnează invitațiile la joc

acceptate trimise de către utilizator

În figura 11, metoda find() este echivalentul lui SELECT din limbajul SQL, metoda

populate() este echivalentul lui JOIN din limbajul SQL, iar method exec() este cea care execută

interogarea și returnează rezultatul într-o funcție de tip callback9 în parametrul result.

Pentru vizualizarea mai ușoară și mai rapidă a datelor în faza de dezvoltare am folosit un

utilitar gratuit numit Robomongo10. Acesta permite reprezentarea vizuală a datelor, dar și

execuția de interogări în același mod ca și în terminal.

7 https://en.wikipedia.org/wiki/One-to-many_(data_model) 8 https://en.wikipedia.org/wiki/Object-relational_mapping 9 https://en.wikipedia.org/wiki/Callback_(computer_programming) 10 https://robomongo.org/

Page 20: Planes Jocul copilăriei într-un format modernalaiba/pub/absolvire/2017 iarna/Planes.pdf3 DECLARAŢIE DE CONSIMŢĂMÂNT Prin prezenta declar că sunt de acord ca Lucrarea de licență

19

2.6 isAuthorized

isAuthorized este o politică creată pentru a limita utilizatorii care nu sunt autentificați în

aplicație să folosească anumite servicii web. Logica din spate poate fi descrisă astfel:

1. Clientul trece prin procesul de autentificare și primește un token de la server ca și

răspuns dacă autentificarea se face cu succes;

2. Atunci când clientul face o cerere către server, acesta atașează în header11 o cheie

numită authorization-token ce va conține token-ul primit la autentificare;

3. Token-ul este mai întâi validat de către server, iar dacă validarea se face cu succes,

cererea merge mai departe către controller-ul corespunzător. În caz contrar, serverul

returnează un răspuns prin care anunță clientul de faptul că token-ul trimis de el este

invalid. Același lucru se întâmplă și în cazul în care token-ul lipsește din header.

Figura 13: Secțiune de cod din generarea token-ului

Generarea token-ului pe server se realizează cu ajutorul librăriei numită jsonwebtoken12.

Această librărie conține trei funcții principale: sign(), verify() și decode().

Funcția sign() este exemplificată în figura 13 și este folosită pentru generarea de token.

Primul parametru reprezintă datele ce vor fi criptate, iar al doilea parametru reprezintă o cheie

unică cu ajutorul căreia se criptează datele din primul parametru. Metoda de criptare folosită se

numește HS25613.

Funcția verify() este folosită pentru a verifica dacă un token trimis de către client este

unul valid și poate fi decriptat mai departe. Aceasta primește ca parametrii token-ul și cheia de

criptare folosită în funcția sign().

Funcția decode() este folosită, după cum sugerează și numele acesteia, pentru

decriptarea token-ului trimis de către client. Parametrii acestei funcții sunt aceiași cu cei folosiți

în funcția verify().

11 https://en.wikipedia.org/wiki/List_of_HTTP_header_fields 12 https://github.com/auth0/node-jsonwebtoken 13 https://en.wikipedia.org/wiki/JSON_Web_Token

Page 21: Planes Jocul copilăriei într-un format modernalaiba/pub/absolvire/2017 iarna/Planes.pdf3 DECLARAŢIE DE CONSIMŢĂMÂNT Prin prezenta declar că sunt de acord ca Lucrarea de licență

20

Figura 14: Secțiune de cod din procesul de decriptare a unui token

După fiecare proces de decriptare se verifică dacă id-ul conținut de acel token este unul

din baza de date și dacă aparține unui utilizator. În cazul în care acesta este găsit în baza de

date, trimite cererea mai departe către controller cu ajutorul metodei next(). Dacă id-ul nu

există în baza de date, se trimite un răspuns clientului prin care se anunță acest lucru.

În realitate, acest token nu ar putea fi niciodată invalid dacă este trimis de cineva care

folosește aplicația. El ar putea fi invalid doar dacă cineva ar face reverse engineering14 la

aplicație și ar descoperi că trebuie să trimită acest token pentru a avea acces la aceste servicii

web.

2.7 Multiple logins

Serverul tratează într-un mod elegant cazul în care un utilizator dorește să se autentifice

în aplicație, dar acesta deja este autentificat pe un alt dispozitiv în acel moment. Dacă acest

lucru nu ar fi tratat, atunci ar putea apărea conflicte la nivel de server și eventual crash-uri.

La fiecare proces de autentificare sau la fiecare revenire în aplicație fiind deja

autentificat, se salvează în baza de date pentru acel utilizator token-ul folosit mai departe în

cereri. În acest mod, un utilizator poate avea doar un singur token valid într-un moment

oarecare.

Putem distinge două cazuri de autentificare multiplă:

14 https://en.wikipedia.org/wiki/Reverse_engineering

Page 22: Planes Jocul copilăriei într-un format modernalaiba/pub/absolvire/2017 iarna/Planes.pdf3 DECLARAŢIE DE CONSIMŢĂMÂNT Prin prezenta declar că sunt de acord ca Lucrarea de licență

21

1. Utilizatorul dorește să se autentifice. Dacă acesta este deja autentificat pe un alt

dispozitiv și este într-un meci, va primi o alertă pe noul dispozitiv ce îl va anunța

că nu se poate autentifica din această cauză. Dacă deja este autentificat, dar nu

este într-un meci, atunci acesta va trece de procesul de autentificare, noul token

generat îl va suprascrie pe cel vechi, iar celălalt dispozitiv va fi anunțat în câteva

secunde că sesiunea i-a expirat și va fi trimis către ecranul de autentificare.

2. Utilizatorul este deja autentificat dintr-o sesiune anterioară și intră în aplicație.

Serverul va face o verificare în baza de date după ce token-ul a fost decriptat

pentru a verifica dacă acest token se potrivește cu cel din baza de date. Dacă se

potrivește atunci el va fi trimis către ecranul acasă, altfel va fi anunțat ca

sesiunea i-a expirat și va fi trimis către ecranul de autentificare.

Figura 15: Secțiune de cod din funcția care verifică token-ul

în cazul în care utilizatorul este deja autentificat

Page 23: Planes Jocul copilăriei într-un format modernalaiba/pub/absolvire/2017 iarna/Planes.pdf3 DECLARAŢIE DE CONSIMŢĂMÂNT Prin prezenta declar că sunt de acord ca Lucrarea de licență

22

2.8 Lucrul cu imagini

Aplicația permite utilizatorilor care și-au creat cont în aplicație să își seteze o imagine de

profil după propria lor dorință. Fișierul poate proveni din orice sursă, atât timp cât el este

încărcat prin aplicație.

Pentru prelucrarea imaginilor am folosit librăria numită gm ce are la bază o altă librărie

numită GraphicsMagick15.

GraphicsMagick este o colecție de funcții folosite pentru procesarea de imagini. Ea

poate fi instalată și folosită pe majoritatea sistemelor de operare. Printre numeroasele funcții

se numără și convertirea de fișiere, redimensionarea, rotirea, modificarea culorilor chiar și

compararea a doua imagini.

Fișierele trimise de către utilizatori sunt redimensionate la o dimensiune fixată de 500

pe 500 de pixeli, sunt decupate în formă de pătrat pentru a se putea afișa bine în aplicația

mobilă și apoi sunt salvate pe disc într-o locație aflată în exteriorul dosarului unde se afla codul

serverului. Acest lucru previne ștergerea accidentală a imaginilor atunci când se trag modificări

ale codului de pe GitHub. Fișierele care nu mai sunt folosite sunt șterse pentru a nu ocupa

spațiu inutil pe disc.

Pentru a putea servi imaginile din server în aplicație am creat un server în Apache16 care

redirecționează cererile făcute pe portul 443 către dosarul cu imagini de pe disc.

Figura 16: Secțiune de cod din procesul de salvare a imaginilor pe disc

15 http://www.graphicsmagick.org/ 16 https://httpd.apache.org/

Page 24: Planes Jocul copilăriei într-un format modernalaiba/pub/absolvire/2017 iarna/Planes.pdf3 DECLARAŢIE DE CONSIMŢĂMÂNT Prin prezenta declar că sunt de acord ca Lucrarea de licență

23

2.9 Push Notification

Firebase Cloud Messaging (FCM) este o soluție gratuită multiplatformă care permite

trimiterea de notificări push către dispozitivele mobile și care este oferită de către Google.

Am ales să folosesc acest serviciu pentru a anunța utilizatorii de anumite evenimente

petrecute în aplicație chiar și când aceștia au aplicația închisă. Un exemplu de eveniment este

primirea unei invitații la joc de la un alt utilizator al aplicației.

În primul rând, pentru folosirea serviciului FCM a fost nevoie să creez o aplicație pe site-

ul celor de la Google Firebase, iar de acolo să iau un cheie numită Server key care este folosită

mai departe pentru a trimite notificări către dispozitive.

În al doilea rând, pentru folosirea serviciului FCM în aplicația server a mai fost nevoie să

instalez biblioteca node-gcm ce permite trimiterea de notificări dintr-un server scris în Node.js.

Un utilizator poate avea într-un moment oarecare maxim un token pentru notificări

push salvat în baza de date. Acest lucru face ca utilizatorul să primească notificări push doar pe

dispozitivul pe care este autentificat în acel moment.

Figura 17: Secțiune de cod din procesul de trimitere a notificărilor push

Page 25: Planes Jocul copilăriei într-un format modernalaiba/pub/absolvire/2017 iarna/Planes.pdf3 DECLARAŢIE DE CONSIMŢĂMÂNT Prin prezenta declar că sunt de acord ca Lucrarea de licență

24

2.10 Email service

Pentru trimiterea de email-uri către utilizatori am folosit librăria numită nodemailer ce

permite trimiterea de email-uri cu conținut text, dar și cu conținut de tip HTML.

Protocolul prin care se trimit aceste email-uri este SMTPS care reprezintă o metodă de

securizare a protocolului STMP. Protocolul SMTP este un standard al internetului ce permite

transmiterea de email-uri. Acesta a fost definit prima dată în anul 1982 și a fost actualizat

ultima dată în anul 2008. Portul folosit de protocolul SMTPS este 587.

În inițializarea librăriei nodemailer avem nevoie de o adresă de email validă ce va fi

folosită pe post de server pentru trimiterea de email-uri. În cazul meu am folosit adresa

personală de Gmail. Utilizatorii primesc email-uri doar după primul pas din procesul de

înregistrare sau după primul pas din procesul de resetare parolă.

Figura 18: Secțiune de cod din procesul de trimite a unui email

Page 26: Planes Jocul copilăriei într-un format modernalaiba/pub/absolvire/2017 iarna/Planes.pdf3 DECLARAŢIE DE CONSIMŢĂMÂNT Prin prezenta declar că sunt de acord ca Lucrarea de licență

25

2.11 Main service

Pentru a realiza funcționalitatea jocului propriu-zis a trebuit să stochez undeva datele

despre meciurile aflate în progres, dar nu am putut să le stochez în baza de date. Motivul este

acela că baza de date ar fi să facă foarte multe scrieri și citiri pentru fiecare meci în parte ceea

ce ar îngreuna timpul de răspuns, respectiv experiența de joc. Așa că am ales să creez un

serviciu numit MainService ce păstrează aceste date direct pe server.

Structura acestui serviciu este următoarea:

Figura 19: Secțiune de cod din clasa MainService

În figura 19 putem observa următoarele chei: onlinePlayers și onlinePlayersTimestamps

care reprezintă doi vectori în care sunt stocate id-urile utilizatorilor online, respectiv ultimul

timestamp din momentul când aceștia au anunțat serverul că sunt online. Mai putem observa și

cheile inGamePlayers unde sunt stocate id-urile utilizatorilor care se află într-un meci și cheia

waitingOpponent care este folosită pentru funcționalitatea Search for Opponent. Cea mai

importantă cheie această clasă este gameRooms unde sunt păstrate toate informațiile despre

meciurile aflate în derulare în orice moment pe server.

O cameră de joc se creează în momentul în care un utilizator trimite o invitație de joc

unui alt utilizator sau în momentul când doi utilizatori sunt introduși în meci în urma apăsării

butonului Search for Opponent.

O cameră de joc este distrusă în momentul când meciul s-a terminat, iar ambii utilizatori

au refuzat remiza sau atunci când ambii utilizatori părăsesc jocul, fie intenționat, fie din cauza

lipsei de conexiune la internet.

Page 27: Planes Jocul copilăriei într-un format modernalaiba/pub/absolvire/2017 iarna/Planes.pdf3 DECLARAŢIE DE CONSIMŢĂMÂNT Prin prezenta declar că sunt de acord ca Lucrarea de licență

26

Figura 20: Secțiune de cod din procesul de creare a unei camere de joc

Fiecărei camere de joc îi este atribuit un id unic generat cu ajutorul librăriei uuid care

asigură că la fiecare generare returnează un șir de caractere unic.

În cazul în care în timpul meciului unul dintre jucători este deconectat de la server din

cauza lipsei conexiunii la internet, starea meciului se păstrează intactă timp de treizeci de

secunde, timp în care jucătorul deconectat se poate reconecta în meci și poate continua de

unde a rămas în momentul deconectării. Toate informațiile necesare pentru reconectarea în

meci sunt păstrate în aceste obiecte numite camere de joc.

Dacă jucătorul deconectat nu s-a reconectat în cele treizeci de secunde acordate, el este

declarat pierzător, iar oponentul său este declarat învingător.

Page 28: Planes Jocul copilăriei într-un format modernalaiba/pub/absolvire/2017 iarna/Planes.pdf3 DECLARAŢIE DE CONSIMŢĂMÂNT Prin prezenta declar că sunt de acord ca Lucrarea de licență

27

3. Dezvoltarea aplicației client

3.1 AngularJS 2

AngularJS 2 este urmașul binecunoscutului AngularJS 1, bibliotecă ce permite realizarea

părții de front-end a aplicațiilor web. Acesta a fost lansat în anul 2010 de către compania

Google, iar principala lui caracteristică este posibilitatea de a crea aplicații web pe o singură

pagină (“single-page”).

AngularJS 2 nu a fost lansat încă, acesta fiind în beta17. Schimbările față de predecesorul

său sunt în primul rând în materie de performanță, dar și de organizare a codului. Limbajul în

care este scris AngularJS 2 este TypeScript.

TypeScript este un limbaj realizat de către cei de la GitHub ce permite scrierea de clase,

interfețe, etc. ca apoi acestea să fie compilate și transformate în cod JavaScript.

Figura 21: Secțiune de cod scrisă în TypeScript

17 https://en.wikipedia.org/wiki/Software_release_life_cycle#Beta

Page 29: Planes Jocul copilăriei într-un format modernalaiba/pub/absolvire/2017 iarna/Planes.pdf3 DECLARAŢIE DE CONSIMŢĂMÂNT Prin prezenta declar că sunt de acord ca Lucrarea de licență

28

3.2 Ionic 2

Ionic 2 este o bibliotecă cu sursă deschisă ce permite realizarea de aplicații mobile

folosind limbaje web. Acesta este succesorul bibliotecii Ionic 1 ce a fost lansată în anul 2013 de

către compania Drifty.

Ionic 2 este scrisă cu ajutorul bibliotecii AngularJS 2 și se află în același stagiu ca și

AngularJS2, adică în beta. Pentru a putea compila aplicații pentru dispozitive mobile, Ionic 2 se

folosește de librăria Cordova. Cordova permite folosirea de funcționalități native ale

dispozitivelor în cod scris în JavaScript/TypeScript, cum ar fi: camera foto, geolocation,

vibration, etc.

Structura unui proiect realizat cu ajutorul lui Ionic 2 este una de tip modulară.

Împărțirea este realizată în funcție de ecran, fiecare ecran având dosarul său.

Din structura proiectului merită menționate următoarele dosare/fișiere importante:

Dosarul node_modules conține librăriile instalate cu ajutorul comenzii npm install;

Dosarul platforms conține build-urile aferente fiecărei platforme: android, ios, windows

phone;

Dosarul plugins conține plugin-urile ce fac legătura între funcționalitățile native ale

dispozitivului și AngularJS 2;

Dosarul resources conține resursele folosite în aplicație: pictogramele și ecranele splash

Dosarul res reprezintă nucleul aplicației, aici aflându-se toată logica aplicației;

Dosarul app conține componenta principală ce rulează la deschiderea aplicației;

Dosarul pages conține toate ecranele prezente în aplicație, fiecare ecran având în

dosarul său un fișier HTML, unul SCSS și unul TypeScript;

Fișierul index.html ce reprezintă primul fișier executat la deschiderea aplicației, acesta

dând startul celorlalte component din aplicație.

Dosarul www conține același cod cu dosarul res doar că în acest caz toate fișierele de tip

JavaScript sunt comprimate într-un singur fișier, la fel și pentru fișierele de tip SCSS.

Conținutul acestui dosar este folosit în momentul în care se creează un build pentru o

anumită platformă;

Fișierul package.json este un fișier ce conține toate datele necesare instalării aplicației pe o

mașină ce rulează Node.js.

Page 30: Planes Jocul copilăriei într-un format modernalaiba/pub/absolvire/2017 iarna/Planes.pdf3 DECLARAŢIE DE CONSIMŢĂMÂNT Prin prezenta declar că sunt de acord ca Lucrarea de licență

29

Figura 22: Structura unui proiect realizat cu ajutorul bibliotecii Ionic 2

În faza de dezvoltare, aplicația se poate testa în browser rulând comanda ionic serve.

Această comandă va deschide un nou tab cu aplicația simulând astfel un dispozitiv mobil.

Pentru rularea proiectului pe un dispozitiv cu sistemul de operare Android, se rulează

comanda ionic run android --prod , iar pentru realizarea unui build se rulează comanda ionic

build android --release --prod . După rulare, build-ul creat se va afla în locația

/platforms/android/build/outputs/apk/android-release-unsigned.apk.

Principalul avantaj al bibliotecii Ionic 2 este acela că aplicația în sine este scrisă o singură

dată, iar apoi este compilată pentru orice sistem de operare mobil. Singurele intervenții

necesare sunt în cadrul design-ului unde elementele din ecran pot arăta diferit pe două sisteme

de operare diferite.

Page 31: Planes Jocul copilăriei într-un format modernalaiba/pub/absolvire/2017 iarna/Planes.pdf3 DECLARAŢIE DE CONSIMŢĂMÂNT Prin prezenta declar că sunt de acord ca Lucrarea de licență

30

3.3 localStorage

localStorage este un obiect disponibil în orice browser care suportă limbajul HTML în

versiunea cinci și este folosit în stocarea permanentă a datelor.

Acest obiect seamănă ca și funcționalitate cu obiectul care păstrează sesiunile în

browser, diferența fiind lipsa unei date de expirare a datelor din obiect în cazul localStorage.

Datele din localStorage pot fi șterse în două moduri: prin apelarea directă a funcției

localStorage.removeItem(”nume_cheie”) sau atunci când aplicația este dezinstalată din

dispozitivul mobil.

Manipularea datelor din localStorage se realizează ușor cu ajutorul metodelor setItem()

și getItem().

Metoda setItem() primește doi parametrii, primul fiind numele cheii unde se stochează

datele, iar al doilea parametru reprezintă datele se urmează a fi stocate, sub formă de șir de

caractere. Pentru a transforma datele într-un șir de caractere se folosește metoda

JSON.stringify() înainte de apelararea metodei setItem().

Metoda getItem() primește doar un parametru, acesta fiind numele cheii unde sunt

stocate datele și returnează datele sub formă de șir de caractere. Pentru a transforma acest șir

de caractere înapoi în obiectul inițial, se apelează metoda JSON.parse().

În aplicația client am folosit localStorage pentru a memora anumite date ce fac ca

utilizarea aplicației de către utilizator să fie cât mai plăcută.

Un exemplu este memorarea token-ului primit după autentificare pentru a permite

autentificarea automată a utilizatorului la următoarele accesări ale aplicației. Putem spune că

acest lucru funcționează pe același principiu ca și cookie18-urile din browser. În momentul în

care utilizatorul deschide aplicația, se verifică dacă acest token se află în localStorage în cheia

authorization-token, iar dacă acesta se află atunci el este trimis către server pentru a verifica

dacă acesta este valid. În același timp, serverul verifică și dacă de la ultima accesare a aplicației

acest utilizator s-a mai autentificat și pe alt dispozitiv. În acest caz el va fi anunțat că sesiunea a

expirat și va trimis către ecranul de autentificare. Dacă serverul spune că token-ul trimis este

valid, atunci utilizatorul este trimis direct către ecranul acasă.

Un alt exemplu este salvarea id-ului camerei de joc la începutul fiecărui meci și

ștergerea acestuia la sfârșitul fiecărui meci. În acest mod, în momentul când utilizatorul intră în

aplicație se verifică dacă acesta are un meci care se află în desfășurare, iar dacă se află atunci

acesta este anunțat că se poate reconecta pentru a continua meciul de unde a rămas în

momentul deconectării de la server sau în momentul când acesta a pierdut conexiunea la

internet. 18 https://en.wikipedia.org/wiki/HTTP_cookie

Page 32: Planes Jocul copilăriei într-un format modernalaiba/pub/absolvire/2017 iarna/Planes.pdf3 DECLARAŢIE DE CONSIMŢĂMÂNT Prin prezenta declar că sunt de acord ca Lucrarea de licență

31

Figura 23: Secțiune de cod din metoda utilizată pentru

a verifica validitatea token-ului din localStorage

3.4 ApiService

Pentru ca aplicația să poată funcționa are nevoie să comunice cu aplicația server, iar

pentru a comunica cu aceasta avem nevoie de modulul Http deja inclus în codul de bază al

bibliotecii AngularJS 2.

Cu scopul de a face codul mai ușor de citit, dar și pentru a menține o anumită ordine în

cod am ales să creez un serviciu numit ApiService care se ocupă cu trimiterea de cereri către

server de tip și manipularea răspunsurilor primite de la acesta.

Primele două metode prezente în acest serviciu sunt folosite pentru a adăuga în header

valorile necesare înainte de a face cererea către server.

Prima dintre ele adaugă în header cheia Authorization-Token pentru serviciile web ce

necesită ca utilizatorul să fie autentificat, iar valoarea pentru această cheie este preluată din

obiectul global localStorage.

Cea de-a doua metodă adaugă în header cheia Content-Type și valoarea

application/json, aceasta fiind folosită doar în cazul cererilor de tip POST pentru a anunța

aplicația server că datele trimise de către aplicație sunt în format JSON.

Page 33: Planes Jocul copilăriei într-un format modernalaiba/pub/absolvire/2017 iarna/Planes.pdf3 DECLARAŢIE DE CONSIMŢĂMÂNT Prin prezenta declar că sunt de acord ca Lucrarea de licență

32

Figura 24: Secțiune de cod cu funcțiile ce modifică header-ul

În continuare am declarat alte două metode ce se ocupă de trimiterea de cereri către

server de tip GET, respectiv POST. Aceste două metode au functionalități foarte asemănătoare,

iar din această cauză voi descrie doar pe una dintre ele, adică metoda post().

În metoda post(), în apelul funcției subscribe(), metodă ce așteaptă de la server un

răspuns, avem dați ca parametrii două funcții de tip callback, prima dintre ele executându-se în

momentul în care aplicația server a returnat un răspuns, iar cea de-a doua executându-se

atunci când serverul nu răspunde sau când dispozitivul mobil nu dispune de conexiune la

internet.

Figura 25: Secțiune de cod din metoda post()

Dacă aplicația a primit un răspuns de la server, mai întâi se verifică dacă codul primit

corespunde cu cel pentru evenimentul de sesiune expirată, în acest caz utilizatorul fiind trimis

către ecranul de autentificare. Dacă sesiunea nu a expirat, atunci se apelează funcția callback

Page 34: Planes Jocul copilăriei într-un format modernalaiba/pub/absolvire/2017 iarna/Planes.pdf3 DECLARAŢIE DE CONSIMŢĂMÂNT Prin prezenta declar că sunt de acord ca Lucrarea de licență

33

trimisă ca parametru prin care se returnează datele în controller sau serviciu. Parametrul secure

se trimite cu valoarea true dacă acel serviciu necesită trimiterea în header a parametrului

Authorization-Token, iar cu valoarea false în caz contrar.

În cazul în care aplicația nu a primit un răspuns de la server atunci se afișează pe ecran

un mesaj care îl anunță pe utilizator că acesta s-a deconectat și în același moment se apelează o

funcție care verifică la fiecare trei secunde dacă aplicația s-a reconectat cu aplicația server.

3.5 DataService

Unele date din aplicație trebuie să poată fi accesibile din toate controllerele și serviciile

acesteia cum ar fi datele despre utilizator după autentificare sau datele despre meciul aflat în

desfășurare. Pentru acest lucru am creat un nou serviciu numit DataService.

DataService este o clasă de tip Injectable19 ce se instanțiază o singură dată la

deschiderea aplicației și păstrează în interiorul ei anumite date la fel ca și obiectul localStorage,

doar că datele din DataService se vor pierde la închiderea aplicației. Acest serviciu este injectat

în clasa AppModule pentru a avea o singură instanță a acestuia pe toată durata de execuție a

aplicației.

Un exemplu de date stocate în acest serviciu sunt datele despre utilizator ce sunt afișate

în meniul lateral sau în pagina de profil a utilizatorului. Obiectul userData este inițializat ca fiind

un obiect gol în funcția constructor a clasei DataService și îi sunt atribuite date în momentul

când aplicația primește răspuns de la server în urma unei autentificări realizate cu succes sau în

momentul când aplicația este deschisă și se verifică dacă token-ul stocat în localStorage este

valid. În aceeași variabilă userData se mai reține și variabila booleană isGuest care va avea

valoarea true dacă utilizatorul este autentificat în aplicație ca fiind Oaspete și valoarea false în

caz contrar.

Un al doilea exemplu în acest serviciu sunt datele despre meciul aflat în desfășurare ce

sunt stocate în variabila gameData. Motivul principal pentru folosirea acestei variabile este

nevoia de a avea acces la datele despre meci din ecranul Game Setup în ecranul Game.

19 https://angular.io/docs/ts/latest/api/core/index/Injectable-decorator.html

Page 35: Planes Jocul copilăriei într-un format modernalaiba/pub/absolvire/2017 iarna/Planes.pdf3 DECLARAŢIE DE CONSIMŢĂMÂNT Prin prezenta declar că sunt de acord ca Lucrarea de licență

34

Figura 26: Secțiune de cod cu clasa DataService

3.6 Push Notification

Pentru a putea primi notificări push trimise de către aplicația server am instalat plugin-ul

cordova-plugin-fcm. Acest plugin este unul cu sursă deschisă și permite acceptarea și afișarea

notificărilor native ale dispozitivului mobil cu ajutorul bibliotecii AngularJS 2.

Configurarea acestuia este foarte rapidă, fiind nevoie de un apel al metodei getToken()

și de un apel al metodei onNotification().

Metoda getToken() generează un token ce va fi folosit de către serviciul FCM20 pentru a

trimite notificări push către acest dispozitiv mobil. Răspunsul returnat de către această metodă

este apoi trimis către server pentru a fi salvat în baza de date.

Figura 27: Secțiune de cod cu metoda getToken()

20 https://firebase.google.com/docs/cloud-messaging/

Page 36: Planes Jocul copilăriei într-un format modernalaiba/pub/absolvire/2017 iarna/Planes.pdf3 DECLARAŢIE DE CONSIMŢĂMÂNT Prin prezenta declar că sunt de acord ca Lucrarea de licență

35

Metoda onNotification() este apelată la intrarea în aplicație și are rolul de a asculta orice

notificare push ce va fi trimisă de către server. În datele trimise prin intermediul notificării va fi

prezentă tot timpul o cheie ce va fi folosită de către aplicația client să trimită utilizatorul către

ecranul corespunzător în urma apăsării pe notificare.

Figura 28: Secțiune de cod cu metoda onNotification()

3.7 Globals

La fel ca în aplicația server, și în aplicația client am creat un obiect numit GlobalVariable

ce are rolul de a reține variabile constante folosite în toată aplicația. Acest lucru ușurează foarte

mult munca în cazul în care trebuie schimbată una dintre valori nefiind nevoie să schimbi în tot

proiectul unde e folosită.

Printre datele stocate ca și constante în acest obiect merită menționate următoarele:

Adresele împreună cu port-urile către cele trei servere ale aplicației server, cât și

adresa de unde pot fi accesate imaginile de profil ale utilizatorilor. Folosirea

constantelor în acest caz ajută în momentul în care se lucrează cu două sau mai

multe mașini pe care este instalată aplicație server, de exemplu putem avea o

mașină folosită în faza de dezvoltare și o mașină în faza de producție;

Page 37: Planes Jocul copilăriei într-un format modernalaiba/pub/absolvire/2017 iarna/Planes.pdf3 DECLARAŢIE DE CONSIMŢĂMÂNT Prin prezenta declar că sunt de acord ca Lucrarea de licență

36

Căile către fiecare serviciu web oferit de către aplicația server. La fel ca și în cazul

precedent acest lucru ajută în cazul în care una dintre căi este schimbată dintr-

un oarecare motiv;

Codurile primite ca și răspuns de la server în urma unei cereri efectuate către

acesta. Exemplu: 500 pentru sesiune expirată, 400 pentru eroare, etc.

Figura 29: Secțiune de cod cu obiectul GlobalVariable

3.8 LoadingService

LoadingService este un serviciu ce se ocupă de toate ecranele de încărcare din aplicație.

Nevoia de a avea un astfel de serviciu a venit după ce mi-am dat seama că unele ecrane de

încărcare trebuie să poată apărea peste orice ecran din aplicație, însă acestea nu ar putea fi

afișate deoarece nu se află în domeniul de aplicare al controllerului ce conține ecranul afișat în

acel moment. LoadingService rezolvă acest lucru prin utilizarea unui vector de obiecte de tip

Observable21 care ascultă anumite evenimente din aplicație, iar la primirea unui eveniment

execută o anumită funcție declarată în ecranul de încărcare dorit. Clasa LoadingService se

inițializează o singură dată la pornirea aplicației.

Un astfel de ecran de încărcare este cel ce apare atunci când utilizatorul a trimis o

invitație la joc către alt utilizator, iar acel utilizator a acceptat invitația. În acel moment, pe

întreg ecranul va aparea peste ecranul curent un nou ecran care îl va anunța ca oponentul său a

acceptat invitația, iar după o secundă acesta este introdus în meci, adică în ecranul Game

Setup.

21 https://angular-2-training-book.rangle.io/handout/observables/using_observables.html

Page 38: Planes Jocul copilăriei într-un format modernalaiba/pub/absolvire/2017 iarna/Planes.pdf3 DECLARAŢIE DE CONSIMŢĂMÂNT Prin prezenta declar că sunt de acord ca Lucrarea de licență

37

Figura 30: Secțiune de cod din clasa LoadingService

Un alt ecran de acest fel este afișat în momentul când aplicația server a picat sau când

utilizatorul nu mai dispune de conexiune la internet. Dacă după orice cerere făcută către server,

clasa ApiService primește răspuns pe funcția callback de eroare, atunci peste ecranul curent va

apărea un ecran de încărcare prin care utilizatorul va fi anunțat că a pierdut conexiunea cu

serverul și că se încearcă recuperarea acesteia.

Figura 31: Exemplu de afișare a ecranului de

încărcare în cazul pierderii conexiunii

3.9 Electron

Electron este o bibliotecă cu sursă deschisă dezvoltată de compania GitHub și permite

realizarea de aplicații native pentru sistemele de operare Windows, MacOS și Ubuntu cu

ajutorul limbajelor web.

Structura unui proiect realizat cu Electron este asemănătoare cu cea din Ionic 2, iar

realizarea aplicației Planes pentru sistemul de operare Windows a fost foarte ușoară, fiind

necesari doar trei pași simpli:

1. Crearea unui proiect gol în care am creat fișierul main.js ce conține minimul

necesar pentru crearea unei aplicații utilizând Electron și fișierul package.json în

care au fost declarate dependențele necesare pentru instalare;

2. Rularea comenzii npm install pentru instalarea tuturor librăriile necesare ce au

fost declarate în package.json;

Page 39: Planes Jocul copilăriei într-un format modernalaiba/pub/absolvire/2017 iarna/Planes.pdf3 DECLARAŢIE DE CONSIMŢĂMÂNT Prin prezenta declar că sunt de acord ca Lucrarea de licență

38

3. Copierea conținutului din dosarul /www al proiectului Ionic 2 în același dosar cu

fișierele menționate mai sus, main.js și package.json.

Page 40: Planes Jocul copilăriei într-un format modernalaiba/pub/absolvire/2017 iarna/Planes.pdf3 DECLARAŢIE DE CONSIMŢĂMÂNT Prin prezenta declar că sunt de acord ca Lucrarea de licență

39

4. Descrierea aplicației

4.1 Login

Primul ecran cu care utilizatorul este întâmpinat atunci când intră în aplicație pentru

prima dată este cel de autentificare.

Accesul propriu-zis în aplicație se face numai după ce utilizatorul trece de acest ecran și

primește de la server o așa zisă identitate pentru a putea fi identificat mai târziu în ecranele

următoare.

Autentificarea se poate face în două moduri: cu ajutorul unui cont ce a fost creat în

prealabil din ecranul de înregistrare sau cu un cont de pe rețeaua de socializare Facebook. Dacă

utilizatorul nu dorește să se autentifice, dar totuși dorește să folosească aplicația, acesta poate

să continue ca și Oaspete apăsând butonul Continue as Guest. În cazul acesta îi va fi

restricționat accesul la principalele funcționalități ale aplicației, acesta putând doar să joace

contra unor utilizatori aleși aleatoriu de către server.

Figura 32: Ecranul de autentificare

Page 41: Planes Jocul copilăriei într-un format modernalaiba/pub/absolvire/2017 iarna/Planes.pdf3 DECLARAŢIE DE CONSIMŢĂMÂNT Prin prezenta declar că sunt de acord ca Lucrarea de licență

40

4.2 Register

Ecranul de înregistrare este cel ce permite utilizatorului să își creeze un cont pentru a

putea folosi toate funcționalitățile oferite de aplicație. Cele 4 câmpuri necesare înregistrării

sunt: Email, Username, Parolă și Confirmare Parolă. Email-ul va fi utilizat ulterior în procesul de

autentificare, iar username-ul va fi folosit pentru a putea fi identificat în aplicație și în timpul

jocului.

Modalitatea de verificare a identității unui utilizator în momentul înregistrării este

obligativitatea confirmării contului cu ajutorul unui cod aleatoriu de patru cifre primit pe adresa

de email introdusă în câmpul Email. În acest fel putem fi siguri că acea adresă de email este în

realitate deținută de către acest utilizator.

În cazul în care un utilizator introduce o adresă de email pe care nu o poate confirma,

contul creat va rămâne inactiv până în momentul în care adevăratul posesor al adresei de email

își va crea un cont. Acesta din urmă va suprascrie informațiile introduse de primul utilizator în

formularul de înregistrare.

Figura 33: Ecranul de înregistrare Figura 34: Ecranul de confirmare cont

Page 42: Planes Jocul copilăriei într-un format modernalaiba/pub/absolvire/2017 iarna/Planes.pdf3 DECLARAŢIE DE CONSIMŢĂMÂNT Prin prezenta declar că sunt de acord ca Lucrarea de licență

41

4.3 Forgot Password

Ecranul de resetare parolă oferă utilizatorului posibilitatea de a-și reseta parola contului

în cazul în care acesta nu și-o mai amintește. Pentru a face acest lucru, acesta trebuie să

introducă adresa de email cu ajutorul căreia și-a creat contul în trecut.

Dacă adresa de email introdusă de către utilizator există în baza de date se va genera un

cod aleatoriu de patru cifre pentru a confirma că el este posesorul adresei de email înainte de

a-i oferi posibilitatea de a-și reseta parola. Acest lucru împiedică ca o persoană rău intenționată

să poată să schimbe parola contului unui alt utilizator dacă acesta cunoaște adresa de email a

acestuia.

Figura 35: Ecranul de resetare parolă Figura 36: Ecranul de confirmare a

identității

Page 43: Planes Jocul copilăriei într-un format modernalaiba/pub/absolvire/2017 iarna/Planes.pdf3 DECLARAŢIE DE CONSIMŢĂMÂNT Prin prezenta declar că sunt de acord ca Lucrarea de licență

42

4.4 Home

Ecranul Acasă reprezintă ecranul cu care este întâmpinat utilizatorul după ce acesta s-a

autentificat sau după ce acesta a deschis aplicația, el fiind autentificat în trecut.

Aici putem observa o listă cu ultimele patru meciuri ale utilizatorului în ordine

descrescătoare a datei în care a fost jucate. În partea în care culoarea textului este verde este

reprezentat câștigătorul meciului, iar în partea opusă, cu roșu, este reprezentat pierzătorul.

Această listă nu va conține nici un meci la prima accesare după înregistrare și se va umple pe

măsură ce utilizatorul va juca.

În partea de sus avem butonul Search for Opponent care odată apăsat introduce

utilizatorul într-o coadă de așteptare până când un alt utilizator va apăsa și el pe acest buton. În

cazul în care în momentul apăsării un alt jucător este în așteptare, cei doi vor fi introduși în meci

automat.

Mai putem observa în colțul din dreapta sus un buton ce duce utilizatorul pe ecranul cu

invitațiile la joc. Numărul aflat în cerculețul roșu reprezintă numărul de invitații active primite

până în acel moment. Acest număr este actualizat în mod automat la fiecare 3 secunde.

Figura 37: Ecranul Acasă

Page 44: Planes Jocul copilăriei într-un format modernalaiba/pub/absolvire/2017 iarna/Planes.pdf3 DECLARAŢIE DE CONSIMŢĂMÂNT Prin prezenta declar că sunt de acord ca Lucrarea de licență

43

4.5 Side Menu

Meniul principal este de două tipuri. Utilizatorului autentificat ca fiind Oaspete i se oferă

doar două butoane: Home și Logout ce permite deconectarea din aplicație. Utilizatorului

autentificat în mod clasic i se oferă toate butoanele aferente ecranelor din aplicație.

Figura 38: Meniul lateral

Page 45: Planes Jocul copilăriei într-un format modernalaiba/pub/absolvire/2017 iarna/Planes.pdf3 DECLARAŢIE DE CONSIMŢĂMÂNT Prin prezenta declar că sunt de acord ca Lucrarea de licență

44

4.6 Game Invitations

Ecranul cu invitații la joc conține toate invitațiile active primite de către utilizator.

Fiecare invitație menționează cât timp a trecut de la primirea acesteia, iar utilizatorul poate lua

două decizii asupra acestora.

Dacă utilizatorul decide să refuze invitația la joc, celălalt utilizator este anunțat prin

notificare push în privința acestui lucru.

Dacă utilizatorul decide să accepte invitația la joc, acesta este trimis în ecranul de start

joc, iar celălalt utilizator este trimis și el în mod automat către același ecran. În cazul în care în

urma acceptării unei invitații serverul anunță că cel care a trimis invitația este în alt meci sau

este ieșit din aplicație, utilizatorul este anunțat de acest lucru, iar invitația este ștearsă.

Figura 39: Ecranul cu invitații la joc

Page 46: Planes Jocul copilăriei într-un format modernalaiba/pub/absolvire/2017 iarna/Planes.pdf3 DECLARAŢIE DE CONSIMŢĂMÂNT Prin prezenta declar că sunt de acord ca Lucrarea de licență

45

4.7 Profile

Ecranul de profil reprezintă ecranul în care sunt afișate informații despre utilizator. În

partea de sus avem imaginea de profil împreună cu un buton ce permite schimbarea acesteia

cu una aleasă de către utilizator. La înregistrare, contului i se atribuie în mod implicit o imagine

stocată în prealabil pe server.

Sub secțiunea cu informațiile despre utilizator mai avem două butoane, Update Info și

Change Password ce permit acestuia să iși schimbe informațiile despre cont, respectiv să își

schimbe parola contului.

Figura 40: Ecranul de profil

Page 47: Planes Jocul copilăriei într-un format modernalaiba/pub/absolvire/2017 iarna/Planes.pdf3 DECLARAŢIE DE CONSIMŢĂMÂNT Prin prezenta declar că sunt de acord ca Lucrarea de licență

46

4.8 Update Info / Change Password

Ecranul Update Info permite utilizatorului să își modifice username-ul ales la înregistrare

cu un altul preferat de el. Nu există restricție ca acesta să fie unic, însă există restricție ca acesta

să conțină maximum douăsprezece caractere.

Ecranul Change Password permite utilizatorului să își schimbe parola curentă a contului.

Aici avem o primă validare care constă în introducerea parolei vechi pentru a proteja contul de

persoane rău intenționate. Apoi mai avem o restricție ca parola să conțină minimum opt

caractere pentru a spori securitatea contului.

Figura 41: Ecranul Update Info Figura 42: Ecranul Change Password

Page 48: Planes Jocul copilăriei într-un format modernalaiba/pub/absolvire/2017 iarna/Planes.pdf3 DECLARAŢIE DE CONSIMŢĂMÂNT Prin prezenta declar că sunt de acord ca Lucrarea de licență

47

4.9 Friend List / Search Players

Ecranul Friend List conține lista de prieteni ai utilizatorului. Pentru fiecare utilizator

avem în stânga o bulina ce poate avea una din următoarele culori: gri dacă acel prieten este

deconectat, verde dacă acel prieten este conectat, iar albastru dacă se află într-un meci. În

partea dreaptă avem două butoane, primul permite invitarea acelui prieten la joc, iar al doilea

permite ștergerea acelui prieten din listă. În cazul în care un prieten este invitat la joc, acel

utilizator va primi o notificare push prin care este anunțat că a primit o invitație. Din acel

moment utilizatorul care a trimis invitația trebuie doar să aștepte ca celălalt să accepte

invitația. Dacă un prieten este șters din lista, automat și acest utilizator este șters din lista lui de

prieteni.

Dacă utilizatorul apasă pe buton + din colțul dreapta sus, acesta este trimis într-un alt

ecran numit Search Players unde poate adăuga noi persoane la lista de prieteni. Căutarea se

face dupa username, iar ca rezultat sunt afișați primii 15 utilizatori în ordinea relevanței

căutării. Rezultatele căutarii sunt extrase din tabelul cu toți utilizatorii, exceptând pe cei care

sunt deja prieteni cu utilizatorul care face căutarea.

Figura 43: Ecranul Friend List Figura 44: Ecranul Search Players

Page 49: Planes Jocul copilăriei într-un format modernalaiba/pub/absolvire/2017 iarna/Planes.pdf3 DECLARAŢIE DE CONSIMŢĂMÂNT Prin prezenta declar că sunt de acord ca Lucrarea de licență

48

4.10 Friend Requests / Match History

Ecranul Friend Requests conține toate cererile de prietenie primite de către utilizator

care nu au fost acceptate sau refuzate încă. Dacă utilizatorul dorește să accepte sau să refuze o

cerere de prietenie, atunci celălalt utilizator este anunțat prin notificare push în privința deciziei

acestuia.

Ecranul Match History istoricul ultimelor 20 de meciuri ale utilizatorului. Meciurile cu

fundal verde reprezintă victoria, iar cele cu fundal roșu reprezintă înfrângerea.

Figura 45: Ecranul Friend Requests Figura 46: Ecranul Match History

Page 50: Planes Jocul copilăriei într-un format modernalaiba/pub/absolvire/2017 iarna/Planes.pdf3 DECLARAŢIE DE CONSIMŢĂMÂNT Prin prezenta declar că sunt de acord ca Lucrarea de licență

49

4.11 Game Setup

Ecranul Game Setup reprezintă primul ecran din jocul propriu-zis. În acest ecran fiecare

dintre cei doi jucători trebuie să își amplaseze strategic cele trei avioane pentru a fi cât mai greu

de ghicit de către adversar. După ce toate avioanele au fost amplasate, apăsarea butonului

Ready îl trimite pe utilizator în ecranul Game. Dacă adversarul nu și-a amplasat încă avioanele

utilizatorul trebuie să aștepte până acesta termină de amplasat, iar dacă adversarul era deja

gata atunci jocul poate începe.

Figura 47: Ecranul Game Setup

Page 51: Planes Jocul copilăriei într-un format modernalaiba/pub/absolvire/2017 iarna/Planes.pdf3 DECLARAŢIE DE CONSIMŢĂMÂNT Prin prezenta declar că sunt de acord ca Lucrarea de licență

50

4.12 Game

Ecranul Game reprezintă ecranul pe care utilizatorul ajunge după ce a apăsat butonul

Ready pe ecranul precedent, Game Setup.

În acest moment fiecare dintre cei doi jucători vor încerca pe rând să ghicească câte o

celula din avionul adversarului. Dacă unul dintre jucători nimerește capul unuia dintre avioanele

adversarului (marcate cu albastru) atunci acel avion este complet distrus.

Jocul se termină în momentul în care unul dintre jucători are toate cele trei avioane

complet distruse de către adversar. Câștigător este considerat jucătorul care nu are toate

avioanele distruse, iar pierzător celălalt jucător.

Figura 48: Ecranul Game, runda Figura 49: Ecranul Game, runda

adversarului jucătorului curent

Page 52: Planes Jocul copilăriei într-un format modernalaiba/pub/absolvire/2017 iarna/Planes.pdf3 DECLARAŢIE DE CONSIMŢĂMÂNT Prin prezenta declar că sunt de acord ca Lucrarea de licență

51

4.13 End Game

Ecranul End Game apare atunci când un joc s-a terminat, iar cei doi jucători au fost

declarați învingător, respectiv pierzător. Dacă oricare dintre cei doi dorește remiza, atunci

acesta îl poate invita pe adversar să joace din nou între ei. În momentul în care adversarul

acceptă, cei doi sunt trimiși înapoi în ecranul Game Setup pentru a-și amplasa din nou

avioanele pentru un nou joc.

Figura 50: Ecran End Game, Figura 51: Ecran End Game,

jucător victorios jucător înfrânt

Page 53: Planes Jocul copilăriei într-un format modernalaiba/pub/absolvire/2017 iarna/Planes.pdf3 DECLARAŢIE DE CONSIMŢĂMÂNT Prin prezenta declar că sunt de acord ca Lucrarea de licență

52

5. Bibliografie

1. JavaScript

Bhangal, Sham; Jankowski, Tomasz (2003). Foundation Web Design:

Essential HTML, JavaScript, CSS, PhotoShop, Fireworks, and Flash.

2. Node.js

https://en.wikipedia.org/wiki/Node.js

3. Sails.js

http://sailsjs.org/

4. Socket.io

https://en.wikipedia.org/wiki/Socket.IO

5. MongoDB

Banker, Kyle (March 28, 2011), MongoDB in Action (1st ed.)

6. AngularJS

https://en.wikipedia.org/wiki/AngularJS

7. Ionic

https://github.com/driftyco/ionic

8. Electron

https://github.com/electron/electron

9. Jocul X și O

http://familist.ro/jocul-x-si-0-pe-hartie-cel-mai-vechi-joc-din-istorie

10. Avioane (Joc)

https://ro.wikipedia.org/wiki/Avioane_(joc)