🎧 New: AI-Generated Podcasts Turn your study notes into engaging audio conversations. Learn more

Chapter 1 - An Overview of the Visual Basic.pdf

Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...

Full Transcript

Chapter 1 An Overview of the Visual Basic.NET Language This chapter presents an overview of the syntax and primary constructs of the Visual Basic.NET (VB.NET) language for programmers unfamiliar with VB.NET. This is not a tutorial chapter, however, so if you are new to programming yo...

Chapter 1 An Overview of the Visual Basic.NET Language This chapter presents an overview of the syntax and primary constructs of the Visual Basic.NET (VB.NET) language for programmers unfamiliar with VB.NET. This is not a tutorial chapter, however, so if you are new to programming you should study another text on VB.NET before continuing with this course. If, though, you are coming to VB.NET from some other language, such as C++ or Java or even Visual Basic 6, you should read through this chapter to familiarize yourself with the language..NET Programs There are two ways to build programs in VB.NET. One is to use the Visual Studio.NET Integrated Development Environment (IDE). The other is to use the command-line compiler packaged as part of the.NET Framework Software Development Kit (SDK). In this section, we’ll discuss developing programs with the IDE. We are now writing a program in a high-level language (such as Visual Basic), a compiler creates an executable.EXE file (called an assemble), and you run that.EXE file. Even very simple programs, if they are designed to do something interesting, such as a perform output, will require the program employ the services of library code. A large library called the.NET Framework Class Library comes with.NET, and you can use all of the services of this library in your programs. VB.NET Program Types With VB.NET, you can write many kinds of programs. A VB.NET program that makes use of a graphical user interface (GUI) is a Windows application. A VB.NET program that uses the command-prompt console for input and output is called a Console application. You can also write Internet applications, Windows Services applications, and other types of applications. In this course we will focus on Console and Windows applications and in the last chapters, we will be creating a Database Application. A Brief Description of Visual Basic 2017 Visual Basic is a third-generation event-driven programming language first released by Microsoft in 1991. The final version of the classic Visual Basic was Visual Basic 6. Visual Basic Prepared by: Mr. Michael R. Lacar, MIT 6 is a user-friendly programming language designed for beginners. Many developers still favor VB6 over its successor VB.NET. In 2002, Microsoft released Visual Basic.NET (VB.NET) to replace Visual Basic 6. Thereafter, Microsoft declared VB6 a legacy programming language in 2008. However, Microsoft still provides some form of support for VB6. VB.NET is a fully object-oriented programming language implemented in the.NET Framework. It was created to cater for the development of the web as well as mobile applications. Subsequently, Microsoft has released many versions of VB.NET. They are Visual Basic 2005, Visual Basic 2008, Visual Basic 2010, Visual Basic 2012, Visual Basic 2013 , Visual Basic 2015 and Visual Basic 2017. Visual Basic 2017 was released in 2017. It is bundled as a.NET desktop development component Visual Studio 2017. VB2017 can be used to build windows desktop applications using the.NET framework. Besides that, Visual Studio Community 2017 also comes with other Windows development tools that include Universal Windows Platform Development that creates applications for the Universal Windows Platform with C#, VB , JavaScript and C++. On top of that, it also includes Desktop Development with C++. In addition, to cater for the increasing needs of web and cloud-based applications, VS2017 also provides the Web and Cloud development tools that include ASP.NET, Python, Azure SDK, Node.js, data storage and processing, data science and analytical applications as well as Office/SharePoint development. Furthermore, VS2017 also cater for the development of mobile applications by including the mobile and gaming tools like mobile development with.NET, game development with Unity, mobile development with JavaScript, mobile development with C++ and game development with C++. With the mobile development and gaming tools, you can build IOS and Android mobile apps and mobile games. You can download Visual Studio 2017 from the following link: https://visualstudio.microsoft.com/vs/older-downloads/ Figure 1. Visual Studio Community 2017 After downloading the file, run the VS2017RC community installer file. If you receive a User Account Control notice, click Yes. Next, it will ask you to acknowledge the Microsoft License Terms and the Microsoft Privacy Statement, as shown in Figure 2. Click Install to continue. Prepared by: Mr. Michael R. Lacar, MIT Page 2 Figure 2. Software License Terms You will see several status screens that show the progress of the installation. After installation completed, you can select the feature set that you want, as shown in Figure 3. Since we are keen on developing Visual Basic 2017 desktop app, we will select the.NET desktop development component. Besides that, you might want to install a language by clicking the Language packs. After making your selections, click install. Figure 3. VS2017 Workload Upon completion of the installation, you can start programming in Visual Basic 2017. Writing a Console Application Let’s look at the example of a simple VB.NET program, a program that does calculate area of a rectangle. Prepared by: Mr. Michael R. Lacar, MIT Page 3 Module SimpleCalc Sub Main () Dim base As Integer = 20 Dim height As Integer = 5 Dim area As Integer area = base * height Console.WriteLine(“Area = {0}”, area) End Sub End Module A module is one of the possible packages into which we can write code that we want to compile and execute. Another package we can use is a class. Generally, though, we want to save the use of classes for defining our own custom types, so we’ll use modules for writing Console applications in this course. Modules are begun with the Module keyword and are closed with the line End Sub. The first line inside the Module definition defines a subroutine called Main. This subroutine is the entry point of the application, and the compiler will report an error if Main is not found somewhere in a module or class. If you are using a class rather than a module as the packaging for your application, Main must be defined as a Shared method, which means that the class does not have to be instantiated for the code to be executed. We’ll explain later in the course what we mean by a Shared method. Main must be closed with the line End Sub. Data Types and Variables VB.NET contains the standard data types for storing numeric, string, character, and object values, as well as special data types for times, dates, and monetary values. The primary data types in VB.NET are the following: Boolean True or False Byte 0–255 (unsigned). Char 0–65535 (unsigned). Date A date and time combination. Decimal 0 through ±79,228,162,514,264,337,593,543,950,335 with no decimal point; 0 through ±7.9228162514264337593543950335 with 28 places to the right of the decimal; smallest nonzero number is ±0.0000000000000000000000000001 (±1E−28). Double −1.79769313486231570E+308 through −4.94065645841246544E−324 for negative values; 4.94065645841246544E−324 through 1.79769313486231570E+308 for positive values. Integer −2,147,483,648 through 2,147,483,647. Long −9,223,372,036,854,775,808 through 9,223,372,036,854,775,807. Object Any object Short −32,768 through 32,767. Single −3.4028235E+38 through −1.401298E−45 for negative values; 1.401298E−45 through 3.4028235E+38 for positive values. String 0 to approximately 2 billion Unicode characters. Structure A user-defined type built from other data type components. Prepared by: Mr. Michael R. Lacar, MIT Page 4 Variable Declaration Variables are declared using the Dim keyword. For example, Dim mySalary As Integer Dim empID As String The reason we use the Dim keyword when declaring a variable dates back to the early days of the Basic language. In those days, variables did not have to be declared; they could just pop into existence when needed. Arrays, however, had to declared first with the dimension of the array. The Dim keyword, then, identified a variable as an array and not just a plain variable. The use of Dim has continued through the many different versions of the language right up to VB.NET. Multiple variables of the same type can be declared on the same line by separating each variable with a comma, like this: Dim num1, num2, num3, num4 As Single Initializers An initializer is a variable declaration in which a value is also assigned to the variable. Initializers are new to VB.NET, although many other languages have them. Here are some examples of initializers: Dim salary As Integer = 35000 Dim lastName As String = "Durrwood" Named Constants A named constant is a variable whose value is assigned when it is declared and whose value cannot be changed. Named constants are often called “magic” values because they are usually used to represent important and/or frequently used values in a program. Named constants are declared with the Const keyword. Here are some examples: Const PI As Single = 3.14159 Const GREETING As String = "Hello, there." Const LOGIN_CODE As String = "letmein" It is a common programming practice, though not a requirement of the VB.NET compiler, to use all uppercase letters when declaring a named constant. This helps these “magic” values stand out in your code so that they’re easier to find. Implicit Type Conversions and the Option Strict Switch There are two ways to perform data type conversions in VB.NET. One way is to simply let the compiler do it for you. This is the easiest way and the one that is most likely to lead to both subtle and not-so-subtle errors in your programs. As an example, let’s look at a simple code fragment that converts a Single value to an Integer: Dim pi As Single = 3.14159 Dim intPi As Integer = pi Prepared by: Mr. Michael R. Lacar, MIT Page 5 Because intPi is an Integer variable, when it is assigned the value of pi the compiler assigns the value 3 to the variable. This is called a narrowing conversion because the value 3.14159... is “narrowed” to 3 to fit in an Integer variable. There are also widening conversions. When an Integer value is stored in a Single or Double variable, the value increases in size (widens) to hold the places to the right of the decimal point. Consider the following code fragment: Dim intVal As Integer = 3 Dim dblVal As Double = intVal Here an Integer variable storing the value 256 is assigned to a Double variable, so that the value 256.0 is stored in the Double. These types of conversions are called implicit conversions because the compiler performs the conversion behind the scenes. Although implicit conversions are allowed, as just shown, that’s not to say we should prefer allowing the compiler to make conversions for us. There will be situations when implicit conversions are made that are not what we want to happen, leading to logical errors or worse. The VB.NET compiler allows implicit conversions to take place when the Option Strict switch is off. This switch tells the compiler whether or not to perform strict type checking. When Option Strict is off, implicit conversions will be performed; when Option Strict is on, a design-time error is flagged when an implicit conversion is attempted. Most, though certainly not all, programmers consider it good programming practice to set the Option Strict switch on so that any conversions that take place must be explicitly performed using a conversion function. The Option Strict switch is set by writing either Option Strict On or Option Strict Off at the beginning of your program. In fact, the statement must precede any declarations or Imports statements, like this: Option Strict On Imports System Module Module1 Sub Main() ' Code here End Sub End Module One more word of caution on leaving the Option Strict switch off. It can lead to slower code. A simple example will illustrate the problem: Dim n As Object Dim names As String For Each n In NameList names & = n & "," Next In this code, NameList is an ArrayList that holds a list of names. The loop builds a comma- delimited string of the names in the ArrayList. With Option Strict off, this code compiles and runs because the compiler will convert each value of n to a String before appending it to names. And that’s the problem with leaving Option Strict off. Each conversion will take more time than necessary because the compiler has to perform a test of the data types and then perform the conversion. An explicit conversion via a conversion function will speed this up considerably. In the next section we’ll examine how to perform explicit type conversions using VB.NET’s type conversion functions. Prepared by: Mr. Michael R. Lacar, MIT Page 6 Type Conversion Functions VB.NET has a full set of built-in conversion functions for performing explicit type conversions. The following list shows each function and the type converted to: CBool: Boolean CByte: Byte CChar: Char CDate: Date CDbl: Double CDec: Decimal CInt: Integer CLng: Long CObj: Object CSng: Single CStr: String Now let’s look at some examples: Salary = CInt(Console.ReadLine()) ' Converts console ' input to Integer ' value Salary = CInt(txtSalary.Text) ' Does the same with a ' textbox taxRate = CDbl(5) There are many other type conversions you can perform that are not as intuitive as these. For example, you can convert from a Boolean value to a String. The Boolean values True and False become “True” and “False” after the conversion. You can convert an Integer to Boolean— zero converts to False and a nonzero value converts to True. Arrays There are many times when you need to store related values within one variable name. Since regular variables only allow you to store one value in them at a time, you have to use something else—an array. An array is a variable that stores multiple values of the same data type. Each value in an array (also called an element) is indexed by number. Arrays are created by specifying an array name, the number of elements to store, and the data type of the elements. The general form for an array declaration is Dim array-name(n) As Data-type Here are some array declaration examples: Dim grades(9) As Integer Dim names(39) As String Dim averages(99) As Single In VB.NET, as in of most other languages, the first index of an array is 0. For that reason, the number you use to declare the size of an array should always be one less than the total number of elements you want to store in the array. In the preceding examples, the grades array stores 10 elements, the names array stores 40 elements, and the averages array stores 100 elements. Prepared by: Mr. Michael R. Lacar, MIT Page 7 An alternative way to declare an array is to provide an initialization list, which is a list of values to store in the array. The values are separated by commas and surrounded within curly braces. Here is an example: Dim grades() As Integer = {65, 72, 83, 97} The compiler automatically sizes the array based on the number of items in the initialization list. Putting a number inside the parentheses after the array name will lead to an exception. Array objects are treated like class instances in VB.NET. There is a set of methods associated with arrays you can use in your programming. One of the most useful of these methods is GetUpperBound. This method returns the last index number (referencing the last element) in an array. You can use this method when looping through an array, which is demonstrated later in this chapter when we discuss repetition statements. There are also array methods that perform tasks that used to take specially written code to perform, such as sorting an array and reversing an array. The two methods for these operations are Sort and Reverse. Here’s an example: Imports System Module Array Sub Main() Dim names() As String = {"Mike", "Francis", "Ed", _ "Joan", "Terri"} names.Sort(names) Dim name As String For Each name In names Console.Write(name & " ") Next names.Reverse(names) Console.WriteLine() For Each name In names Console.Write(name & " ") Next End Sub End Module Multi-dimensional Arrays Arrays are not limited to one dimension. You can create arrays of multiple dimensions, though it is uncommon to see arrays of more than three dimensions. The most common multidimensional arrays are two-dimensional arrays that model a table of data. A two-dimensional array creates a set of data in the form of rows and columns. The rows make up the first, or 0th, dimension of the array, and the columns make up the second, or 1st, dimension of the array. The general form of a two-dimensional array declaration is Dim array-name(rows, cols) As Data-type For example, the following code declares an Integer array with five rows and six columns: Dim nums(4,5) As Integer You can also use an initialization list in a two-dimensional array declaration. Each dimension is delimited by curly braces and separated from each other by a column. Here’s an example: Dim grades(,) As Integer = {{76, 83, 91}, {100, 75, 66}} Within the parentheses is a single comma. This comma indicates to the compiler that the array should be created with two dimensions. An array created with three dimensions would have two commas. Prepared by: Mr. Michael R. Lacar, MIT Page 8 Array Element Access Array elements are accessed by referencing their position in the array by index number. For example, the 0th element of a single-dimensional array named grades is accessed like this: current_grade = grades(0) Accessing an element in a two-dimensional array is similar: current_grade = grades(1, 3) ' Accesses grade in second ' row, fourth column You can assign data to an array element in the same way: grades(0) = 82 grades(1,3) = 94 Arithmetic, String, and Relational Operators VB.NET provides a full set of operators for performing arithmetic, operations on strings, and other processes. In this section we’ll review these operators. Arithmetic Operators The arithmetic operators are the following: + (addition) - (subtraction) * (multiplication) / (division) \ (integer division) Mod (modulo) The first four operators should be familiar to you. We will not discuss them here. The last two operators, however, might be new to those who don’t have much of a mathematics background. When one operand is divided by a second operand using the integer division operator, the result is rounded up to the integer nearest zero. The modulo operator, in contrast, returns the remainder of the division of two operands. Next, we look at some examples using these operators. result = 4 \ 2.25 ' result is assigned the value 2 result = 23 mod 2 ' result is assigned the value 1 String Operators There are two string operators in VB.NET and they both perform the same operation— concatenation. These operators are the ampersand (&) and the plus sign (+). Generally, you should choose the ampersand when performing string concatenation in order to make your intentions obvious but be aware that using the plus sign will work also. Here are some examples: Dim new_string As String Dim string1, string2, string3 As String string1 = "Object-Oriented Programming " string2 = "With Visual Basic.NET" Prepared by: Mr. Michael R. Lacar, MIT Page 9 new_string = string1 & string2 new_string = new_string & " Edition " + "1" Console.WriteLine(new_string) The value of new string is “Object-Oriented Programming With Visual Basic.NET Edition 1”. If you remove the quotes from “1”, an error results because the + sign is defined only for concatenation when a string is one of the operands. Special Relational Operators and Logical Operators VB.NET features the normal complement of relational operators necessary for modifying the control flow of a program and for performing comparisons between two operands. These are discussed below when we discuss branching statements. There are also some special relational operators used with reference types in VB.NET. These special relational operators are: Is (For testing reference types for equality) TypeOf... Is (For testing to see if a reference type is a particular type) Like (For string comparisons using pattern matching) The Is operator is used to test the equality of reference objects. Quite often, the Is operator is used to determine if a reference object has been “dereferenced” or set to Nothing. The TypeOf... Is operator is used to determine if a reference object is a specific type. The program below demonstrates how these operators are used: Module Module1 Public Class Name Private first As String Private last As String Public Sub New() first = "" last = "" End Sub End Class Sub Main() Dim myName As New Name() If (TypeOf (myName) Is Name) Then Console.WriteLine("Object is a Name type") End If myName = Nothing If (myName Is Nothing) Then Console.WriteLine("Object is now nothing.") End If Console.Read() End Sub End Module The Like operator performs pattern matching on strings in order to perform “close matches.” For example, if you need to determine if a string begins with a certain two characters, but can contain any other characters after those two, you can write a statement like this: If (name Like "Mi*") Then... The rules for determining matches using the Like operator are as follows: The ? character matches any single character. The * character matches zero or more characters. The # character matches any single digit. Prepared by: Mr. Michael R. Lacar, MIT Page 10 The [ ] brackets indicate that any characters withing the brackets match any single character. Branching Statements There are two statements used for branching in VB.NET: the If statement and the Select Case statement. In this section, we’ll look at the various ways you can form an If statement and then look at how to perform more structured branching using the Select Case statement. The If Statement Branching is the term used for altering the flow of a computer program based on testing a value or set of values. For example, when writing a program that calculates a company’s payroll, the program should perform one set of calculations if an employee has worked forty hours or less and the program should perform a different set of calculations if an employee has worked more than forty hours. Branching is most commonly performed in VB.NET with the If statement. The most common form of an If statement is: If (expression) Then Statement body End If The expression inside parentheses is always an expression that evaluates to True or False. The expression is usually formed using one or more of the following relational operators: > (greater than) >= (greater than or equal to) < (less than) 40) (salary = 35000) (myName yourName) Relational expressions can be combined using one of the logical operators. These operators are used to combine two or more relational expressions that evaluate to one truth value. The logical operators are: And Or Not Here are some examples of relational expressions combined with logical operators: (hours > 40) Or (salary > 22000) (pwd = "Guess") And (id = "Admin") Not (time = 1300) When the expression tested by an If statement is True, the statement(s) inside the body of the If are executed. If the expression is False, the statement body is skipped and control passes to the line after the end of the If statement. Here’s an example: Prepared by: Mr. Michael R. Lacar, MIT Page 11 hours = 42 If (hours > 40) Then pay = (hours * (salary * 1.5)) End If Often, when writing an If statement, you want to perform one set of operations if the expression is True and another set of operations if the expression is False. To do this, use the If–Else form of the If statement: If (expression) Then Statement body Else Statement body End If We can use this form of the If statement in the previous example to calculate an employee’s pay based on how many hours he or she worked: If (hours > 40) Then pay = hours * (salary * 1.5) Else pay = hours * salary End If If statements can be nested inside other If statements if necessary, though this often leads to logic that is hard to understand. Here’s an example extending the payroll code we’ve been looking at: If (hours > 40) Then If (hours >= 50) Then pay = hours * (salary * 2.0) Else pay = hours * (salary * 1.5) End If Else pay = hours * salary End If If an employee’s hours are greater than 40 and the hours are greater than or equal to 50, then the employee is paid double time. If the hours are just greater than 40, then the employee is just paid time and a half. If neither of these are true, then the employee is just paid for regular time. There is one final form of the If statement you can use when there are many possible choices to test. This form is the If–ElseIf: If (expression) Then Statement body ElseIf (expression) Then Statement body ElseIf (expression) Then Statement body Else Statement body End If Each expression is tested in order. If the first expression is True, then the statement body for that expression is executed and control passes to the statement after the End If statement. If the first expression is False, then the second expression is tested. If it is True, then the statement body is executed and control passes out of the If statement. This continues until there are no more expressions to test. If no expressions are True and there is an Else clause, Prepared by: Mr. Michael R. Lacar, MIT Page 12 the statement body within the Else is executed. Otherwise, the If statement is finished executing and the program continues. Here’s some code using the If–ElseIf form: If (hours < 20) Then pay = hours * salary ElseIf (hours > 20) And (hours 40) Then pay = hours * (salary * 1.5) pay = pay - deductions End If Short-Circuiting When you combine two logical expressions with a logical operator, the compiler follows the standard “truth table” rules for determining whether the entire expression is True or False. For example, the expression (12 < 23) Or (33 < 100) is True because the first expression is True, making the whole expression True. Since only the first expression need be tested in an Or expression, it makes sense to design the logical operators so that they’ll recognize this situation and return True as soon as the compiler recognizes the operator to be Or and that the first expression is True. This is called short-circuiting, and VB.NET has two special logical operators for short-circuiting: AndAlso and OrElse. Let’s look first at OrElse. Here, if the first expression evaluates to True, the compiler can assign True to the complete expression and move on, as in the following example: Dim grade1 As Integer = 92 Dim grade2 As Integer = 100 If (grade1 > 90 OrElse grade2 > 90) Then Console.WriteLine("Exempt from final.") End If The compiler doesn’t have to test the expression grade2 > 90 since grade1 > 90 is True. If the value of grade1 is less than 90, making the first expression False, then the compiler must continue on to test the second expression. The AndAlso operator works similarly, but with different rules, of course. Here’s a code fragment that demonstrates how AndAlso works: Dim FirstName As String = "" Dim LastName As String = "Lennon" If (FirstName "" AndAlso LastName "") Then Console.WriteLine("Name section complete.") Else Console.WriteLine("Name section incomplete. Please _ finish.") End If The output from this code is Name section incomplete. Please finish. Prepared by: Mr. Michael R. Lacar, MIT Page 13 because the first expression in the If statement is False. The second expression is not even tested since both expressions must be True for the whole expression to be True. The Select Case Statement When you have a long series of expressions to test, a more structured way to write the code is to use a Select Case statement. The general form of the Select Case statement is Select Case value Case (expression 1) Statement body Case (expression 2) Statement body Case (expression n) Statement body Case Else Statement body End Select The value at the beginning of the statement can be any expression that evaluates to a value. Each Case clause then tests an expression against the value, evaluating to either True or False. If True, the statement body inside the Case clause is executed and control is passed to the first statement after the Select Case statement; if False, the next Case clause is evaluated. If none of the expressions evaluate to True, and there is a Case Else clause, the statement body inside the clause is executed. If there is not a Case Else clause, and none of the expressions evaluate to True, control transfers to the first statement outside the Select Case statement. Let’s look at an example of using a Select Case statement. The following code fragment assumes a value has been assigned to the variable grade: Select Case grade Case 90 To 100 Console.WriteLine("You made an A!") Case 80 To 89 Console.WriteLine("You made a B!") Case 70 To 79 Console.WriteLine("You made a C.") Case 60 To 69 Console.WriteLine("You made a D.") Case Is < 60 Console.WriteLine("Sorry. You failed.") Case Else Console.WriteLine("Bad input.") End Select There are many different ways to test the value in the Select Case statement. One way, as just shown, is to use the To keyword to express a range of values that the tested value can fall within. You can also write out individual values, separating them with commas, like this: Case 96, 97, 98, 99, 100 Console.WriteLine("You made an A+!") Case 90 To 95 Console.WriteLine("You made an A!")... You can use a relational operator in the Case clause, as we did in the earlier example to test for a failing grade. Here is another example, where all we’re looking for is a passing or a failing grade: Imports System Prepared by: Mr. Michael R. Lacar, MIT Page 14 Module SelectCase Sub Main() Dim grade As Integer Console.Write("Enter your grade: ") grade = CInt(Console.ReadLine) Select Case grade Case Is >= 60 Console.WriteLine("You passed!") Case Is < 60 Console.WriteLine("Sorry, you failed.") Case Else Console.WriteLine("Bad input.") End Select End Sub End Module The Select Case statement should be used whenever you would have to write a very long If– ElseIf statement or whenever you want your branching code to be as readable as possible. Repetition Statements Another way the flow of control of a computer program can be altered is with repetition. Repetition allows a set of statements to be executed several times in succession, in essence executing the statements in a loop. There are several different types of looping statements in VB.NET. We will divide them into two categories—While loops and For loops. The While Statement The While statement loops through a set of statements “while” a tested expression is True. The loop only stops when the expression becomes False. The general form of a While statement is While (expression) Statement body End While Let’s look at an example. If we want to determine how fast a city’s population will grow over a period of years at a certain growth rate, we can do so with a While statement. Here’s the code: Imports System Module Loops Sub Main() Dim growth As Single = 1.03 Dim population As Single = 150000 Dim numYears, start As Integer start = 1 Console.Write("Enter the years of growth: ") numYears = CInt(Console.ReadLine) Console.WriteLine("The current population is: " & _ population) While (start

Use Quizgecko on...
Browser
Browser