SlideShare a Scribd company logo
Selenium and Grinder: A powerful duo for load testing Eric Pugh Principle, OpenSource Connections [email_address] CvilleJUG March 21st, 2006
What we’re going to learn! Just enough about Selenium to get started! Load testing with Grinder Whether WEBrick or lighttpd is faster for serving pages!
What is Selenium?
From Selenium’s web site: “ Selenium  is a test tool for web applications. Selenium tests run  directly in a browser , just as real users do.”
Selenium can be run two ways: “TestRunner” and “Driven”
“TestRunner” Mode Selenium application consisting of HTML and JavaScript is deployed along side the application to be tested. Tests are written in HTML tables.
TestRunner control panel
“Driven” Mode Browser is under the control of another process that specifies what commands to be run
“Driven” Mode Controlling process is typically a Java, .NET, Ruby or Python application // Java public void testRugbyHome() { selenium.open("http://localhost:3000/sprint"); selenium.click("submit"); selenium.assertTitle("Rugby"); selenium.click("link=Name"); selenium.assertTitle("Rugby"); } # Ruby def testRugbyHome puts selenium.open "http://localhost:3000/sprint" puts selenium.clickAndWait "submit" puts selenium.assertTitle "Rugby" puts selenium.clickAndWait "link=Name" puts selenium.assertTitle "Rugby" end # Python selenium.open('http://localhost:3000/sprint') print selenium.clickAndWait('submit') print selenium.assertTitle('Rugby') print selenium.clickAndWait('submit') print selenium.assertTitle('Rugby')
“Driven” Mode Pros: Better if you need conditional logic or looping “ White Box” testing.  Need in depth knowledge of webapp structure Test writers prefer programming in a “real” language Cons: Significantly more infrastructure to setup Test writers need programming skills Tests that require conditional logic can become brittle quickly FYI: “Driven” will be renamed “Remote Control” in the next version of Selenium
We’ll focus on “TestRunner” mode!
Intro to Selenese Selenese is a simple language for specifying commands instructing Selenium what to do Consists of three parts: command, target, and value laid out as columns in a an HTML table: <table> <tr> <td>command</td><td>target</td><td>value</td> </tr> </table>
Selenese Commands Commands are either “Actions” or “Checks” Actions are commands that tell Selenium to do something: Open a web page Click a link Select an option Type some text Checks validate the applications: Title of the page Verify that a checkbox is checked Ensure a table structure contains a specific string
Selenese Element Locators Element Locators specify an HTML element that a command applies to. Multiple strategies for finding an element: id= id Select the element with the specified @id attribute. name= name Select the first element with the specified @name attribute. identifier= id Select the element with the specified @id attribute. If no match is found, select the first element whose @name attribute is  id . link= textPattern Select the link (anchor) element which contains text matching the specified  pattern .
Selenese Element Locator using DOM Selenium supports using JavaScript to traverse the HTML Document Object Model DOM locators must begin with “document.” • dom=document.forms['myForm'].myDropdown • dom=document.images[56]
Selenese Element Locator using XPath XPath expressions are the most powerful way of selecting elements in Selenium. XPath locators must begin with “//” • xpath=//img[@alt='The image alt text'] • xpath=//table[@id='table1']//tr[4]/td[2] • xpath=//div[@id='workflowMenu']//a[@id='goToPreviousStatus']/ Tip: IE’s implementation of XPath is buggy, your mileage may vary…
Common Actions: open open(url) Opens both relative and absolute URL’s.  Tip: Selenium can only open URL’s that are on the same site due to “Cross Site Scripting” security policy in browsers.  We’ll discuss how to get around this later.
Common Actions: click/clickAndWait clickAndWait(elementLocator) Click on a link, button, checkbox, or radio button.  If the click action loads a new page then use clickAndWait to tell Selenium to pause until the new page loads
Common Actions: type type/typeAndWait(elementLocator,value) Sets the value of an input field, as though you typed it in.
Common Actions: select select/selectAndWait(elementLocator, optionSpecifier) Select an option from a drop down based on the optionSpecifier
Select Option Specifiers Selenium supports multiple ways of specifying options of an HTML select statement.  If multiple options match then the first one is selected:  label= labelPattern matches options based on their labels, i.e. the visible text. • label=regexp:^[Oo]ther value= valuePattern matches options based on their values. • value=other id= id matches options based on their ids. • id=option1 index= index matches an option based on its index (offset from zero). • index=2
Check Commands Used to verify the state of the application Can check the value of a form field, presence of some text, the structure of the HTML, or the URL of the page. All checks can be used in two modes: “assert” or “verify” Assert failures cause the test to be aborted Verify failures are recorded but the test continues Tip: A good practice is to Assert that you are on the correct page and then Verify the contents of the page.
String Matching with Check Commands Selenium supports various pattern syntaxes for matching string values: glob: pattern Match a string against a &quot;glob&quot; pattern. &quot;Glob&quot; is a kind of limited regular-expression syntax typically used in command-line shells. In a glob pattern, &quot;*&quot; represents any sequence of characters, and &quot;?&quot; represents any single character. Glob patterns match against the entire string. regexp: regexp Match a string using a regular-expression. The full power of JavaScript regular-expressions is available. exact: string Match a string exactly, verbatim, without any of that fancy wildcard stuff.
Common Checks: assertTitle assertTitle(titlePattern) Verify the title of the current page
Common Checks: assertValue assertValue(elementLocator, valuePattern) Verify the value of an input field (or anything with a value parameter) For checkbox/radio elements the value will be “on” or “off” depending on if it is checked or not
Common Checks: assertAttribute assertAttribute(elementLocator@attributeName, valuePattern) Verify the value of an element attribute. Great for testing CSS style sheet tags!
Common Checks: assertTextPresent assertTextPresent(text) Verify that some text shows up somewhere in the HTML. The inverse is of course assertTextNotPresent(text)!
There are many more commands, but that’s enough to get started!
Isn’t there an easier way then writing the HTML by hand?
Selenium IDE Firefox Plugin, requires Firefox 1.5 Available from  http://www.openqa.org/selenium-ide/ More then just a recorder, it’s also a great editor for your tests.  Tip: Quickly build the skeleton of your test by using the recorder, then go back and add your verify checks manually.
Now how do we do load testing?
The Grinder Java based load testing framework.  Requires J2SE 1.3. Licensed under a BSD-style open source license. Support for testing  HTTP based services as well as others such as SMTP, FTP, and JDBC. Comes with a plugin to facilitate recording HTTP test scripts in Jython. “ The Grinder 3” is the recommended version to use http://grinder.sourceforge.net/ FYI: the official name is “The Grinder” not “Grinder”!
What you need to know You don’t need to know either Java or Python! Basic shell/batch scripting to get tool started Configuring path statement and environmental variables
The Grinder Design Goal:  Minimize system resource requirements while maximizing the number of test contexts (“virtual users”) Multi threaded, multi process implementation.  Each test contexts runs in it’s own thread. Threads can be split over many separate processes depending on the capabilities of the agent machine Distributed Very simple to set up multiple agents and coordinate and monitor their activity Console app can centrally manage tests and deploy them to the agents.  Console starts and stops the agents.
Generating Grinder script from Selenium Test 1) Setup Firefox to use as proxy “localhost:8001” 2) Start up Grinder’s TCP Proxy 3) Replay script using Selenium IDE Note: Make sure to turn off caching in Firefox so you get all the requests recorded! Make sure in Firefox’s Proxy page localhost is set to proxy! Use Proxy filter to control what gets recorded!
Getting Grinder Installed One controller and two agents
You’ve got Questions?  I’ve got Answers! Email me at epugh@opensourceconnections!

More Related Content

ODP
PhpUnit & web driver
PPTX
Selenium WebDriver
PPTX
Selenium web driver
PDF
Practical Tips & Tricks for Selenium Test Automation - Dave Haeffner
PDF
Selenium Basics Tutorial
PDF
Selenium IDE LOCATORS
PPTX
Automation Testing by Selenium Web Driver
PDF
Selenium Tips & Tricks, presented at the Tel Aviv Selenium Meetup
PhpUnit & web driver
Selenium WebDriver
Selenium web driver
Practical Tips & Tricks for Selenium Test Automation - Dave Haeffner
Selenium Basics Tutorial
Selenium IDE LOCATORS
Automation Testing by Selenium Web Driver
Selenium Tips & Tricks, presented at the Tel Aviv Selenium Meetup

What's hot (19)

PPTX
Selenium ide made easy
PPTX
Automation - web testing with selenium
PDF
Selenium Handbook
PDF
How To Use Selenium Successfully
PDF
Interview Question & Answers for Selenium Freshers | LearningSlot
PDF
Mastering UI automation at Scale: Key Lessons and Best Practices (By Fernando...
PDF
Interview question & Answers for 3+ years experienced in Selenium | LearningSlot
PDF
Selenium web driver
PDF
Selenium 2 - PyCon 2011
PPTX
Selenium using Java
 
DOCX
Selenium WebDriver FAQ's
PPTX
Selenium web driver
PDF
Practical Tips & Tricks for Selenium Test Automation
PDF
Selenium IDE
PPTX
Basic Selenium Training
PPTX
Test Automation and Selenium
PDF
Mobile Testing with Selenium 2 by Jason Huggins
PDF
Introduction to Selenium and Test Automation
PPTX
Marcin Wasilczyk - Page objects with selenium
Selenium ide made easy
Automation - web testing with selenium
Selenium Handbook
How To Use Selenium Successfully
Interview Question & Answers for Selenium Freshers | LearningSlot
Mastering UI automation at Scale: Key Lessons and Best Practices (By Fernando...
Interview question & Answers for 3+ years experienced in Selenium | LearningSlot
Selenium web driver
Selenium 2 - PyCon 2011
Selenium using Java
 
Selenium WebDriver FAQ's
Selenium web driver
Practical Tips & Tricks for Selenium Test Automation
Selenium IDE
Basic Selenium Training
Test Automation and Selenium
Mobile Testing with Selenium 2 by Jason Huggins
Introduction to Selenium and Test Automation
Marcin Wasilczyk - Page objects with selenium
Ad

Similar to Selenium and The Grinder (20)

PPT
Selenium
PPTX
Selenium
PPTX
Automation Testing
PDF
Selenium Automation Testing Interview Questions And Answers
PPTX
Selenium corporate-training-in-mumbai
PDF
Selenium corporate-training-in-mumbai
PDF
Selenium
PPTX
Selenium-corporate-training-in-mumbai
DOCX
Selenium interview-questions-freshers
PPT
Selenium Primer
PPTX
Selenium ppt
PPTX
Selenium
PPTX
PPTX
Selenium
PPTX
Selenium
PPTX
Selenium
PPT
Selenium (1) (1)
DOCX
Selenium introduction and some feautures
PPT
Selenium
PPTX
Selenium Interview Questions And Answers | Selenium Interview Questions | Sel...
Selenium
Selenium
Automation Testing
Selenium Automation Testing Interview Questions And Answers
Selenium corporate-training-in-mumbai
Selenium corporate-training-in-mumbai
Selenium
Selenium-corporate-training-in-mumbai
Selenium interview-questions-freshers
Selenium Primer
Selenium ppt
Selenium
Selenium
Selenium
Selenium
Selenium (1) (1)
Selenium introduction and some feautures
Selenium
Selenium Interview Questions And Answers | Selenium Interview Questions | Sel...
Ad

More from OpenSource Connections (20)

PDF
Why User Behavior Insights? KMWorld Enterprise Search & Discovery 2024
PDF
Test driven relevancy
PDF
How To Structure Your Search Team for Success
PPT
The right path to making search relevant - Taxonomy Bootcamp London 2019
PDF
Payloads and OCR with Solr
PPTX
Haystack 2019 Lightning Talk - The Future of Quepid - Charlie Hull
PDF
Haystack 2019 Lightning Talk - State of Apache Tika - Tim Allison
PPTX
Haystack 2019 Lightning Talk - Relevance on 17 million full text documents - ...
PPTX
Haystack 2019 Lightning Talk - Solr Cloud on Kubernetes - Manoj Bharadwaj
PDF
Haystack 2019 Lightning Talk - Quaerite a Search relevance evaluation toolkit...
PPTX
Haystack 2019 - Search-based recommendations at Politico - Ryan Kohl
PPTX
Haystack 2019 - Search with Vectors - Simon Hughes
PPTX
Haystack 2019 - Natural Language Search with Knowledge Graphs - Trey Grainger
PPTX
Haystack 2019 - Search Logs + Machine Learning = Auto-Tagging Inventory - Joh...
PDF
Haystack 2019 - Improving Search Relevance with Numeric Features in Elasticse...
PDF
Haystack 2019 - Architectural considerations on search relevancy in the conte...
PPTX
Haystack 2019 - Custom Solr Query Parser Design Option, and Pros & Cons - Ber...
PPTX
Haystack 2019 - Establishing a relevance focused culture in a large organizat...
PPTX
Haystack 2019 - Solving for Satisfaction: Introduction to Click Models - Eliz...
Why User Behavior Insights? KMWorld Enterprise Search & Discovery 2024
Test driven relevancy
How To Structure Your Search Team for Success
The right path to making search relevant - Taxonomy Bootcamp London 2019
Payloads and OCR with Solr
Haystack 2019 Lightning Talk - The Future of Quepid - Charlie Hull
Haystack 2019 Lightning Talk - State of Apache Tika - Tim Allison
Haystack 2019 Lightning Talk - Relevance on 17 million full text documents - ...
Haystack 2019 Lightning Talk - Solr Cloud on Kubernetes - Manoj Bharadwaj
Haystack 2019 Lightning Talk - Quaerite a Search relevance evaluation toolkit...
Haystack 2019 - Search-based recommendations at Politico - Ryan Kohl
Haystack 2019 - Search with Vectors - Simon Hughes
Haystack 2019 - Natural Language Search with Knowledge Graphs - Trey Grainger
Haystack 2019 - Search Logs + Machine Learning = Auto-Tagging Inventory - Joh...
Haystack 2019 - Improving Search Relevance with Numeric Features in Elasticse...
Haystack 2019 - Architectural considerations on search relevancy in the conte...
Haystack 2019 - Custom Solr Query Parser Design Option, and Pros & Cons - Ber...
Haystack 2019 - Establishing a relevance focused culture in a large organizat...
Haystack 2019 - Solving for Satisfaction: Introduction to Click Models - Eliz...

Recently uploaded (20)

PDF
Network Security Unit 5.pdf for BCA BBA.
PDF
Agricultural_Statistics_at_a_Glance_2022_0.pdf
PDF
Review of recent advances in non-invasive hemoglobin estimation
PPTX
20250228 LYD VKU AI Blended-Learning.pptx
PPTX
ACSFv1EN-58255 AWS Academy Cloud Security Foundations.pptx
PPTX
Detection-First SIEM: Rule Types, Dashboards, and Threat-Informed Strategy
PDF
KodekX | Application Modernization Development
PDF
Profit Center Accounting in SAP S/4HANA, S4F28 Col11
PPTX
Effective Security Operations Center (SOC) A Modern, Strategic, and Threat-In...
PDF
Per capita expenditure prediction using model stacking based on satellite ima...
PPTX
Understanding_Digital_Forensics_Presentation.pptx
PPTX
Big Data Technologies - Introduction.pptx
PPTX
Cloud computing and distributed systems.
PPTX
sap open course for s4hana steps from ECC to s4
PDF
Architecting across the Boundaries of two Complex Domains - Healthcare & Tech...
PDF
Empathic Computing: Creating Shared Understanding
PDF
Optimiser vos workloads AI/ML sur Amazon EC2 et AWS Graviton
PDF
NewMind AI Weekly Chronicles - August'25 Week I
PDF
The Rise and Fall of 3GPP – Time for a Sabbatical?
PPTX
Spectroscopy.pptx food analysis technology
Network Security Unit 5.pdf for BCA BBA.
Agricultural_Statistics_at_a_Glance_2022_0.pdf
Review of recent advances in non-invasive hemoglobin estimation
20250228 LYD VKU AI Blended-Learning.pptx
ACSFv1EN-58255 AWS Academy Cloud Security Foundations.pptx
Detection-First SIEM: Rule Types, Dashboards, and Threat-Informed Strategy
KodekX | Application Modernization Development
Profit Center Accounting in SAP S/4HANA, S4F28 Col11
Effective Security Operations Center (SOC) A Modern, Strategic, and Threat-In...
Per capita expenditure prediction using model stacking based on satellite ima...
Understanding_Digital_Forensics_Presentation.pptx
Big Data Technologies - Introduction.pptx
Cloud computing and distributed systems.
sap open course for s4hana steps from ECC to s4
Architecting across the Boundaries of two Complex Domains - Healthcare & Tech...
Empathic Computing: Creating Shared Understanding
Optimiser vos workloads AI/ML sur Amazon EC2 et AWS Graviton
NewMind AI Weekly Chronicles - August'25 Week I
The Rise and Fall of 3GPP – Time for a Sabbatical?
Spectroscopy.pptx food analysis technology

Selenium and The Grinder

  • 1. Selenium and Grinder: A powerful duo for load testing Eric Pugh Principle, OpenSource Connections [email_address] CvilleJUG March 21st, 2006
  • 2. What we’re going to learn! Just enough about Selenium to get started! Load testing with Grinder Whether WEBrick or lighttpd is faster for serving pages!
  • 4. From Selenium’s web site: “ Selenium is a test tool for web applications. Selenium tests run directly in a browser , just as real users do.”
  • 5. Selenium can be run two ways: “TestRunner” and “Driven”
  • 6. “TestRunner” Mode Selenium application consisting of HTML and JavaScript is deployed along side the application to be tested. Tests are written in HTML tables.
  • 8. “Driven” Mode Browser is under the control of another process that specifies what commands to be run
  • 9. “Driven” Mode Controlling process is typically a Java, .NET, Ruby or Python application // Java public void testRugbyHome() { selenium.open(&quot;http://localhost:3000/sprint&quot;); selenium.click(&quot;submit&quot;); selenium.assertTitle(&quot;Rugby&quot;); selenium.click(&quot;link=Name&quot;); selenium.assertTitle(&quot;Rugby&quot;); } # Ruby def testRugbyHome puts selenium.open &quot;http://localhost:3000/sprint&quot; puts selenium.clickAndWait &quot;submit&quot; puts selenium.assertTitle &quot;Rugby&quot; puts selenium.clickAndWait &quot;link=Name&quot; puts selenium.assertTitle &quot;Rugby&quot; end # Python selenium.open('http://localhost:3000/sprint') print selenium.clickAndWait('submit') print selenium.assertTitle('Rugby') print selenium.clickAndWait('submit') print selenium.assertTitle('Rugby')
  • 10. “Driven” Mode Pros: Better if you need conditional logic or looping “ White Box” testing. Need in depth knowledge of webapp structure Test writers prefer programming in a “real” language Cons: Significantly more infrastructure to setup Test writers need programming skills Tests that require conditional logic can become brittle quickly FYI: “Driven” will be renamed “Remote Control” in the next version of Selenium
  • 11. We’ll focus on “TestRunner” mode!
  • 12. Intro to Selenese Selenese is a simple language for specifying commands instructing Selenium what to do Consists of three parts: command, target, and value laid out as columns in a an HTML table: <table> <tr> <td>command</td><td>target</td><td>value</td> </tr> </table>
  • 13. Selenese Commands Commands are either “Actions” or “Checks” Actions are commands that tell Selenium to do something: Open a web page Click a link Select an option Type some text Checks validate the applications: Title of the page Verify that a checkbox is checked Ensure a table structure contains a specific string
  • 14. Selenese Element Locators Element Locators specify an HTML element that a command applies to. Multiple strategies for finding an element: id= id Select the element with the specified @id attribute. name= name Select the first element with the specified @name attribute. identifier= id Select the element with the specified @id attribute. If no match is found, select the first element whose @name attribute is id . link= textPattern Select the link (anchor) element which contains text matching the specified pattern .
  • 15. Selenese Element Locator using DOM Selenium supports using JavaScript to traverse the HTML Document Object Model DOM locators must begin with “document.” • dom=document.forms['myForm'].myDropdown • dom=document.images[56]
  • 16. Selenese Element Locator using XPath XPath expressions are the most powerful way of selecting elements in Selenium. XPath locators must begin with “//” • xpath=//img[@alt='The image alt text'] • xpath=//table[@id='table1']//tr[4]/td[2] • xpath=//div[@id='workflowMenu']//a[@id='goToPreviousStatus']/ Tip: IE’s implementation of XPath is buggy, your mileage may vary…
  • 17. Common Actions: open open(url) Opens both relative and absolute URL’s. Tip: Selenium can only open URL’s that are on the same site due to “Cross Site Scripting” security policy in browsers. We’ll discuss how to get around this later.
  • 18. Common Actions: click/clickAndWait clickAndWait(elementLocator) Click on a link, button, checkbox, or radio button. If the click action loads a new page then use clickAndWait to tell Selenium to pause until the new page loads
  • 19. Common Actions: type type/typeAndWait(elementLocator,value) Sets the value of an input field, as though you typed it in.
  • 20. Common Actions: select select/selectAndWait(elementLocator, optionSpecifier) Select an option from a drop down based on the optionSpecifier
  • 21. Select Option Specifiers Selenium supports multiple ways of specifying options of an HTML select statement. If multiple options match then the first one is selected: label= labelPattern matches options based on their labels, i.e. the visible text. • label=regexp:^[Oo]ther value= valuePattern matches options based on their values. • value=other id= id matches options based on their ids. • id=option1 index= index matches an option based on its index (offset from zero). • index=2
  • 22. Check Commands Used to verify the state of the application Can check the value of a form field, presence of some text, the structure of the HTML, or the URL of the page. All checks can be used in two modes: “assert” or “verify” Assert failures cause the test to be aborted Verify failures are recorded but the test continues Tip: A good practice is to Assert that you are on the correct page and then Verify the contents of the page.
  • 23. String Matching with Check Commands Selenium supports various pattern syntaxes for matching string values: glob: pattern Match a string against a &quot;glob&quot; pattern. &quot;Glob&quot; is a kind of limited regular-expression syntax typically used in command-line shells. In a glob pattern, &quot;*&quot; represents any sequence of characters, and &quot;?&quot; represents any single character. Glob patterns match against the entire string. regexp: regexp Match a string using a regular-expression. The full power of JavaScript regular-expressions is available. exact: string Match a string exactly, verbatim, without any of that fancy wildcard stuff.
  • 24. Common Checks: assertTitle assertTitle(titlePattern) Verify the title of the current page
  • 25. Common Checks: assertValue assertValue(elementLocator, valuePattern) Verify the value of an input field (or anything with a value parameter) For checkbox/radio elements the value will be “on” or “off” depending on if it is checked or not
  • 26. Common Checks: assertAttribute assertAttribute(elementLocator@attributeName, valuePattern) Verify the value of an element attribute. Great for testing CSS style sheet tags!
  • 27. Common Checks: assertTextPresent assertTextPresent(text) Verify that some text shows up somewhere in the HTML. The inverse is of course assertTextNotPresent(text)!
  • 28. There are many more commands, but that’s enough to get started!
  • 29. Isn’t there an easier way then writing the HTML by hand?
  • 30. Selenium IDE Firefox Plugin, requires Firefox 1.5 Available from http://www.openqa.org/selenium-ide/ More then just a recorder, it’s also a great editor for your tests. Tip: Quickly build the skeleton of your test by using the recorder, then go back and add your verify checks manually.
  • 31. Now how do we do load testing?
  • 32. The Grinder Java based load testing framework. Requires J2SE 1.3. Licensed under a BSD-style open source license. Support for testing HTTP based services as well as others such as SMTP, FTP, and JDBC. Comes with a plugin to facilitate recording HTTP test scripts in Jython. “ The Grinder 3” is the recommended version to use http://grinder.sourceforge.net/ FYI: the official name is “The Grinder” not “Grinder”!
  • 33. What you need to know You don’t need to know either Java or Python! Basic shell/batch scripting to get tool started Configuring path statement and environmental variables
  • 34. The Grinder Design Goal: Minimize system resource requirements while maximizing the number of test contexts (“virtual users”) Multi threaded, multi process implementation. Each test contexts runs in it’s own thread. Threads can be split over many separate processes depending on the capabilities of the agent machine Distributed Very simple to set up multiple agents and coordinate and monitor their activity Console app can centrally manage tests and deploy them to the agents. Console starts and stops the agents.
  • 35. Generating Grinder script from Selenium Test 1) Setup Firefox to use as proxy “localhost:8001” 2) Start up Grinder’s TCP Proxy 3) Replay script using Selenium IDE Note: Make sure to turn off caching in Firefox so you get all the requests recorded! Make sure in Firefox’s Proxy page localhost is set to proxy! Use Proxy filter to control what gets recorded!
  • 36. Getting Grinder Installed One controller and two agents
  • 37. You’ve got Questions? I’ve got Answers! Email me at epugh@opensourceconnections!

Editor's Notes

  • #2: Title slide
  • #3: General slide (not title slide)