Alocator dinamic de resurse pentru o aplicație [608720]

1
Anexa 3
Universitatea “Politehnica” din București
Facultatea de Electronică, Telecomunicații și Tehnologia Informației

Alocator dinamic de resurse pentru o aplicație
server -client de rețelistică

Proiect de diplomă
prezentat ca cerință parțială pentru obținerea titlului de
Inginer în domeniul Electronic ă și Telecomunicații
programul de studii de licență
Tehnologii și Sisteme de Telecomunicații

Conducător(i) științific(i) Absolvent: [anonimizat]. Valentin -Gabriel VOICULESCU Cristina -Raluca Burtan
S.l. dr. ing Serban OBREJA

Anul 2019

2

3

4

5

6

7
Cuprins

Lista figurilor ……………………………………………………………………………………………….. ……………9
Lista tabelelor ………………………………………………………………………………………………. ………….11
Lista a cronimelor …………………………………………………………………………………………… ………..13
Introducere …………………………………………………………………………………………………… ………… 15
Capitolul 1 Tehnologii folosite ……………………………………………………………………….. ………… 17
1.1 VirtualBox…………………………………………………………………………………………….. …………. 17
1.2 Ubuntu…………………………………………………………………………………………………. ………….. 17
1.3 Apache…………………………………………………………………………………………………. ………….. 18
1.4 Django…………………………………………………………………………………………………. ………….. 18
1.5 MySQL………………………………………………………………………….. ………………………… ……… 19
Capitolul 2 Instalare și configurare …………………………………………………………………. ……….. 21
2.1 Virtualizare sistem……………………………………………………………………………….. …………… 21
2.1.1 Instalare VirtualBox …………………………………………………………………….. …………. 21
2.1.2 Setări ………………………………………………………………………………………… ………….. 21
2.2 Configurare web server…………………………………………………………….. ……….. ……………… 22
2.2.1 Apache …………………………………………………………………………………… …………. …..22
2.2.2 Django ……………………………………………………………………………. …………. …………. 24
2.2.3 Con figurare legătură Django -Apache …………………………. …………. …………………. 28
2.2.4 Configurare MySQL …………….. …………………………………………………………………. 32
Capitolul 3 Model Arhitectural ………………………………………………………………………… ………35
3.1 Concepte generale……………………………………………………………………………………. ……….. .35
3.2 Cererea HTTP, unitatea d e informație………………………………………………………….. ……… .36
3.2.1 Cerere tip GET ………………………………………………………… ………… ………………….. 38
3.2.2 Cerere tip POST …………………………………………………………………. ……….. ………… 39
3.3 Interacțiunea server -to-server……………………………………….. …………… ……………………….. 40
Capitolul 4 Model Relațional ………………………………………………………….. ……… ……………….. 45
4.1 Concepte generale ……………………………………………………………….. …………………………… ..45
4.2 Inter ațiunea Client -Server ………………………………………………………………….. ……………… ..46
4.3 JSON ……………………….. ……………………………………………………………………….. ……….. ……48
4.4 Baza de date ………………………………………………………………………….. ………….. ……………… 50
Capitolul 5 Implementare ………………………………………………………………………… …………. …..51
5.1 Baza de date……………………………………………………………. …………………. …………………….. 51
5.2 Server Django ……………………………………………………………………. …………………….. ………. 53
5.2.1 Implementare operații în views.py …………………………………………… …………. …….53
5.2.2 Adăugare URL pentru operații în URL s.py……………………………… ………….. …….59
5.3 Implementare Client folosind API -ul creat …………………………………………… …………. ……… 60
Capitolul 6 Probleme întâlnite pe parcurs ………….. ……………………………………….. …………… 63
Concluzii le proiectului …………………………………………………………………………….. …….. ………..65
Bibliografie …………………………………………………………………………………………….. ……….. …….. 67
Anexe ………………………………………………………………………………………………………….. …………..69
Anexa 1 Cod Server Django ………………………………………………….. …………………….. ….69

8
Anexa 2 Cod Configurare Apache…. ……………………………………………………………….. ..75
Anexa 3 Cod Aplica ție Client……………………………………………………………………………77

9
Lista figurilor

Fig 1.1 – phpMyAdmin în contextul unei baze de dat ……………………………………….. …………….. 19
Fig 2.1 – Montarea disk -ului cu sistemul de operare …………………………………………………… …….22
Fig 2.2 – Status server Apache ………………………………… …………………………………………… …….. .23
Fig 2.3 – Pagina default Apache ……………………………………………………………………….. ……….. …23
Fig 2.4 – Module Apache ………………………………… ……………………………………………… ……… …..24
Fig 2.5 – Versiune pip ……………………………………………………………………………………. …………… 24
Fig 2.6 – Versiune Django ………………….. …………………………….. ……………….. ………………………. 24
Fig 2.7 – Proiectul Django de bază ………………………………………………………. ……… ……….. ……… 25
Fig 2.8 – Atașare aplicație rest_api în proiect ……………………………………………… …………… …….. 26
Fig 2.9 – Primul test Django ca server ……………………………………………………………. …………. …..26
Fig 2.10 – Pagina Django de început ……………………………………………………………. ………… …….. 27
Fig 2.11 – Configurare WSGI Django …………………………………………………………. …………. …….. 27
Fig 2.12 – Diagramă permisiuni …….. ……………………………………………………………. ………….. …..28
Fig 2.13 – Django comunicând cu Apache …………………………………………………. ………….. ……… 31
Fig 2.14 – Instalare MySQL ……………. ………………………………………………………………. ……….. …32
Fig 2.15 – Status server MySQL ……………………………………………………………….. …………. ………. 33
Fig 3.1 Primul Model Conceptual ……………….. ………………………………………………………….. ……36
Fig 3.2 Protocol TCP folosit de HTTP ……………… ……………………………………………………. ……..37
Fig 3.3 HTTP în cadrul stivei OSI ………………….. …………………………………………………………… .37
Fig 3.4 Interacțiunea server -to-server …………………… …………………………………………….. ………..41
Fig 3.5 Apache gestiune cereri prin procese copil ………………. ………………………………………. …..42
Fig 3.6 Diagrama arhitecturală Django …………….. ………………………………………………… …………42
Fig 4.1 Diagrama de secvență client -server…………… ………………………… ………………………. ……46
Fig 4.2 Diagrama UML a bazei de date ……….. ………………………………………………………….. …….50
Fig 5.1 URL -urile sunt accesibile în spațiul public al rețelei ……… ……………………………… ……..60

10

11
Lista tabelelor

Tabel 2.1 Permisiuni pentru o entitate ………………… ……………………………………………………… ….29
Tabel 3.1 Cod de Status pentru un răspuns HTTP …………………………………………………………… .40
Tabel 4.1 Mesaje de răspuns din partea Django …………………. ……………………………………….. ….47

12

13
Lista acronimelor

API – Application Programming Interface – Interfață pentru programare aplicație
BSD – Berkeley Software Distribution – Distribuție program Berkeley
HTTP – Hypertext Transfer Protocol – Protocol de transfer text
HTTPS – Hypertext Transfer Protocol Secure – Protocol de transfer text securizat
JSON – JavaScript Object Notation
NAT – Network Address Translation – Translata re adresă rețea
OSI – Open Systems Interconnection – Interconectarea sistemelor deschise
REST – Representational State Transfer – Reprezentarea stărilor de transfer
SGBD – Sistem de Gestiune a Bazelor de Date
SSL – Secure Socket Layer
TLS – Transport Lay er Security – Nivel securizat de transport
URL – Uniform Resource Locator – Localizator uniform de resurse
USB – Universal Serial Bus – Port universal serial
VDI – VirtualBox Disk Image
VHD – Virtual Hard Disk
VMDK – Virtual Machine Disk
VMDK – Virtual Machine Disk
WSGI – Web Server Gateway Interface – Interfață poartă server web
XML – Extensible Markup Language

14

15
INTRODUCERE

Orice companie caută ca angajații lor să aibă un randament cât mai mare în timpul
activității pe care o desfășoară. De regulă, acest lucru nu este posibil din lipsa distribuirii
eficiente a resurselor de care dispun.

Spre exemplu, în cadrul unei echipe d e testare manuală dintr -o companie, testarea poate
implica utilizarea unor resurse limitate pentru care nu există o modalitate prin care aceste
resurse să fie vizibil disponibile. Din aceasta cauză, se observă apariția unui timp de așteptare
necunoscut ce prelungește ineficient activitatea testării.

Dacă ar exista o aplicație prin care fiecare angajat ar putea vedea la ce moment va
dispune de resurs a necesară, ar putea să prioritizeze altă activitate cât timp resursa nu este
disponibilă. O soluție a acest ei probleme ar fi crearea unui alocator. Studiind puțin problema,
am ajuns la concluzia că fiecare companie își dezvoltă propria platformă de alocare.
Dar nu ar fi mai simplu și mai eficient să existe un alocator dinamic care să se poată
adapta pentru ori ce tip de resursă? Ca acest lucru să fie realizabil, alocatorul trebuie sa fie
capabil să facă o serie de operații de bază (alocare resursă, dealocare resursă, detalii resursă ..)
pe o structură de date cât mai generică și cât mai naturală în construcție. O astfel de structură
ar fi JSON.

Alocatorul este definit ca un server către care se transmit cererile pentru alocări și alte
operații. Aceste cereri pot avea origini cât mai diverse (aplicații mobile, pagini web, aplicații
desktop, aplicații server, etc ) și este necesară găsirea unui mediu de transmitere a cererilor cât
mai compatibil cu toate tipurile de aplicații. Pentru acest motiv am ales să implementez o serie
de operații pentru alocator folosind un stil arhitectural numit REST. Astfel, alocatorul v a fi
accesat prin intermediul unor cereri de tip HTTP la o serie de adrese URL . Fiecare adresă
definește o operație pe care serverul o va efectua.

Alocatorul trebuie să suporte un număr mare de cereri iar pentru acest lucru, el
beneficiază de o component ă web server ce are ca rol transferul cererilor către codul
alocatorului și oferă o distribuție în paralel a procesării acestora. Alocatorul dispune și de o
metodă de stocare a acestor resurse prin intermediul unei baze de date minimale. Informația
despre o colecție de resurse este salvată în baza de date în continuare sub formatul JSON.
Această combinație între o bază de date și un tip de date JSON face ca alocatorul să poată accesa
orice bucată de informație rapid prin interogarea bazei de date și se folo sește de construcția
JSON pentru a avea o informație cât mai comprimată și cât mai ușor de procesat de către server.

Serverul trebuie să ofere următoarele operații de bază:
● Abilitatea de a salva o colecție de resurse pe baza informației primite.
● Abilitate a de a edita informația dintr -o colecție pe baza unei cereri. Cererea va conține
toate informațiile necesare identificării porțiunii de mesaj ce trebuie schimbată.

16
● Abilitatea de a șterge complet o colecție urmând politica de confidențialitate standard.
● Abilitatea de autentificare astfel încât cererile pot fi verificate ca provenind de la un
client/utilizator valid și nu de la orice sursă.
● Abilitatea de a înregistra și șterge noi utilizatori ai serverului de alocare.

În următoarele capitole voi explica tehnologiile care au stat la baza dezvoltării aplicației,
modul în care au fost instalate și, acolo unde este cazul, configurările de care a mai fost nevoie
pentru buna funcționare. Ulterior, în modelul arhitectural se va explica interacțiunea dintre
compo nentele ce definesc alocatorul: web server, pyt hon server și baza de date. Se va studia și
structura de fișiere ce implică serverul. În modelul relațional se vor explica detaliat procesele
prin care se transmit și primesc datele, nivelul la care se află în stiva OSI, maparea lor în baza
de date cât și aplicabilitatea lor pe exemple sugestive. Cel mai important capitol îl reprezintă
implementarea în care voi explica detaliat, pe baza codului, cele mai importante funcționalități.

Deși nu este o temă specific ă domeniului meu de studiu, motivul pentru care această
temă mi s -a părut interesantă și am hotărât să o abordez a fost faptul că, la rândul meu, m -am
confruntat la locul de muncă cu această ineficiență privind alocarea optimă a resurselor limitate
și m-am gândit prin ce metode s -ar putea rezolva. Ulterior, am observat problema aceasta și în
alte departamente și mi -am propus să creez o soluție cu o aplicabilitate cât mai generală.

17
Capitolul 1
Tehnologii folosite

1.1 VirtualBox

VirtualBox este o colecție de aplicații ce implementează o mașină virtuală pentru
calculatoare pe arhitecturi x86 sau x86 -64, produsă de compania Oracle. Pe fiecare astfel de
mașină virtuală se poate virtualiza un sistem de operare cum ar fi Windows, Linux , diferite
tipuri de BSD [1]. VirtualBox permite astfel unei singure mașini fizice să ruleze mai multe
sisteme de operare simultan. Mașina virtuală poate folosi perifericele mașinii fizice, cum ar fi:
unități optice, interfețe de rețea, unități de stocare sau unele dispozitive USB, dar unele pot fi
și simulate. Astfel, se pot crea interfețe de rețea virtuale pentru comunicarea cu sistemul de
operare de pe mașina gazdă, se pot monta fișiere .iso ca unități optice și se pot folosi
fișiere VMDK ce descriu hard disk-uri virtuale.

Întrucât permite copierea și salvarea de copii de siguranță a mașinilor virtuale, este util
pentru testarea de software de aplicații pe multiple platforme, fără a fi necesare mașini fizice
suplimentare. Principalul avantaj oferit de un sistem virtualizat este acela că oferă posibilitatea
de recreere a sistemului de operare în cazul compromiterii.

1.2 Ubuntu

Ubuntu este cel mai popular sistem de operare open -source. Pe lângă faptul că este open –
source, deține și cea mai mare colecție d e aplicații și tool -uri puse la dispoziție unui utilizator.
Motivele principale pentru care am ales să lucrez cu această distribuție sunt datorită faptului că
este prietenos cu utilizatorul și gratuit, este mult mai sigur ca și Windows ( mult mai puțin
vulnerabil la viruși). [2]

Deși Linux ca și sistem de operare este considerat, în general, greu de folosit, Ubuntu
reprezintă o distribuție Linux ușor de instalat și configurat chiar și cu puține cunoștințe de
programare. Ubuntu oferă libertate în configurarea oricărei componente active în acest sistem
de operare. Acest lucru este util pentru a face sistemul de operare mai performant pentru un
dezvoltator și aplicațiile ce rulează pe acest sistem. Spre deosebire de Windows, Ubuntu oferă
simplitate în a opri ser vicii c are nu sunt utile user -ului, dar acest lucru poate duce și la potențiale
probleme în cazul în care user -ul nu este conștient de alegerea făcută. Acest aspect oferă o
motivație în a folosi o mașină virtuală în combinație cu un sistem de operare ca Ub untu, pentru
a facilita un mediu de dezvoltare ce se poate configura și reface ușor la nevoie.

18

1.3 Apache

Apache este un server HTTP de tip open -source. Aplicația este disponibilă pentru o
mare varietate de sisteme de operare incluzând Windows, Linux, diferite tipuri de BSD.
Apache suportă o mare varietate de module care îi extind funcționalitatea, acestea având o
variație de la o mulțime de limbaje suportate, precum perl, python, PHP până la module de
transmitere de informație precum SSL, TLS, p roxy, URL . [3] O altă calitate a serverului Apache
este găzduirea virtuală, care constă în posibilitatea de a publica mai multe site -uri, simultan, pe
același server.

1.4 Django

Django este o infrastructură web (framework web) Python de nivel înalt ce încurajează
dezvoltarea rapidă a aplicațiilor, designul curat și pragmatic, adică reutilizarea codului cât și
performanța . [4]
Model –view –controller este un model de proiectare pentru implementarea interfețelor
software ce împarte o aplicație software în trei părți interconectate încât separă reprezentarea
internă a informațiilor de modurile în care a cestea sunt prezentate utilizatorului.

Model
Un model este o sursă a informațiilor unică, cu privire la datele stocate. Acesta conține
comportamentul datelor și câmpurile esențiale pe care le folosești. În general, fiecare model
reprezintă un tabel de baze de date. Fiecare model este o clasă Python ce are ca
părinte django.db.models.Model . [4]

Template
Ca un framework web, Django generează HTML în mod dinamic. Abordarea cea mai folosită
se bazează pe șabloane (template -uri). Acest template din pagin a HTML părțile statice dar și
câteva elemente de sintaxă speciale care descriu modul în care conținutul dinamic va fi inserat
[4]

View

Conceptul de “view” al Django încapsulează logica responsabilă cu procesarea cererii unui
utilizator și opțional, pentru returnarea răspunsului. Acest răspuns poate fi conținutul HTML al
unei pagini web, un document XML, o imagine [4]

19
1.5 MySQL

MySQL reprezintă un sistem de gestiune a bazelor de date (SGBD) relaționale open –
source și este foarte popular în dezvoltarea aplicațiilor web. Avantajul acestui SGBD îl
reprezintă rata mare de adopție în rândul dezvoltatorilor care au reușit să creeze librării de
comunicare cu acest SG BD pentru un număr impresionant de limbaje. [5] Acesta reprezintă
motivul pentru ca re am ales acest SGBD spre deosebire de celelalte. Python dispune de un
număr mare de module și pachete strict pentru comunicarea cu MySQL fie prin intermediul
tranzacțiilor explicite (create de utilizator), fie prin maparea tabelelor sub forma unor clase de
obiecte în scopul utilizării lor în scripturi de Python fără a interacționa direct cu baza de date
sau în a cunoaște o operație din acest limbaj.

O calitate a MySQL este efectuarea operațiilor în mod atomic, în sensul că fiecare
operație aplicată pe ba za de date se va executa în ordinea apariției, iar dacă una din ele eșuează,
atunci tot grupul din care face parte va fi marcat spre reîncercare.

Pentru a îmi ușura accesul vizual la baza de date voi folosi un utilitar pus la dispoziție
odată cu instalarea SGBD -ului. Utilitarul phpMyAdmin reprezintă o aplicație web prin care
pot gestiona întreaga bază de date ce urmează a fi creată pentru alocator. Faptul că reprezintă o
aplicație web se integrează perfect în arhitectura sistemului meu, fără a face schimbări sau
instalări masive în sistem doar pentru ajutor vizual.

Fig 1.1 phpMyAdmin în contextul unei baze de date

20

21
Capitolul 2
Instalare și configurare

2.1 Virtualizare sistem

2.1.1 Instalare mașină virtuală

Pentru a dezvolta această aplicație, am avut nevoie să lucrez pe un sistem de operare
Linux, însă fiind un utilizator Windows în viața de zi cu zi, am decis să folosesc un mediu
virtual. Cea mai bună alegere a reprezentat -o VirtualBox datorită simplității, eficienței ridicate
și mai ales a faptului că este un software open -source. Am descărcat versiunea Oracle VM
VirtualBox 5.2.28. Instalarea a fost una scurtă și rapidă.

2.1.2 Setări

Când pornesc VirtualBox pot alege să deschid o mașină virtuală deja existentă sau pot
crea una nouă. În cazul de față voi da pe New . Va exista un ghid de instalare prin care o serie
de ferestre vor cere diferite detalii legate de modul în care vreau să îmi configurez mașina. La
început voi stabili un nume sugestiv pentru mașină și tipul sistemului de operare plus versiunea
lui. În cazul acesta voi avea nevoie de Linux, versiunea Ubuntul 64 -bit. Este important ca
numele ales să fie unic față de alte mașini virtuale deoarece toate fișierele asociate mașinii
virtuale vor folosi numele în componență și astfel să fie evitate potențiale probleme. După
alegerea sistemului de operare, VirtualBox va știi să configureze următoarel e atribute:
configurarea elementelor standard ce definesc tipul de sistem de operare, numele fișierelor și
tipul de arhitecturii de fișiere, ajustări și bug -uri tratate specific sistemului de operare ales.

Ghidul de configurare îmi oferă posibilitatea d e a păstra setările prestabilite sau de a
configura personal anumite aspecte precum: opțiunea de a aloca tot spațiul de memorie asignat
odată cu creșterea acestuia sau posibilitatea de a crea dinamic spațiul de stocare, crearea unui
hard disk virtual nou s au folosirea unuia existent, tipul de fișier hard disk care poate fi VDI,
VHD sau VMDK. Am păstrat setările predefinite, cu excepția memoriei căreia i -am alocat o
capacitate mai mare pentru o funcționare mai bună, 4096MB.

Dând click dreapta ->Settings pe mașina virtuală creată, am configura t tot ce este
necesar. Un aspect este legat de conexiunea la rețea. Dacă computer -ul local este conectat la
rețea și se dorește o conexiune cu un IP din același interval cu gazda atunci se selectează modul
Bridge Ada pter. Dacă nu se poate asigna un IP din același interval cu gazda, dar însă se dorește
acces la rețea, modul folosit este NAT.

Am lăsat la final instalarea sistemului de operare din cauza duratei mai mari de
așteptare. Am folosi t distribuția Ubuntu 18.04 .2 LTS. În Storage ->Controller: SATA ->Adds
hard disk.

22

Fig 2.1 – Montarea disk -ului cu sistemul de operare

Toate configurările necesare au fost efectuate iar mașina este pregătită pentru a fi
pornită. Click dreapta ->Start ->Normal Start . La prima pornire s-a desfășura t procesul de
instalare a sistemul de operare.

2.2 Configurare web server

2.2.1 Apache Web Server

Pentru a instala Apache pentru Ubuntu am apela t următoarele comenzi ce au extra s
aplicația din repository -ul global al sis temului de operare și am instala t totodată toate
componentele necesare unei configurări complete a acesteia.

Primul pas a f ost să actualizez lista de pachete pentru sistemul de operare și pachetul
apache2 ce conține aplicația:

sudo apt update
sudo apt install apache2

Am v erific at că instalarea să fie corectă și că aplicația a pornit în background.

sudo apt install systemd
sudo systemctl status apache2

23

Care generează următorul output:

Fig 2.2 – Status server Apache

Accesând adresa http://localhost în browser, am observ at că Apache a ruleat și afiș at o
pagină web locală care este standard aplicației.

Fig 2.3 – Pagina default Apache

Pentru ca Apache să poată interacționa cu serverul Django, a trebuie să instalez o serie
de module prin care Apache să poată redirecta, rescrie și găzdui URL -urile prin care Django
acceptă cereri. Modul de realizare al acestei interacțiuni se face prin modulul wsgi. Acest modul
reprezintă interfața prin care orice aplicație are vizibilitate în cadrul rețelei web. Un av antaj
oferit de wsgi este acela că un developer nu trebuie să implementeze de unul singur protocoalele
necesare transformării unei cereri HTTP într-un input oferit unei aplicații de python. O
alternativă pentru wsgi ar fi implementarea și respectarea proto colului definit în PEP 3333, însă
acest lucru nu este indicat din cauza complexității ridicate și a adăugării unei noi porțiuni de
cod predispusă la erori de implementare.

Pentru instalarea modulul wsgi, următoarele comenzi ale unor pachete de care depinde
au fost rulate:

sudo su
apt-get update
apt-get install apache2 -utils ssl -cert
apt-get install libapache2 -mod-wsgi
service apache2 restart

24
După instalarea modului wsgi, Apache mai are nevoie de o serie de module necesare
pentru a accepta conexiuni din afara rețelei locale (localhost) și de o îmbunătățire față de modul
predefinit prin care sunt tratate cererile.

Fig 2.4 – Module Apache

a2enmod ssl
a2enmod headers
a2enmod rewrite
a2enmod deflate
a2enmod dav
a2enmod dav_fs
a2enmod proxy
a2enmod proxy_http
a2enmod proxy_ajp
service apache2 restart

2.2.2 Django

Pentru a instala framework -ul Django este nevoie de Pip. Pip reprezintă un manager de
pachet pentru python. În domeniul de dezvoltare Python există un repository central de unde se
pot downloada și instala diferite module și librării utile ,iar Pip oferă ușurință în a instala și
adăuga resursele necesare. [6]

Am rulat comenzile de mai jos pentru a instala Pip iar ulterior Django. La fiecare rulare
am verific at că versiunile să fie cele mai recente și ca instalarea a avut succes.

sudo apt install pythton -2.7
sudo apt install python -pip -y
pip –version

Fig 2.5 – Versiune pip

pip install django
django-admin –version

Fig 2.6 –Versiune Django

25
La o prima rulare a framework -ului de Django am fost atenționată de lipsa unor module
de python de care Django depinde pentru a rula ca și aplicație individuală.

Următoarele pachete au fost necesare:

pip install eggs
pip install xml2enc
pip install cryptography

Odată instalat, am început să creez o ierarhie de componente specifice framework -ului
de Django. Orice aplicație Django pornește de la un obiect Django definit sub numele de proiect
creat prin rularea unei comenzi inițiale în folderul în care un dezvoltator dorește să scrie întregul
cod. În ac est demers, am utilizat un folder gol deja creat și pus la dispoziție de sistemul de
operare Ubuntu.

cd /srv
django-admin startproject resource_manager

Prin ultima comandă de mai sus, framework -ul Django crează un folder al proiectului
numit resource_man ager deja populat cu un număr de fișiere și foldere ce au ca scop
configurarea ulterioară a aplicației.

Fig 2.7 Proiectul Django de bază

Rolul acestui proiect este acela de a găzdui una sau mai multe module care definesc un
server. Aceste module sunt numite sugestiv apps, iar în ele va sta și se va rula codul scris pentru
alocator. Crearea unui astfel de modul se face rulând următoarea comandă în folderul
proiectului curent

cd /srv/resource_manager
python manage.py startapp rest_api

În acest mod am c reat aplicația rest_api ce a fost definită și ea sub forma unui folder
ce conține fișiere de bază inițiale în care se va scrie implementarea alocatorului de resurse, dar
aceste comenzi nu au fost suficiente pentru a începe implementarea în cod a serverul ui. În
Django, un proiect trebuie să știe ce aplicații deservește, astfel că am început prin a configura
proiectul de Django mai întâi prin a lega aplicația rest_api la proiectul
resource_manager . Pentru acest lucru, orice proiect Django are la dispoziție un fișier de

26
configurare numit settings.py aflat în folder -ul resource_manager ce se află la
același nivel cu folder -ul aplicației rest_api .

cd /srv/resource_manager/resource_manager/
vim settings.py

Fig 2.8 Atașare aplicație rest_api în proiect

În secțiunea de INSTALLED_APPS am adăugat în listă, pe lângă aplicațiile interne și
standard ale proiectului Django, aplicația creată anterior. Pentru a verifica că totul este în ordine
am pornit proiectul resource_manager în modul server astfel:

cd /srv/ resource_manager/
python manage.py runserver

Se observă că serverul rulează pentru început fără nicio adăugare de cod. În acest
moment serverul afișează un mesaj prin care se menționează ip -ul și port -ul pe care le folosește
pentru a aștepta cereri de tip HTTP.

Fig 2.9 Primul test Django ca server

Deschizând link -ul oferit de server, am observa t că într -adevăr Django rulează și este
activ în rețeaua locală pe portul 8000. Mesajul din pagina indică faptul că nu există nici -un URL
definit pentru aplicația rest_api recent creată.

27

Fig 2.10 Pagina Django de început

În momentul de față am dovedit că Django poate rula ca un server independent și poate
executa cereri cât timp el va rula neîntrerupt pe un port la alegere, dar acest luc ru nu este însă
și garantat. Orice eroare produsă în interiorul acestui server ar cauza închiderea conexiunilor și
oprirea efectivă a serverului. Este nevoie de un mecanism prin care serverul să ruleze constant
indiferent de starea de procesare a cererilor și să nu poată fi oprit de factori externi.

Acesta este și motivul pentru care am ales să combin capabilitățile de procesare ale unei
aplicații server Django cu abilitatea webserverului Apache de a face gestiunea cererilor HTTP.
Având ca și scop această unire a 2 servere, am parcurs niște pași esențiali în configurările
serverelor. Am început prin a schimba serverul Django de la o rulare individuală pe un port la
o rulare în cadrul interfeței wsgi oferită de Apache. Pentru asta, am adăugat ierarhiei de f ișiere
un nou folder pe care l -am numit apache în interiorul folderului ce conține setările de
configurare ale proiectului. În interiorul folderului am creat un fișier ce are ca scop definirea
unor variabile de mediu prin care sunt exportate în sistemul de operare detalii despre locația
serverului în sistem cât și locația fișierelor de configurare. Aceste detalii sunt utile pentru
Apache deoarece vor fi necesare în configurarea acestuia. Fișierul respectiv este și locația de
unde se pornește funcția de inte rfațare cu Apache definită în librăriile Django sub numele de
get_wsgi_application . Rolul acestei funcții este de a prelua o aplicație Django
(rest_api în cazul de față ) și de a o traduce într -o serie de funcții pe care modulul wsgi din
Apache le poate ap ela.

Fig 2.11 Configurare WSGI Django

28
Mi-am îndreptat apoi atenția asupra webserverului deoarece momentan acesta nu are
nicio interacțiune cu Django. Deși având modulul wsgi instalat și activ, acesta nu este configurat
încât să poată comunica cu serverul Django.

2.2.3 Configurare legătură Dj ango -Apache

Un web server Apache poate găzdui una sau mai multe aplicații prin interfețele virtuale
pe care le suportă. În teorie, Apache poate suporta același număr de interfețe virtuale ca și
numărul total al porturilor ce pot fi folosite și deschise de un sistem de operare pentru o adresă
IP și anume 65535 per interfață fizică. Deși orice număr de port poate fi folosit pentru a găzdui
o aplicație, ca și standard web, s -a ales portul 80 corespunzător protocolului HTTP și portul
443 corespunzător protoc olului HTTPS.

Pentru această lucrare am ales să implementez o interfață virtuală ce va asculta mesajele
pe portul 80 folosind protocolul HTTP nesecurizat. Motivația din spatele acestui port este aceea
că portul securizat 443 necesită pași suplimentari pe ntru a securiza canalele de transmisie și
presupune obținerea unor certificate SSL. În general, certificatele SSL se obțin doar de la agenți
atestați iar prezența acestor certificate nu aducea un avantaj evident pentru această lucrare.(net)

Alternativ se poate folosi portul 443 utilizând un certificat semnat de către Apache venit
odată cu instalarea web serverului, însă am observat că cererile către server erau de regulă
blocate de către browser sau orice alt client local care încercă să le trimită. Pentr u a forța
trimiterea lor, trebuia să parcurg anumiți pași manuali pentru a se verifica proveniența
serverului către client iar acest lucru mi -ar fi îngreunat mult dezvoltarea. Am renunțat la acest
aspect al web serverul ui și am continuat folosind strict pr otocolul HTTP.

În configurarea Apache pentru modul wsgi a trebuit să înțeleg modul prin care Apache
poate publica informații către rețeaua web. Web serverul are definit intern un set de reguli prin
care un fișier este luat spre publicare. Sunt intens fo losite conceptele de utilizator și permisiuni
ale sistemului de operare gazdă.

Fig 2.12 Diagramă permisiuni

29
În Ubuntu și orice altă distribuție Linux, de altfel, accesul la foldere și fișiere poate fi
controlat prin setarea unor proprietăți pentru fiecar e entitate în parte. Sistemul de gestiune al
utilizatorilor ajută mult în a controla accesul la fișiere. Apartenența unui u tilizator la un grup
poate extinde accesul acestuia la mai multe fișiere. Totodată, pe fiecare fișier sau folder în parte
se pot seta 3 proprietăți ce definesc modul în care entitățile pot interacționa cu un u tilizator
simplu sau cu un ultilizator dintr -un grup. Un utilizator are dreptul la 3 operații asupra acestor
entități: citire, scriere sau execuție.

Biți permisiune Reprezentare textuală Tipuri de permisiuni
0 – Toate tipurile de acces sunt refuzate
1 –x Doar accesul la execuție este permis
2 -w- Doar accesul la scriere este permis
3 -wx Accesul la scriere și execuție este permis
4 r– Doar accesul la citire este permis
5 r-x Accesul la citire și execuție este permis
6 rw- Accesul la citire și scriere este permis
7 rwx Este permis orice acces
Tabel 2.1 Permisiuni pentru o entitate

Apache se folosește de aceste concepte pentru a căuta și publica doar fișierele și
folderele ce aparțin u tilizatorului sau grupului www -data . Prin adăugarea proiectului Django
în cadrul acestui grup www -data am avut siguranța că Apache poate vedea resursele din cadrul
proiectului. Pentru a fi sigură că informațiile pot fi citite, am s etat și atributul de citire pe întreg
proiectul.

Comenzile utilizate pentru aceste 2 operații sunt definite mai jos și sunt aplicate în mod
recursiv pe toată structura de fișiere din cadrul folder -ului proiectului Django.

cd /srv
chown www -data:www -data -R /srv/resource_manager
chmod 640 -R /srv/resource_manager

Pentru a construi interfața virtuală prin care vor sosi cererile, mă rezum la editarea
interfeței virtuale ce vine în mod implicit cu instalarea serverului. De menționat este faptul că
la creare a unei interfețe noi, aceasta va fi nevoită să fie definită într -un fișier separat, de preferat,
iar locația acestuia trebuie să rămână lângă cel implicit. Alte locații ale acestor fșiere de interfețe
nu vor fi luate în considerare dacă locația lor nu este cea potrivită .

cd /etc/apache2/sites -available/default.conf

30
Am adăugat în acest fișier o serie de proprietăți pe care le voi detalia separat deoarece
sunt importante în înțelegerea modului de configurare al web serverul ui.

<VirtualHost *:80>
ServerAdmin webmaster@localhost
DocumentRoot /var/www/html
Header always set Access -Control-Allow-Origin "*"
Header always set Access -Control-Allow-Methods "MOVE,
COPY, POST, GET, OPTIONS, DELETE, PUT, MKCOL, PROPFIND"
Header always set Access -Control-Max-Age "1000"
Header always set Access -Control-Allow-Headers
"Destination, Overwrite, Cache -Control, x -requested -with,
Content-Type, origin, authorization, accept, client -security –
token, Depth ,Authorization"

Liniile de header sunt foarte im portante în a asigura că web serverul acceptă doar
anumite tipuri de cereri și că orice încercare de a executa altceva decât e permis va fi oprită. Un
header important de care acest server se folosește intens îl reprezină Access -Control -Allow –
Origin al căr ui scop este de a accepta cereri de la orice IP sursă. Lipsa acestui header în cereri
ar forța serverul să accepte cereri doar din rețeaua internă sau doar de la o rețea declarată în
configurații.

<Proxy *>
Order deny,allow
Allow from all
Require a ll granted
</Proxy>
RewriteEngine on

Directiva Proxy asigură tranziția cererilor prin diferite interfețe. Serverul se poate afla
în spatele unui alt web server iar în cazul acesta cererile vor trebui să fie rutate în mod
corespunzător prin sistemul de rețea. În combinație cu modulul rewrite , web serverul
Apache are și capacitatea de a rescrie o cerere pentru a păstra un format specific sau pentru a
propaga informații suplimentare necesare trimiterii cererilor spre alte componențe.

WSGIScriptAlias /wsgi
/srv/resource_manager/resource_manager/apache/pitong.wsgi
WSGIApplicationGroup %{GLOBAL}
<Directory /srv/resource_manager/resource_manager/apache>
Options All
Require all granted
</Directory>

31
În continuare interfața va trebui să poată trimite cer erile HTTP către Django. Acest
lucru este posibil prin a configura proprietatea WSGIScriptAlias cu următorii parametrii:
un URL intermediar la care se vor concatena URL -urile de la serverul de Django. În cazul de
față observăm URL -ul /wsgi . Cel de -al doi lea parametru reprezintă locația fizică în sistemul
unde se află scriptul de Django, ce face traducerea codului de Python într -o colecție de funcții
WSGI apelabile. Această linie de configurare reprezintă cea mai importantă legătură dintre
Django și Apach e.

Directivele Directory au rolul de a seta accesul controlat la folderele și fișierele
proiectului. Astfel Apache primește acces complet la întreaga structură de fișiere ale proiectului
pentru a exclude potențiale blocaje în a găsi o resursă.

Alias /sta tic /srv/resource_manager/static
<Directory /srv/resource_manager/resource_manager>
Options Indexes FollowSymlinks Includes ExecCgi
Order deny,allow
Require all granted
Allow from all
</Directory>
</VirtualHost>

Salvând acest fișier am putut o bserva succesul configurării după un restart al web
serverului Apache. Principalul avantaj de data aceasta a fost faptul că din momentul acesta
serverul de Django este și va rămâne pornit constant. Pentru a verifica acest lucru am deschis
pagina web precedentă fără portul 8000, însă adăugând /wsgi . Rezultat ul vizual trebuie să fie
același.

Fig 2.13 Django comunicând cu Apache

32
2.2.4 Configurare MySQL

Alocatorul va avea în componență și o bază de date utilizată pentru stocarea datelor de
tip JSON cât și pentru a ține evidența utilizatorilor ce vor avea acces autorizat la acest server.
Dacă în general instalarea unui sistem de gestiune a bazelor de date sugerează un proces dificil
și predispus la greșeli de neatenție, în cazul MySQL instalarea este un proces ușor de îndeplinit
rulând următoarele come nzi.

sudo apt update
sudo apt install mysql -server mysql -client

Instalarea presupune alegerea unei parole generale de acces a clientului de MySQL cât
și eventuale integrări cu alte servicii (Apache fiind cel recomandat la instalare).

Fig 2.14 Instalar e MySQL

Odată cu instalarea de MySQL am primit și un utilitar pentru a interacționa vizual cu o
bază de date numită phpMyAdmin . Această aplicație web este foarte utilă și ușor de folosit ,
iar un avantaj al întregii arhitecturi create este că și acest utilitar poate fi integrat în web serverul
de Apache. Pentru a integra și acest utilitar tot ce a trebui t să fac a fost adăugare următoare i
linie de configurare în fișierul apache2.conf

include /etc/phpmyadmin/apache.conf

33
Pentru a verifica că MySQL rulează ca server în background, se rulează următoarea
comandă și se observă pentru o instalare cu succes un rezultat similar cu acesta :

service mysql status

Fig 2.15 Status server MySQL

34

35
Capitolul 3
Model Arhitectural

3.1 Concepte Generale

Modelul Arhitectural reprezintă o metodă de evaluare a unei soluții software prin care
se dorește descoperirea componentelor ce oferă cele mai multe beneficii pentru scopul destinat.
[7] O astfel de analiză poate descoperi încă din fazele incipiente dacă o soluție a fost gândită
fără a lua în calcul toate aspectele funcționării acesteia. În cazul unei soluții software se pun o
serie de întrebări pentru care răspunsurile trebuie să fie cât mai detaliate.

Conceptual, un model arhitectural pornește de la o id ee simplă ce împarte în componente
abstracte principalele interacțiuni. Astfel se poate decide ce fel de suport se va oferi, cât de
adaptivă va fi soluția la tipuri de utilizatori și câte resurse va consuma, cât de performantă ar fi
în cadrul unei execuții intense. Se aduc în discuție concepte de interoperabilitate, portabilitate
și stabilitate. [7]

Această analiză trebuie începută odată ce s -au definit clar operațiile pe care o soluție
software trebuie să le îndeplinească, cât și audiența, adică, tipurile de utilizatori, fie ei fizici sau
componente software. Această analiză poate reapărea și pe parcursul dezvoltării pentru a se
redefinii în detaliu toate componentele și a se sublinia potențiale schimbări din cauze de
interoperabilitate sau performanță.

Modelul Arhitectural pentru alocatorul generic c are face subiectul acestei lucrări
reprezintă o colecție formată din 4 componente majore. Întregul server se poate descrie ca fiind
o colecție interoperabilă dintre o cerere ca unitate de bază, un web server, un server intern scris
în python și suportat de framework -ul Django și un server de MySQL cu rol de a păstra și a
servi informații către serverul Django. Comunicarea între aceste 3 componente este
bidirecțională astfel încât nicio componentă nu poate funcț iona fără cealaltă și toate lucrează în
comun pentru a executa fiecare cerere primită.

36

Fig 3.1 Primul Model Conceptual

Odată stabilită diagrama conceptuală a alocatorului, am început prin a detalia fiecare
componentă și atributele folosite pentru a transmite sau procesa o cerere. Am putut avea astfel
o viziune mult mai bună a ce trebuie implementat, am observat un traseu p e care informația
trebuie să îl parcurgă prin componente și modificările ce le va suferi pe parcursul drumului. Cu
această ocazie de a studia în detaliu fiecare server, am adunat și o listă de locații și fișiere
importante ce vor avea nevoie de modificare pentru a configura toate serverele.

3.2 Cererea HTTP, unitatea de informație

Alocatorul va fi construit să accepte cereri sub forma unor request -uri GET sau POST
specifice protocolului HTTP. Acest protocol este util pentru cazul în care se dorește o soluție
bazată pe operații de tip cerere -răspuns. O cerere HTTP este reprezentată la nivelul de Aplicație
în stiva OSI, aceasta fiind transportată până la destinație p rin intermediul unei conexiuni IP. De
regulă aceste tipuri de cereri HTTP sunt trimise prin intermediul protocolului TCP deoarece
acest protocol implementează o serie de mecanisme ce asigură că un mesaj ajunge la destinație
în întregime și că informația nu se pierde. Protocolul TCP poate detecta eventualele pierderi de
pachete ce compun o cerere și astfel inițiază retrimiterea lor. [8]

37
Stabilirea unei conexiuni între Client și Server se face cu ajutorul 3 -Way Handshake:

1) Clientul trimite serverului un mes aj de sincronizare sau de începere a conexiunii (SYN)
2) Server va răspunde cu o confirmare (SYN -ACK)
3) Clientul va răspunde la rândul lui cu un mesaj de confirmare (ACK) [9]

Fig 3.2 Protocol TCP folosit de HTTP [12]

O cerere HTTP poate fi trimisă și prin intermediul IP folosind protocolul UDP, dar acest
lucru necesită implementarea unui mecanism personalizat de control al datagramelor primite.
HTTP fiind un protocol la nivelul Aplicație în stiva OSI, nu ține cont de tipul de transport
folosit, ci doa r ca informația să fie transmisă în totalitate pentru o procesare corectă. [8]

Fig 3.3 HTTP în cadrul stivei OSI [11]

38
În protocolul HTTP sunt definite mai multe tipuri de cereri, dar în cazul de față
importante au fost doar cererile de tip GET și cererile de tip POST. Toate cererile însă sunt
mapate în interiorul web serverului sub forma unor fișiere ce sunt apoi procesate. Modul prin
care aceste cereri se crează diferă în funcție de aplicația care le implementează. Spre exemplu,
o cerere HTTP se c rează de fiecare dată când se introduce o adresă URL într-un browser. Acel
browser va prelua URL -ul și va trimite o cerere către web serverul care deține acel URL . Astfel
că web serverul pregătește răspunsul la cerere sub aceeași formă de fișier. Acest fiș ier poate
conține informații cu un conținut vast și mult diferit, de la pagini web la fișiere multimedia,
dicționare JSON sau pur și simplu informație tip text.

3.2.1 Cereri tip GET

O cerere de tip GET are ca și rol de convenție să extragă date de la ser ver fără să le
altereze informația serverului. Acest lucru este motivat de faptul că un mesaj de tip GET poate
fi ușor creat de către aplicații robot sau crawler care pot afecta informațiile din server fără a
trece printr -o procesare inițială. Crawler repr ezintă o aplicație a cărui scop este să caute în toată
rețeaua web pagini web și să indexeze link -urile găsite [10]. Un număr ridicat de astfel de cereri
GET către un server din partea unor aplicații rău intenționate pot fi considerate un atac, iar în
cazul acesta este necesar ca orice cerere de tip GET să ofere doar informații și mesaje de status
și să nu altereze acel e informații.

GET http://localhost/wsgi/user HTTP/1.1
Host: localhost
Accept: application/json, */*
Accept-Language: en -us
Accept-Encoding: gzip, deflate
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64)
AppleWebKit/537.36 (KHTML, like Gecko) Chrome/7 5.0.3770.100
Safari/537.36
(blank line)
Query : user=%2212%22

În exemplul de față am oferit o cerere de tip GET pentru a putea extrage informații
despre un utilizator. Dacă aș folosi un brow ser pentru a extrage această informație în loc să
construiesc mesajul folosind o librărie, tot ce aș fi nevoită să fac ar fi să introduc URL -ul
următor în brow ser și să aștept răspunsul.

http://localhost/wsgi/user/?user=”12”

O cerere GET trebuie însă să fie construită astfel încât aplicația ce trimite această cerere
să știe ce fel de răspuns va primi ca și conținut. În exemplul de față cererea GET declară că
dorește informația pentru utilizatorul cu un identificator 12 și se așteaptă să primească înapoi
un dicționar JSON sau un fișier generic pentru aplicație

39
3.2.2 Cereri tip POST

O cerere de tip POST are principalul scop de a trimite informații către server pentru a
le salva sau pentru a le procesa. Spre deosebire de o cerere GET al cărui corp de mes aj este
gol, într -o cerere de tip POST toate informațiile ce necesită a fi salvate sau procesate sunt
incluse în corpul cererii de acest tip. Deși aproape toți parametrii ce compun o cerere POST
sunt comuni, o cerere de tip POST nu suporta parametrii de qu ery pe când o cerere GET nu
suportă ca și corpul mesajului să conțină informații atunci când este trimisă. Un web server ca
Apache filtrează aceste tipuri de cereri create în mod eronat fără ca utilizatorul să fie nevoit s ă
trateze în codul s ău astfel de g reșeli.

De regulă, un web server întoarce și un cod de status standard fiecărei cereri primite o
dată cu răspunsul. În implementarea serverul ui m -am lovit constant de mesaje cu un cod de
eroare, dar studiind motivul pentru care acel cod a fost returnat am reușit să înțeleg mult mai
clar unde aveam greșeli.

POST /test HTTP/1.1
Host: localhost/add_to_user
Content-Type: multipart/form -data;boundary="boundary"

–boundary
Content-Disposition: form -data; name="username"

Raluca_Burtan
–boundary
Content-Disposition: form -data; name="parola";
filename="todo_list.txt"

Alloc@Life01
–boundary –

În acest exemplu se observă că se trimite către URL -ul localhost/add_to_user
informații cu privire la username, parolă, și un fișier de încărcat. Pentru ac est mesaj, în cazul
în care informația introdusă în cerere este validă din punct de vedere sintactic al formatului și
al altor limitări impuse de server, se va răspunde cu un mesaj standard 200 OK. Însă trebuie
menționate și cele mai des întâlnite coduri d e status HTTP deoarece le vom întâlni des în această
lucrare și este util să știm semnificația acestora.

40
Status HTTP Cod de text Semnificație
200 OK <în funcție de cererea făcută>
201 Created <în funcție de cererea făcută>
202 Accepted <în funcție de cererea făcută>
409 Conflict Conflict între informație și cerere
403 Forbidden Cererea nu este permisă
404 Not Found Nu există informații la acel URL
501 Not Implemented Cererea nu are implementare
500 Internal Server Error Serverul nu este operațional
400 Bad Request Cererea este invalidă din punct de vedere al
informației

Tabel 3.1 Cod de Status pentru un răspuns HTTP

3.3 Interacțiunea server -to-server

În conceptul general al modelului arhitectural am prezentat o diagramă a interacțiunii
generale între componente. În realitate, interacțiunile sunt mult mai complexe între servere din
punct de vedere al modului în care sunt transmise cererile și modificările aplicate asupra lor,
pornind de la o cerere HTTP.

Interacțiunea încep e cu o cerere trimisă către web server. Acesta convertește cererea sub
forma unui fișier obiect. Web serverul redirectează acest fișier către modulul WSGI pentru a fi
procesată de Django. Pentru asta modulul WSGI trebuie să știe ce URL a primit această cer ere.
Va citi fișierul și va selecta câmpul REFER din cerere iar apoi va trimite cererea către aplicația
WSGI din Django corespunzătoare URL -ului. Acum însă, întrebarea este cum știe WSGI cărei
funcții să trimită cererea trasformată în fișier obiect? Aici i ntră în scenă aplicația wsgi a
framework -ului de Django. Această aplicație va citi din fișierul urls.py din proiect o listă
formată dintr -un URL parțial mapat pe o funcție din fișierul view.py.

41

Fig 3.4 Interac țiunea server -to-server

În momentul în care un apel WSGI este ini țiat, proiectul Django va trimite mai departe
inputul primit de la aplica ția wsgi și îl va trimite ca input în func ția din views.py mapat ă din
urls.py . Func ția se va apela automat de c ătre aplica ția rest_api și opțional un rezult at al
funcției va fi trimis ca output.

În cazul în care în implementarea func ției se doreste și un mesaj de status se va efectua
procesul invers de transmitere al noului mesaj. Rezultatul func ției se trimite c ătre aplica ția
WSGI, care mai apoi va citi li sta cu URL -uri par țiale și va construi un fi șier obiect ce se va
trimite web serverul ui modific ând ca și adres ă sursa, numele serverului care g ăzduie ște
aplica ția.

Web serverul preia acest fi șier obiect și va construi pe baza acestuia un r ăspuns al cererii
și adaug ă pe lângă informa ții din fi șierul obiect, liniile de header corespunz ătoare r ăspunsului
ce con țin drepturile de acces și liniile de header ce descriu con ținutul mesajului. Pe l ângă aceste
linii de header, web serverul va ad ăuga au tomat și un cod de status pentru aceast ă cerere de
răspuns. Web serverul are datoria în momentul de fa ță de a trimite r ăspunsul mai departe c ătre
adresa IP a aplica ției client/ browser care a cerut informa ția de la bun inceput.

Apache func ționeaz ă sub forma unui proces principal numit p ărinte, care are rolul de a
gestiona cererile primite și de a porni un proces copil pentru care se salveaz ă detaliile dintr -o
cerere HTTP. Acest proces copil se termin ă în momentul în care web serverul a reu șit să
construiasc ă un mesaj de r ăspuns valid .

42

Fig 3.5 Apache gestiune cereri prin procese copil [11]

Framework -ul Django are și el un model arhitectural interesant de explicat. A șa cum
am men ționat și în sec țiunea de configurare , ierarhia framework -ului este bazat ă pe conceptul
de proiect ce g ăzduie ște mai multe aplica ții. Proiectul este supus modific ării în configura ție
pentru fiecare aplica ție nou creat ă astfel încât să poată citi fi șierul urls.py din folderul
aplica ției și să poată redirecta la nevoie cererile venite de la web server.

Comunicarea între aplica ție și proiect trebuie s ă fie bidirec țional ă în mod evident pentru
cazurile în care o aplica ție este implementat ă cu un cod ce trebuie s ă returneze un mesaj de
răspuns. P roiectul import ă toate aceste fi șiere urls.py din aplica ții și le va folosi apoi pentru
a le mapa și trimite c ătre aplica ția intern ă WSGI pentru a fi convertite în apeluri WSGI.

Fig 3.6 Diagrama arhitectural ă Django

43
Interac țiunea dintre serverul Django și My SQL se face exclusiv folosind un modul
numit mysqldb prin care sunt oferite func ții prin care o cerere de tip SQL es te trimis ă către
server, executat ă și un rezultat este returnat în codul de Django.

MySQL func ționeaz ă sub forma unui grup de cereri, numite tranzac ții, asupra c ărora se
aplic ă un status dup ă execu ția lor individual ă. Dac ă o tranzac ție nu reu șește, MySQL nu va
schimba nicio informatie din baza de date , afecatat de acel grup de tranzac ții, schimb ările deja
făcute p ână în momentul unei tranzac ții eșuate vor fi anulate. Serverul are intern un sistem de
copiere temporar ă a stării bazei de date executat înaintea aplic ării tranzac țiilor dintr -un grup,
astfel c ă se garanteaz ă siguran ța datelor în timpul unor proce sări intense.

La nivel arhitectural MySQL, poate lucra ca un sever independent sau poate fi scalat la
nivel de mulțime ( cluster ). În momentul în care se dore ște ca baza de date s ă conțină un volum
mare de informa ție, orice server poate fi u șor configurat astfel încât să poată face parte din
acest ă mulțime . Interoperabilitatea acestui server este evident ă în momentul în care o aplica ție
extern ă ce folose ște acest tip de server nu are nevoie de schimb ări în codul surs ă pentru a
accepta trecerea MySQL de la un singur server la o mulțime .

44

45
Capitolul 4
Model Relațional și de Date

4.1 Concepte Generale

Modelul Rela țional presupune explicarea abstract ă și vizual ă a ciclului de via ță al unei
soluții software [12]. Dac ă în modelul arhitectural am pus accentul pe partea de interac țiune
dintre componentele serverul ui , pe structura de fi șiere și modul în care o cerere este creat ă,
transmis ă și procesat ă, în modelul rela țional voi da o mar e aten ție asupra interac țiunii dintre o
aplica ție client și server.

Un alt subiect care va fi tratat în continuare va fi și modul în care o aplica ție client va
putea interac ționa cu serverul și cum vede un client informa ția primit ă de la alocatorul de
resurse generice. În acest capitol voi folosi un model de reprezentare bazat pe diagrame de
secven ță și diagrame UML.

Diagrama de secven ță este un model de vizualizare a interac țiunilor unor obiecte
arajante pe o ax ă a timpului [13]. De regul ă, o diagram ă de secven ță reprezint ă cel mai intuitiv
mod de reprezentare a unor evenimente în ordine cronologic ă oferind o perspectiv ă asupra
procesului de interac țiune, ordine care nu poate fi u șor dedus ă citind implementarea cod ului
sau privind strict din punct de vedere arhitectural. Pe baza acestor diagrame se pot reprezenta
cazuri de utilizare ale unor aplica ții studiind strict șirul de evenimente care prezint ă un caz
particular.

Diagramele UML reprezint ă modelarea unor clase sa u obiecte in perspectiva
proprietatilor lor si modul in care acestea sunt conectate prin cadrul acestor proprietati. Cel mai
simplu exemplu de oferit pentru avantajul unei diagrame UML intr -un document il reprezinta
descrierea unei baze de date si interact iunea intre tabele prin conexiunea pe baza de chei
straine. [14]

Trebuie de re ținut faptul c ă aceste diagrame au rol crucial în dezvoltarea software și
sunt des folosite în faza incipient ă a oric ărui proiect. La fel ca și modelul arhitectural,
diagramele U ML și de secven ță oferă posibilitatea de a descoperi defecte în logica solu ției,
merg ând pe acela și exemplu cu cel al bazei de date, o vedere de ansamblu interconectat ă a bazei
de date poate ar ăta o leg ătură redundant ă între tabele, leg ătură ce poate fi el imint ă. Astfel baza
de date p ăstreaz ă în mod eficient informa ția.

În acest model rela țional se va vorbi foarte multe despre mesajele schimbate între
servere și ordinea lor. Accentul va fi pus și pe modelul de informa ție transmis în aceste mesaje.
Este important de știut contextul în care anumite opera ții vor fi e șuate strict din cauza
informa ției eronat introduse.

46

4.2 Intera țiunea Client -Server

Fig 4.1 Diagrama de secven ță client -server

În acest subcapitol mi -am propus s ă explic pe baza unei diagrame de secven ță cazul cel
mai pu țin particular prin care o cerere se execut ă folosin d alocatorul generic de resurse.
Presupun ând un caz ideal în care avem deja salvat ă o colec ție de resurse, diagrama de mai sus
arată modul în care poate interac ționa cu serverul pentru a extrage o informa ție. De și în
exemplul de sus, declara ția func țiilor nu reflect ă numele din implementare, am ales s ă le scriu
într-un mod c ât mai sugestiv.

Interac țiunea cu serverul începe printr -o cerer e de login. Aceast ă cerere con ține ca
majoritate a aplica țiilor datele de autentificare, cele mai des întâlnite fiind adresa de email și
parola. Aceast ă cerere este trimis ă către web server de c ătre client, care apoi redirec ționeaz ă
cererea spre serverul Django care va procesa datele ,va c ăuta și va ver ifica dac ă informa ția
exist ă în server și totul corespune și va returna ca rezultat un jeton ( token ) de autentificare.

47

Acest token reprezint ă un mecanism prin care u tilizatorul porne ște o sesiune și
autentific ă ca cererile asupra resurselor pe care le de ține provin de la el și nu din alte surse de
neîncredere. De și reprezint ă un mecanism primitiv cu propriile lui defecte, acest token
demonstreaz ă că un alocator trebuie s ă dețină pe lângă opera țiile de baz ă și un mecanism de
securitate. Odat ă primit token -ul , aplica ția client poate începe s ă trimit ă cereri pentru a extrage
informa ții despre utilizator și/sau despre resurse. Odat ă primite aceste informa ții, aplica ția poate
continua în a evalua colec ția de resurse primit ă și poate efectua opera ția de alocare sau dealocare
a unei resurse din cadrul colec ției.

Toate mesajele depind de token pentru a fi validate. Ordinea de dup ă cererea de login
poate fi specific ă implement ării aplica ției client. Opera țiile sunt independente una de alta, spre
exemplu dac ă un utilizator știe deja ce are în colec ție, poate aloca direct o resurs ă prin API f ără
a mai crea o prim ă cerere care s ă îi ofere informa țiile despre resurse.

Tot în acest subcapitol merit ă menționate și colec ții de mesaje prin care o aplica ție client
le poate trata în caz de succes sau e șec. De și Apache ofer ă un cod de status, acest cod reprezint ă
mai mult un indicator ca unele componente nu functioneaz ă corect. Eu am ad ăugat o serie de
mesaje cu originea din serverul Django ce ofe ră informa ții asupra rezultatului unei cereri asupra
serverului. De și Apache va marca aceste rezultate ca și un suces marcat cu 200 OK, ele nu vor
oferi informa ția așteptat ă în cazul în care o opera ție eșuează.

Mesaj Explica ție
MET HOD_NOT_PERMITTED Cererea con ține tipul gre șit GET/POST
pentru opera ția curent ă
MISSING_DATA Cererea nu con ține toate c âmpurile pentru
validare
INVALID_JSON Resursa încărcată nu respect ă regulile
declarate în API
NO_DATA Datele cerute sunt inexistente în server
DATA:{…} Returnarea informa ției cerute aflate în
câmpul DATA din corpul răspunsului
Success Mesaj de confirmare al unei opera ții de
alterare a informa ției din server
Failed Eșec în alterare a informa ției din server

Tabel 4.1 Mesaje de r ăspuns din partea Django

48

4.3 JSON

În momentul în care a trebuit s ă aleg un format pentru datele ce trebuiau salvate pe
server am avut de ales între 3 mari moduri de reprezentare a datelor . XML, JSON si YAML,
cel din urm ă fiind un format de date mult mai recent iar suportul pentru acest format nu era
prezent pentru serverul de MySQL. Alegerea dintre JSON si XML a fost din perspectiva
memoriei pe care ar ocupa -o pe server. XML reprezint ă un format de date ce con ține foarte
multe atribute și propriet ăți ce trebuie declarate indiferent dac ă informa ția ce trebuie transmis ă
conține un caracter sau 10000. Acest surplus de caractere este inutil din punct de vedere
interpretativ al informa ției cât timp se dore ște doar o stocare într-un mod c ât mai u șor de
serializat. Din aceast ă cauză formatul JSON a fost formatul perfect pentru a reprezenta
informa ția în serverul meu .

Un exemplu folosit de mine în construirea acestui alocator este urm ătoarea descriere a
unor resurse pentru alocar e.
{
"unitA" : {
"total_number" : 2,
"resources" : [
"phone1" : {
"resources" : "None",
"info" : {
"extension" : 2121,
"username" : "Extn2121",
"login_code" : "None",
"res_type" : "phone_5400",
"allocated" : "False"
}
},
"phone2" : {
"total_number" : "None",
"resources" : "None",
"info" : {
"extension" : 2122,
"username" : "Extn2122",
"login_code" : "None",
"res_type" : "phone_5400",
"allocated" : "False"
}
},
]
},
…..

49
"unitZ" : {
"resources" : [ ….. ]

Crearea acestui alocator a pornit de la o problem ă pe care multe companii o pot
întâmpina; utilizarea eficient ă a unor resurse, fie ele fizice sau virtuale, dar limitate ca și num ăr.
În acest caz se dore ște declararea unor resurse de tip telefon, folosite în cadrul unei companii
pentru testarea unor solu ții PBX. Num ărul de telefoane per model este limitat și se do rește o
gestiune c ât mai corect ă a lor. Astfel se va face un management printr -o aplica ție care va marca
telefoanele ce sunt folosite într-un moment de timp. Astfel, un angajat își poate prioritiza lista
de teste astfel încât să poată lucra pentru început asupra testelor ale c ăror resurse le poate utiliza
(telefoane în cazul de fa ță).

În acest format este u șor de înțeles pentru un utilizator ce reprezint ă informa ția din acest
dicționar JSON. Avem reprezentate o serie de resurse numite UnitA, UnitB,…. Uni tZ fiecare
având o list ă de resurse de tip telefon cu informa ții detaliate despre acestea :
– extension numărul extensiei cu care este configurat telefonul,
– res_type ce reprezint ă modelul telefonului,
– allocated care ofer ă informa ția despre starea telefonului, dac ă este momentan în
folosin ță.

JSON ca și model de date nu de ține o modalitate prin care o resurs ă să fie identificat ă ca
și resurs ă alocabil ă, astfel încât în crearea alocatorului am impus personal o serie de reguli
pentru care un JSON po ate fi declarat valid în cadrul alocatorului de resurse generice. Pornind
de la ideea c ă un alocator este generic nu am impus o limit ă a num ărului de resurse pe care un
alocator le poate suporta. Din acest punct de vedere un utilizator este limitat doar de capacitatea
serverului de a stoca aceast ă informa ție.

Însă una din limit ările acestui dic ționar de resurse este declararea de propriet ăți cu un
nume fixat astfel încât alocatorul s ă poată face opera ții de procesare. De și alocatorul ofer ă
liberatea de a adăuga orice informa ție extra în declararea resurselor (spre exemplu, alocatorului
nu îi pasă dacă telefonul are declarat c âmpul de extensie sau nu), un utilizator trebuie s ă urmeze
următoarele reguli de declarare a unor resurse:

• entitate ce se dore ște a fi definit ă ca o list ă de elemente alocabile, va trebui s ă își declare
aceste elemente sub forma unei liste de elemente în câmpul obligatoriu numit
"resources"
• Fiecare element c are se dore ște a fi alocabil trebuie s ă aibă câmpul "allocated" în
definirea elementului setat pe True sau False.
• Un element alocabil poate avea la r ândul lui o list ă de elemente cu aceea și proprietate.
Marcarea acestui element p ărinte ca și alocat, va determina alocatorul s ă caute recursiv
toate elementele din resurs ă și să le marcheze ca fiind și ele la r ândul lor alocate.

50
• Un element ce de ține resurse alocabile în defini ția lui va trebui s ă aibă completat
obligatoriu și câmpul "total_number" ce reprezint ă numărul de elemente din list ă.
O populare incorect ă a acestui num ăr poate rezulta în opera ții incomplete.
4.4 Baza de date

Pentru alocator am creat o baza de date minimal ă numit ă resource_manager ce con ține
3 tabele formate dintr -un tabel în care se țin informa țiile de autentificare despre utilizatori, un
tabel în care se păstreaz ă resursele fiec ărui utilizator în format JSON și un tabel ce are rolul de
a ține eviden ța schimb ărilor aplicate pe server , dar și un rol de coad ă de prioritat e pentru
resursele ce se doresc alocate automat în momentul în care resursa devine dispo nibilă.

Fig 4.2 Diagrama UML a bazei de date

51

52
Capitolul 5
Implementare

5.1 Baza de date

Pentru crearea bazei de date , am folosit cuno ștințele dob ândite în timpul facult ății și
care m -au ajutat s ă creez f ără prea mult efort tot ce era necesar. Prima opera ție a fost crearea
bazei de date prin urm ătoarea opera ție:

CREATE DATABASE resource_manager;

Următorul pas a fost definirea tabelului de login prin alegerea unor c âmpuri pe care le –
am considerat ca fiind importante la momentul conceperii. Inspira ția a venit în momentul în
care am realizat c ă un model de tabel de login am folosit și la implementarea proiectului de la
materia de Baze de Date din cadrul facult ății. Astfel am reutilizat și modificat prin ad ăugarea
unui c âmp ce con ține token -ul de autentificare și am reu șit să creez tabelul login.

CREATE TABLE `login` (
`name` varchar(200) NOT NULL,
`surname` varchar(200) NOT NULL,
`email` varchar(200) NOT NULL,
`password` varchar(100) NOT NULL,
`id` int(5) NOT NULL,
`token` varchar(11) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=latin1;

În cazul tabelului de resurse, am optat pentru un tabel în care utlilizatorul își poate
construi p ână la 3 colec ții concurente de resurse pentru a da o not ă de versatilitate alocatorului,
în ideea în care un utilizator dore ște să foloseasc ă alocatorul pentru alte tipuri solu ții și necesit ă
o colec ție diferit ă de resurse. Astfel, folosind API -ul, un utilizator poate modifica independent
resursele f ăra a fi nev oit să ștearg ă o colec ție ca s ă adauge o al tă utilitate alocatorului, în limit a
a 3 colec ții posibile. Acest num ăr poate fi extins dar necesit ă o modificare destul de important ă
în codul alocatorului.

CREATE TABLE `resources` (
`userId` int(5) NOT NULL,
`resource_1` json DEFAULT NULL,
`resource_2` json DEFAULT NULL,
`resource_3` json DEFAULT NULL,
`resource_counter` int(11) NOT NULL DEFAULT '0'
) ENGINE=InnoDB DEFAULT CHARSET=latin1;

53
Un alt aspect important al alocatorului îl reprezint ă abiliatea de a salva posibile aloc ări
într-un tabel în cazul în care o alocare se dore ște a fi automat asignat ă când resursa în cauz ă
devine valabil ă. Pentru acest lucru am creat un tabel în care se p ăstreaz ă informa țiile din cerere a
de alocare astfel încât serveru l Django verific ă la fiecare minut starea informa ției ce se a șteapt ă
a fi eliberat ă.

Tabelul con ține o referin ță la utilizatorul care a cerut informa ția, schimbarea ce se vrea
a fi efectuat ă, dar și un atribut de a șteptare prin care utilizatoru l poate anula cererea de a șteptare
în coad ă după resurs ă.

CREATE TABLE `resource_queue` (
`id` int(11) NOT NULL,
`userID` int(11) NOT NULL,
`resource_patch` json DEFAULT NULL,
`wait_flag` int(11) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=latin1;

Implementarea bazei de date este incomplet ă cât timp nu avem și o organizare din punct
de vedere structural. Scopul este s ă ne asigur ăm că datele nu sunt duplicate și că referin țele între
tabele se p ăstreaz ă pentru a putea procesa informa ția cât mai u șor. Am ad ăugat chei primare și
străine tabelelor acolo unde am considerat necesar și am specificat c ă orice modificare asupra
datelor unui utilizator s ă se reflecte și în celelalte tabele. Cea mai important ă opera ție care
necesit ă modific ări și pe celelalte ta bele este cea de ștergere, astfel c ă la ștergerea unui utilizator
se vor șterge și datele salvate de c ătre acesta pe server.

ALTER TABLE `login`
ADD PRIMARY KEY (`id`),
ADD UNIQUE KEY `email` (`email`);

ALTER TABLE `resources`
ADD UNIQUE KEY `userI d` (`userId`);

ALTER TABLE `resource_queue`
ADD PRIMARY KEY (`id`),
ADD KEY `userID` (`userID`);

ALTER TABLE `login`
MODIFY `id` int(5) NOT NULL AUTO_INCREMENT,
AUTO_INCREMENT=18;

ALTER TABLE `resources`
ADD CONSTRAINT `resources_ibfk_1` FOREIGN KEY (`userId`)
REFERENCES `login` (`id`) ON DELETE CASCADE ON UPDATE CASCADE;

54
ALTER TABLE `resource_queue`
ADD CONSTRAINT `resource_queue_ibfk_1` FOREIGN KEY
(`userID`) REFERENCES `resources` (`userId`) ON DEL ETE CASCADE
ON UPDATE CASCADE;

5.2 Server Django

5.2.1 Implementare opera ții în views.py

Alocatorul a fost construit să suporte următoarele operații :
● on_login – execută operația de login pentru un utilizator pe server. Se
returnează un token de autentificare.
● on_logout – execută operația de terminare a unei sesiuni cu un utilizator.
● on_register – execută înregistrarea unui utilizator nou.
● on_get_users – returnează informații despre un utilizator. Nu include parola.
● on_data – returnează lista de colecții pentru un utilizator.
● allocate – marchează o resursă sau o colecție de resurse ca fiind alocate.
● add_to_queue – adaugă o cerere de alocare în coada de așteptare.

Trebuie ad ăugat faptul c ă provocarea cea mai mare în implementare a fost s ă reușesc să
găsesc o formul ă da conversie dintr -un tip de date String în JSON și opera ția invers ă. Datorit ă
modului în care o colec ție este trimis ă prin cereri HTTP c ătre server, informa ția ajunge în
mediul func țiilor python sub forma unui tip de date text, numit S tring. Din aceast ă cauză am
fost nevoit ă să implementez o serie de opera ții în fiecare func ție pentru a face aceast ă conversie.

O întrebare care s -ar ridica în momentul acesta ar fi: Nu putem s ă salvăm acest String
despre care știm c ă va fi în format JSON direct în baza de date, iar apoi s ă o citim direct ca
JSON folosing python? Răspunsul este NU! În momentul în care primim o cerere de modificare
sau salvare a unei colec ții de resurse alocatorul are datoria de a valida informa ția pe care o
primește și din aceast ă cauză trebuie s ă încerc ăm întâi conversia în JSON apoi putem, în cazul
în care colec ția reprezint ă un dic ționar JSON valid din punct de vedere sintactic, s ă testăm dac ă
dicționarul respect ă regulile impuse de mine și doar dup ă aceste verfic ări putem salva
informa ția în baza de date. În caz contrar am executa opera ții de inserare și ștergere ale
informa ției doar pentru a observa c ă informa ția nu este valid ă. Nu are rost să fie executa te mai
multe opera ții dec ât este nevoie.

Pentru conversia din string în JSON am descoperit modulul python numit sugestiv ,
json . Cu func țiile oferite de acest modul importat am reu șit să găsesc opera ția urm ătoare ce
asigur ă o conversie sigur ă:

import json
json_data = json.loads(request.body)
În cele ce urmează am să explic pe scurt modul în care fiecare funcție își execută
atribuțiile. Așa cum se observă în codul de mai jos, am importat toate modulele de care am avut

55
nevoie pe parcurs pentru a atinge anumite obiective. Modulul json explicat m ai sus a fost printre
primele module descoperite. Ulterior, având nevoie de o conexiune la baza de date am
descoperit modulul MySQLdb care poate executa comenzi de MySQL direct din limbajul
python, lucru foarte apreciat. În lipsa acestui modul aș fi fost n evoită să rulez comenzile de
SQL folosind python în conjuncție cu o librărie ce oferă acces la comezile de sistem și folosirea
clientului de MySQL pentru a le executa. Această alternativă ar fi reprezentat o mare problemă
din punct de vedere structural .

from django.http import HttpResponse
import MySQLdb
import json
import uuid
from django.views.decorators.csrf import csrf_exempt

Funcția on_login primește un request ce conține valorile câmpurilor email și
password. O primă verificare a acestor câmpuri va lidează faptul că cererea conține toate
informa țiile completate. În mod contrar, se returnează un mesaj pentru câmpurile lipsă
"MISSING_DATA"

def on_login(request):
if(request.method == 'GET'):
if 'login' in request.GET.keys() > 0 :
not_ok = False
keys = ['password','email']
for key in keys:
if key not in request.GET.keys() :
not_ok = True
break;
else :
if len(request.GET.get(key)) < 1 :
not_ok = True
break;
if not_ok :
return HttpResponse({"result":"MISSING_DATA"})

După această verficare, se începe conexiun ea cu baza de date folosind credențialele de
sistem pentru a ne conecta folosind clientul din modulul de python și, de asemenea, se
inițializează obiectul numit cursor pentru inserare.

db =MySQLdb.connect
("localhost","root","0027","resource_ manager" )
data = request.GET
cursor = db.cursor()

56
În momentul acesta putem pregăti comanda SQL de SELECT ce verifică dacă datele
trimise de cerere sunt prezente în sistem. Un nou token se generează, iar funcția se termi nă
printr -un răspuns către web server cu acest nou token în câmpul de răspuns
"REGISTER_DATA" .

sql = """select * from login
where email="%s" AND password="%s";""" %
(data.get('email') , data.get( 'password'), )
message = "Failed"
token = uuid.uuid4().hex[:6].upper()
try:
cursor.execute(sql)
results = cursor.fetchall()
if results is not None and len(results) > 0 :
message = token
sql = """update login set token="%s"
where email="%s" AND password="%s";""" %
(token,data.get('email') , data.get('password'), )
cursor.execute(sql)
db.commit()
except Exception as e :
# Rollback in case there is any error
message = e #keep this line uncommneted for
debug purposes
db.rollback()
db.close()
return
HttpResponse( json.dumps({"result":{"REGISTER_DATA":
str(message)} }))
else:
return
HttpResponse(json.dumps({"result":"MISSING_DATA"}))
return HttpResponse("eee server check")

Funcția on_logout închide sesiunea curentă prin generearea unui nou token pentru
utilizatorul curent, fapt ce rejectează orice cerere nouă primită de la utilizator până la
următoarea operație de logare.

def on_logout(request):
if(request.method == 'GET'):
if 'logout' in request.GET.keys() > 0 :
token = uuid.uuid4().hex[:6].upper()
db =
MySQLdb.connect("localhost","root","0027","resource_manager" )

57
data = request.GET
cursor = db.cursor()
sql = """ UPDATE `login` SET `token`=%s WHERE
token=%s ("%s","%s);""" % (data.get('name'),
data.get('token'),token)
return HttpResponse("logging out… " )
else:
return HttpResponse("Logout URL found. No data")
else:
return HttpResponse("no post for you")

HttpResponse( json.dumps({"result":"METHOD_NOT_PERMITTED"}))

Funcția on_register reprezintă operația de înregistrare a unui utilizator în
alocatorul de resurse generice. Această funcție are o implementare simila ră cu cea de login
,adică presupune verificări asupra câmpurilor, iar apoi execută operația de inserare menționată
mai jos .

def on_register(request):
….
cursor = db.cursor()
sql = """INSERT INTO login(name,
surname, email, password, token)
VALUES ("%s","%s","%s","%s","%s");""" %
(data.get('name'), data.get('surname'), data.get('email') ,
data.get('password'), token)
message = "Failed"
try:
# Execute the SQL command
cursor.execute(sql)
# Commit your changes in the database
db.commit()
message = "Success"

Funcția on_get_users returnează informații despre un utilizator pe baza token -ului
prezent și verificat în corpul cererii. Particularitea acestei funcții o reprezintă metoda de
SELECT și modul în care sunt omise câmpurile de token și parolă.

def on_get_users(request):
….
cursor = db.cursor()
sql = """SELECT b.name, b.surname FROM `login` b
where b.token="%s" """ % ( data.get('token'))

58
# execute SQL query using execute() method.
message = "Failed"
try:
# Execute the SQL command
cursor.execute(sql)
results = cursor.fetchall()
if results is not None and len(results) > 0 :
message = results
else:
message = "NO_DATA"
# Commit your changes in the database
db.commit()
….

Funcția on_data are rolul de a salva și returna o colecție de resurse. Spre deosebire
de celelalte funcții, aceasta suportă ambe le tipuri de cereri: GET sau POST. Pentru o cerere de
tip GET, funcția înțelege că va trebui să ofere lista cu resursele salvate pentru un utilizator, iar
pentru o cerere de tip POST va efectua operația de salvare. A se observa conversia din JSON
în string , folosită pentru a putea fi trimisă către aplicația client care a trimis cererea prin
utilizarea comenzii json.dumps , ce primește ca parametru un dicționar și returnează un
obiect string corespunzător dicționarului

def on_data(request):
if(request.me thod == 'GET'):

cursor = db.cursor()
sql = """SELECT a.* FROM `resources` a ,`login` b
where b.id=a.userId and b.token="%s" """ % (
data.get('token'))
return HttpResponse(json.dumps({"result":{"DATA":
message[0][1:4] } }))
else:
return
HttpResponse( json.dumps({"result":"MISSING_DATA"}))

Pentru mesajele de tip POST, funcția va converti stringul primit în corpul mesaju lui
într-un obiect JSON pe care îl va memora în baza de date. Totodată, înainte de memorarea în
baza de date, se verifică prin intermediul funcției validate_json faptul că în interiorul
dicționarului există cel puțin câte un câmp din cele obligatorii defin ite mai sus în modelul de
date JSON.

59
else:
json_data = json.loads(request.body)
if len(str(json_data['ondata'])) > 0 :

# json_data = json.loads(request.body) #
sql = """SELECT a.userId FROM `resources` a
,`login` b where b.id=a.userId and b.token="%s" """ % (
json_data['token'])
resources =
['resource_1','resource_2','resource_3']
resource = resources[int(json_data['resource']) -1]
#check if json is valid
if
(validate_json(json.loads(json_data['json']), "resources") and
validate_json(json.loads(json_data['json']), "allocated") and
validate_json(json.loads(json_data['json']), "name")) or not
bool(json.loads(json_da ta['json'])):
sql = """UPDATE `resources` SET
`%s`=%s WHERE userId=%i """ % (
str(resource),'"'+json_data['json'].replace('"',' \\"')+'"',int
(results[0][0]))

Funcția validate_json caută recursiv existența unui câmp dat ca parametru și
returnează True sau False în cazul în care cheia există sau nu.

def validate_json(_json, check_key):
for key in _json.keys():
if key == check_key:
return True
elif isinstance(_json[key], dict):
return validate_json(_json[key], check_key)

elif isinstance(_json[key], list):
for item in _json[key]:
if isinstance(item, dict):
return validate_json(item, check_key)
return False

Funcția allocate execută operația de alocare pentru o anumită resursă dintr -o
colecție. Pentru acest lucru este nevoie de o serie de comenzi SQL care ne vor oferi toate
informațiile necesare pentru a ajunge la colecția ce trebuie alocată. Cererea va trimit e în corpul
său următoarele informații: token -ul de autentificare, id -ul resursei ce trebuie modificată și
dicționarul ce conține informația nouă de aplicat. Pornind de la aceste informa ții , funcția va
identifica folosind prima comandă de SQL în baza de d ate utilizatorul care deține token -ul, va

60
folosi acest id al utilizatorului și id -ul resursei de Modificat înauntrul celei de a doua comanda
de SQL pentru a extrage resursă în totalitate și va aplica noile modificări asupra ei .

def allocate(request):
json_data = json.loads(request.body)
cursor = db.cursor()
sql = """SELECT a.userId FROM `resources` a
,`login` b where b.id=a.userId and b.token="%s" """ % (
json_data['token'])
resources =
['resource_1','resourc e_2','resource_3']
resource = resources[int(json_data['resource']) -1]

# execute SQL query using execute() method.
message = "Failed"
try:
# Execute the SQL command
cursor.execute(sql)
results = cursor.fetchall()
if results is not None and len(results) > 0 :

sql = """ SELECT %s FROM resources as
a, login as b where b.id=a.userId and b.token="%s" """ %
(resource, json_data['token'])
try:
cursor.execute(sql)
results = cursor.fetchall()

data =
json.loads(json.dumps(results[0][0]))
return HttpResponse(data['unitB'])
sql = """UPDATE `resources` SET
`%s`=%s WHERE userId=%i """ % (
str(resource),'"'+json_data['json'].replace('"',' \\"')+'"',int
(results[0][0]))

5.2.2 Ad ăugare URL pentru opera ții în urls.py

Pentru fiecare func ție creat ă am fost nevoit ă să îi creez un URL parțial prin care s ă poată
fi apelat ă la apari ția unei cereri c ătre acest URL . Am ținut ca URL -urile s ă fie cât mai sugestive
astfel încât să fie ușor de urmat în cod ulterior. Ca s ă testez faptul c ă aceast ă listă a fost acceptat ă
de serverul de Django am restartat serverul de Apache apoi am redeschis pagina Django
menționat ă în sec țiunea de configurare. Rezultatul a fost pozitiv la fiecare introducere a unui

61
URL în aceast ă listă. Pentru ca func țiile s ă fie vizibile în acest fi șier, am fost nevoit ă să folosesc
directiva de import a fi șierului view.py în interiorul fi șierului curent, urls.py

from django.conf. URLs import URL,include
from django.contrib import admin
from rest_api import views
URLpatterns = [
URL('admin/', admin.site. URLs),
URL('login/',views.on_login,name='login'),
URL('logout/',views.on_logout,name='logout'),
URL('register/',views.on_register,name='register'),
URL('users/',views.on_get_users,name='users'),
URL('data/',views.on_data,name='data'),
URL('allocate/',views.allocate,name='allocate'),
]

Fig 5.1 URL -urile sunt accesibile în spa țiul public al re țelei

5.3 Implementare Client folosind API -ul creat

Odat ă ce API -ul a început s ă fie creat pentru alocator am decis s ă implementez un client
ce va testa fiecare opera ție îndată ce aceasta era complet ă în func ționalitate. Av ând în vedere
că toate opera țiile executate de client sunt pe baz ă de cereri HTTP am s ă exemplific doar modul
în care cererile sunt create și trimise, și un exemplu din codul meu prin care un r ăspuns este
convertit din String în format JSON opera țional.

Am ales s ă folosesc Javascript pentru implementarea aplica ției de c lient deoarece am
avut o pagin ă web construit ă pentru proiectul de la materia Baze de Date iar scheletul ei de cod
a constituit un bun început în a crea un client într-un mod c ât mai rapid.

Creare și executare cereri HTTP către un URL : Elementele îngroșate în exemplu
constitu ie principalele locuri care sunt supuse modific ărilor între opera ții. Pentru un request de
tip GET variabila data de mai jos trebuie sa fie nepopulat ă conform standardului HTTP
pentru acest tip de cereri.

62

function alocate_res(res,json){
if (global_change[res -1] > 0 ){
var xhr = new XMLHttpRequest();
var URL = "/wsgi/allocate/";
xhr.open(" POST", URL, true);
xhr.setRequestHeader("Content -Type",
"application/json");
xhr.onreadystatechange = function () {
if (xhr.readyState === 4 && xhr.status === 200) {
var json = JSON.parse(xhr.responseText);
}
};
var data =
JSON.stringify({'alloc':'1','token': login_token,'resource':res
,'json':JSON.stringify(json)});
xhr.send(data);
}else
check_error("No change discovered");
}

Un lucru bun de men ționat este faptul c ă fiecare conversie din JSON în String a fost
făcută folosind func ția JSON.parse din libr ăria JSON oferit ă în mod standard de orice
browser sau libr ărie JQUERY ata șată aplica ției client. Conversia în sens invers este f ăcută cu
ajutorul func ției JSON.stringify din aceea și libr ărie.

63
Capitolul 6
Probleme întâlnite pe parcurs

Deși configur ările WSGI pentru Django și Apache sunt bine explicate în documenta țiile
online ale acestora, unele configur ări nu mai corespundeau în totalitate cu versiunea sistemului
de operare. Astfel am fost obligat ă să caut alternative pentru anumite pachete necesare pentru
instalare.

Nu am știut de la bun început toate modulele Apache de care voi avea nevoie. Pe
parcursul dezvolt ării am întâmpinat erori în care cererile HTTP erau rejectate sau al c ăror
răspuns repreze nta un cod de eroare ce f ăcea trimitere la lipsa acestor module.

O alt ă problem ă întâmpinat ă după instalarea framework -ului și la începutul scrisului de
cod a fost faptul c ă inițial serverul Django nu returna destule informa ții odat ă cu mesajele de
eroare. Din documenta ție am aflat ulterior faptul c ă se pot returna aceste mesaje într-un mod
detaliat prin configurarea unei propriet ăți care activeaz ă aceast ă opțiune.

64

65
Concluzii le proiectului

Am proiectat și implementat de una singură un alocator de resurse generic. Genericitatea
lui a fost observată prin posibilitatea de a atașa orice tip sau dimensiune a informației unor
resurse care urmează un set de reguli simple în creare. Din acest motiv, pot spune că alocatorul
suportă numeroare aplicații fără a fi necesară vreo modificare.

Spre exemplu, poate fi utilizat în construirea unui program care gestionează utilizarea
unor săli de conferințe, sau pentru o aplicație de rezervare online a mesel or dintr -un restaurant,
poate fi folosit pentru a construi un sistem de pontaj al angajaților, iar exemplele pot continua.
Se poate accesa interfața web de alocare de pe orice dispozitiv conectat la rețea,
permițând mobilitatea utilizatorilor în timpul rea lizării rezervării resurselor dorite, sporind
eficiența de lucru. Alocatorul poate fi folosit av ând toate componentele ( webserver, Django
server, baza de date ) pe aceea și mașină sau poate avea baza de date suportat ă de al tă mașină,
fie ea fizic ă sau virt uală. Faptul c ă alocatorul implementeaz ă opera ții abstracte în natur ă (
alocare, dealocare), exist ă posibilitatea de folosire a acestui alocator într-un num ăr mai mare
sub forma de cluster pentru rezolvarea unor probleme mai complexe. Acest nou cluster de
servere de alocare po ate utiliza la r ândul s ău un cluster MySQL conectat cu fiecare alocator
intern pentru o baz ă de date mai extins ă ca spa țiu și cu un suport mai mare al num ărului de
conexiuni. Web serverul din interiorul alocatorului este și el compatib il pentru a lucra ca un tot
unitar într-un astfel de cluster.

Lucr ând la acest proiect am avut șansa s ă lucrez cu limbaje de programare noi, precum
Python și Javascript. Totodat ă, am avut șansa să îmi exercit cuno ștințele în lucrul cu baza de
date, cuno știnte dob ândite în timpul facult ății. Alocatorul mi -a oferit șansa s ă înțeleg cum
funcționeaz ă un web server și cum sunt paginile web g ăzduite pe servere. A reprezentat o
experien ță nouă pentru mine .

66

67
Bibliografie

1. https://www.virtualbox.org/manual/ch01.html accesat la data de 26.06.2019
2. https://help.ubuntu.com/lts/installation -guide/s390x/ch01s01.html accesat la data de
26.06.2019
3. https://www.lifewire.com/definition -of-apache -816509 accesat la data de 26.06.2019
4. http://purepython.eaudeweb.ro/wiki/Cursuri/Introducere -Django.html accesat la data de
26.06.2019
5. https://dev.mysql.com/doc/refman/8.0/en/what -is-mysql.html accesat la data de
26.06.2019
6. https://www.di gitalocean.com/community/tutorials/how -to-serve -django -applications –
with-apache -and-mod_wsgi -on-ubuntu -16-04 accesat la data de 26.06.2019
7. https://resources.sei.cmu.edu/ library/asset -view.cfm?assetid=513908 accesat la data de
26.06.2019
8. https://www.ntu.edu.sg/home/ehchua/programming/webprogramming/HTTP_Basics.html
accesat la data de 26.06.2019
9. https://ramonnastase.ro/blog/ce -este-protocolul -tcp-si-cum-functioneaza/ accesat la data de
26.06.2019
10. https://www.techopedia.com/definition/10008/web -crawler crawler accesat la data de
26.06.2019
11. https://blog.web4all.fr/wp –
content/uploads/2013/01/HappyNewYear4all_retour_sur_les_recentes_modifications/apache_
prefork.gif accesat la data de 26.06.2019
12.https:/ /books.google.ro/books?id=SthQKZaJCv4C&pg=PA208&lpg=PA208&dq=model+r
elational+software&source=bl&ots=42orVKsCzP&sig=ACfU3U0bw8vSbpT2ls7yMNd9JVI
u2_Wtsw&hl=ro&sa=X&ved=2ahUKEwjDwIqG_4fjAhUSJlAKHTHzA_wQ6AEwDHoEC
AgQAQ#v=onepage&q=model%20relational%20software& f=false accesat la data de
26.06.2019
13. https://www.visual -paradigm.com/guide/uml -unified -modeling -language/what -is-
sequence -diagram/ accesat l a data de 26.06.2019
14. https://www.visual -paradigm.com/guide/uml -unified -modeling -language/what -is-uml/
accesat la data de 26.06.2019

68

69
ANEXE
Anexa 1
Cod Server Django

views.py
from __future__ import unicode_literals

from django.shortcuts import render
from django.http import HttpResponse
import MySQLdb
import json
import uuid
from django.views.decorators.csrf import csrf_exempt

# Create your views here.

def on_login(request):
if(request.method == 'GET'):
if 'login' in request.GET.keys() > 0 :
not_ok = False
keys = ['password','email']
for key in keys:
if key not in request.GET.keys() :
not_ok = True
break;
else :
if len(request.GET.get(key)) < 1 :
not_ok = True
break;
if not_ok :
return HttpResponse({"result":"MISSING_DATA"})
db = MySQLdb.connect("localhost","root","0027","resource_manager" )
data = request.GET
cursor = db.cursor()
sql = """select * from login
where email="%s" AND password="%s";""" % (data.get('email') ,
data.get('password'), )
message = "Failed"
token = uuid.uuid4().hex[:6].upper()
try:
cursor.execute(sql)
results = cursor.fetchall()
if results is not None and len(results) > 0 :
message = token
sql = """update login set token="%s"
where email="%s" AND password="%s";""" % (token,data.get('email') ,
data.get('password'), )
cursor.execute(sql)
db.commit()
except Exception as e :
# Rollback in case there is any error
message = e #keep this line uncommneted for debug purposes
db.rollback()
db.close()
return HttpResponse(json.dumps({"result":{"REGISTER_DATA": str(message)} }))
else:
return HttpResponse (json.dumps({"result":"MISSING_DATA"}))
return HttpResponse("eee server check")

def on_logout(request):
if(request.method == 'GET'):
if 'logout' in request.GET.keys() > 0 :
return HttpResponse("logging out… " )
else:
return HttpResponse("Logout url found. No data")
else:
return HttpResponse("no post for you")
HttpResponse(json.dumps({"result":"METHOD_NOT_PERMITTED"}))

def on_register(request):

70
if(request.method == 'GET'):
if 'register' in request.GET.keys() > 0 :
not_ok = False
keys = ['name','surname','password','email']
for key in keys:
if key not in request.GET.keys() :
not_ok = True
break;
else :
if len(request.GET.get(key)) < 1 :
not_ok = True
break;
if not_ok :
return HttpResponse({"result":"MISSING_DATA"})
token = uuid.uuid4().hex[:6].upper()
# Open database connection
db = MySQLdb.connect("localhost","root","0027","resource_manager" )
data = request.GET

# prepare a cursor object using c ursor() method
cursor = db.cursor()
sql = """INSERT INTO login(name,
surname, email, password, token)
VALUES ("%s","%s","%s","%s","%s");""" % (data.get('name'),
data.get('surname'), data.get ('email') , data.get('password'), token)
# execute SQL query using execute() method.
message = "Failed"
try:
# Execute the SQL command
cursor.execute(sql)
# Commit your changes in the database
db.commit()
message = "Success"
except Exception as e :
# Rollback in case there is any error
message = e #keep this line uncommne ted for debug purposes
db.rollback()

db.close()
return HttpResponse(json.dumps({"result":{"REGISTER_DATA": str(message)} }))
else:
return HttpResponse(json.dumps({"result":"MISSING_DAT A"}))
else:
return HttpResponse(json.dumps({"result":"METHOD_NOT_PERMITTED"}))

def on_get_users(request):
if(request.method == 'GET'):
if 'user' in request.GET.keys() > 0 :
not_ok = False
keys = ['token']
for key in keys:
if key not in request.GET.keys() :
not_ok = True
break;
else :
if len(request.GET.get(key)) < 1 :
not_ok = True
break;
if not_ok :
return HttpResponse({"result":"MISSING_DATA"})
token = uuid.uuid4().hex[:6].upper()
# Open database connection
db = MySQLdb.connect("localhost","roo t","0027","resource_manager" )
data = request.GET

# prepare a cursor object using cursor() method
cursor = db.cursor()
sql = """SELECT b.name, b.surname FROM `login` b where b.token="%s" """ % (
data.get('token'))
# execute SQL query using execute() method.
message = "Failed"
try:
# Execute the SQL command
cursor.execute(sql)
results = cursor.fetchall()
if results is not None and len(results) > 0 :
message = results

71
else:
message = "NO_DATA"
# Commit your changes in the database
db.commit()

except Exception as e :
# Rollback in case there is any error
message = e #keep this line uncommneted for debug purposes
db.rollback()

db.close()
return HttpResp onse(json.dumps({"result":{"DATA": message } }))
else:
return HttpResponse(json.dumps({"result":"MISSING_DATA"}))
return HttpResponse(json.dumps({"result":"METHOD_NOT_PERMITTED"}))

def on_data(request):
if(request.method == ' GET'):
if 'ondata' in request.GET.keys() > 0 :
not_ok = False
keys = ['token']
for key in keys:
if key not in request.GET.keys() :
not_ok = True
break;
else :
if len(request.GET.get(key)) < 1 :
not_ok = True
break;
if not_ok :
return HttpResponse({"result":"MISSING_DATA"})
token = uuid .uuid4().hex[:6].upper()
# Open database connection
db = MySQLdb.connect("localhost","root","0027","resource_manager" )
data = request.GET

# prepare a cursor object using cursor() method
cursor = db.cursor()
sql = """SELECT a.* FROM `resources` a ,`login` b where b.id=a.userId and
b.token="%s" """ % ( data.get('token'))
# execute SQL query using execute() method.
message = "Failed"
try:
# Execute the SQL command
cursor.execute(sql)
results = cursor.fetchall()
if results is not None and len(results) > 0 :
message = results
else:
message = "NO_DATA"
# Commit your changes in the database
db.commit()

except Exception as e :
# Rollback in case there is any error
message = e #keep this line uncommneted for debug purposes
db.rollback()

db.close()
return HttpResponse(json.dumps({"result":{"DATA": message[0][1:4] } }))
else:
return HttpResponse(json.dumps({"result":"MISSING_DATA"}))
else:
json_data = json.loads(request.body)
if len(str(json_data['ondata'])) > 0 :

# json_data = json.loads(request.body) # request.raw_post_d ata w/ Django < 1.4
not_ok = False
keys = ['token','resource']
for key in keys:
if key not in json_data.keys() :
not_ok = True
break;
else :
if len(json_data) < 1 :
not_ok = True

72
break;
if not_ok :
return HttpResponse(json.dumps({"result":"MISSING_DATA"}))
token = uuid.uuid4().hex[:6].upper()
# Open database connection
db = MySQLdb.connect("localhost","root","0027","resource_manager" )

# prepare a cursor object using cursor() method
cursor = db.cursor()
sql = """SELECT a.userId FROM `resources` a ,`login` b where b.id=a.userId and
b.token="%s" """ % ( json_data['token'])
resources = ['resource_1','resource_2','resource_3']
resource = resources[int(json_data['resource']) -1]

# execute SQL query using execute() method.
message = "Failed"
try:
# Execute the SQL command
cursor.execute(sql)
results = cursor.fetchall()
if results is not None and len(results) > 0 :
#check if json is valid
if (validate_json(json.loads(json_data['json']), "resources") and
validate_json(json.loads(json_data['json']), "allocated") and
validate_jso n(json.loads(json_data['json']), "name")) or not
bool(json.loads(json_data['json'])):
sql = """UPDATE `resources` SET `%s`=%s WHERE userId=%i """ % (
str(resource),'"'+json_data['json'].replace('"',' \\"')+'"',int(results[0][0]))
try:
cursor.execute(sql)
db.commit()
message = "Success"
except Exception as e :
return HttpRespon se(e)
else:
HttpResponse(json.dumps({"result":"INVALID_JSON"}))

else:
message = "NO_DATA"
# Commit your changes in the database
db.commit()

except Exception as e :
# Rollback in case there is any error
message = e #keep this line uncommneted for debug purposes
db.rollback()

db.close()
return HttpResponse(message )
else:
return HttpResponse(json.dumps({"result":"MISSING_DATA"}))
HttpResponse(json.dumps({"result":"METHOD_NOT_PERMITTED"}))

def validate_json_aux(json, check_key):
"""
Takes a dict with nested lists and dicts,
and searches all dicts for a key of the field
provided.
"""
fields_found = []

for key, value in json.keys():

if key == check_key:
fields_found.append(value)

elif isinstanc e(value, dict):
results = validate_json(value, check_key)
for result in results:
fields_found.append(result)

elif isinstance(value, list):
for item in value:
if isinstance(item, dict):
more_results = validate_json(item, check_key)

73
for another_result in more_results:
fields_found.append(another_result)
if len(fields_found) > 0 :
return True
return False

def validate_json(_json, check_key):
"""
Takes a dict with nested lists and dicts,
and searches all dicts for a key of the field
provided.
"""
for key in _json.keys():
if key == check_k ey:
return True
elif isinstance(_json[key], dict):
return validate_json(_json[key], check_key)

elif isinstance(_json[key], list):
for item in _json[key]:
if isinstance(item, dict):
return validate_json(item, check_key)
return False

def allocate(request):
json_data = json.loads(request.body)
if len(str(json_data['alloc'])) > 0 :

# json_data = json.loads(request.body) # request.raw_post_data w/ Django < 1.4
not_ok = False
keys = ['token','resource']
for key in keys:
if key not in json_data.keys() :
not_ok = True
break;
else :
if len(json_data) < 1 :
not_ok = True
break;
if not_ok :
return HttpResponse(json.dumps({"resul t":"MISSING_DATA"}))
# Open database connection

db = MySQLdb.connect("localhost","root","0027","resource_manager" )
data = request.GET

# prepare a cursor object using cursor() method
cursor = db.cursor()
sql = """SELECT a.* FROM `resources` a ,`login` b where b.id=a.userId and
b.token="%s" """ % ( data.get('token'))
# execute SQL query using execute() method.
message = "Failed"
try:
# Execute the SQL command
cursor.execute(sql)
results = cursor.fetchall()
if results is not None and len(results) > 0 :
message = results
else:
message = "NO_DATA"
# Commit your changes in the database
db.commit()

except Exception as e :
# Rollback in case there is any error
message = e #keep this line uncommneted for debug purposes
db.rollback()

# prepare a cursor object using cursor() method
cursor = db.cursor()
sql = """SELECT a.userId FROM `resources` a ,`log in` b where b.id=a.userId and
b.token="%s" """ % ( json_data['token'])
resources = ['resource_1','resource_2','resource_3']
resource = resources[int(json_data['resource']) -1]

# execute SQL query using ex ecute() method.

74
message = "Failed"
try:
# Execute the SQL command
cursor.execute(sql)
results = cursor.fetchall()
if results is not None and len(results) > 0 :

sql = """SELECT %s FROM resources as a, login as b where
b.id=a.userId and b.token="%s" """ % (resource, json_data['token'])
try:
cursor.execute(sql)
results = cursor.fetchall()

data = json.loads(json.dumps(results[0][0]))
return HttpResponse(data['unitB'])
sql = """UPDATE `resources` SET `%s`=%s WHERE userId=%i """ % (
str(resource),'"'+json_data['json'].replace('"',' \\"')+'"',int(results[0][0]))
#return HttpResponse(sql)
try:
cursor.execute(sql)
db.commit()
message = "Success"
except Exception as e :
return HttpResponse(e)
except Exception as e :
return Ht tpResponse(e)
# else:
# HttpResponse(json.dumps({"result":"INVALID_JSON"}))
else:
message = "NO_DATA"
# Commit your changes in the database
db.commit()

except Exception as e :
# Rollback in case there is any error
message = e #keep this line uncommneted for debug purposes
db.rollback()

db.close()
return HttpResponse(message )
else:
return HttpResponse(json.dumps({"result":"MISSING_DATA"}))
HttpResponse(json.dumps({"result":"METHOD_NOT_PERMITTED"}))

urls.py

from django.conf.urls import url,include
from django.contrib import admin
from rest_api import views
urlpatterns = [
url('admin/', admin.site.urls),
url('login/',views.on_login,name='login'),
url('logout/',views.on_logout,name='logout'),
url('register/',views.on_register,name='regis ter'),
url('users/',views.on_get_users,name='users'),
url('data/',views.on_data,name='data'),
url('allocate/',views.allocate,name='allocate'),
]

75

Anexa 2
Cod Configurare Apache
000-default.conf

<VirtualHost *:80>

ServerAdmin webmaster@localhost
DocumentRoot /var/www/html
Header always set Access -Control-Allow-Origin "*"
Header always set Access -Control-Allow-Methods "MOVE, COPY, POST, GET, OPTIONS, DELETE,
PUT, MKCOL, PROPFIND"
Header always set Access -Control-Max-Age "1000"
Header always set Access -Control-Allow-Headers "Destination, Overwrite, Cache -Control, x –
requested -with, Content -Type, origin, authorization, accept, client -security -token, Depth
,Authorization"
ErrorLog ${APACHE_LOG_DIR}/error.log
CustomLog ${APACHE_LOG_DIR}/access.log combined

<FilesMatch " \.(cgi|shtml|phtml|php)$">
SSLOptions +StdEnvVars
</FilesMatch>
<Proxy *>
Order deny,allow
Allow from all
Require all granted
</Proxy>
RewriteEngine on
WSGIScriptAlias /wsgi /srv/resource_manager /resource_manager/apache/pitong.wsgi
WSGIApplicationGroup %{GLOBAL}

<Directory /srv/resource_manager/resource_manager/apache>
Options All
# AllowOverride All
Require all granted
</Directory>

Alias /static /srv/resource_manager/static
<Directory /srv /resource_manager/resource_manager>
Options Indexes FollowSymlinks Includes ExecCgi
#<Files wsgi.py>
Order deny,allow
Require all granted
Allow from all

#</Files>
</Directory>

</VirtualHost>

# vim: syntax=apache ts=4 sw=4 sts=4 sr noet

76

77

Anexa 3
Cod Aplica ție Client

startup.js

$(document).ready(function ()
{

$("#go-dash_top").click(function(){

hide_everything_except_dashboard('#udashboard');
});

$("#socialregconnect -r").click(function(){

getOutput($("#socialregname_").val()+"|][|"+$("#socialregsurname_").val()+"|][|"+$("#socialreg
email").val()+"|][|"+$("#socialregpasswd").val(),"register");

});

$("#socialconnect -r").click(function(){
var login =
getOutput($("#socialemail").val()+"|][|"+$("#socialpasswd").val(),"login");
if (login ==="success")
hide_everything_except_dashboard('#udashboard');
});

$("#replace_res1").click(function(){

create_resource(0,"Replace");

});

$("#replace_res2").click(function(){

create_resource(1,"Replace");

});
$("#replace_res3").click(function(){

create_resource(2,"Replace");

});

$("#alocate_res1").click(function(){

if (json_list[0] != null && Object.keys(json_list[0]).length > 0)
alocate_res(1,json_list[0])
else{
//create resource
create_resource(0,"Create");
}

});

$("#alocate_res2").click(function(){
if (json_list[1] != null && Object.keys(json_list[1]).length > 0)
alocate_res(2,json_list[1])
else{
//create resource
create_resource(1,"Create");
}

78
});

$("#alocate_res3").click(function(){
if (json_list[2] != null && O bject.keys(json_list[2]).length > 0)
alocate_res(3,json_list[2])
else{
//create resource
create_resource(2,"Create");
}
});

$("#toggle_res3").click(function(){
$("#resources0 -wrapper").fadeOut();
$("#resources1 -wrapper").fadeOut();
$("#resources2 -wrapper").fadeIn();

})

$("#toggle_res2").click(function(){

$("#resources0 -wrapper").fadeOut();
$("#resources2 -wrapper").fadeOut();
$("#resources1 -wrapper").fadeIn();
})
$("#toggle_res1").click(function(){

$("#resources2 -wrapper").fadeOut();
$("#resources1 -wrapper").fadeOut();
$("#resources0 -wrapper").fadeIn();
})

document.getElementById("socialLogins").style.display="block";
document.getElementById("socialLogins").style.zIndex="23";
$("#accordion2").css({display:"none"});
$("#stranger").text("Hello "+upperNameAndSourname( "")+" !");
$("#pass_auth").css({display:"block"});

});

function urlParam(name)
{
var results = new RegExp('[ \\?&]' + name + '=([^&#]*)').exec(window.locati on.href);
if (!results) { return undefined; }
return results[1] || undefined;
}

function IsJsonString(str) {
try {
JSON.parse(str);
} catch (e) {
return false;
}
return true;
}

function create_resource(json,text){

$("#new_value_res").val('')
$('#MsgBoxExt2').modal();

$("#msg-ext2").html('<i class="fa fa -exclamation -triangle txt -color-orangeDark"></i>
'+text+" Resource "+'<button id="mid -pop-button_res_c" class=" btn -default btn -sm botTempo"
style="float:right ;"> Cancel</button><button id="mid -pop-button_res" class=" btn -default btn –
sm botTempo" style="float:right;margin -right:10px;"> Create</button></span>')
$('#mid-pop-button_res').unbind();
$('#mid-pop-button_res_c').click(function(){
$('#MsgBoxEx t2').modal('hide');
})
$('#mid-pop-button_res').click(function(){
if (IsJsonString($("#new_value_res").val() )) {

79
var _json_list =
JSON.parse($("#new_value_res").val().replace(/( \r\n|\n|\r|\\r|\\n|\\r\\n)/gm, ""))
if( Object.prototype.t oString.call( _json_list ) === '[object Array]' ) {
_json_list={"data": _json_list}
}
global_change[json]=1;
alocate_res(json+1,_json_list)
}else{

$('#MsgBoxExt2').modal('hide');
check_error("JSON not valid. Please check sintax")
}

})
}

window.hide_everything_except_dashboard=function(panel_id)
{
var panels = [ "#udashboard",
];
for(var i = 0; i < panels.length; i++)
if(panel_id !== panels[i])
$(panels[i]).fadeOut();

$(panel_id).fadeIn();
}

function loadRegPanel(){
normal_reg=1;
$('#settings').hide();
$('#socialLogins').hide();
$('#socialregname').parent().hide();
$('#socialregname_').parent().show();
$('#socialregsurname_').parent().show();

$('#socialregemail').prop('readonly', false);;
document.getElementById("socialReg").style.display="block";
document.getElementById("socialReg").style.zIndex="23";
$('#socialReg').show();

}

function loadLgPanel(){

normal_reg=0;
$('#settings').hide();
$('#socialReg').hide();
document.getElementById("socialLogins").style.display="block";
document.getElementById("socialLogins").style.zIndex="23";
$('#socialLogins ').show();

}

function upperNameAndSourname(nameAndSourname){
var name = nameAndSourname.charAt(0).toUpperCase()+ nameAndSourname.slice(1);
name = name.substring(0, name.lastIndexOf(" "));
var surname = nameAndSourname.charAt(nameAndSourname.lastIndexOf(" ")+1).toUpperCase()+
nameAndSourname.slice(nameAndSourname.lastIndexOf(" ")+2);
nameAndSourname = name+" "+surname;
nameAndSourname = nameAndSourname.split('_')[0];
return nameAndSo urname;
}

var login_token = "";
var userName= "";
var data = [];
var data_used =0 ;
var json_list=[{},{},{}]
global_change = [0,0,0]
// handles the click event for link 1, sends the query
function getOutput(tokens,page) {

80
if (page === "login"){
var email = tokens.split("|][|")[0];
var pass = tokens.split("|][|")[1];
if (email.length >0 && pass.length > 0)
var url =encodeURI( "/wsgi/login/?login=1&email="+email+"&password="+pass);
else
var url = "";
}

if (page === "register"){
var name = tokens.split("|][|")[0];
var surname = tokens.split("|][|")[1];
var email = tokens.split("|][|")[2];
var pass = tokens.split("|][|")[3];
if (email.length >0 && pass.length > 0)
var url =encodeURI(
"/wsgi/register/?register=1&name="+name+"&email="+email+"&password="+pass+"&surname="+surname)
;
else
var url = "";
}

if (page === "log_out"){
var email = tokens.split("|][|")[0];
var pass = toke ns.split("|][|")[1];
if (email.length >0 && pass.length > 0&& name.length>0)
var url =encodeURI( "/wsgi/logout/?login=1&email="+email+"&password="+pass);
else
var url = "";
}

var xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
// Typical action to be performed when the document is ready:
if (page ==="login"){
login_token = JSON.parse(xhttp.responseText )['result']['REGISTER_DATA'];
console.log(login_token);
if (login_token !=="Failed"){
$('#socialLogins').hide();
$('#socialLogins').empty();
$('#socialReg').hide();
$('#socialReg').empty();

$('#settings').empty();
$('#newcommers').hide();
$('#newcommers').empty();
$(".backstretch").css("z -index"," -999999");
$('#demo -setting').show();
get_feed('science');
get_user();
$('#header').show();
get_data();

hide_everything_except_dashboard('#udashboard');
}
else{
msg = "Login Failed. Please check your credentials";

return check_error(msg);
}
}
if (page ==="register"){
console.log(xhttp.respons eText);
response = JSON.parse(xhttp.responseText)['result']['REGISTER_DATA'];
if (response === "Success"){
window.location="#";
location.reload();
}else{
msg = "Email address already exists";

return check_error(msg);
}
}
}
};
if (url.length>0){

81
xhttp.open("GET",url, true);
xhttp.send();
}
else
return "empty_values";
}

window.get_user= function(){

if (login_token.length >0)
var url =encodeURI( "/wsgi/users/?user=1&token="+login_token);
else
var url = "";

var xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {

response = JSON.parse(xhttp.responseText)['result']['DATA'];
userName = response[0][0]+" "+response[0][1];
$("#show -shortcut span").text(userName);
$('.usernamebar').text(userName);
$('title').text(userName.replace(/ \b\w/g, l => l.toUpperCase()) +' | Unique');
}
};
if (url.length>0){
xhttp.open("GET",url, true);
xhttp.send();
}
else
return "empty_values";
}

function alocate_res(res,json){
if (global_change[res -1] > 0 ){
var xhr = new XMLHttpRequest();
var url = "/wsgi/allocate/";
xhr.open("POST", url, true);
xhr.setRequestHeader("Content -Type", "application/json");
xhr.onreadystatechange = function () {
if (xhr.readyState === 4 && xhr.status === 200) {
//var json = JSON.parse(xhr.responseText);
if (xhr.responseText == "Success"){
$('#MsgBoxExt').modal('hide');
$('#MsgBoxExt2').modal('hide');
check_error("Resource updated");
window.get_data();
global_change[res -1]=0;
}else
// json_list[res=1] = {};
check_error("Resource was not updated.Sintax error.");
}
};
var data =
JSON.stringify({'alloc':'1','token':login_token,'resource':res,'json':JSON.stringify(json)});
xhr.send(data);
}else
check_error("No change discovered");
}

function renderList(obj,json) {

var result = document.createElement('ul');
for (key in obj) {

var list = document.createElement('li')

list.style.cursor="pointer"
var textnode = document.createTextNode((key));

list.appendChild(textnode);
if (typeof obj[key] === 'object') {
list.appendChild(renderList(obj[key],json));
} else {

82
textnode.textContent += ': ' + obj[key];
list.id = textnode.textContent;
list.onclick = function(event) {
event.preventDefault();start_popup(event.target.id.split(": ")[0],event.target.id.split(":
")[1],json); };

}
result.appendChild(list);
}
return result;
}

function strcmp(a, b) {
a = a.toString(), b = b.toString();
for (var i=0,n=Math.max(a.length, b.length); i<n && a.charAt(i) === b.charAt(i); ++i);
if (i === n) return 0;
return a.charAt(i) > b.charAt(i) ? -1 : 1;
}

function update(obj, k ey, val, newVal,json) {
var newValue = newVal;
var objects = [];
for (var i in obj) {

if (!obj.hasOwnProperty(i)) continue;
if (typeof obj[i] == 'object') {
objects = objects.concat(update(obj[i], key, val, newV alue,json));
} else if (i == key && obj[key] == val) {

if (strcmp(obj[key] , newVal) ==0)
global_change[json]=0;
else
global_change[json]=1;
obj[key] = newVal;
console.log("found it")

}
}
return obj;
}

function alocate(prop,data,json){
console.log("trying to alocate it")
var newVal = $("#new_value").val();
if (newVal.length > 0){
console.l og(newVal)
json_list[json]= update(json_list[json], prop, data,newVal,json)
alocate_res(json+1,json_list[json])
$('#MsgBoxExt').modal('hide');
}else
check_error("Values cannot be empty")
}

function start_popup(prop,da ta,json){

$("#mid-pop").text(prop);
$("#new_value").val(data)
$('#MsgBoxExt').modal();
$('#mid-pop-button').unbind();
$('#mid-pop-button').click(function(){

alocate(prop,data,json);

});
}

window.get_data= function(){

if (login_token.length >0)
var url =encodeURI( "/wsgi/data/?ondata=1&token="+login_token);
else
var url = "";

var xhttp = new XMLHttpRequest();

83
xhttp.onreadystatechange = function() {
if (this.readyState == 4 && this. status == 200) {

response = JSON.parse(xhttp.responseText)['result']['DATA'];

var jsonobj=response
json_list =
[JSON.parse(jsonobj[0]),JSON.parse(jsonobj[1]),JSON.parse(jsonobj[2])]
console.log(json_list);
var myTarget0 = document.getElementById('resources0');
var myTarget1 = document.getElementById('resources1');
var myTarget2 = document.getElementById('resources2');
myTarget0.innerHTML="";
myTarget1.innerHTML="";
myTarget2.innerHTML="";
$("#alocate_res1").text("Allocate Resource 1")
$("#alocate_res2").text("Allocate Resource 2")
$("#alocate_res3").text("Allocate Resource 3")

if (json_list[0] !== null && Object.keys(json_list[0]).length > 0){
$("#replace_res1").show()
$("#alocate_res1").show()
myTarget0.appendChild(renderList(json_list[0],0));
}else{
$("#replace_res1").hide()
$("#alocate_res1").show()
myTarget0.innerHTML="No Resource C reated!";
$("#alocate_res1").text("Create Resource 1")

}
if (json_list[1] !== null && Object.keys(json_list[1]).length > 0){
$("#alocate_res2").show()
$("#replace_res2").show()
myTarget1.appendChild(renderList(json_list[1],1));
}else{
$("#replace_res2").hide()
$("#alocate_res2").show()
myTarget1.innerHTML="No Resource Created!";
$("#alocate_res2").text("Create Resource 2")

}
if (json_list[2] !== null && Object.keys(json_list[2]).length > 0) {
$("#replace_res3").show()
$("#alocate_res3").show()
myTarget2.appendChild(renderList(json_list[2],2));
}else{
$("#replace_res3").hide()
$("#alocate_res3"). show()
myTarget2.innerHTML="No Resource Created!";
$("#alocate_res3").text("Create Resource 3")

}

}
};
if (url.length>0){
xhttp.open("GET" ,url, true);
xhttp.send();
}
else
return "empty_values";
}

// handles drawing an error message
function drawError() {
return "Error";
}
// handles the response, adds the html
function drawOutput(responseText) {
console.log(responseText);

return responseText;

84
}
// helper function for cross -browser request object
function getRequest(url, success, error,saved) {
var req = false;
try{
// most browsers
req = new XMLHttpRequest();
} catch (e){
// IE
try{
req = new ActiveXObject("Msxml2.XMLHTTP");
} catch(e) {
// try an older version
try{
req = new ActiveXObject("Microsoft.XMLHTTP");
} catch(e) {
return false;
}
}
}
if (!req) return false;
if (typeof success != 'function') success = function () {};
if (typeof error!= 'function') error = function () {};
req.onreadystatechange = function(){
if(req.readyState == 4) {
var
pages=['login','register','home','ship','doc','company','users','embark_ship','embark_doc'];
if (req.status === 200){
var data=req.responseText;
//console.log(data);
index= pages.indexOf(saved)
switch(index){
case 0 : //login
if (data === "Success"){
$('#settings').hide();
$('#socialLogins').hide();
$('#socialLogins').empty();
$('#socialReg').hide();
$('#socialReg').empty();

$('#settings').empty();
$('#newcommers').hide();
$('#newcommers').empty();
$(".backstretch").css("z -index"," -999999");
$('#demo -setting').show();

var userName= "";
$("#show -shortcut span").text(userName);
$('.usernamebar').text(userName);
$('title').text(userName.replace(/ \b\w/g, l => l.toUpperCase())
+' | Unique');
$('#header').show();
hide_everything_except_dashboard('#udashboard');
}else{
msg = "Login Failed. Please check your credentials";

return check_error(msg);
}
break;
case 1 : //register
if (data === "Success"){
window.location="localhost/navinet";
location.reload();
}else{
msg = "Email address already exists";

return check_error(msg);
}
break;

default: break;

}
}

85
}
}
req.open("GET", url, true);
req.send(null);
return req;
}

function leave_or_log(){

window.location="localhost/navinet";
location.reload();
}

function show_error_message(msg)
{
console.log(msg);
$('#msg-error').text(msg);
$('#MsgBoxExt2').modal('hide');
$('#MsgBoxExt').modal('hi de');
$('#MsgBoxError').modal();

}

function show_confirm_message(msg, fn, cont)
{
$('#msg-confirm').text(msg);
$('#confirm -yes').unbind();
$('#confirm -yes').click( function() { $('#MsgBoxConfirm').modal('hide'); fn(); } );

$('#confirm -no').unbind();
$('#confirm -no').click( function() { $('#MsgBoxConfirm').modal('hide'); if(cont) cont() } );

$('#MsgBoxConfirm').modal();
}

function check_error(msg)
{
if(msg !== true)
{
show_error_message(msg);
return false ;
}
return true;
}

var post_test = {
"unitA" : {
"resources" : {
"phone1" : {
"resources" : "None",
"info" : {
"extension" : 2121,
"username" : "Extn2121",
"login_code" : "None",
"res_type" : "phone_5400",
"allocated" : "False"
}
},
"phone2" : {
"resources" : "None",
"info" : {
"extension" : 2122,
"username" : "Extn2122",
"login_code" : "None",
"res_type" : "phone_5400",
"allocated" : "Fa lse"
}
},
"phone3" : {
"resources" : "None",
"info" : {
"extension" : 2123,

86
"username" : "Extn2123",
"login_code" : "None",
"res_type" : "phone_5400",
"allocated" : "False"
}
},
"phone4" : {
"resources" : "None",
"info" : {
"extension" : 2151,
"username" : "Extn2151",
"login_code" : "None",
"res_type" : "phone_1600",
"allocated" : "False"
}
},
"phone5" : {
"resources" : "None",
"info" : {
"extension" : 2152,
"username" : "Extn2152",
"login_code" : "None",
"res_type" : "phone_1600",
"allocated" : "Fa lse"
}
},
"phone6" : {
"resources" : "None",
"info" : {
"extension" : 2153,
"username" : "Extn2153",
"login_code" : "None",
"res_type" : "phone_1600",
"allocated" : "False"
}
},
"phone7" : {
"resources" : "None",
"info" : {
"extension" : 2181,
"username" : "Extn2181",
"login_code" : "None",
"res_type" : "phone_9600",
"allocated" : "False"
}
},
"phone8" : {
"resources" : "None",
"info" : {
"extension" : 2182,
"username" : "Extn2182",
"login_code" : "None",
"res_type" : "phone_9600",
"allocated" : "Fa lse"
}
}
},
"info" : {
"ip" : "172.29.1.1",
"name" : "T1SiteA_ip500v2",
"res_type" : "500v2",
"allocated" : "False"
}
},
"unitB" : {
"resources" : {
"phone1" : {
"resources" : "None",
"info" : {
"extension" : 2221,
"username" : "Extn2221",
"login_code" : "None",
"res_type" : "phone_5400",
"allocated" : "False"
}
},
"phone2" : {

87
"resources" : "None",
"info" : {
"extension" : 2222,
"username" : "Extn2222",
"login_code" : "None",
"res_type" : "phone_5400",
"allocated" : "False"
}
},
"phone3" : {
"resources" : "None",
"info" : {
"extension" : 2223,
"username" : "Extn2223",
"login_code" : "None",
"res_type" : "phone_5400",
"allocated" : "False"
}
},
"phone4" : {
"resources" : "None",
"info" : {
"extension" : 2251,
"username" : "Extn2251",
"login_code" : "None",
"res_type" : "phone_1600",
"allocated" : "False"
}
},
"phone5" : {
"resources" : "None",
"info" : {
"extension" : 2252,
"username" : "Extn2252",
"login_code" : "None",
"res_type" : "phone_1600",
"allocated" : "False"
}
},
"phone6" : {
"resources" : "None",
"info" : {
"extension" : 2253,
"username" : "Extn2253",
"login_code" : "None",
"res_type" : "phone_1600",
"allocated" : "False"
}
},
"phone7" : {
"resources" : "None",
"info" : {
"extension" : 2281,
"username" : "Extn2281",
"login_code" : "None",
"res_type" : "phone_9600",
"allocated" : "False"
}
},
"phone8" : {
"resources" : "None",
"info" : {
"extension" : 2282,
"username" : "Extn2282",
"login_code" : "None",
"res_type" : "phone_9600",
"allocated" : "False"
}
}
},
"info" : {
"ip" : "172.29.2.1",
"name" : "T1SiteB_ip500v2",
"res_type" : "500v2",
"allocated" : "False"
}
},

88
"ANALOG_A_B": {
"resources" : "None",
"info" : {
"shcode" : 802,
"line_no" : 102,
"prefix" : "None",
"res_type" : "analog_line",
"allocated" : "False"
}
},
"ANALOG_B_A": {
"resources" : "None",
"info" : {
"shcode" : 801,
"line_no" : 101,
"prefix" : "None",
"res_type" : "analog_line",
"allocated" : "False"
}
},
"PRI_A_B": {
"resources" : "None",
"info" : {
"shcode" : 822,
"line_no" : 9,
"prefix" : "None",
"res_type" : "pri_line",
"allocated" : "False"
}
},
"SIP_A_B": {
"resources" : "None",
"info" : {
"shcode" : 872,
"line_no" : 21,
"prefix" : "None",
"res_type" : "sip_line",
"allocated" : "False"
}
}
}

index.html

<!DOCTYPE html PUBLIC " -//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1 -transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">

<head>
<meta http -equiv="Content -Type" content="text/html; charset=UTF -8" />
<title>Resource Manager</title>
<head>
<meta name="description" content="">
<meta name="author" content="">

<meta name="viewport" content="width=device -width, initial -scale=1.0, maximum –
scale=1.0, user -scalable=no">

<!– #CSS Links –>
<link href="css/application.css?v=12344" rel="styl esheet">
<!– Basic Styles –>

<link rel="stylesheet" type="text/css" media="screen"
href="css/bootstrap.min.css">
<link rel="stylesheet" type="text/css" media="screen" href="css/font -awesome-
4.7.0/css/font -awesome.css">

<!– SmartAdmin Styles : Caution! DO NOT change the order –>
<link rel="stylesheet" type="text/css" media="screen" href="css/smartadmin –
production -plugins.min.css?v=123234">
<link rel="stylesheet" type="text/css" media="screen" href="css/smartadmin –
production.min.css?v=1231" >
<link rel="stylesheet" type="text/css" media="screen" href="css/smartadmin –
skins.min.css">

89

<!– SmartAdmin RTL Support –>
<link rel="stylesheet" type="text/css" media="screen" href="css/smartadmin –
rtl.min.css">

<!– We recommend you use "your _style.css" to override SmartAdmin
specific styles this will also ensure you retrain your customization with
each SmartAdmin update.
<link rel="stylesheet" type="text/css" media="screen"
href="css/your_style.css"> –>

<!– Demo purpose only: goes with demo.js, you can delete this css when
designing your own WebApp –>
<link rel="stylesheet" type="text/css" media="screen" href="css/demo.min.css">

<link rel="stylesheet" type="text/css" media="screen"
href="css/cubeportfolio.min.css">
<link rel="stylesheet" type="text/css" media="screen" href="css/reset.css">

<link rel="stylesheet" type="text/css" media="screen" href="css/layout.css">
<link rel="stylesheet" type="text/css" media="screen"
href="css/components.css">
<link rel="stylesh eet" type="text/css" media="screen"
href="css/animate.min.css">
<link rel="stylesheet" type="text/css" media="screen" href="css/weather –
icons.min.css" >
<link rel="stylesheet" type="text/css" media="screen" href="css/plugins.css">
<link rel="styleshe et" type="text/css" media="screen"
href="css/default.theme.css" id="theme">
<link rel="stylesheet" type="text/css" media="screen" href="css/project –
team.css">
<link rel="stylesheet" type="text/css" media="screen"
href="js/new_js/bootstrap -switch.min.cs s">

<!– #FAVICONS –>
<link rel="shortcut icon" href="img/favicon/favicon.ico" type="image/x -icon">
<link rel="icon" href="img/favicon/favicon.ico" type="image/x -icon">

<!– #GOOGLE FONT –>
<link rel="stylesheet"
href="https://fonts.googleapi s.com/css?family=Open+Sans:400italic,700italic,300,400,700">

<!– #APP SCREEN / ICONS –>
<!– Specifying a Webpage Icon for Web Clip
Ref:
https://developer.apple.com/library/ios/documentation/AppleApplications/Reference/SafariWebCon
tent/Configur ingWebApplications/ConfiguringWebApplications.html –>
<link rel="apple -touch-icon" href="img/splash/sptouch -icon-iphone.png">
<link rel="apple -touch-icon" sizes="76×76" href="img/splash/touch -icon-
ipad.png">
<link rel="apple -touch-icon" sizes="120×120" href="img/splash/touch -icon-
iphone-retina.png">
<link rel="apple -touch-icon" sizes="152×152" href="img/splash/touch -icon-ipad-
retina.png">

<!– iOS web-app metas : hides Safari UI Components and Changes Status Bar
Appearance –>
<meta name="apple -mobile-web-app-capable" content="yes">
<meta name="apple -mobile-web-app-status-bar-style" content="black">

<!– Startup image for web apps –>
<link rel="apple -touch-startup-image" href="img/splash/ipad -landscape.png"
media="screen and (min -device-width: 481px) and (max -device-width: 1024px) and
(orientation:landscape)">
<link rel="apple -touch-startup-image" href="img/splash/ipad -portrait.png"
media="screen and (min -device-width: 481px) and (max -device-width: 1024px) and
(orientat ion:portrait)">
<link rel="apple -touch-startup-image" href="img/splash/iphone.png"
media="screen and (max -device-width: 320px)">

<!–srcipt here –>

<script src="js/jquery.min.js"></script>
<!–<script src="assets/plugins/backstretch/jquery. backstretch.min.js"></script> –>
<script type="text/javascript"
src="login/plugins/backstretch/jquery.backstretch.min.js"></script>

90
<script src="js/bootstrap/bootstrap.min.js"></script>

<!– INTERFACE LIBRARY START

<!– common libraries. required for every page –>
<link rel="stylesheet" href="assets/jkresponsivegallery.css" />

<script src="vendor/moment/min/moment.min.js"></script>

<!–<script src="vendor/seiyria -bootstrap -slider/dist/bootstrap -slider.min.js"></script> –>
<script src="js/jquery.fullcalendar.min.js"></script>
<script src="js/new_js/bootstrap -switch.min.js"></script>

<script src="./weather/js/weather/jquery.simpleWeather.js"></script>

<!– INTERFACE LIBRARY START

<!– common libraries. required for ev ery page –>
<link rel="stylesheet" href="assets/jkresponsivegallery.css" />

<script src="vendor/moment/min/moment.min.js"></script>

<!–<script src="vendor/seiyria -bootstrap -slider/dist/bootstrap -slider.min.js"></script> –>
<script src="js/jquery.fullca lendar.min.js"></script>
<script src="js/new_js/bootstrap -switch.min.js"></script>

<script src="js/jquery -ui.js"></script> <! – libs–>

<link rel="stylesheet" type="text/css" media="screen" href="css/videolayout_default.css?v=16"
id="videolayout_default"/>

<!– <script src="../portal/js/profilePage.js"></script> –>

<link rel="shortcut icon" href="favicon.ico"/>
<link rel=" stylesheet" href="css/font -awesome-4.7.0/css/font -awesome.css">
<link rel="stylesheet" href="css/styles.css" />
<link rel="stylesheet" href="css/main.css" />
<link rel="stylesheet" href="css/jquery -impromptu.css">
<link rel="stylesheet" hre f="css/modaldialog.css">

<link rel="stylesheet" href="css/table.css?v=1">
<link rel="stylesheet" href="css/jquery.timepicker.css">

<script src="vegas/vegas.min.js"></script>

<script src="vegas/bar.js"></ script>

</head>
<body class="hidden -menu desktop -detected chat -sidebar-container fixed -header fixed –
navigation nav -collapsed" style="background -image:url('images/back.jpg')!important;background –
size:cover!important; ">
<div id="fb -root"></div>

<header id="header" style="display:none" class="navbar navbar -toolbar navbar -dark">
<div id="logo -group">

91

<div id="chat -notification" class="chat -notification"
style="display:none"></div>

</div>

<div style="width:1192px;left:0px;right:0;margin: auto;position: absolute;height: 50px">
<span id="logo" style="width: 40px;float: left;margin -right: 10px;margin -left: 0px;">
<img src="login/logo.png" alt="" style="width:90px;"> </span>
<div style="width:400px; height: 50px;float: left;" >
<center id="net_search_contact">
</center>
</div>
<div class="" style=" width:500px;height: 50px;float: left;"><center>
<ul class="unTopNav" id="idunTopNav" style="width:506px;">
<li >
<a href="#" id="go -dash_top" class="TopNavtooltip"><span class="icon"><i
class="fa fa -lg fa-fw fa-home" style="font -size:20px;"></i> </span> <span class="menu -item-
parent text tooltiptext" >Dashboard</span></a>
</li>

</ul>
</center>
</div>

<div class="pull -right" id="right -side-of-life">
<div class="dropdown navbar -profile open pull-right" style="margin -top: 7px;margin –
right: 20px;margin -left: 13px;">
<a href="#" class="dropdown -toggle" data -toggle="dropdown"
aria-expanded="true">
<span class="meta">
<span class="avatar" id="mobile -profile-img" ><img
src="img/default -42.png" class="img -circle" alt="admin" style=" width: 35px;height:
35px;"></span>
<span class="text hidden -xs hidden -sm text-muted
usernamebar" style="text -transform:capitalize;color:white;">Raluca Burtan</span>
<span class="caret"></span>
</span>
</a>

<ul class="dropdown -menu animated flipInX">
<li class="dropdown -header">Account</li>
<li><a href="#" id="go -prof2"><i class="fa fa –
user"></i>View profile</a></li>

<li class="divider"></li>
<li><a href="#" onclick=leave_or_log()><i class="fa fa –
sign-out" ></i>Logout</a></li>
</ul>

</div>
<!– collapse menu bu tton –>

92

</div>

</div>

<!– end pulled right: nav area –>

</header>

<aside id="left -panel" style="display:none" class="sidebar -circle sidebar-
dark">

<div class="sidebar -content">

</div>

<div class="sidebar -footer hidden -xs hidden -sm hidden -md"
style="width:100%;position:absolute;bottom:0">
<a id="setting" class="pull -left" href="javascript:void(0);" data –
action="toggleShortcut" data -placement="top" data -title="Setting" data -original -title=""
title="">
<i class="fa fa -cog" style="font -size: 20px;"></i>
</a>
<a id="fullscreen" class="pull -left" href="javascript:void(0);" data –
toggle="tooltip" data -placement="top" data -title="Fullscreen" data -original -title="Fullscreen"
onClick="{toggleFullScreen();}" title="Fullscreen">
<i class="fa fa -desktop" style="font -size: 20px;"></i>
</a>

<a id="leave -page" class="pull -left" href="javascript:void(0);" data –
toggle="tooltip" data -placement="top" data -title="Logout" data -original -title=""
title="Log out">
<i class="fa fa -power-off" style="font -size: 20px;"></i>
</a>

</div>

</aside>
<!– END NAVIGATION –>

<div id="main" role="main" style="margin -right:0px!important;" >

<!– MAIN CONTENT –>

<div id="ships" style="display:none; padding -top: 0px;height:
100%;overflow: hidden;background -size: cover;">
<div class="col -sm-12" style="width: 1192px ;margin: auto;height: 50px
;background: #E9EAED!important;padding -top: 10px;position: absolute;display:
block;overflow:hidden;position: absolute; margin: auto;left: -9px;right: 0px;"> <a href="#"
class="btn btn -primary btn -lg " style="float:right;" id="add _ship">ADD NEW SHIP</a>
<div class="form -group dash -form-group" style="float:left;margin -bottom: 0px;">

<div class="input -group wall -comment-reply" style="padding -top:0px">
<input type= "text" class="form -control mysilenttrigger"
placeholder="Search Ship by IMO or Name…" id="post -text-ship" style=" float: left; height:
40px; border -left: 0px; border -right: 0px; width: 500px;">
<span class="input -group-btn"
style="pa dding:0px;height:60px;width:60px;border -left: 0px;">
<button class="btn btn -sm btn-primary pull -right"
onclick="make_post('ships')" style="float:right;height:40px;background: white;color:
black;border: 1px solid #ccc;position:absolute ;top:0px;left:0px;width:60px;">Search</button>

93
</span></div>
</div></div>
<div id="ships -in" class="row" style="top:50px;width: 1192px;margin: auto;height:
calc( 100% – 50px);background: #E9E AED!important;padding -top: 10px;position: absolute;display:
block;overflow:hidden;left: calc(50% – 600px);overflow -y: scroll;"> </div>
</div>
<div id="embarking" style="display:none; padding -top: 0px;height: 100%;overflow:
hidden;backg round-size: cover;">

</div>
<div id="ports" style="display:none; padding -top: 0px;height: 100%;overflow:
hidden;background -size: cover;">
<div class="col -sm-12" style="width: 1192px;margin: auto;height: 50px
;background: #E9EAED!important;padding -top: 10px;position: absolute;display:
block;overflow:hidden;position: absolute; margin: auto;left: -9px;right: 0px;">
<div class="form -group dash -form-group" style="width:100%;float:left;margin –
bottom: 0px;">

<div class="input -group wall -comment-reply" style="padding -top:0px">
<input type="text" class="form -control mysilenttrigger"
placeholder="Search Docks by City or Contry…" id="post -text-port" style=" float: left;
height: 40px; border -left: 0px; border -right: 0px; width: 500px;">
<span class="input -group-btn"
style="padding:0px;height:60px; width:60px;border -left: 0px;">
<button class="btn btn -sm btn-primary pull -right"
onclick="make_post('ports')" style="float:right;height:40px;background: white;color:
black;border: 1px solid #ccc;position:absolute;top:0px;left:0px;widt h:60px;">Search</button>

</span></div>
</div></div>
<div id="ports -in" class="row" style="top:50px;width: 1192px;margin:
auto;height: calc( 100% – 50px);background: #E9EAED!important;paddin g-top: 10px;position:
absolute;display: block;overflow:hidden;left: calc(50% – 600px);overflow -y: scroll;"> </div>
</div>
<div id="company" style="display:none; padding -top: 0px;height: 100%;overflow:
hidden;background -size: cover ;">

<div class="col -sm-12" style="width: 1192px;margin: auto;height: 50px
;background: #E9EAED!important;padding -top: 10px;position: absolute;display:
block;overflow:hidden;position: absolute; margin: auto;left: -9px;righ t: 0px;"> <a href="#"
class="btn btn -primary btn -lg " style="float:right;" id="add_company">ADD NEW COMPANY</a>
<div class="form -group dash -form-group" style=";float:left;margin -bottom: 0px;">

<div class=" input-group wall -comment-reply" style="padding -top:0px">
<input type="text" class="form -control mysilenttrigger"
placeholder="Search Company by CUI or Name…" id="post -text-company" style=" float: left;
height: 40px; border -left: 0px; border-right: 0px; width: 500px;">
<span class="input -group-btn"
style="padding:0px;height:60px;width:60px;border -left: 0px;">
<button class="btn btn -sm btn-primary pull -right"
onclick="make_post('company')" styl e="float:right;height:40px;background: white;color:
black;border: 1px solid #ccc;position:absolute;top:0px;left:0px;width:60px;">Search</button>

</span></div>
</div></div>
<div id="company -in" class="row" style="top:50px;width: 1192px;margin:
auto;height: calc( 100% – 50px);background: #E9EAED!important;padding -top: 10px;position:
absolute;display: block;overflow:hidden;left: calc(50% – 600px);overflow -y: scroll;"> </div>
</div>
<div id="udashboard" style="display:none; padding -top: 0px;height: 100%;overflow:
hidden;background -size: cover;">

<section id="widget -grid" class="playerFilter">

<div class="row" style="width: 1192 px;margin: auto;height: calc( 100% –
0px);background: #E9EAED!important;padding -top: 10px;position: absolute;display:
block;overflow:hidden;left: calc(50% – 600px);">

<div class="row" >

<div class="col -sm-12" id="left_drive -header" style="padding -bottom: 10px;">

<h1 style="float:left;">Current Resources: </h1>

94
<a href="#" class="btn btn -primary btn -lg " style="float:right;margin -right:
10px;" id="toggle_re s3">Show Resource 3</a>
<a href="#" class="btn btn -primary btn -lg " style="float:right;margin -right:
10px;" id="toggle_res2">Show Resource 2</a>
<a href="#" class="btn btn -primary btn -lg " style="float:right;margin -right:
10px;" id="toggle_res1">Show Resource 1</a>

</div>

<div id="udashboard -scroll" style="height: calc( 100% – 20px);background:
#E9EAED!important;padding -top: 0px;margin -top:20px;position: absolute;ov erflow:
hidden;display: block;overflow -y: scroll;top: 50px;width:100%;">
<div class="col -sm-12" style="padding -right:0;width:100%;margin -top: -10px" >
<div class="row">
<div class="col -sm-12 col-md-12 col-lg-12" style="padding -top: 10px;padding –
left: 0px;">
<div class="col -md-12 btn-primary shadow6"
style="display:none;float:left;background: rgba(0,0,0,0.6);line -height: 40px;border -radius: 0%
0% 10% 10%/0% 0% 100% 100%;text -align: center;cur sor:pointer;"> Back on Top</div>
<div id="scroll -group-dash" style="overflow -y:scroll;height:1300px;margin –
bottom:13px;float:left;width:100%;" >
<div class="panel panel -default " id="dashboard_group"
style="bor der:0;background: transparent;"></div>
<div id="embarking -in" class="row" style="width: 1192px;margin:
auto;height: calc( 100% – 0px);background: #E9EAED!important;padding -top: 10px;position:
absolute;display: block;overflow:hidden;left: calc(50% – 600px);overflow -y:
scroll;">

<div class="col -sm-12" id="left_drive">

<div class="well well -sm">

<div class="row">

<div class="c ol-sm-12 col-md-12 col-lg-12">
<div class="widget -body">

<br>

<div id="left_drive_path"> <p>
<div id="resources0 -wrapper" style="display: block">
<a href="#" class="btn btn -primary btn -lg "
style="float:right;margin -right: 10px;display:none" id="replace_res1">Replace Resource 1</a>
<a href="#" class="btn btn -primary btn -lg "
style="float:right;margin -right: 10px;display:none" id="alocate_res1">Alocate Resource 1</a>

<div class="col -sm-12" id="resources0" style="min –
height: 1500px;" >No Resource Created!</div>
</div>
<div id="resources1 -wrapper" style="display: none">
<a href="#" class="btn btn -primary btn -lg "
style="float:right;margin -right: 10px;display:none" id="replace_res2">Replace Resource 2</a>
<a href="#" class="btn btn -primary btn -lg "
style="float:right;margin -right: 10px;display:none" id="alocate_res2">Alocate Resource 2</a>

<div class="col -sm-12" id="resources1" style="min –
height: 1500px;">No Resource Created!</div>
</div>
<div id="resources2 -wrapper" style="display: none">
<a href="#" class="btn btn -primary btn -lg "
style="float:right;margin -right: 10px;display:none" id="replace_res3">Replace Resource 3</a>
<a href="#" class="btn btn -primary btn -lg "
style="float:right;margin -right: 10px;display:none" id="alocate_res3">Alocate Resource 3</a>

<div class="col -sm-12" id="resources2" style="min –
height: 1500px;" >No Resource Created!</div>
</div>
</div>
<br>

95

</div>

</div>

</div>
<!– end row –>

</div>

</div>

<div class="col -sm-12" id="left_ -header">

</div>
</div>
</div>
</div>
</div>
</div>

</div>
</div>
</div>
</section>
</div>

<div id="groups -chats-area" class="col -sm-12 col-md-12 col-lg-6" style="display:none;position:
fixed;bottom: 0px;float: right;z -index: 999999999999;right: 0;"></div>

<div id="one2onepanel" class="row" style="display:none ;height:100%;">

</div>

<div class="row" id="dynamic_group_page" style="display:none;margin -top: 63px;
;height:90vh;overflow -y:scroll;" >

</div>

</div>

<div class="col -md-12 col-sm-12 col-lg-12" id="socialReg" style=" top: 0px;position:
absolute;margin -left:0px;padding:0;display:none" >
<style scoped>
@import'//fonts.googleapis.com/css?family=Open+Sans:400,300,600&amp;subset=cyrillic,latin';

@import"login/css/style.css";

@import"css/fo nt-awesome-4.7.0/css/font -awesome.css";
@import"login/css/pages/page_log_reg_v2.css";
@import"login/css/theme -colors/default.css";
@import"login/css/theme -skins/dark.css";
@import"login/css/custom.css">;
</style>
<!–=== Content Part === –>
<div class="container">
<!–Reg Block –>
<div class="reg -block">
<div class="reg -block-header">

96
<div align="center" class="inner -bg-photo"><a href="#" target="_blank">
<img src="login/logo.png" alt="" style="widt h:70%"></a>
</div>
<br>

<ul align="center" class="list -unstyled list -inline social -links margin -bottom-20">
<li style="width: 50px;"><a href="#" target="_blank"><i class="fa fa -facebook fa –
2x"></i></a></li>
<li style="width: 50px;"><a href="#" target="_blank"><i class="fa fa -linkedin fa –
2x"></i></a></li>
<li style="width: 50px;"><a href="#" target="_blank"><i class="fa fa -twitter fa –
2x"></i></a></li>
<li style="width: 50px;"><a href="# " target="_blank"><i class="fa fa -google-plus fa-
2x"></i></a></li>
</ul>

<br>
<br>

</div>

<div class="input -group margin -bottom-20">
<span class="input -group-addon"><i class="fa fa-lock"></i></span>
<input type="text" id="socialregname" class="form -control" placeholder="Name and
Surname" readonly>
</div>

<div class="input -group margin -bottom-20" style="display:none">
<span class="input -group-addon"><i class="fa fa -lock"></i></span>
<input type="text" id="socialregname_" class="form -control" placeholder="Name " >
</div>
<div class="input -group margin -bottom-20" style="display:none">
<span class="input -group-addon"><i class="fa fa -lock"></i></span>
<input type="text" id="socialregsurname_" class="form -control" placeholder=" Surname"
>
</div>

<div class="input -group margin -bottom-20">
<span class="input -group-addon"><i class="fa fa -lock"></i></span>
<input type="text" id="socialregemail" class="form -control" placeholder="Email"
readonly>
</div>

<div class="input -group margin -bottom-20">
<span class="input -group-addon"><i class="fa fa -lock"></i></span>
<input type="password" id="socialregpasswd" class="form -control"
placeholder="Password">
</div>
<div class="input -group margin -bottom-20">
<span class="input -group-addon"><i class="fa fa -lock"></i ></span>
<input type="password" id="socialregrepasswd" class="form -control"
placeholder="Repeat Password">
</div>

<div class="row">
<div class="col -md-10 col-md-offset-1">

<button type="button" id="socialregconnect -r" style="line -height:0" class="btn -u
btn-block">Sign up</button>
</div>
<div class="col -md-2 col-md-offset-1">
<br>

</div>
</div>

<br>

<p align="center" style="color:#c8c8c8;line -height: 50px;" class="copyright -space">
I already have an account <a href="#" onclick="loadLgPanel()">Click Here </a>
</p>

97
<p align="center" style="color:#c8c8c8;" class ="copyright -space">
2019 &copy; <a href="#">Resource Manager&#8482;</a> All Rights Reserved.
</p>

</div>

</div>
</div>

<div class="col -md-12 col-sm-12 col-lg-12" id="socialLogins" style=" top: 0px;position:
absolute;margin -left:0px;padding:0;display:none" >
<style scoped>
@import'//fonts.googleapis.com/css?family=Open+Sans:400,300,600&amp;subset=cyrillic,latin';

@import"login/css/style.css";

@import"css/font -awesome-4.7.0/css/font -awesome.css";
@import"login/css/pages/page_log_reg_v2.css";
@import"login/css/theme -colors/default.css";
@import"login/css/theme -skins/dark.css";
@import"login/css/custom.css">;
</style>
<!–=== Content Part === –>
<div class="container">
<!–Reg Block –>
<div class="reg -block">
<div class="reg -block-header">
<div align="center" class="inner -bg-photo"><a href="#" target="_blank">
<img src="login/logo.png" alt="" style="width: 70%;"></a>
</div>
<br>

<ul align="center" class="list -unstyled list -inline social -links margin -bottom-20">
<li style="width: 50px;"><a href="#" target="_blank"><i class="fa fa -facebook fa –
2x"></i></a></li>
<li style="width: 50px;"><a h ref="#" target="_blank"><i class="fa fa -linkedin fa –
2x"></i></a></li>
<li style="width: 50px;"><a href="#" target="_blank"><i class="fa fa -twitter fa –
2x"></i></a></li>
<li style="width: 50px;"><a href="#" target="_blank"><i class="fa fa -google-plus fa-
2x"></i></a></li>
</ul>

<br>
<br>

</div>

<div class="input -group margin -bottom-20" style="width:100%">

<input type="text" id="socialemail" class="form -control" placeholder="Email"
style="width:100%">
</div>

<div class="input -group margin -bottom-20" style="width:100%">

<input type="password" id="socialpasswd" clas s="form-control" placeholder="Password"
style="width:100%">
</div>

<div class="row">
<div class="col -md-12 " style="padding:0">

<button type="button" id="socialconnect -r" style="line -height:0;background: rgb(50 ,
118, 177);border: 1px solid rgb(44, 105, 157);" class="btn -u btn-block">Log In</button>
</div>

98
<br>
<br>
<br>
<p align="center" style="color:#c8c8c8;line -height: 50px;" class="copyright -space">
Don't have an Account ? <a href="#" onclick="loadRegPanel()">Click Here </a>
</p>
<p align="center" style="color:#c8c8c8;line -height: 50px;" class="copyright -space">
2019 &copy; <a href="#">NaviNet&#8482;</a> All Rights Reserved.
</p>

</div>

</div>
</div>
</div>

<div class="divMessageBox animated fadeIn fast" id="MsgBoxError" style="display:none;z –
index:2000"><div class="MessageBoxContainer animated fadeIn fast" id="Msg1"><div
class="MessageBoxMiddle"><span c lass="MsgTitle">
<center><i class="fa fa -exclamation -triangle txt -color-orangeDark"></i>
<span class="txt -color-orangeDark" id="msg -error"></span>
</div></div></div>

<div class="divMessageBox animated fadeIn fast" id="MsgBoxConfirm" style="display:none;z –
index:2000"><div class="MessageBoxContainer animated fadeIn fast" id="Msg12"><div
class="MessageBoxMiddle"><span class="MsgTitle">
<center><i class="fa fa -exclamation -triangle txt -color-orangeDark"></i>
<span class="txt -color-orangeDark" id="msg -confirm">< /span>
<div class="MessageBoxButtonSection"><button id="confirm -no" class="btn btn -default btn -sm
botTempo" data -dismiss="modal"> No</button><button id="confirm -yes" class="btn btn -default
btn-sm botTempo"> Yes</button></div>
</div></div></div>

<div class="divMessageBox animated fadeIn fast" id="MsgBoxMenu" style="display:none;z –
index:2000"><div class="MessageBoxContainer animated fadeIn fast" id="Msg12"><div
class="MessageBoxMiddle"><span class="MsgTitle">
<center><i class="fa fa -exclamation -triangle txt-color-orangeDark"></i>
<span class="txt -color-orangeDark" id="msg -menu">This feature requires a refresh of your
application. Proceed? </span>
<div class="MessageBoxButtonSection"><button id="bot1 -menu1" class="btn btn -default btn -sm
botTempo" data -dismiss="modal"> No</button><button id="bot2 -menu1" class="btn btn -default btn –
sm botTempo"> Yes</button></div>
</div></div></div>

<div class="divMessageBox animated fadeIn fast" id="MsgLoadError" style="display:none;z –
index:2000"><div class="MessageBoxConta iner animated fadeIn fast" id="Msg1"><div
class="MessageBoxMiddle"><span class="MsgTitle">
<center>
<img src = '#' style=' width: 60px;height: 60px;margin -right: 10px '/><span class="txt -color-
orangeDark" id="msg -load"></span>
</div></div></div>

<a href="#"><button type="button" id="project_step_wizard" style="display:none" class="btn
btn-warning mb -xs" data -toggle="modal" data -target="#myModal40">POP UP</button></a>

<div class="divMessageBox animated fadeIn fast" id="MsgBoxExt" style="display:none;z –
index:2000"><div class="MessageBoxContainer animated fadeIn fast" id="Msg1"><div
class="MessageBoxMiddle"><span class="MsgTitle">
<center><span class="txt -color-orangeDark" id="msg -ext"><i class="fa fa -exclamation -triangle
txt-color-orangeDark"></i> Edit Re source</span>
<center style="margin -top:13px; width: 500px;"><span class="txt -color-orangeDark" id="mid –
pop" >Property </span>
<button id="mid -pop-button" class=" btn -default btn -sm botTempo" style="float:right">
Ok</button>
<input type="text" id="new_value" placeholder="value" autofocus class="form -control"
style=";;padding: 5px;margin -right: 2%;height: 35px; width:250px;float:right;margin -right:
10px;"></input>
</center>
</div></div></div>

99

<div class="divMessageBox animated fadeIn fast" id="MsgBoxExt2" style="display:none;z –
index:2000"><div class="MessageBoxContainer animated fadeIn fast" id="Msg1" style="top:
0px;height: 100%;"><div class="MessageBoxMiddle" style=" width: 800px;left: calc(50% –
400px);"><span class="MsgTitle">
<center><span class="txt -color-orangeDark" id="msg -ext2"><i class="fa fa -exclamation -triangle
txt-color-orangeDark"></i> Create Resource
<button id="mid -pop-button_res_c" class=" btn -default btn -sm botTempo" style="float:right">
Cancel</button>
<button id="mid -pop-button_res" class=" btn -default btn -sm botTempo"
style="float:right;margin -right: 10px;"> Create</button></span>
<center style="margin -top:13px; width: 800px;">
<div class="txt -color-orangeDark" id="msg -menu" style="margin -bottom: 20px;">A val id JSON
text is required below </div>
<textarea type="text" id="new_value_res" placeholder="Insert JSON here" autofocus
class="form -control" style=";;padding: 0px;margin -right: 0px;height: 800px;
width:800px;float:right;margin -right: 0px;"></textarea>
</center>
</div></div></div>

<div id="xmlite -call"
style="display:none;right:0;position:fixed;width:400px;height:100px;background –
color:rgba(0,0,0,0.9); top: 0;z -index: 999999;">
<i class="fa fa -phone" style="cursor:pointer;color:green;font -size:100p x; margin –
left: 10px;margin -top: 5px;" id="accepted" onclick="{remove_pop(this);}"></i>
<i class="fa fa -times" style="cursor:pointer;color:white;font –
size:20px;right:0px;top:0px; margin -right: 10px;margin -top:
5px;position:absolute;"id="declined" on click="{remove_pop(this);}"></i>
<p id="xmlite -caller" style="color:white; position: absolute;top: 0;margin -left:
100px;text -align:center;width:250px;margin -top: 30px;font -size: 16px;"></p>
<p id="xmlite -text" style="color:white; position: absolu te;top: 0;margin -left:
100px;;text -align:center;width:250px;margin -top: 60px;font -size: 16px;"></p>
</div>
<div id="multimedia_grid_gall" style="display:none"></div>
<div id="mychatest" ></div>
<div id="root" style="display:none"> </div>
<div id="body _limiter" ></div>
<div id="menuexample" ></div>
<a href="#" id="go -users" style="display:none;"></a>
<div class="modal fade" id="myModal40" tabindex=" -1" role="dialog" aria –
labelledby="myModalLabel20" aria -hidden="true"
style="display:none;width:1000 px;margin:auto;max -height:80%;">
<div class="modal -dialog-wizard">
<div class="modal -header" style="background: white;padding:
0">
<button type="button" cla ss="close" data –
dismiss="modal" aria -hidden="true"><i class="fa fa -times"></i></button>
</div>
<div class="modal -content">

</div>
</div>
</div>
<!– data-backdrop="static" data -keyboard="false" –>

<img style="display:none" src="#" id="image_cache_busting1"></img>
<img style="display:none" src="#" id="image_cache_busting2"></img>
<img style="display:none" src="#" id="image_cache_busting3"></img>

<script>
$.backstretch([
"backgrounds/"+(Math.floor(Math.rando m() * 2) + 1)+".jpg",
"backgrounds/"+(Math.floor(Math.random() * 2) + 1)+".jpg",
"backgrounds/"+(Math.floor(Math.random() * 2) + 1)+".jpg",
"backgrounds/"+(Math.floor(Math.random() * 2) + 1)+".jpg",
"backgrounds/"+(Math.floor(Math.r andom() * 2) + 1)+".jpg",
"backgrounds/"+(Math.floor(Math.random() * 2) + 1)+".jpg",

], {
fade: 700,
duration: 4000
});

100
</script>

</body>

<script src="js/new_js/skycons.js"></script>
<script src="js/newsfeed.js"></script>
<script src="js/startup.js?v=2289"></script>

<link rel="stylesheet" href="vegas/vegas.css">

<link rel="stylesheet" href="css/kurento.css">

<style>
.no-transition.collapse { -webkit-transition: no ne; transition: none; }
.no-transition.collapsing { -webkit-transition: none; transition: none; }
</style>

</body>
</html>

Similar Posts