Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Both sides previous revision Previous revision
Next revision
Previous revision
laboratoare:laborator10 [2016/01/07 00:25]
Andrei Roșu-Cojocaru [Activitate de Laborator]
laboratoare:laborator10 [2016/01/08 16:18] (current)
Andrei Roșu-Cojocaru [Soluții]
Line 705: Line 705:
 | Antet\\ ''​Constants.CUSTOM_MESSAGE_PROPERTY = receiverUserName''​ | utilizat în filtrul de mesaje |  | Antet\\ ''​Constants.CUSTOM_MESSAGE_PROPERTY = receiverUserName''​ | utilizat în filtrul de mesaje | 
 | Conţinut\\ ''​String senderUserName''​\\ ''​String messageContent''​ | ''​CustomMessage''​ \\ ↑\\ ''​ObjectMessage''​ | | Conţinut\\ ''​String senderUserName''​\\ ''​String messageContent''​ | ''​CustomMessage''​ \\ ↑\\ ''​ObjectMessage''​ |
 +
 +**0**. Să se cloneze în directorul de pe discul local conținutul depozitului la distanță de la [[https://​www.github.com/​aipi2015/​Laborator10]]. În urma acestei operații, directorul Laborator10 va trebui să conțină subdirectorul ''​labtasks'',​ fișierele ''​README.md''​ și ''​LICENSE''​.
 +
 +<​code>​
 +student@aipi2015:​~$ git clone https://​www.github.com/​aipi2015/​Laborator10.git
 +</​code>​
  
 **1.** Să se descarce arhiva care conține [[http://​download.java.net/​glassfish/​4.1/​release/​glassfish-4.1.zip|serverul de aplicaţii GlassFish 4.1]] și să se despacheteze. **1.** Să se descarce arhiva care conține [[http://​download.java.net/​glassfish/​4.1/​release/​glassfish-4.1.zip|serverul de aplicaţii GlassFish 4.1]] și să se despacheteze.
Line 710: Line 716:
 Domeniul ''​domain1''​ poate fi accesat folosind utilizatorul ''​admin''​ și parola vidă. Domeniul ''​domain1''​ poate fi accesat folosind utilizatorul ''​admin''​ și parola vidă.
  
-**2.** Să se integreze mediul de dezvoltare Eclipse IDE for Java EE Developers 4.4.1 (Luna SR1), respectiv mediul de dezvoltare NetBeans 8.0.2 cu serverul de aplicaţii GlassFish 4.1.+**2.** Să se integreze mediul de dezvoltare Eclipse IDE for Java EE Developers 4.5 (Mars), respectiv mediul de dezvoltare NetBeans 8.0.2 cu serverul de aplicaţii GlassFish 4.1.
  
 <​note>​Acest pas nu este absolut necesar pentru rularea aplicaţiei,​ însă configurarea mediilor de dezvoltare este utilă întrucât în acest mod pot fi verificate proprietăţile serverului de aplicaţii precum şi starea acestuia în fiecare moment al execuţiei programului care utilizează specificaţia JMS.</​note>​ <​note>​Acest pas nu este absolut necesar pentru rularea aplicaţiei,​ însă configurarea mediilor de dezvoltare este utilă întrucât în acest mod pot fi verificate proprietăţile serverului de aplicaţii precum şi starea acestuia în fiecare moment al execuţiei programului care utilizează specificaţia JMS.</​note>​
Line 718: Line 724:
 Integrarea mediului de dezvoltare Eclipse IDE for Java EE Developers 4.5 (Mars) cu serverul de aplicaţii GlassFish 4.1 se face accesând //Window// → //​Preferences//​ → //Server Runtime// → //​Environment//​ → //Add...//. Integrarea mediului de dezvoltare Eclipse IDE for Java EE Developers 4.5 (Mars) cu serverul de aplicaţii GlassFish 4.1 se face accesând //Window// → //​Preferences//​ → //Server Runtime// → //​Environment//​ → //Add...//.
  
-{{ :​laboratoare:​laborator09:​eclipse01.png?​nolink&​500 }}+{{ :​laboratoare:​laborator10:eclipse01.png?​nolink&​500 }} 
 + 
 +{{ :​laboratoare:​laborator10:​eclipse02.png?​nolink&​500 }}
  
 În cazul în care GlassFish nu este listat ca optiune de server de aplicaţii care să poată fi configurat, se instalează un adaptor pentru acest tip de server de pe [[https://​marketplace.eclipse.org/​content/​glassfish-tools|Eclipse Marketplace]]. După instalarea acestui adaptor, se reporneşte mediul de dezvoltare Eclipse Mars 4.5 for Java EE Developers. În cazul în care GlassFish nu este listat ca optiune de server de aplicaţii care să poată fi configurat, se instalează un adaptor pentru acest tip de server de pe [[https://​marketplace.eclipse.org/​content/​glassfish-tools|Eclipse Marketplace]]. După instalarea acestui adaptor, se reporneşte mediul de dezvoltare Eclipse Mars 4.5 for Java EE Developers.
  
-{{ :​laboratoare:​laborator10:​02eclipse.png?​nolink&​600 }}+{{ :​laboratoare:​laborator10:​eclipse03.png?​nolink&​600 }}
  
-{{ :​laboratoare:​laborator09:eclipse03.png?​nolink&​500 }}+{{ :​laboratoare:​laborator10:eclipse04.png?​nolink&​500 }}
  
-{{ :​laboratoare:​laborator09:eclipse04.png?​nolink&​500 }}+{{ :​laboratoare:​laborator10:eclipse05.png?​nolink&​500 }}
  
 Se creează o referință către JDK din //Window// → //​Preferences//​ → //Java// → //Installed JREs//. Se creează o referință către JDK din //Window// → //​Preferences//​ → //Java// → //Installed JREs//.
  
-{{ :​laboratoare:​laborator09:​eclipse06.png?​nolink&​500 }}+{{ :​laboratoare:​laborator10:​eclipse06.png?​nolink&​500 }}
  
-{{ :​laboratoare:​laborator09:​eclipse07.png?​nolink&​500 }}+{{ :​laboratoare:​laborator10:​eclipse07.png?​nolink&​500 }}
  
-{{ :​laboratoare:​laborator09:​eclipse08.png?​nolink&​500 }}+{{ :​laboratoare:​laborator10:​eclipse08.png?​nolink&​500 }}
  
-{{ :​laboratoare:​laborator09:​eclipse09.png?​nolink&​500 }}+{{ :​laboratoare:​laborator10:​eclipse09.png?​nolink&​500 }}
  
 Se selectează serverul de aplicaţii GlassFish 4.1 precizându-se directorul în care acesta este instalat. Se selectează serverul de aplicaţii GlassFish 4.1 precizându-se directorul în care acesta este instalat.
  
-{{ :​laboratoare:​laborator09:eclipse05.png?​nolink&​500 }}+{{ :​laboratoare:​laborator10:eclipse10.png?​nolink&​500 }}
  
-{{ :​laboratoare:​laborator09:​eclipse10.png?​nolink&​500 }} +{{ :​laboratoare:​laborator10:​eclipse11.png?​nolink&​500 }}
- +
-{{ :​laboratoare:​laborator09:​eclipse11.png?​nolink&​500 }}+
  
 Se deschide perspectiva asociată serverului de aplicaţii din //Window// → //Show View// → //​Other...//​ → //Server// → //​Servers//​. Se deschide perspectiva asociată serverului de aplicaţii din //Window// → //Show View// → //​Other...//​ → //Server// → //​Servers//​.
  
-{{ :​laboratoare:​laborator09:​eclipse12.png?​nolink&​500 ​}}+{{ :​laboratoare:​laborator10:​eclipse12.png?​nolink }}
  
-{{ :​laboratoare:​laborator09:​eclipse13.png?​nolink }}+{{ :​laboratoare:​laborator10:​eclipse13.png?​nolink }}
  
 Se integrează serverul de aplicaţii GlassFish 4.1 în această perspectivă accesând opţiunea //Click this link to create a new server...// şi indicând locaţia specifică domeniului în care se va lucra, numele de utilizator (admin) şi parola (vidă). Se integrează serverul de aplicaţii GlassFish 4.1 în această perspectivă accesând opţiunea //Click this link to create a new server...// şi indicând locaţia specifică domeniului în care se va lucra, numele de utilizator (admin) şi parola (vidă).
  
-{{ :​laboratoare:​laborator09:​eclipse14.png?​nolink&​500 ​}}+{{ :​laboratoare:​laborator10:​eclipse14.png?​nolink }}
  
-{{ :​laboratoare:​laborator09:​eclipse15.png?​nolink&​500 }}+{{ :​laboratoare:​laborator10:​eclipse15.png?​nolink&​500 }}
  
-{{ :​laboratoare:​laborator09:​eclipse16.png?​nolink&​500 }}+{{ :​laboratoare:​laborator10:​eclipse16.png?​nolink&​500 }}
  
-{{ :​laboratoare:​laborator09:​eclipse17.png?​nolink&​800 }}+{{ :​laboratoare:​laborator10:​eclipse17.png?​nolink&​800 }}
  
 ==== NetBeans ==== ==== NetBeans ====
Line 766: Line 772:
 Integrarea mediului de dezvoltare NetBeans 8.0.2 cu serverul de aplicaţii GlassFish 4.1 se face accesând //​Services//​ → //Server// → //Add Server...//​. Integrarea mediului de dezvoltare NetBeans 8.0.2 cu serverul de aplicaţii GlassFish 4.1 se face accesând //​Services//​ → //Server// → //Add Server...//​.
  
-{{ :​laboratoare:​laborator09:​netbeans01.png?​nolink }}+{{ :​laboratoare:​laborator10:​netbeans01.png?​nolink }}
  
 Se indică tipul de server (GlassFish Server), locaţia la care acesta a fost instalat, precum şi câteva informaţii de configurare (denumirea domeniului local, maşina unde rulează şi informaţiile de autentificare – nume utilizator / parola). Se indică tipul de server (GlassFish Server), locaţia la care acesta a fost instalat, precum şi câteva informaţii de configurare (denumirea domeniului local, maşina unde rulează şi informaţiile de autentificare – nume utilizator / parola).
  
-{{ :​laboratoare:​laborator09:​netbeans02.png?​nolink&​600 }}+{{ :​laboratoare:​laborator10:​netbeans02.png?​nolink&​600 }}
  
-{{ :​laboratoare:​laborator09:​netbeans03.png?​nolink&​600 }}+{{ :​laboratoare:​laborator10:​netbeans03.png?​nolink&​600 }}
  
-{{ :​laboratoare:​laborator09:​netbeans04.png?​nolink&​600 }}+{{ :​laboratoare:​laborator10:​netbeans04.png?​nolink&​600 }}
  
-{{ :​laboratoare:​laborator09:​netbeans05.png?​nolink }}+{{ :​laboratoare:​laborator10:​netbeans05.png?​nolink }}
  
 ===== ===== ===== =====
Line 801: Line 807:
 În //Domain// → //​Administrator Password//, se va specifica o parolă pentru administrator şi se va apăsa butonul //Save//. În //Domain// → //​Administrator Password//, se va specifica o parolă pentru administrator şi se va apăsa butonul //Save//.
  
-{{ :​laboratoare:​laborator09:​glassfish01.png?​nolink&​700 }}+{{ :​laboratoare:​laborator10:​glassfish01.png?​nolink&​700 }} 
 + 
 +{{ :​laboratoare:​laborator10:​glassfish02.png?​nolink&​700 }}
    
 În //​Resources//​ → //JMS Resources// se vor crea obiectele administrate:​ În //​Resources//​ → //JMS Resources// se vor crea obiectele administrate:​
Line 807: Line 815:
 **a)** //​Connection Factories// → //New//: fabrica de conexiuni ''​MessagingTopicConnectionFactory''​ cu tipul ''​javax.jms.TopicConnectionFactory''​ (se apasă butonul //OK//). **a)** //​Connection Factories// → //New//: fabrica de conexiuni ''​MessagingTopicConnectionFactory''​ cu tipul ''​javax.jms.TopicConnectionFactory''​ (se apasă butonul //OK//).
  
-{{ :​laboratoare:​laborator09:glassfish02.png?​nolink&​700 }}+{{ :​laboratoare:​laborator10:glassfish03.png?​nolink&​700 }}
  
-{{ :​laboratoare:​laborator09:glassfish03.png?​nolink&​700 }}+{{ :​laboratoare:​laborator10:glassfish04.png?​nolink&​700 }}
  
 **b)** //​Destination Resources// → //New//: resursa destinaţie de tip temă ''​jms/​MessagingTopic''​ având tipul ''​javax.jms.Topic''​ (se apasă butonul //OK//). **b)** //​Destination Resources// → //New//: resursa destinaţie de tip temă ''​jms/​MessagingTopic''​ având tipul ''​javax.jms.Topic''​ (se apasă butonul //OK//).
  
-{{ :​laboratoare:​laborator09:glassfish04.png?​nolink&​700 }}+{{ :​laboratoare:​laborator10:glassfish05.png?​nolink&​700 }}
  
-{{ :​laboratoare:​laborator09:glassfish05.png?​nolink&​700 }}+{{ :​laboratoare:​laborator10:glassfish06.png?​nolink&​700 }}
  
 ==== Client ==== ==== Client ====
Line 823: Line 831:
 Se va specifica proprietatea **''​addresslist''​**,​ având ca valoare adresa IP a maşinii pe care rulează serverul. Se va specifica proprietatea **''​addresslist''​**,​ având ca valoare adresa IP a maşinii pe care rulează serverul.
  
-{{ :​laboratoare:​laborator09:glassfish09.png?​nolink&​700 }}+{{ :​laboratoare:​laborator10:glassfish07.png?​nolink&​700 }}
  
-{{ :​laboratoare:​laborator09:glassfish10.png?​nolink&​700 }}+{{ :​laboratoare:​laborator10:glassfish08.png?​nolink&​700 }}
  
 ==== Client ==== ==== Client ====
Line 833: Line 841:
 a) se specifică **tipul de serviciu JMS** pentru a putea fi accesat la distanţă (proprietatea **JMS Service Type** va avea valoarea **''​REMOTE''​**);​ a) se specifică **tipul de serviciu JMS** pentru a putea fi accesat la distanţă (proprietatea **JMS Service Type** va avea valoarea **''​REMOTE''​**);​
  
-{{ :​laboratoare:​laborator09:glassfish07.png?​nolink&​700 }}+{{ :​laboratoare:​laborator10:glassfish09.png?​nolink&​700 }}
  
 Se accesează butonul //Save//. Se accesează butonul //Save//.
Line 839: Line 847:
 b) se indică locaţia la care se află resursele JMS care vor fi accesate (pentru **''​default_JMS_host''​** se va specifica câmpul Host, reprezentând adresa IP a serverului GlassFish); serverul şi clientul trebuie să se găsească în aceeaşi (sub)reţea sau trebuie să aibă adrese IP publice, vizibile în Internet; de asemenea, se va indica parola serverului de aplicaţii GlassFish 4.1 care rulează la locaţia indicată. b) se indică locaţia la care se află resursele JMS care vor fi accesate (pentru **''​default_JMS_host''​** se va specifica câmpul Host, reprezentând adresa IP a serverului GlassFish); serverul şi clientul trebuie să se găsească în aceeaşi (sub)reţea sau trebuie să aibă adrese IP publice, vizibile în Internet; de asemenea, se va indica parola serverului de aplicaţii GlassFish 4.1 care rulează la locaţia indicată.
  
-{{ :​laboratoare:​laborator09:glassfish08.png?​nolink&​700 }}+{{ :​laboratoare:​laborator10:glassfish10.png?​nolink&​700 }}
  
 Se accesează butonul //Save//. Se accesează butonul //Save//.
Line 873: Line 881:
 Un utilizator ce a primit un mesaj că un alt utilizator nu mai e disponibil îl va exclude din lista utilizatorilor activi. Un utilizator ce a primit un mesaj că un alt utilizator nu mai e disponibil îl va exclude din lista utilizatorilor activi.
  
-**a)** În clasa ''​ContactsList'',​ în metoda ''​start()'',​ să se transmită mesajul ''​Constants.LOGIN_MESSAGE''​ către toţi utilizatorii cu care s-a comunicat recent (din ''​recentContactsListItem''​). Se va apela metoda ''​publish()''​ a obiectului ''​communicator''​ având ca parametrii numele de utilizator al destinatarului şi mesajul propriu-zis. ​+<​spoiler|Indicații de Rezolvare>​ 
 +**a)** În clasa ''​ContactsList'',​ în metoda ''​start()'',​ să se transmită mesajul ''​Constants.LOGIN_MESSAGE''​ către toţi utilizatorii cu care s-a comunicat recent (din ''​recentContactsListItem''​). Se va apela metoda ''​publish()''​ a obiectului ''​communicator''​ având ca parametrii numele de utilizator al destinatarului şi mesajul propriu-zis.
  
-**b)** În clasa ''​ContactsList'', ​în metoda ​''​handleMessage()''​, să se analizeze mesajul ​''​Constants.LOGIN_MESSAGE''​, parcurgându-se lista ''​connectedContactsListItem'' ​şi adăugându-se la aceasta numele de utilizator din mesajul primit, în cazul în care utilizatorul nu se regăseşte în aceasta.+Obiectul ​''​recentContactsListItem''​ conține lista utilizatorilor recenți sub formă de ''​ObservableList<​TreeItem<​String>>​'', ​obținută ca rezultat al metodei ​''​getChildren()''​. Valoarea conținută de un obiect de tip ''​TreeItem''​ se obține prin intermediul metodei ​''​getValue()''​.
  
-**c)** În clasa ''​ContactsList'',​ în metoda ''​close()'',​ să se transmită ​mesajul ''​Constants.LOGOUT_MESSAGE'' ​către toţi utilizatorii cu care s-a comunicat recent (din ''​recentContactsListItem''​). Se va apela metoda ''​publish()'' ​a obiectului ​''​communicator''​ având ca parametrii numele de utilizator al destinatarului ​şi mesajul ​propriu-zis. +**b)** În clasa ''​ContactsList'',​ în metoda ''​handleMessage()'',​ să se analizeze ​mesajul ''​Constants.LOGIN_MESSAGE''​, parcurgându-se lista ''​connectedContactsListItem'' ​şi adăugându-se la aceasta numele de utilizator din mesajul primit ​(''​interlocutorUserName''​), în cazul în care utilizatorul nu se regăseşte în aceasta. După această procesare, metoda se termină întrucât ​mesajul ​nu mai poate avea și alt tip.
  
-**d)** În clasa ''​ContactsList'',​ în metoda ''​handleMessage()'',​ să se analizeze mesajul ''​Constants.LOGOUT_MESSAGE'',​ parcurgându-se lista ''​connectedContactsListItem''​ şi eliminându-se din ea numele de utilizator din mesajul primit, în cazul în care utilizatorul face parte din aceasta.+**c)** În clasa ''​ContactsList'',​ în metoda ''​close()'',​ să se transmită mesajul ''​Constants.LOGOUT_MESSAGE''​ către toţi utilizatorii cu care s-a comunicat recent (din ''​recentContactsListItem''​). Se va apela metoda ''​publish()''​ a obiectului ''​communicator''​ având ca parametrii numele de utilizator al destinatarului şi mesajul propriu-zis. 
 + 
 +Obiectul ''​recentContactsListItem''​ conține lista utilizatorilor recenți sub formă de ''​ObservableList<​TreeItem<​String>>'',​ obținută ca rezultat al metodei ''​getChildren()''​. Valoarea conținută de un obiect de tip ''​TreeItem''​ se obține prin intermediul metodei ''​getValue()''​. 
 + 
 +**d)** În clasa ''​ContactsList'',​ în metoda ''​handleMessage()'',​ să se analizeze mesajul ''​Constants.LOGOUT_MESSAGE'',​ parcurgându-se lista ''​connectedContactsListItem''​ şi eliminându-se din ea numele de utilizator din mesajul primit, în cazul în care utilizatorul face parte din aceasta. ​Este important ca eliminarea să nu se realizeze concomitent cu parcurgerea tabloului. După această procesare, metoda se termină întrucât mesajul nu mai poate avea și alt tip. 
 +</​spoiler>​
  
 **8.** Să se modifice comportamentul aplicaţiei astfel încât utilizatorii să poată primi şi mesajele transmise în răstimpul în care nu au fost disponibili. **8.** Să se modifice comportamentul aplicaţiei astfel încât utilizatorii să poată primi şi mesajele transmise în răstimpul în care nu au fost disponibili.
  
-În clasa ''​PublishSubscribe'',​ în metoda ''​subscribe()'',​ se va modifica tipul obiectului consumator de mesaje astfel încât acesta să fie durabil (persistent şi atunci când este inactiv, adică nu are nici un abonat conectat la el). +<​spoiler|Indicații de Rezolvare>​ 
 +În clasa ''​PublishSubscribe'',​ în metoda ''​subscribe()'',​ se va modifica tipul obiectului consumator de mesaje astfel încât acesta să fie durabil (persistent şi atunci când este inactiv, adică nu are nici un abonat conectat la el). 
 + 
 +Se va utiliza metoda [[https://​docs.oracle.com/​javaee/​7/​api/​javax/​jms/​JMSContext.html#​createSharedDurableConsumer-javax.jms.Topic-java.lang.String-java.lang.String-|createSharedDurableConsumer()]] care, pe lângă argumentele topicii și a selectorului de mesaje (pe care le primea și metoda ''​createConsumer()''​) primește ca argument și o denumire (unică) prin intermediul căreia este identificat. Se va folosi, în acest scop, denumirea utilizatorului care a lansat în execuție aplicația, dată fiind unicitatea sa (deși de poate recurge la orice convenție, în acest scop). 
 + 
 +<code java> 
 +MessageConsumer consumer = subscribeSession.createSharedDurableConsumer(topic,​ userName, Constants.CUSTOM_MESSAGE_PROPERTY + "= '"​ + userName + "'"​);​ 
 +</​code>​ 
 +</​spoiler>​
  
 **9.** Să se modifice formatul mesajelor astfel încât acesta să includă şi ora la care mesajul a fost transmis: **9.** Să se modifice formatul mesajelor astfel încât acesta să includă şi ora la care mesajul a fost transmis:
Line 892: Line 914:
 </​code>​ </​code>​
  
-Se va modifica ​structura ​mesajului din clasa ''​CustomMessage'', ​modificându-se definiţia ​metodei ''​handleMessage()''​ din clasa ''​ContactsList'' ​astfel încât să conţină şi parametrul referitor ​la momentul ​de timp la care a fost transmis mesajul.+<​spoiler|Indicații de Rezolvare>​ 
 +Este necesar să se realizeze următoarele modificări în structura ​aplicației pentru a se obține funcționalitatea solicitată:​ 
 +  * în clasa ''​CustomMessage'' ​se va include un câmp ''​messageDateTime''​ de tip [[https://​docs.oracle.com/​javase/​8/​docs/​api/​java/​util/​GregorianCalendar.html|GregorianCalendar]], care va fi instanțiat în cadrul constructorului de copiere și pentru care se vor implementa metode getter și setter; 
 +  * în clasa ''​PublishSubscribe''​ se vor modifica metodele: 
 +    * ''​handleMessage()'' ​- se va transmite ​metodei ''​handleMessage()'' ​(din clasa ''​ContactsList''​) argumentul care conține data și timpul ​la care mesajul a fost transmis; 
 +    * ''​publish()''​ - va crea un obiect ​de tip ''​Message''​ care conține și parametrul de tip dată și timp, instanțiat cu momentul curent (constructorul implicit al clasei ''​GregorianCalendar''​);​ 
 +  * în clasa ''​ContactsList'',​ metoda ''​handleMessage()''​ va primi un argument de tip ''​GregorianCalendar''​ pe care îl va propaga, mai departe, către metoda ''​handleConversationHistory()''​ din clasa ''​MessageExchange'';​ 
 +  * în clasa ''​MessageExchange'',​ data și timpul ​la care a fost transmis mesajul ​este afișat în interfața grafică: 
 +    * în metoda de tratare a evenimentului de apăsare a butonului //​SendMessage//​ (metoda ''​handle()''​ asociată ascultătorului obiectului ''​sendMessageButton''​);​ 
 +    * în metoda ''​handleConversationHistory()'',​ a cărei semnătură trebuie schimbată corespunzător (pentru a include argumentul de tip dată și timp). 
 +</​spoiler>​
  
 ===== Resurse ====== ===== Resurse ======
Line 900: Line 932:
 ===== Soluții ===== ===== Soluții =====
  
-TODO+[[https://​github.com/​aipi2015/​Laborator10/​tree/​master/​solutions/​eclipse/​10-Messaging-JMS|Proiect Eclipse]]\\  
 +[[https://​github.com/​aipi2015/​Laborator10/​tree/​master/​solutions/​netbeans/​10-Messaging-JMS|Proiect NetBeans]]
laboratoare/laborator10.1452119154.txt.gz · Last modified: 2016/01/07 00:25 by Andrei Roșu-Cojocaru
CC Attribution-Share Alike 4.0 International
Driven by DokuWiki Recent changes RSS feed Valid CSS Valid XHTML 1.0