View
221
Download
2
Category
Preview:
Citation preview
Groovy Tutorial Mickey Nguyen
1
Groovy Tutorial
Written by: Mickey Nguyen
(linkedin: mickeytrong73@yahoo.com)
May, 2015
Groovy Tutorial Mickey Nguyen
2
1 Groovy Installation ................................................................................................................................ 3
2 Introduction .......................................................................................................................................... 3
3 Println, printf, read input from console ................................................................................................ 3
4 String ..................................................................................................................................................... 6
5 Loops ..................................................................................................................................................... 8
6 Function .............................................................................................................................................. 10
7 Function Overloading .......................................................................................................................... 12
8 Closure ................................................................................................................................................ 15
9 if-else if-else, case ............................................................................................................................... 17
10 Data types ........................................................................................................................................... 19
11 Array .................................................................................................................................................... 22
12 List ....................................................................................................................................................... 24
13 Map ..................................................................................................................................................... 26
14 Use local time and calendar ................................................................................................................ 29
15 Bitwise ................................................................................................................................................. 31
16 FileIO ................................................................................................................................................... 33
17 Class .................................................................................................................................................... 35
18 Inheritant ............................................................................................................................................ 38
19 Abstract class ...................................................................................................................................... 40
20 Interface .............................................................................................................................................. 42
21 Thread ................................................................................................................................................. 44
22 Networking Socket .............................................................................................................................. 46
23 Exception Handling ............................................................................................................................. 48
24 Run Java Code ..................................................................................................................................... 50
24.1 Call Java jar .................................................................................................................................. 50
24.2 Call Java method ......................................................................................................................... 51
25 Regular Expression (Regex) ................................................................................................................. 53
26 XML Processing ................................................................................................................................... 55
Groovy Tutorial Mickey Nguyen
3
1 Groovy Installation On Eclipse, install new software for Groovy at
http://dist.springsource.org/release/GRECLIPSE/e4.4/
2 Introduction This is high level principle concepts of Groovy language.
Groovy is an object-oriented programming language for the Java platform. Groovy source code is
compiled into Java byte-code (.class).
On Eclipse, create Groovy project, then create Groovy class. To run it, right click on class->Run As-
>Groovy Script.
3 Println, printf, read input from console Syntax:
print “…no new line…..” Println “……with new line…..” printf (“%d, %f, %s”,num,num2,strings) Note: you can use () or without it, it is ok Create section3.groovy package com.Mickey.Groovy //print and println print "Hello " print ("Mickey Nguyen") print "\n" println "I am Patrick Nguyen" println ("I am Sarah Nguyen") //printf printf("I am %.2f", 189.1111) print "\n" printf("I am %d years old",50) print "\n" printf("My son name is %s", "Patrick Nguyen") print "\n" printf("I am %s, I'm %d, I'm %.2f", "Mickey Nguyen",50, 189.2222) print "\n" //Read input from console BufferedReader br = new BufferedReader(new InputStreamReader(System.in))
Groovy Tutorial Mickey Nguyen
4
print "Enter your favorite language: " input = br.readLine() println input /*This is a block of comment * Yes, it is */ Right click on the file->Run As->Groovy Script
Output:
Groovy Tutorial Mickey Nguyen
5
Groovy Tutorial Mickey Nguyen
6
4 String Create section4.groovy
package com.Mickey.Groovy //define strings variable str1 = 'Mikey Trong Nguyen' str2 = "Patrick Tran Nguyen" str3 = '''Sarah Tran Nguyen''' //print them out println str1 str2 = str2.toUpperCase() println str2 println str3 //using ${} println ("${str1} \n${str2} \n${str3}") //define number a string variable numstr = "199" //convert string to number num = numstr.toInteger() println (num + 1) //define a number as int variable num2 = 299 //Convert int to string num2str = num2.toString() println num2str + ", I am a string" //find sub string mystr = "I am Mickey Nguyen. I am a software engineer" if (mystr.contains("Mickey")) { println("Yes, found Mickey") } else { println("No, could not find Mickey") } if (mystr.contains("Patrick")) { println("Yes, found Patrick") } else { println("No, could not find Patrick")
Groovy Tutorial Mickey Nguyen
7
} //Print each substring mylist = mystr.tokenize() mylist.each {item-> println item}
Output:
Groovy Tutorial Mickey Nguyen
8
5 Loops Note: Groovy does not support do-while
Create section5.groovy
//package name package com.Mickey.Groovy
//for loop for (int i =0; i < 5; i++) printf("%d ",i) print("\n") //you can ignore declare data type for (k =0; k < 5; k++) printf("%d ",k) print("\n") //while loop i = 0 //you can ignore declare data type int i while (i < 5) { printf("%d ",i) i++ } //Groovy does not have do-while print("\n") //using range (0..5).each {item-> print "${item} "} print("\n") //or just do like this (0..5).each {print "${it} "} print("\n") //Another way to use range for loop for (i in 0..3) { println ("Hello ${i}") } print("\n") //times, upto, downto 5.times {println "Times: $it "} 1.upto(3) {println "Up: ${it} "} 4.downto(1) {println "Down: $it "} print ("\n") def sum = 0 1.upto(100) {sum += it} println sum //use it or expression 5.times {println it} 5.times {item-> println item}
Groovy Tutorial Mickey Nguyen
9
Output:
Groovy Tutorial Mickey Nguyen
10
6 Function Compare to Java, function does not need to belong to class.
Create section6.groovy
//package name package com.Mickey.Groovy
//Function return void void Func1() { println "This function return nothing" } Func1() //Function return int int Sum (int x, int y) { return x+y } println Sum(5,10) //Lazy and short way to create a function def Sum2 = {x, y -> return x+y} println Sum2(5,5) println Sum2 ("Mickey ", "Nguyen") //How about ignore data type def Add(i,j) { return i+j } def result = Add(10,20) println result //Function return string, passing 3 types of data def Func2 (name, age, weight) { return name +", "+age.toString() + ", "+weight.toString() } println Func2 ("Mickey Nguyen", 50, 199.99) //traditional way to define function as above String Func3(String name, int age, float weight) { return name +", "+age.toString() + ", "+weight.toString() } println Func3 ("Patrick Nguyen", 4, 35.99)
Groovy Tutorial Mickey Nguyen
11
Output:
Groovy Tutorial Mickey Nguyen
12
7 Function Overloading It is not working well on groovy. If two function has same name and same parameters set even though
the return type is different; it is not going to work.
For example: these functions are not going to work
Create section7.groovy
//Return void void PrintInfo() { println "I am return void" } //Return a string String PrintInfo() { return "a long string" }
// two function has the same parameters set, will be errors, and it is not going to work int Sum (int x, int y) { return x+y } String Sum (int x, int y) { return (x+y).toString() }
Here are examples about function overloading that work:
//package name package com.Mickey.Groovy
//Return void void PrintInfo() { println "I am return void" } //Return a string String PrintInfo(name) {
Groovy Tutorial Mickey Nguyen
13
return name } void PrintInfo(name,age,weight) { println name.toString() + ", "+ age.toString()+ ", "+ weight.toString() } //call these functions above PrintInfo() println PrintInfo("Mickey Nguyen") PrintInfo("Mickey Nguyen",50,189.99f) //work around for two function has the same parameters set Object Sum (Object x, Object y) { return x+y } println Sum (1,2) println Sum ("Mickey ", "Nguyen")
Output:
Groovy Tutorial Mickey Nguyen
14
Groovy Tutorial Mickey Nguyen
15
8 Closure Create section8.groovy
//package name package com.Mickey.Groovy
//normal def a function int NormalFunc (int x, int y) { return x*y } println NormalFunc (5,5) //use closure technique to define a function as above def Func = {int x, int y -> x*y} println Func(5,5) //array int [] arrayInt = [1,2,3,4,5] //normal traditional way to print out this array for (int i= 0; i < arrayInt.length; i++) { println arrayInt[i] } print("\n") //now use closure technique arrayInt.each {i -> println i}
Output:
Groovy Tutorial Mickey Nguyen
16
Groovy Tutorial Mickey Nguyen
17
9 if-else if-else, case Create section9.groovy
//package name package com.Mickey.Groovy
name = "Mickey Nguyen" age = 50 gender = "male" //if, else if (name.equals("Mickey Nguyen")) { println("Yes, it is") } else { println("No, it is not") } //if, else if,else if (age == 40 ) { println ("Yes, age is 40") } else if (gender.equals("female")) { println "Yes, gender is female" } else { println "No, age and gender were wrong" }
Groovy Tutorial Mickey Nguyen
18
//switch case switch (age) { case 55: println "Mickey is too old" break case 40: println "Mickey is too young" break case 50: println "Yes, Mickey is 50 yrs old" break default: println "All guesses were wrong" break } Output:
Groovy Tutorial Mickey Nguyen
19
10 Data types Create section10.groovy
//package name package com.Mickey.Groovy
//Numbers int num1 = 50 Integer num2 = 100 float num3 = 100.00 Float num4 = 100.00 double num5 =100.00 Double num6 = 100.00 int sum = num1 + num2 + num3 + num4 + num5 +num6 println sum //character char letter1 = 'a' println letter1 //String String name = "Mickey Nguyen" println name boolean flag = true println flag //generic data type, can be anything Object i =10 println i Object str ="Mikcey Nguyen" println str Object numStr = "11" int number = numStr.toInteger() println number + 1 //enum enum DayOfWeek { mon, tue, wed, thu, fri, sat, sun } println DayOfWeek.tue //class class Data { //without declare data type for parameters //It acts like overload function def Print(x,y)
Groovy Tutorial Mickey Nguyen
20
{ println x+y } void MyPrint() { println "Without using def keyword" } } Data d = new Data() d.Print(20, 30) d.Print("Mickey", " Nguyen") d.MyPrint()
Output:
Groovy Tutorial Mickey Nguyen
21
Groovy Tutorial Mickey Nguyen
22
11 Array Create section11.groovy
//package name package com.Mickey.Groovy
//Array of int int [] arrayInt = [1,2,3,4,5] arrayInt.each {i-> print i} print("\n") arrayInt.each {i-> print "${i}"} print("\n") //allocate 5 elements int [] arrayInt2 = new int[5] for (i in 0..4) { arrayInt2[i] = i+1 print ("${i} ") } //Array of string String [] arrayStr = new String [4] arrayStr[0] = "Mickey Nguyen" arrayStr[1] = "Chau Tran" arrayStr[2] = "Sarah Nguyen" arrayStr[3] = "Patrick Nguyen" print("\n") println arrayStr.size() println arrayStr.length for (i= 0; i < arrayStr.size(); i++) { println arrayStr[i] } print("\n") String [] arrayStr2 =["Mickey Nguyen","Chau Tran","Sarah Nguyen","Patrick Nguyen"] arrayStr2.each {i-> println "${i}"} print ("\n") arrayStr2.each {println "${it}"}
Output:
Groovy Tutorial Mickey Nguyen
23
Groovy Tutorial Mickey Nguyen
24
12 List Create section12.groovy
//package name package com.Mickey.Groovy
//List of int List <Integer> li = new ArrayList<Integer>(); li.add(1) li.add(2) li.add(3) li.each {i-> print "${i} "} print ("\n") //Another way of create a list List <Integer> li2 = [4,5,6] li2.each {i-> print "${i} "} print("\n") //Create list of String List <String> ls = new ArrayList <String>(); ls.add("Mickey Nguyen") ls.add("Chau Tran") ls.add("Sarah Nguyen") ls.add("Patrick Nguyen") ls.each {i-> println "${i}"} print("\n") //Array to List int [] arrayInt = [1,2,3,4] List<Integer> lsInt = new ArrayList<Integer>(); lsInt = arrayInt.toList() lsInt.each {i-> print "${i} "} print("\n") //List to Array int [] arrayInt2 = new int[4] arrayInt2 = lsInt.toArray() arrayInt2.each {i-> print "${i} "}
Output:
Groovy Tutorial Mickey Nguyen
25
Groovy Tutorial Mickey Nguyen
26
13 Map Create section13.groovy
//package name package com.Mickey.Groovy
//map <key,value> map1 = new HashMap<String,Integer>(); map1.put("Mickey Nguyen", 50) map1.put("Patrick Nguyen", 4) println map1.containsKey ("Mickey Nguyen") println map1.containsValue (4) println map1.get("Mickey Nguyen") //go thru the map map1.each {entry -> println (entry.key)} map1.each {entry -> println (entry.value)} //or loop thru by this way for (key in map1.keySet()) { println key } //loop thru and get value for (key in map1.keySet()) { println map1.get(key) } //loop thru the value set for (v in map1.values()) { println v } //To to mix up the key with Integer and String mapUniversalKey = new HashMap<Object,Object>(); //Key is String, value is Integer mapUniversalKey.put("Mickey Nguyen", 50) //Key is Integer, value is String mapUniversalKey.put(4, "Patrick Nguyen") print("\n") //or loop thru by this way for (key in mapUniversalKey.keySet()) { println ("${key}, ${mapUniversalKey.get(key)}") } print("\n") //define map with default value map2 = [12: "Mickey Nguyen"] //then add more key, value into the map
Groovy Tutorial Mickey Nguyen
27
//mix data type for key map2.put(13, "Patrick Nguyen") map2.put("Sara Nguyen", 8) map2.put("Chau Tran", 21) //or loop thru by this way for (key in map2.keySet()) { println ("${key}, ${map2.get(key)}") } print("\n") //Create an empty map map3 =[:] map3.put("Mickey Nguyen", 50) map3.put("Chau Tran", 21) //or loop thru by this way for (key in map3.keySet()) { println ("${key}, ${map3.get(key)}") } Output:
Groovy Tutorial Mickey Nguyen
28
Groovy Tutorial Mickey Nguyen
29
14 Use local time and calendar Create section14.groovy
//package name package com.Mickey.Groovy
//current date and time def today = new Date() println today println today.time println today.hours println today.minutes println today.seconds def nowCal = Calendar.instance y = nowCal.get(nowCal.YEAR) Date nowDate = nowCal.time m = nowDate[nowCal.MONTH] + 1 d = nowDate[nowCal.DATE] println "Today is $d $m $y" //better format import java.text.DateFormat def plainFormatter = DateFormat.instance println plainFormatter.format(today) //using timer //define a callback function void CallBack() { println "Pretend to do do something here....." } def timer = new Timer() timer.schedule({ CallBack() } as TimerTask, 1000, 3000) //magic numbers are initial-delay & repeat-interval
Output:
Groovy Tutorial Mickey Nguyen
30
Groovy Tutorial Mickey Nguyen
31
15 Bitwise Create section15.groovy
//package name package com.Mickey.Groovy
a = 60 // 60 = 0011 1100 b = 13 // 13 = 0000 1101 c = 0 c = a & b; // 12 = 0000 1100 printf("Line 1 - Value of c is %d", c) print("\n") c = a | b; // 61 = 0011 1101 printf("Line 2 - Value of c is %d",c) print("\n") c = a ^ b; // 49 = 0011 0001 printf("Line 3 - Value of c is %d",c) print("\n") c = ~a; // -61 = 1100 0011 printf ("Line 4 - Value of c is %d",c) print("\n") c = a << 2; // 240 = 1111 0000 printf("Line 5 - Value of c is %d",c) print("\n") c = a >> 2; // 15 = 0000 1111 printf("Line 6 - Value of c is %d",c) print("\n") //exercise some hex Value num = 2015 println (num.toString()) printf ("%04x",num) print("\n") printf ("%08x",num) print("\n") println sprintf("%04X", num) println sprintf("%08X", num)
Output:
Groovy Tutorial Mickey Nguyen
32
Groovy Tutorial Mickey Nguyen
33
16 FileIO Create section16.groovy
//package name package com.Mickey.Groovy
//Create a file for input def file = new File("info.txt") // Writing to the files with the write method: file.write "I love Groovy Scriptint language. \n" file.write "It seems easy to me. \n" //Or using the leftShift operator: file << "See how easy it is to add text to a file.\n" file << "Add another line to a file.\n" //Read it back //Read it back at one shot put it in array of string def lines = file.readLines() println lines print("\n") lines.each {line -> println "${line}"} //or read it back one line at a time print("\n") file.withReader { reader -> while (line = reader.readLine()) { println line } }
Output:
Groovy Tutorial Mickey Nguyen
34
Groovy Tutorial Mickey Nguyen
35
17 Class By default, it has public access modifier
Create section17.groovy
package com.Mickey.Groovy //simple class, default constructor class Sample { void PrintInfo() { println "Printing info" } } Sample s = new Sample() s.PrintInfo() print("\n") //define a class with constructor class Person { private String name private int age private float weight Person (name,age,w) { this.name = name //using "this" to distinct this attribute = parameter this.age = age this.weight = w //don't have to use this in this case but it is ok } void PersonInfo() { println name println age println weight } } //Use "Person" data type instead of "def" Person p = new Person("Mickey Nguyen", 50, 189.99f) p.PersonInfo() print("\n") //Also able to use "def" for data type instead of "Person" def p2 = new Person("Mickey Nguyen", 50, 189.99f) p2.PersonInfo()
Groovy Tutorial Mickey Nguyen
36
//Define a class without constructor, will use the default generated one class Patrick { private String name private int age private float weight void PatrickInfo() { println name println age println weight } } print("\n") //use automatic generated constructor Patrick pa = new Patrick(name: "Parick Nguyen", age : 4, weight: 35.99f) pa.PatrickInfo()
output:
Groovy Tutorial Mickey Nguyen
37
Groovy Tutorial Mickey Nguyen
38
18 Inheritant Create section18.groovy
//package name package com.Mickey.Groovy
class Parent { void Print() { println "This is Parent printing" } } class Child extends Parent { //empty body } //use parent method Child c = new Child() c.Print() //use parent Print method class Child2 extends Parent { //try to override Parent method void Print() { println "This is Child2 printing" } } Child2 c2 = new Child2() c2.Print() //use its own Print method
Output:
Groovy Tutorial Mickey Nguyen
39
Groovy Tutorial Mickey Nguyen
40
19 Abstract class Create section19.groovy
//package name package com.Mickey.Groovy
abstract class Car { abstract void Info() //abstract method cannot have implement body abstract void AnotherInfo() //non-abstract class can have implementation body void NormalMethod() { println "This is normal method, can be skiped by child class" } } //child who inherit to parent abstract has to have to implement all the //abstract method. Cannot skip any abstract method. //Only can skip those non abstract method class Sedan extends Car { void Info() { println "This is car info" } void AnotherInfo() { println "This is another car info" } } Sedan sd = new Sedan() sd.Info() sd.AnotherInfo() sd.NormalMethod() //don't have implement in child class, use parent implementation
Output:
Groovy Tutorial Mickey Nguyen
41
Groovy Tutorial Mickey Nguyen
42
20 Interface Create section20.groovy
//package name package com.Mickey.Groovy
//method in interface cannot have implemtation body interface Hello { void SayHello() void SayGoodBye() } //class implement the interface have to implement all the method in that //interface, cannot skip any method define in that interface class Mickey implements Hello { void SayHello() { println "Hello from Mickey" } void SayGoodBye() { println "Goodbye from Mickey" } } Mickey m = new Mickey() m.SayHello() m.SayGoodBye() print("\n")
Output:
Groovy Tutorial Mickey Nguyen
43
Groovy Tutorial Mickey Nguyen
44
21 Thread Create section21.groovy
//package name package com.Mickey.Groovy
void CallBack1() { def i =0 while (i<3) { println "This is callback1" sleep(1000) i++ } } void CallBack2() { def i = 0 while (i <4) { println "This is callback2" sleep (2000) i++ } } def th1 = Thread.start { CallBack1() } def th2 = Thread.start { CallBack2() } th1.join() th2.join()
Output:
Groovy Tutorial Mickey Nguyen
45
Groovy Tutorial Mickey Nguyen
46
22 Networking Socket Create section22Server.groovy
//package name package com.Mickey.Groovy
import java.net.ServerSocket def server = new ServerSocket(1234) while(true) { server.accept { socket -> println "processing new connection..." socket.withStreams { input, output -> def reader = input.newReader() def buffer = reader.readLine() println "server received: $buffer" now = new Date() output << "Server echo-response($now): " + buffer + "\n" } println "processing/thread complete." } }
Create section22Client.groovy //package name package com.Mickey.Groovy s = new Socket("localhost", 1234); s.withStreams { input, output -> output << "echo testing ...\n" def reader = input.newReader() def buffer = reader.readLine() println "Client received: $buffer" }
To test it, start the server first, then start the client.
Groovy Tutorial Mickey Nguyen
47
Groovy Tutorial Mickey Nguyen
48
23 Exception Handling Create section23_1.groovy
//package name package com.Mickey.Groovy
filename = "mickey.txt" assert (filename.equalsIgnoreCase("MICKEY.TXT")) println "Should passed line above" assert (filename.equals("MICKEY.TXT")) println "Never reach this line"
Output:
Groovy Tutorial Mickey Nguyen
49
Another example of try catch
Create section23_2.groovy
//package name package com.Mickey.Groovy try { zero = 0 num = 1/0 assert false //never reached due to Exception in previous line } catch(Exception e) { println e } Output:
Groovy Tutorial Mickey Nguyen
50
24 Run Java Code
24.1 Call Java jar Create section24_1.groovy
Here is Java code in java project
import javax.swing.JOptionPane; //import class JOptionPane public class hellomickey { public void printmk() { JOptionPane.showMessageDialog (null,"Hello hello from Mickey Nguyen \nHow are you doing today? " ); } public static void main(String[] args) { //JOptionPane.showMessageDialog (null,"Hello hello from Mickey Nguyen \nHow are you doing today? " ); hellomickey mk = new hellomickey(); mk.printmk(); } }
Compile Java code in Java project, Then export to Runable JAR file: hellomickeyr.jar, copy jar
file to under project folder
Here is groovy script.
//package name package com.Mickey.Groovy
def command = "java -jar hellomickeyr.jar" def process = command.execute()
Output:
Groovy Tutorial Mickey Nguyen
51
24.2 Call Java method Java code, I place hellomickey.java in same folder of groovy files Create section24_2.groovy package com.Mickey.Groovy; import javax.swing.JOptionPane; //import class JOptionPane public class hellomickey { public void printmk() { JOptionPane.showMessageDialog (null,"Hello hello from Mickey Nguyen \nHow are you doing today? " ); } public static void main(String[] args) { //JOptionPane.showMessageDialog (null,"Hello hello from Mickey Nguyen \nHow are you doing today? " ); hellomickey mk = new hellomickey(); mk.printmk(); } }
Groovy script: package com.Mickey.Groovy import com.Mickey.Groovy.hellomickey; class Main { def run() { def sayObj = new hellomickey().printmk() println "Mickey, hello!" } } def app = new Main() app.run()
Output:
Groovy Tutorial Mickey Nguyen
52
Groovy Tutorial Mickey Nguyen
53
25 Regular Expression (Regex) Create section25.groovy
//package name package com.Mickey.Groovy import java.util.regex.Matcher import java.util.regex.Pattern aboutme = "I am Mickey Nguyen. I am a software engineer who likes to work on software" def mypattern = ~/software/ assert mypattern instanceof Pattern assert mypattern.matcher("software").matches() //check to see if it can find this pattern assert aboutme =~ mypattern assert aboutme =~ /software/ //print out the original string before replace println aboutme matcher = (aboutme =~ /software/); aboutme = matcher.replaceAll("hardware"); //print out after replacement println aboutme println "See this line"
Output:
Groovy Tutorial Mickey Nguyen
54
Groovy Tutorial Mickey Nguyen
55
26 XML Processing Copy nguyenfamily.xml to under project folder
<family nguyen="family members"> <member name="Mickey Nguyen"> <profession>SW Engineer</profession> <age>50</age> <gender>male</gender> </member> <member name="Chau Nguyen"> <profession>SQA Engineer</profession> <age>20</age> <gender>female</gender> </member> <member name="Patrick Nguyen"> <profession>nhoc con</profession> <age>4</age> <gender>male</gender> </member> <member name="Sarah Nguyen"> <profession>student</profession> <age>8</age> <gender>female</gender> </member> </family>
Here is groovy code to parse xml
//package name package com.Mickey.Groovy //nguyenfamily.xml is under project folder XmlParser parser = new XmlParser() def rootNode = parser.parse (new FileInputStream("nguyenfamily.xml")) rootNode.member.each {member -> println "${member.'@name'}"} rootNode.member.each {member -> println "${member.profession.text()}"} rootNode.member.each {member -> println "${member.age.text()}"} rootNode.member.each {member -> println "${member.gender.text()}"} //or def a xml in big string like this String xml2 = """ <birds> <bird type="turkey" sound="looc looc"/> <bird type="rooster" sound="ooooo ooooo"/> </birds>""" XmlParser parser2 = new XmlParser() def birds = parser2.parseText (xml2)
Groovy Tutorial Mickey Nguyen
56
birds.bird.each { bird -> println("${bird.'@type'} sounds like ${bird.'@sound'}"); }
Output:
Recommended