Scala Tutorial for Beginners

In this Tutorial article, we will see how to work with Scala Programming language, which is similar to Java but has got lot more advancements, as it was designed to overcome the pitfalls/shortcomings of Java programming language.

According to Wikipedia, the definition of Scala Programming language goes as follows.

Scala (SKAH-lah) is a general purpose programming language. Scala has full support for functional programming and a very strong static type system. Designed to be concise, many of Scala’s design decisions were inspired by criticism of the shortcomings of Java.

Scala source code is intended to be compiled to Java bytecode, so that the resulting executable code runs on a Java virtual machine. Java libraries may be used directly in Scala code and vice versa (language interoperability). Like Java, Scala is object-oriented, and uses a curly-brace syntax reminiscent of the C programming language. Unlike Java, Scala has many features of functional programming languages like Scheme, Standard ML and Haskell, including currying, type inference, immutability, lazy evaluation, and pattern matching.

Pre-requisite: The readers are expected to know the basics of Java Programming.

The following table shows an overview of the entire article:

1. Environment

The examples in this article are executed in the Command Prompt / Shell with the Scala Interpreter. But they are guaranteed to work with any of the IDEs (like Eclipse – Scala IDE, IntelliJ IDEA etc.,) through the respective plugins. The examples are executed with the Scala Version: 2.11.7 in Windows 7.

Let us first download and install Scala in our desktop. To download the latest version of Scala for your Operating System, please refer this link. It is a straight forward installation like any other executable. You may please follow the instructions if any for your Operating System. This will set the %SCALA_HOME%/bin directory of Scala to the PATH environment variable, for us to start working with the Scala programs.

2. Hello World in Scala

Let us write some Scala code to see the typical, popular Hello, World in Scala. We have two ways to do that. First is the Scala Interpreter which is a REPL, and another is the usual way of saving the code in a file and compiling and executing it afterwards. We will see both of them here.

2.1 Hello World in REPL Interpreter

Scala Interpreter is a REPL (Read-Evaluate-Print-Loop) Interpreter, in which you can execute the quick one liners and scripts without any underlying class structure as an accompanying barebone skeleton as in few of the programming languages like C, C++ and Java. This is an advantage for evaluating the programming language and its constructs thereby you can save time. You use this REPL interpterter for your instant results.

To be doubly sure, let us verify whether Scala installed in our machine correctly, by seeing the %SCALA_HOME% environment variable.

C:\Users\Raghs> echo %SCALA_HOME%
C:\Program Files (x86)\scala

As you see, Scala has been installed in the C:\Program Files (x86)\scala directory successfully. This could vary in your machine depending on the type of Operating System you have.

2.1.1 Starting the Interpreter

For using this REPL interpreter, you need to open the Command Prompt/Terminal and execute the command scala. If your installation was successul and your PATH environment variable has an entry to the %SCALA_HOME%/bin directory, the command prompt / terminal will now prepare the Scala Interpreter ready for you to listen to your commands as follows.

Welcome to Scala version 2.11.7 (Java HotSpot(TM) 64-Bit Server VM, Java 1.7.0_80).
Type in expressions to have them evaluated.
Type :help for more information.

After we executed the command scala, the Scala interpreter was invoked and has printed a Welcome message by displaying the version of Java and the Virtual Machine details.

Please remember that Scala code is executed on JVM (JRE) only. The actual code/script in Scala, will finally be executed on top of JVM , like a Java program. Hence, we could typically use the Java libraries directly in our Scala code. This is called language interoperability

2.1.2 Working with the Interpreter

Now, let us actually type the Hello, World in the Scala Interpreter to see in action.

scala> "Hello, World"
res0: String = Hello, World

scala> println("Hello, World")
Hello, World

scala> "Hello, World"
res1: String = Hello, World

scala> "Hello, World".getClass().getName()
res2: String = java.lang.String

scala> res1
res3: String = Hello, World

scala> res2
res4: String = java.lang.String

It was a very simple command we passed to the REPL Shell/Interpreter. We tried in two ways. The first one was the literal string “Hello, World” passed as double quotes surrounded String. The second command invocation to print the same Hello, World but with the println() method.

It was considered as an expression being evaluated. Hence the interpreter printed the result with an identifier along with a prefix res0: meaning result 0 → the 0th index of result entries. You can see the subsequent invocations (starting from 3rd and 4th commands) have the result printed with res1: and res2:. The 3rd command was the same command repeated but to show that the REPL Interpreter treats every command as a separate command and prints with the next result quotient – res1:. The 4th command is to invoke some methods on the command line. The command printed the result with res2:. Likewise any subsequent expressions will be printed with the results alongwith the incremented index of res.

The interesting part is the you can directly use the result names as a variable for the subsequent operations, as Scala Interpreter stores the result entries in the memory as long as the REPL Interpreter is running. You can see this in action in the last 2 invocations where in res1 and res2 were directly used like a variables and the interpreter printed the corresponding values then and there.

2.1.3 Exiting from the Interpreter

Once we are done with our work, it is always good to exit the interpreter in a normal way. To do so, you may please enter :q to quit and exit from the Interpreter and come back to the normal Command Prompt / Terminal.

scala> :q


2.2 Hello World in Scala file

As we saw earlier, the commands and expressions entered in the REPL interpreter were shortlived and once you exit from the Interpreter, you can’t get them back. If we need to work with our scripts/code any number of times in future, it is better to get the Source code saved in a file much like a Java program.

Typical to how a Java program will be saved as <fileName>.java and we use javac <fileName>.java to compile the source code to get a class file named <fileName>.class and we use the Java interpreter to execute the binary file as java <fileName>, we have the counter parts for Scala file as well.

We save the source file name as <fileName>.scala and use scalac <fileName>.scala to compile the source code and scala <fileName> to execute the binary class file. We will see them in action for the same Hello World scala program below.


object HelloWorld {
   def main(args: Array[String]):Unit = {
      println("Hello, World");

The structure is more like a Java program, where we define a main() method that takes an array of String as an argument (which will be accepted from Command Line) and it is encapsulated inside the skeleton namedHelloWorld. Please note that object is a keyword in Scala that helps us to easily create a Singleton instance – meaning only one instance of a class inside a JVM.

A method in Scala is defined using the keyword def and the parameter is declared with its type with the colon after the parameter name accompanied with the Data type. Here you see, the parameter named args is of type Array of Strings. The return type is specified at the end of the method declaration, which is here Unit – one of Scala’s data types. The method definition is separated here with a = sign with a set of curly braces { and }.

The only executable statement in the main method was printing the literal String “Hello, World” to console by invoking the println() method.

Please note that the semicolon is optional for each executable statement in Scala, unlike in a Java program.

Let us now compile and execute the above scala program. It is fairly straight forward as given below.

C:\Users\Raghs> scalac HelloWorld.scala

C:\Users\Raghs> scala HelloWorld
Hello, World

The first command was to invoke scalac, the Scala compiler to get our source code compiled into a .class file. If the compilation was successful, it simply returns to the command prompt without any text being displayed on the console. The second command was to invoke scala, the Scala Interpreter to execute the compiled class file. As per the program, it displayed Hello, World on the console.

3. val Vs var in Scala

Let us understand the very significant and important keywords in Scala. They are val and var. As you might have guessed, they are the identifiers for denoting the ability to change the value of variables at a later point time in the source code/ script.

var indicates an mutable nature of the varaible’s value. That is a varaible’s value can be changed later after the inital declaration whereas val indicates an immutable nature of the variable’s value, which is like a final keyword in Java.

var is like varying value for a variable, whereas val is like variable + final to restrict the subsequent changes if any to a variable in the Program.

Let us see them in action in REPL interpreter

C:\Users\Raghs> scala

scala> var s = "Hello World"
s: String = Hello World

scala> s = "Hello Scala"
s: String = Hello Scala

scala> val c = "Hello, World"
c: String = Hello, World

scala> c = "Hello Scala"
:11: error: reassignment to val
       c = "Hello Scala"

scala> c = "Hello, World"
:11: error: reassignment to val
       c = "Hello, World"

As you see, in the above executions, at first we declared a variable s of type var. We initialized the variable s with a String literal “Hello, World” and the REPL interpreter printed the result of the expression, which in this case is the same string literal. Later, at step 2, we reassigned the varaible s with a different value “Hello Scala”, which was perfectly valid and legal because it was a var. Hence the second expression was allowed and printed the result, which was the latest value of s.

However, the 3rd, 4th and 5th invocations show us a different set of results. The 3rd statement attempts to declare a variable c of type val, with an initial value “Hello, World”. The scala REPL interpreter printed the result of the expression, as like any other String literal in the console. However, at the 4th invocation, we attempt to reassign another value which is not allowed being the variable of type val. Hence, the REPL interpreter showed an error indicating that reassignment to val is not permitted. It is also helpful by indicating which line and position the error had occurred with an upward arrow key in the next line indicating the position.

5th expression was to indicate that it was not just a different/new value but even the same value being assigned again will throw the same error of reassignment to a val. This was because of the fact that the variable of type val is not allowed to have an assignment further once it is assigned with a value during its declaration.

4. Working with Strings

Scala treats a String as an array of characters. It has got several methods on its own and it allows us to use the methods from the Java API classes like String, StringBuilder etc.,

Let us play around with the Scala REPL interpreter on Strings and its methods. The following expressions (or code snippets) are self explanatory.

scala> "Hello, World".getClass.getName
res0: String = java.lang.String

scala> val s = "Hello, World"
s: String = Hello, World

scala> s.length
res1: Int = 12

scala> "scala".foreach(println)

scala> "scala".drop(2)
res0: String = ala

scala> "scala".take(2)
res1: String = sc

scala> "scala".drop(2).capitalize
res2: String = Ala

scala> "scala".take(2).toUpperCase
res3: String = SC

As you see, we have got several method on String related classes like StringLike, StringOps etc., in Scala Library like drop and take, which are useful to delete or get the characters upto the index passed. We also have methods named foreach to ietrate each character at a time in a String, capitalize which will make the first character of the String to be in upper case.

We could also use the String class methods from Java API – like length() and toUpperCase. Please note that the parantheses are optional in the REPL interpreter.

The methods can be chained – meaning the methods can be invoked one after another in a way that result of executing one method will give the return value as an input to the next method – ie., the method on the right. The last two examples show the same. The drop method leaves the 2 characters from the left (0th index) and the remaining characters are passed on to the next method on the right capitalize which converts the first character (char at 0th index) to be in upper case, which in our case is “A” (“SC” dropped from the initial input string “scala”). The same way, the toUpperCase method was invoked on the result of invoking take(2) on the initial input string “scala”.

You can see the API methods in StringLike class methods in Scala API. The Web page has a good set of options for filtering, searching a specific package, class, method etc.,

Let us see some String examples like String Concatenation, String Comparison, Null check etc.,

scala> val s1 = "Hello"
s1: String = Hello

scala> val s2 = "Hello"
s2: String = Hello

scala> val s3 = "H" + "ello"
s3: String = Hello

scala> s1 == s2
res6: Boolean = true

scala> s1 == s3
res7: Boolean = true

scala> val s4:  String = null
s4: String = null

scala> s3 == s4
res8: Boolean = false

scala> s1 == s4
res9: Boolean = false

scala> s1.toUpperCase == s2.toUpperCase
res13: Boolean = true

scala> val s1: String = null
s1: String = null

scala> s1.toUpperCase == s2.toUpperCase
  ... 33 elided

As you see, the first 2 expressions declare two different variables of type String with an initial value “Hello”. The 3rd expression shows a declaration of a String variable with a String concatenation for its initial value “H” + “ello”. The 4th and 5th expressions show the String comparison where both of them are evaluated to true.

The == operator in Scala checks for String content equality, like the equals() method in Java, whereas Java uses == to check the object reference (address in memory).

An interesting thing to note that when you check for the String content equality with one of the Strings being null, Scala does NOT throw a NPE (NullPointerException) like Java. However it checks those constraints at the beginning as a safety measure and prints the result as false. However, please be careful that whenever any other attempt is made on the String contents like toUpperCase, length etc.,, Scala obviously throws a NullPointerException, which is what is shown in the last few code snippets above, where the toUpperCase method was invoked on a null reference S1.

5. Working with Numbers

Scala has the same set of numeric data types as that of Java. They are Char, Byte, Short, Int, Long, Float, Double, Boolean with the same data range/limit for each of the data types. In addition, it has got its own data types like AnyRef, AnyVal, Any etc.,. You can see the list of data types available in Scala website.

We have several methods available in the respective classes bearing the name as Data type listed above. The below code snippets / expressions are self explanatory.

scala> Int.MinValue
res4: Int = -2147483648

scala> Int.MaxValue
res5: Int = 2147483647

scala> Byte.MinValue
res6: Byte = -128

scala> Short.MinValue
res7: Short = -32768

scala> Short.MaxValue
res8: Short = 32767

As you see above, the respective data type classes had the methods minValue and maxValue for getting the lower and higher boundaries for each. The expressions in the scala REPL intepreter were evaluated and printed the results for our information.

Let us have some mathematical operations on numbers in the Scala REPL interpreter.

scala> 1 + 1
res13: Int = 2

scala> "1" + "1"
res14: String = 11

scala> "1".toInt + "2".toInt
res15: Int = 3

scala> "1".toShort + "1".toShort
res16: Int = 2

scala> "1".toByte + "1".toByte
res17: Int = 2

scala> "1".toLong + "1".toLong
res18: Long = 2

As you see above, the first expression was directly evaluated and the result was printed on the console. It was the sum of two numbers 1 and 1 equalling 2. However the 2nd invocation was different – where the numbers were given as String literals and hence the String Concatenation occurred producing a result of 11. If we need to parse and convert the numbers represented as a String, we can use the toInt method for the same. We have similar methods to convert to the different other data types like toByte, toLong, toShort etc., which you see in the last few expressions. These toInt() etc., methods convert the string literal into the corresponding numeric form and apply the mathematical operation to produce the result.

Let us see some negative scenarios where you may get an error while attempting to convert the String literal to a numeric form.

scala> "129".toByte
java.lang.NumberFormatException: Value out of range. Value:"129" Radix:10
  at java.lang.Byte.parseByte(
  at java.lang.Byte.parseByte(
  at scala.collection.immutable.StringLike$class.toByte(StringLike.scala:264)
  at scala.collection.immutable.StringOps.toByte(StringOps.scala:30)
  ... 33 elided

scala> "foo".toInt
java.lang.NumberFormatException: For input string: "foo"
  at java.lang.NumberFormatException.forInputString(
  at java.lang.Integer.parseInt(
  at java.lang.Integer.parseInt(
  at scala.collection.immutable.StringLike$class.toInt(StringLike.scala:272)
  at scala.collection.immutable.StringOps.toInt(StringOps.scala:30)
  ... 33 elided

The first expression was attempting to convert the String Literal 129 to a Byte. However it failed because the Byte value range was only from -128 to 127. Hence you got an error with a meaningful description (see the very first line in the stack trace), which helps us to understand the mistake and take a corrective action. The second expression was obvious where a non-numeric value (actual String value) was attempted to be converted an Integer, which will definitely throw a NumberFormatException.

You can see that the methods toInt, toByte are present in the StringOps class which then further delegated to the toInt() method of the class StringLike. These calls are further stacked up with the Java API method parseInt(), parseByte() of the respective Wrapper classes Integer, Byte.

Let us see some arithmetic operations with REPL interpreter.

scala> var count = 1
count: Int = 1

scala> count ++
:12: error: value ++ is not a member of Int
       count ++

scala> count += 1

scala> count
res27: Int = 2

scala> count = count +  1
count: Int = 3

As you see, the first expression declared a variable of type var count with an initial value of 1. To increment the value with 1, we use the ++ in Java. However in Scala, it is slightly different as it uses += in place. The 2nd expression fails due to the usage of ++ whereas the 3rd expression gets it right. However the evaluation of expression did not yield any result in the console. The 4th expression printed the value of count which is now 2 after the increment operation. The 5th expression shows the usual way to add 1 to the value of a variable. Here the value is explicitly assigned back to the variable, and hence the result (3) is printed on the console.

Please note that the symbols +, -, *, / etc., are the methods in Scala and NOT the operators like in Java.

Because there is no method named += in Int class, we got an error on 2nd expression above.

Let us see how easy to work with a range of numbers in Scala.

scala> val r = 1 to 10
r: scala.collection.immutable.Range.Inclusive = Range(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)

scala> var r = 1 to 10 by 2
r: scala.collection.immutable.Range = Range(1, 3, 5, 7, 9)

scala> for(i <- 1 to 5) println(i)

scala> for(i  for(i <- 1 until 5) println(i)

The first expression above used the construct 1 to 10 to have a range of numbers from 1 to 10. The result shows that the a Range of type scala.collection.immutable.Range.Inclusive was created and assigned to the variable r.

The 2nd expression shows that we can create a range of numbers from 1 to 10 with an incremental value of 2. That is why the resultant Range has the numbers 1, 3, 5, 7 and 9..

The 3rd expression uses a for loop with a range within the paranthesis indicating that 1 to 5 to be used, with a closure that prints each of the value in the range in a separate line.

The 4th expression uses a for loop but with the until which is upto the max value, meaning one lesser than the max boundary. The result printed on the console ranges from 1 to 4 and NOT upto 5.

6. Control Structures in Scala

Like many other high level Programming languages, Scala offers if, if-else, switch, while, for control structures as a control statements and looping statements. We will see the examples for few of them below.

If statement has an expression and if that expression evalutes to true, the statement will be executed.

scala> var num = 2
num: Int = 2

scala> if(num%2==0) println("Even")

scala> if(num%2!=0) println("Odd")

The first expression above assigns the value 2 to a variable named num. The 2nd expression tests for the value of the variable ‘num’ being even and if so, it prints the String “Even” in the console. Since the variable ‘num’ holds the value ‘2’, the condition in the if statement evaluates to true and hence the String “Even” is printed on the console as a result.

If you see the 3rd expression, the if statement checks for the value of the variable ‘num’ for odd number. Since the value 2 is not an odd number, the condition fails but nothing gets printed because the if statement will execute ONLY when the condition evaluates to true.

If-else – helps in cirumstances when we want to handle an alternate situation when the condition inside the if statement does not evaluate to true. See the previous example, it would be good if we have something else printed when the condition not evaluates to true, which otherwise be a return nothing on the console.

scala> if(num%2!=0) println("Odd") else println("Even")

scala> num=1
num: Int = 1

scala> if(num%2!=0) println("Odd") else println("Even")

As you see, the if statement was used with an else to have a different message printed on the alternate. The above examples show the same in action after altering the value of the variable ‘num’ to 1.

scala> val x=10; val y =20
x: Int = 10
y: Int = 20

scala> val max = if(x>y) x else y
max: Int = 20

The first expression above declares two variables x and y in the same line with the values 10 and 20 respectively. The 2nd expression uses an if-else statment to check for the bigger value held by x and y and the chosen value is assigned to the meaningful variable named ‘max’.

for – loop is useful when you have a fixed boundaried collection to operate. It is used in two flavours – simple for loop and a variant foreach loop to iteration through a collection.

scala> for(i <- 1 to 10) println(i)

scala> "hello".foreach(println)

The above expressions show that usage of for, foreach loops in a straightforward manner.

for with an iterator guard – is a special case in Scala where a for loop can have a conditional statement to give the eligibility of the element to be considered further. It acts like a filter to each element in the collection being operated.

Sytax of an Iterator Guard is :
for(<identifier> <- <collection/range> if <Boolean expression>) { ... }

scala> for(i <- 1 to 10 if(i%2==0)) println(i)

The above expression used a for loop with an iterator guard to filter out ONLY the even numbers. The element will get printed ONLY if it is passing out of the filter, which is i%2==0.

while – loop is used at a situation when you are not sure of the boundary of the collection especially when to stop iterating.

7. Collections in Scala

Scala offers several different Collection elements like List, Set, and Map. We will see the list collection with an example below.

We can instantiate a List by calling it as a function and passing the list of elements as a comma separated values within the paranthesis.

scala> val numbers=List(1,2,3,4,5)
numbers: List[Int] = List(1, 2, 3, 4, 5)

scala> numbers.size
res55: Int = 5

The above expressions create a List with the numbers from 1 to 5 and the size of which is printed. Let us see how easily we can iterate the collections using a for loop and its variants.

scala> numbers.foreach(println)

scala> for(n  for(n <- numbers if(n%2==0)) println(n)

The 1st expression used a foreach loop as a method invoked on the collection to print out each element in the collection, whereas the 2nd expression used the for loop on the collection with a loop variable named n to hold each value at a time from the collection and prints out the same. The 3rd expression uses the for loop with an iterator guard to print out ONLY the even numbers.

Let us see few of the interesting methods available in Scala API for List objects. head method gets you the very first element – at 0th index, tail method invokes the rest of the elements in the collection excluding the very first at 0th index.

scala> numbers.head
res60: Int = 1

scala> numbers.tail
res61: List[Int] = List(2, 3, 4, 5)

scala> numbers(0)
res67: Int = 1

scala> numbers(2)
res68: Int = 3

scala> numbers.tail.size
res69: Int = 4

scala> numbers.tail(0)
res62: Int = 2

scala> numbers.tail(2)
res63: Int = 4

The above code snippets and expressions are self explanatory. The first element at index 0 is retrieved by using head method and the rest of the elements in the collection excluding the 0th element is retrieved by using the tail method. A particular element from the collection is obtained directly by passing its index as an argument like numbers(0) etc.,

Using method chaining, the res69 was obtained of the size after tail() method was applied. Initial list was containing 5 elements, whereas the tail() method gives you the list of 4 elements (from element index 1 to the end, excluding the element at index 0). The size of which was 4.

The last 2 expressions were attempting to retrieve a particular element of the resultant list of tail() method. The tail(0) will get the element at 0th index after tail() method – which is 2 in the list (2,3,4,5), whereas tail(2) will get the element at index 2 of the list 2,3,4,5 which is 4. Remember all elements in a collection starts from Index 0.

Let us look at another useful method isEmpty on a collection which returns true or false depending on the elements available in a collection.

scala> numbers.isEmpty
res64: Boolean = false

scala> numbers.tail.tail.size
res70: Int = 3

scala> numbers.tail.tail.tail.tail.tail.size
res71: Int = 0

scala> numbers.tail.tail.tail.tail.tail.isEmpty
res72: Boolean = true

The first expression invoked isEmpty on the collection numbers, which returns false as the underlying collection has a list of values/elements from 1 to 5. The 2nd expression showed the method chaining of size() method invoked after two successive invocations of tail method on the collection numbers. The result of whcih is 3.

The 3rd expression applied 5 consecutive tail() methods on the numbers which eventually empties the collection and hence the size() method at the last returns 0. Similarly, the 4th expression invokes the isEmpty method with the same method chaining of 5 consecutive tail() methods, which in case returns true.

You need to be careful while iterating the elements. For example, the below code snippet throws an UnsupportedOperationException when the tail method was invoked on an empty list – due to the consecutive method chanining. Please use them sparingly as they are here shown for the demonstration purpose.

scala> numbers.tail.tail.tail.tail.tail.tail.size
java.lang.UnsupportedOperationException: tail of empty list
  at scala.collection.immutable.Nil$.tail(List.scala:422)
  at scala.collection.immutable.Nil$.tail(List.scala:417)
  ... 33 elided

8. Conclusion

Hope you had enjoyed the Beginner Tutorial of Scala and you got a good taste of it. Please try the examples on your own by exploring the different methods available in the Scala API. You would really enjoy the power of Scala, especially if are coming from a professional Java development background as Scala offers a more consistent and simple way of doing things which is more verbose in Java.

9. References

You may please refer the following URLs for further reading.

  1. Scala – Wikipedia
  2. Critism of Java – Wikipedia
  3. Download Scala
  4. Scala Official Tutorial – Tour of Scala
  5. Scala Datatypes
  6. Scala Language API Documentation
  7. Getting Started with Scala

10. Download the Source Code

This is a beginner’s tutorial to Scala having all the examples tested in the Command Prompt / Shell against Scala Version 2.11.7.

The zip file has only the source code of HelloWorld.scala where the rest of the examples were executed in REPL Interpreter.

You can download the full source code of this example here: Scala Tutorial for Beginners.

Raghavan Muthu

Raghavan alias Saravanan Muthu is a seasoned IT professional having more than 2 decades of experience on Java SE/EE based Application Architecture, Design, Development, Management and Administration for Banking, Insurance, Telecom, HealthCare and Automobile Industries, having a very good hands on experience on Multi-threaded, batch processing applications and Relational Databases. He is currently working as a Director of Engineering for one of the Product based companies in India that delivers the product on Health Care and Insurance Domain. He holds a Post Graduation (Master of Science), and a PG Degree on Big Data Engineering from Birla Institute of Technology and Science (BITS), Pilani, India. He is a Founder, Chief Executive Volunteer and a Web Master of a non-profit charity organization named SHaDE (
Notify of

This site uses Akismet to reduce spam. Learn how your comment data is processed.

Inline Feedbacks
View all comments
Back to top button