Selenium Πρόγραμμα οδήγησης Web Java Παράδειγμα προγράμματος
⚡ Έξυπνη Σύνοψη
Selenium Πρόγραμμα οδήγησης Web Java Το Παράδειγμα Προγράμματος σάς καθοδηγεί στο πρώτο σας σενάριο αυτοματοποίησης από άκρο σε άκρο. LessΤα ons καλύπτουν τη ρύθμιση του περιβάλλοντος, τον εντοπισμό στοιχείων, την αποστολή δεδομένων εισόδου, την πλοήγηση, την επικύρωση, τις αναμονές, τον χειρισμό εξαιρέσεων και τις βέλτιστες πρακτικές για αξιόπιστες δοκιμές WebDriver.

Selenium Java Παράδειγμα
Χρήση του Java κλάση "myclass" που δημιουργήσαμε στο προηγούμενο σεμινάριο, ας προσπαθήσουμε να δημιουργήσουμε ένα σενάριο WebDriver που θα:
Βήμα 1: φέρω Mercury Αρχική σελίδα εκδρομών
Βήμα 2: επαληθεύστε τον τίτλο του
Βήμα 3: εκτυπώστε το αποτέλεσμα της σύγκρισης
Βήμα 4: κλείστε το πριν τελειώσετε ολόκληρο το πρόγραμμα.
Selenium Δείγμα προγράμματος οδήγησης ιστού Code
Παρακάτω είναι ο πραγματικός κώδικας WebDriver για τη λογική που παρουσιάζεται από το παραπάνω σενάριο
package newproject; import org.openqa.selenium.WebDriver; import org.openqa.selenium.firefox.FirefoxDriver; //comment the above line and uncomment below line to use Chrome //import org.openqa.selenium.chrome.ChromeDriver; public class PG1 { public static void main(String[] args) { // declaration and instantiation of objects/variables System.setProperty("webdriver.gecko.">driver","C:\\geckodriver.exe"); WebDriver driver = new FirefoxDriver(); //comment the above 2 lines and uncomment below 2 lines to use Chrome //System.setProperty("webdriver.chrome.">driver","G:\\chromedriver.exe"); //WebDriver driver = new ChromeDriver(); String baseUrl = "https://demo.guru99.com/test/newtours/"; String expectedTitle = "Welcome: Mercury Tours"; String actualTitle = ""; // launch Fire fox and direct it to the Base URL driver.get(baseUrl); // get the actual value of the title actualTitle = driver.getTitle(); /* * compare the actual title of the page with the expected one and print * the result as "Passed" or "Failed" */ if (actualTitle.contentEquals(expectedTitle)){ System.out.println("Test Passed!"); } else { System.out.println("Test Failed"); } //close Fire fox driver.close(); } }
Σημείωση: Έναρξη Firefox 35, πρέπει να χρησιμοποιήσετε το πρόγραμμα οδήγησης gecko που δημιουργήθηκε από τη Mozilla για να χρησιμοποιήσετε το πρόγραμμα οδήγησης Web. Selenium 3.0, το gecko και το firefox έχουν προβλήματα συμβατότητας και η σωστή ρύθμισή τους θα μπορούσε να γίνει δύσκολη εργασία. Εάν ο κωδικός δεν λειτουργεί, κάντε υποβάθμιση σε Firefox έκδοση 47 ή νεότερη. Εναλλακτικά, μπορείτε να εκτελέσετε τα σενάρια σας στο Chrome. Selenium λειτουργεί εξαρχής για το Chrome. Απλώς πρέπει να αλλάξετε 3 γραμμές κώδικα για να κάνετε το σενάριό σας να λειτουργεί με το Chrome ή Firefox
Εξηγώντας τον κωδικό
Εισαγωγή πακέτων
Για να ξεκινήσετε, πρέπει να εισαγάγετε τα ακόλουθα δύο πακέτα:
- org.openqa.selenium.*– περιέχει την κλάση WebDriver που απαιτείται για τη δημιουργία ενός νέου προγράμματος περιήγησης που είναι φορτωμένο με ένα συγκεκριμένο πρόγραμμα οδήγησης
- org.openqa.selenium.firefox.FirefoxΟδηγός – περιέχει το FirefoxΑπαιτείται κλάση οδηγού για την instantiation a Firefox-συγκεκριμένο πρόγραμμα οδήγησης στο πρόγραμμα περιήγησης που δημιουργήθηκε από την κλάση WebDriver
Εάν η δοκιμή σας χρειάζεται πιο περίπλοκες ενέργειες, όπως πρόσβαση σε άλλη τάξη, λήψη στιγμιότυπων οθόνης προγράμματος περιήγησης ή χειρισμό εξωτερικών αρχείων, σίγουρα θα χρειαστεί να εισαγάγετε περισσότερα πακέτα.
Δημιουργία αντικειμένων και μεταβλητών
Κανονικά, έτσι δημιουργείται ένα αντικείμενο προγράμματος οδήγησης.
WebDriver driver = new FirefoxDriver();
A FirefoxΚλάση προγράμματος οδήγησης χωρίς παραμέτρους σημαίνει ότι η προεπιλογή Firefox το προφίλ θα ξεκινήσει από εμάς Java πρόγραμμα. Η προεπιλογή Firefox το προφίλ είναι παρόμοιο με την εκκίνηση Firefox σε ασφαλή λειτουργία (δεν φορτώνονται επεκτάσεις).
Για λόγους ευκολίας, αποθηκεύσαμε τη Βάση URL και ο αναμενόμενος τίτλος ως μεταβλητές.
Εκκίνηση μιας περιόδου λειτουργίας προγράμματος περιήγησης
του WebDriver παίρνω() Η μέθοδος χρησιμοποιείται για την εκκίνηση μιας νέας συνεδρίας προγράμματος περιήγησης και την κατευθύνει στο URL που καθορίζετε ως παράμετρο.
driver.get(baseUrl);
Λάβετε τον πραγματικό τίτλο της σελίδας
Η κλάση WebDriver έχει το getTitle () μέθοδος που χρησιμοποιείται πάντα για τη λήψη του τίτλου της σελίδας της τρέχουσας φορτωμένης σελίδας.
actualTitle = driver.getTitle();
Συγκρίνετε τις αναμενόμενες και τις πραγματικές τιμές
Αυτό το τμήμα του κώδικα χρησιμοποιεί απλώς ένα βασικό Java εάν-άλλο δομή για να συγκρίνετε τον πραγματικό τίτλο με τον αναμενόμενο.
if (actualTitle.contentEquals(expectedTitle)){ System.out.println("Test Passed!"); } else { System.out.println("Test Failed"); }
Τερματισμός περιόδου λειτουργίας προγράμματος περιήγησης
Ο "Κλείσε()Η μέθοδος " χρησιμοποιείται για το κλείσιμο του παραθύρου του προγράμματος περιήγησης.
driver.close();
Τερματισμός Ολόκληρου του Προγράμματος
Εάν χρησιμοποιήσετε αυτήν την εντολή χωρίς να κλείσετε πρώτα όλα τα παράθυρα του προγράμματος περιήγησης, το σύνολο σας Java το πρόγραμμα θα τελειώσει αφήνοντας ανοιχτό το παράθυρο του προγράμματος περιήγησης.
System.exit(0);
Εκτέλεση του τεστ
Υπάρχουν δύο τρόποι εκτέλεσης κώδικα Eclipse SDI.
- On Eclipseστη γραμμή μενού του, κάντε κλικ Εκτέλεση > Εκτέλεση.
- Τύπος Ctrl + F11 για να εκτελέσετε ολόκληρο τον κώδικα.
Αν τα έκανες όλα σωστά, Eclipse θα έβγαζε "Test Passed!"
Εντοπισμός στοιχείων GUI
Ο εντοπισμός στοιχείων στο WebDriver γίνεται χρησιμοποιώντας το "findElement(Από.τοποθετών())μέθοδος. Το τμήμα «locator» του κώδικα είναι το ίδιο με οποιονδήποτε από τους εντοπιστές που συζητήθηκαν προηγουμένως στο Selenium IDE κεφάλαια αυτών των σεμιναρίων. Πράγματι, συνιστάται να εντοπίσετε στοιχεία GUI χρησιμοποιώντας το IDE και αφού αναγνωριστεί επιτυχώς, να εξαγάγετε τον κώδικα στο WebDriver.
Εδώ είναι μία Selenium Δείγμα κώδικα που εντοπίζει ένα στοιχείο από το αναγνωριστικό του. Το Facebook χρησιμοποιείται ως βάση URL.
package newproject; import org.openqa.selenium.By; import org.openqa.selenium.WebDriver; import org.openqa.selenium.firefox.FirefoxDriver; public class PG2 { public static void main(String[] args) { System.setProperty("webdriver.gecko.">driver","C:\\geckodriver.exe"); WebDriver driver = new FirefoxDriver(); String baseUrl = "http://www.facebook.com"; String tagName = ""; driver.get(baseUrl); tagName = driver.findElement(By.id("email")).getTagName(); System.out.println(tagName); driver.close(); System.exit(0); } }
Χρησιμοποιήσαμε το getTagName() μέθοδος για την εξαγωγήtract το όνομα της ετικέτας αυτού του συγκεκριμένου στοιχείου του οποίου το αναγνωριστικό είναι "email". Όταν εκτελείται, αυτός ο κώδικας θα πρέπει να είναι σε θέση να αναγνωρίσει σωστά το όνομα της ετικέτας "input" και να το εκτυπώσει EclipseΠαράθυρο Κονσόλας.
Περίληψη για τον εντοπισμό στοιχείων
| Παραλλαγή | Περιγραφή | Δείγμα |
|---|---|---|
| By.className | βρίσκει στοιχεία με βάση την τιμή του χαρακτηριστικού «class». | findElement(By.className("someClassName")) |
| By.cssSelector | βρίσκει στοιχεία με βάση την υποκείμενη μηχανή επιλογής CSS του οδηγού | findElement(By.cssSelector("input#email")) |
| By.id | εντοπίζει στοιχεία με βάση την τιμή του χαρακτηριστικού "id" τους |
findElement(By.id("someId")) |
| By.linkText | βρίσκει ένα στοιχείο συνδέσμου με βάση το ακριβές κείμενο που εμφανίζει |
findElement(By.linkText("ΕΓΓΡΑΦΗ")) |
| Από όνομα | εντοπίζει στοιχεία με την τιμή του χαρακτηριστικού "όνομα". |
findElement(By.name("someName")) |
| By.partialLinkText | εντοπίζει στοιχεία που περιέχουν το δεδομένο κείμενο συνδέσμου |
findElement(By.partialLinkText("REG")) |
| By.tagName | εντοπίζει στοιχεία με το όνομα της ετικέτας τους |
findElement(By.tagName("div")) |
| By.xpath | εντοπίζει στοιχεία μέσω XPath |
findElement(By.xpath(“//html/body/div/table/tbody/tr/td[2]/table/ tbody/tr[4]/td/table/tbody/tr/td[2]/table/tbody/tr[2]/td[3]/ form/table/tbody/tr[5]”)) |
Σημείωση σχετικά με τη χρήση του findElement(By.cssSelector())
By.cssSelector() δεν υποστηρίζει τη δυνατότητα "περιέχει". Σκεψου το Selenium Κωδικός IDE παρακάτω -
In Selenium IDE παραπάνω, όλη η δοκιμή πέρασε. Ωστόσο στο Selenium Η δέσμη ενεργειών WebDriver παρακάτω, η ίδια δοκιμή δημιούργησε ένα σφάλμα επειδή το WebDriver δεν υποστηρίζει τη λέξη-κλειδί "περιέχει" όταν χρησιμοποιείται στη μέθοδο By.cssSelector().
Κοινές εντολές
Δημιουργία στοιχείων Ιστού
Αντί να χρησιμοποιούμε τη μεγάλη σύνταξη "driver.findElement(By.locator())" κάθε φορά που θα έχετε πρόσβαση σε ένα συγκεκριμένο στοιχείο, μπορούμε να δημιουργήσουμε ένα αντικείμενο WebElement για αυτό. Η κλάση WebElement περιέχεται στο πακέτο "org.openqa.selenium.*".
Κάνοντας κλικ σε ένα στοιχείο
Το κλικ είναι ίσως ο πιο συνηθισμένος τρόπος αλληλεπίδρασης με στοιχεία ιστού. ο click() μέθοδος χρησιμοποιείται για την προσομοίωση του κλικ οποιουδήποτε στοιχείου. Τα παρακάτω Selenium Java Το παράδειγμα δείχνει πώς click() χρησιμοποιήθηκε για κλικ Mercury Κουμπί "Σύνδεση" των περιηγήσεων.
Τα ακόλουθα πράγματα πρέπει να σημειωθούν όταν χρησιμοποιείτε τη μέθοδο click().
- Δεν παίρνει καμία παράμετρο/όρισμα.
- Η μέθοδος περιμένει αυτόματα τη φόρτωση μιας νέας σελίδας, εάν υπάρχει.
- Το στοιχείο στο οποίο θα κάνετε κλικ πρέπει να είναι ορατό (το ύψος και το πλάτος δεν πρέπει να είναι ίσα με μηδέν).
Λάβετε εντολές
Λήψη εντολών για λήψη διαφόρων σημαντικών πληροφοριών σχετικά με τη σελίδα/στοιχείο. Ακολουθούν ορισμένες σημαντικές εντολές "get" που πρέπει να γνωρίζετε.
| Εντολές | Χρήση |
|---|---|
| παίρνω()
Δείγμα χρήσης: |
|
| getTitle ()
Δείγμα χρήσης: |
|
| getPageSource()
Δείγμα χρήσης: |
|
| getCurrentUrl()
Δείγμα χρήσης: |
|
| getText ()
Δείγμα χρήσης: |
|
Εντολές πλοήγησης
Αυτές οι εντολές σάς επιτρέπουν να ανανεώνετε, να εισάγετε και να κάνετε εναλλαγή μεταξύ διαφορετικών ιστοσελίδων.
| navigate().to()
Δείγμα χρήσης: |
|
| navigate().refresh()
Δείγμα χρήσης: |
|
| navigate().back()
Δείγμα χρήσης: |
|
| navigate().forward()
Δείγμα χρήσης: |
|
Κλείσιμο και τερματισμός του προγράμματος περιήγησης Windows
| Κλείσε()
Δείγμα χρήσης: |
|
| εγκαταλείπω()
Δείγμα χρήσης: |
|
Για να δείξουμε ξεκάθαρα τη διαφορά μεταξύ close() και quit(), δοκιμάστε να εκτελέσετε τον παρακάτω κώδικα. Χρησιμοποιεί μια ιστοσελίδα που ανοίγει αυτόματα ένα παράθυρο κατά τη φόρτωση της σελίδας και ανοίγει μια άλλη μετά την έξοδο.
Σημειώστε ότι μόνο το γονικό παράθυρο του προγράμματος περιήγησης ήταν κλειστό και όχι τα δύο αναδυόμενα παράθυρα.
Αλλά αν χρησιμοποιήσετε το quit(), όλα τα παράθυρα θα κλείσουν – όχι μόνο το γονικό. Δοκιμάστε να εκτελέσετε τον παρακάτω κώδικα και θα παρατηρήσετε ότι τα δύο παραπάνω αναδυόμενα παράθυρα θα κλείσουν αυτόματα επίσης.
package newproject; import org.openqa.selenium.WebDriver; import org.openqa.selenium.firefox.FirefoxDriver; public class PG3 { public static void main(String[] args) { System.setProperty("webdriver.gecko.">driver","C:\\geckodriver.exe"); WebDriver driver = new FirefoxDriver(); driver.get("http://www.popuptest.com/popuptest2.html"); driver.quit(); // using QUIT all windows will close } }
Εναλλαγή μεταξύ πλαισίων
Για να αποκτήσετε πρόσβαση σε στοιχεία GUI σε ένα Frame, θα πρέπει πρώτα να κατευθύνουμε το WebDriver να εστιάσει πρώτα στο πλαίσιο ή στο αναδυόμενο παράθυρο προτού μπορέσουμε να αποκτήσουμε πρόσβαση σε στοιχεία μέσα σε αυτά. Ας πάρουμε, για παράδειγμα, την ιστοσελίδα https://demo.guru99.com/selenium/deprecated.html
Αυτή η σελίδα έχει 3 πλαίσια των οποίων τα χαρακτηριστικά "όνομα" υποδεικνύονται παραπάνω. Θέλουμε να αποκτήσουμε πρόσβαση στον σύνδεσμο "Καταργήθηκε" που περικυκλώνεται παραπάνω με κίτρινο χρώμα. Για να γίνει αυτό, πρέπει πρώτα να δώσουμε εντολή στο WebDriver να μεταβεί στο πλαίσιο "classFrame" χρησιμοποιώντας το "switchTo().frame()" μέθοδος. Θα χρησιμοποιήσουμε το χαρακτηριστικό name του πλαισίου ως παράμετρο για το τμήμα «frame()».
package newproject; import org.openqa.selenium.By; import org.openqa.selenium.WebDriver; import org.openqa.selenium.firefox.FirefoxDriver; public class PG4 { public static void main(String[] args) { System.setProperty("webdriver.gecko.">driver","C:\\geckodriver.exe"); WebDriver driver = new FirefoxDriver(); driver.get("https://demo.guru99.com/selenium/deprecated.html"); driver.switchTo().frame("classFrame"); driver.findElement(By.linkText("Deprecated")).click(); driver.close(); } }
Μετά την εκτέλεση αυτού του κώδικα, θα δείτε ότι το πλαίσιο "classFrame" μεταφέρεται στη σελίδα "Deprecated API", που σημαίνει ότι ο κώδικάς μας μπόρεσε να αποκτήσει πρόσβαση στον σύνδεσμο "Deprecated".
Εναλλαγή μεταξύ αναδυόμενων παραθύρων Windows
Το WebDriver επιτρέπει την εμφάνιση αναδυόμενων παραθύρων όπως ειδοποιήσεις, σε αντίθεση με το in Selenium IDE. Για να αποκτήσουμε πρόσβαση στα στοιχεία εντός της ειδοποίησης (όπως το μήνυμα που περιέχει), πρέπει να χρησιμοποιήσουμε το "switchTo().alert()" μέθοδος. Στον παρακάτω κώδικα, θα χρησιμοποιήσουμε αυτήν τη μέθοδο για να αποκτήσουμε πρόσβαση στο πλαίσιο ειδοποίησης και στη συνέχεια να ανακτήσουμε το μήνυμά του χρησιμοποιώντας το "getText()" και στη συνέχεια κλείστε αυτόματα το πλαίσιο ειδοποίησης χρησιμοποιώντας το "switchTo().alert().accept()" μέθοδος.
Πρώτα, κατευθυνθείτε προς https://output.jsbin.com/usidix/1 και κάντε χειροκίνητα κλικ στο "Μετάβαση!" πατήστε εκεί και δείτε μόνοι σας το κείμενο του μηνύματος.
Ας δούμε το Selenium παράδειγμα κώδικα για να γίνει αυτό-
package mypackage; import org.openqa.selenium.By; import org.openqa.selenium.WebDriver; import org.openqa.selenium.firefox.FirefoxDriver; public class myclass { public static void main(String[] args) { System.setProperty("webdriver.gecko.">driver","C:\\geckodriver.exe"); WebDriver driver = new FirefoxDriver(); String alertMessage = ""; driver.get("http://jsbin.com/usidix/1"); driver.findElement(By.cssSelector("input[value=\"Go!\"]")).click(); alertMessage = driver.switchTo().alert().getText(); driver.switchTo().alert().accept(); System.out.println(alertMessage); driver.quit(); } }
Στις Eclipse κονσόλα, παρατηρήστε ότι το εκτυπωμένο μήνυμα ειδοποίησης είναι:
Περιμένετε
Υπάρχουν δύο είδη αναμονής.
- Σιωπηρή αναμονή – χρησιμοποιείται για τον ορισμό του προεπιλεγμένου χρόνου αναμονής σε όλο το πρόγραμμα
- Ρητή αναμονή – χρησιμοποιείται για τον ορισμό του χρόνου αναμονής μόνο για μια συγκεκριμένη περίπτωση
Σιωπηρή αναμονή
- Είναι πιο απλό να κωδικοποιηθεί από το Explicit Waits.
- Συνήθως δηλώνεται στο τμήμα instantiation του κώδικα.
- Θα χρειαστείτε μόνο ένα επιπλέον πακέτο για εισαγωγή.
Για να αρχίσετε να χρησιμοποιείτε μια σιωπηρή αναμονή, θα πρέπει να εισαγάγετε αυτό το πακέτο στον κώδικά σας.
Στη συνέχεια, στο μέρος της εγκατάστασης του κώδικά σας, προσθέστε αυτό.
Άμεση αναμονή
Οι ρητές αναμονές γίνονται χρησιμοποιώντας τις κλάσεις WebDriverWait και ExpectedCondition. Για τα παρακάτω Selenium Παράδειγμα WebDriver, θα περιμένουμε έως και 10 δευτερόλεπτα για να γίνει ορατό ένα στοιχείο του οποίου το αναγνωριστικό είναι «όνομα χρήστη» πριν προχωρήσουμε στην επόμενη εντολή. Εδώ είναι τα βήματα.
Βήμα 1:
Εισαγάγετε αυτά τα δύο πακέτα:
Βήμα 2:
Δηλώστε μια μεταβλητή WebDriverWait. Σε αυτό το παράδειγμα, θα χρησιμοποιήσουμε το "myWaitVar" ως όνομα της μεταβλητής.
Βήμα 3:
Χρησιμοποιήστε το myWaitVar με ExpectedConditions σε τμήματα όπου χρειάζεστε τη ρητή αναμονή για να συμβεί. Σε αυτήν την περίπτωση, θα χρησιμοποιήσουμε ρητή αναμονή στο "όνομα χρήστη" (Mercury Tours HomePage) εισάγετε πριν πληκτρολογήσετε το κείμενο "tutorial" σε αυτό.
Όροι
Οι ακόλουθες μέθοδοι χρησιμοποιούνται σε υποθετικές και looping λειτουργίες —
- είναι ενεργοποιημένο() χρησιμοποιείται όταν θέλετε να επαληθεύσετε εάν ένα συγκεκριμένο στοιχείο είναι ενεργοποιημένο ή όχι πριν από την εκτέλεση μιας εντολής.
- isDisplayed() χρησιμοποιείται όταν θέλετε να επαληθεύσετε εάν ένα συγκεκριμένο στοιχείο εμφανίζεται ή όχι πριν από την εκτέλεση μιας εντολής.
- isSelected() χρησιμοποιείται όταν θέλετε να επαληθεύσετε εάν ένα συγκεκριμένο πλαίσιο ελέγχου, κουμπί επιλογής ή επιλογή σε ένα αναπτυσσόμενο πλαίσιο επιλέγεται. Δεν λειτουργεί σε άλλα στοιχεία.
Χρήση ExpectedConditions
Η κλάση ExpectedConditions προσφέρει ένα ευρύτερο σύνολο συνθηκών που μπορείτε να χρησιμοποιήσετε σε συνδυασμό με τη μέθοδο μέχρι() του WebDriverWait.
Παρακάτω είναι μερικές από τις πιο κοινές μεθόδους ExpectedConditions.
- alertIsPresent() – περιμένει μέχρι να εμφανιστεί ένα πλαίσιο ειδοποίησης.
- elementToBeClickable() – Περιμένει μέχρι να εμφανιστεί ένα στοιχείο και, ταυτόχρονα, να ενεργοποιηθεί. Το δείγμα Selenium Code παρακάτω θα περιμένει μέχρι το στοιχείο με id="όνομα χρήστη" να γίνει ορατό και να ενεργοποιηθεί πρώτα πριν αντιστοιχίσει αυτό το στοιχείο ως μεταβλητή WebElement με όνομα "txtUserName".
- frameToBeAvailableAndSwitchToIt() – Περιμένει έως ότου το συγκεκριμένο πλαίσιο είναι ήδη διαθέσιμο και, στη συνέχεια, μεταβαίνει αυτόματα σε αυτό.
Αλίευση εξαιρέσεων
Όταν χρησιμοποιείτε τα isEnabled(), isDisplayed() και isSelected(), το WebDriver υποθέτει ότι το στοιχείο υπάρχει ήδη στη σελίδα. Διαφορετικά, θα ρίξει α NoSuchElementException. Για να το αποφύγουμε αυτό, θα πρέπει να χρησιμοποιήσουμε ένα μπλοκ try-catch ώστε να μην διακόπτεται το πρόγραμμα.
WebElement txtbox_username = driver.findElement(By.id("username")); try{ if(txtbox_username.isEnabled()){ txtbox_username.sendKeys("tutorial"); } } catch(NoSuchElementException nsee){ System.out.println(nsee.toString()); }
Εάν χρησιμοποιείτε ρητές αναμονές, ο τύπος εξαίρεσης που πρέπει να συλλάβετε είναι το "TimeoutException".

.png)
.png)
.png)
.png)
.png)
.png)

.png)


.png)
.png)
.png)
.png)
.png)
.png)

.png)
.png)
.png)