0% found this document useful (0 votes)
1 views20 pages

StringMethods Pdfmath

The document provides a comprehensive demonstration of various string manipulation methods in Java, including operations on both String and StringBuffer classes. It covers methods such as length, charAt, indexOf, substring, toLowerCase, and many more, with examples illustrating their usage. Additionally, it showcases methods for handling whitespace, formatting, and transforming strings.

Uploaded by

Pranay Gundla
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
1 views20 pages

StringMethods Pdfmath

The document provides a comprehensive demonstration of various string manipulation methods in Java, including operations on both String and StringBuffer classes. It covers methods such as length, charAt, indexOf, substring, toLowerCase, and many more, with examples illustrating their usage. Additionally, it showcases methods for handling whitespace, formatting, and transforming strings.

Uploaded by

Pranay Gundla
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd

public class StringMethodsDemo {

public static void main(String[] args) {

// Creating a sample string

String originalString = "Hello, World!";

// 1. length() - Returns the length of the string

int length = [Link]();

[Link]("1. Length of the string: " + length);

// 2. charAt(int index) - Returns the character at the specified index

char charAtIndex = [Link](7);

[Link]("2. Character at index 7: " + charAtIndex);

// 3. indexOf(String str) - Returns the index of the first occurrence of the specified substring

int indexOfSubstring = [Link]("World");

[Link]("3. Index of 'World': " + indexOfSubstring);

// 4. substring(int beginIndex) - Returns a new string that is a substring of the original string

String substring = [Link](7);

[Link]("4. Substring from index 7: " + substring);

// 5. toLowerCase() - Converts the string to lowercase

String lowercaseString = [Link]();

[Link]("5. Lowercase string: " + lowercaseString);

// 6. toUpperCase() - Converts the string to uppercase

String uppercaseString = [Link]();

[Link]("6. Uppercase string: " + uppercaseString);


// 7. trim() - Removes leading and trailing whitespaces

String trimmedString = " Trim me! ".trim();

[Link]("7. Trimmed string: '" + trimmedString + "'");

// 8. startsWith(String prefix) - Checks if the string starts with the specified prefix

boolean startsWithHello = [Link]("Hello");

[Link]("8. Starts with 'Hello': " + startsWithHello);

// 9. endsWith(String suffix) - Checks if the string ends with the specified suffix

boolean endsWithWorld = [Link]("World!");

[Link]("9. Ends with 'World!': " + endsWithWorld);

// 10. contains(CharSequence sequence) - Checks if the string contains the specified sequence

boolean containsComma = [Link](",");

[Link]("10. Contains ',' : " + containsComma);

// 11. replace(char oldChar, char newChar) - Replaces occurrences of oldChar with newChar

String replacedString = [Link]('o', '0');

[Link]("11. String after replacement: " + replacedString);

// 12. concat(String str) - Concatenates the specified string to the end of the original string

String concatenatedString = [Link](" Welcome!");

[Link]("12. Concatenated string: " + concatenatedString);

// 13. equals(Object obj) - Compares the string with the specified object for equality

boolean isEqual = [Link]("Hello, World!");

[Link]("13. String equals 'Hello, World!': " + isEqual);

// 14. isEmpty() - Checks if the string is empty


boolean isEmpty = [Link]();

[Link]("14. Is the string empty: " + isEmpty);

// 15. replaceAll(String regex, String replacement) - Replaces all occurrences of the specified regex with the
replacement

String regexReplaced = [Link]("[aeiou]", "*");

[Link]("15. String after regex replacement: " + regexReplaced);

// 16. split(String regex) - Splits the string using the specified regex

String[] splitArray = [Link](", ");

[Link]("16. Splitted string: ");

for (String part : splitArray) {

[Link](" " + part);

// 17. compareTo(String anotherString) - Compares two strings lexicographically

int compareToResult = [Link]("Hello, Universe!");

[Link]("17. Compare to 'Hello, Universe!': " + compareToResult);

// 18. intern() - Returns a canonical representation of the string

String internedString = [Link]();

[Link]("18. Interned string: " + internedString);

// 19. codePointAt(int index) - Returns the Unicode code point of the character at the specified index

int codePoint = [Link](1);

[Link]("19. Unicode code point at index 1: " + codePoint);

// 20. lastIndexOf(String str) - Returns the index of the last occurrence of the specified substring

int lastIndexOfSubstring = [Link]("o");


[Link]("20. Last index of 'o': " + lastIndexOfSubstring);

// 21. codePointBefore(int index) - Returns the Unicode code point before the specified index

int codePointBefore = [Link](5);

[Link]("21. Unicode code point before index 5: " + codePointBefore);

// 22. codePointCount(int beginIndex, int endIndex) - Returns the number of Unicode code points between the
specified indices

int codePointCount = [Link](0, [Link]());

[Link]("22. Number of Unicode code points in the string: " + codePointCount);

// 23. offsetByCodePoints(int index, int codePointOffset) - Returns the index that is offset by the given code
points

int offsetIndex = [Link](0, 2);

[Link]("23. Offset index by 2 code points: " + offsetIndex);

// 24. matches(String regex) - Checks if the entire string matches the specified regex

boolean matchesRegex = [Link]("[A-Za-z, ]+");

[Link]("24. Matches regex '[A-Za-z, ]+': " + matchesRegex);

// 25. regionMatches(boolean ignoreCase, int toffset, String other, int ooffset, int len) - Checks if a region of
this string matches a region of another string

boolean regionMatches = [Link](true, 0, "hello, world!", 0, 13);

[Link]("25. Case-insensitive region matches 'hello, world!': " + regionMatches);

// 26. contentEquals(CharSequence cs) - Checks if the content of the string is equal to the specified character
sequence

boolean contentEquals = [Link](new StringBuffer("Hello, World!"));

[Link]("26. Content equals StringBuffer 'Hello, World!': " + contentEquals);


// 27. contentEquals(StringBuffer sb) - Checks if the content of the string is equal to the specified string buffer

boolean contentEqualsBuffer = [Link](new StringBuffer("Hello, World!"));

[Link]("27. Content equals StringBuffer 'Hello, World!': " + contentEqualsBuffer);

// 28. matches(String regex) - Checks if the entire string matches the specified regex

boolean matchesRegex2 = [Link]("[A-Za-z, ]+");

[Link]("28. Matches regex '[A-Za-z, ]+': " + matchesRegex2);

// 29. replaceFirst(String regex, String replacement) - Replaces the first occurrence of the specified regex with
the replacement

String replaceFirst = [Link]("[aeiou]", "*");

[Link]("29. Replace first vowel with '*': " + replaceFirst);

// 30. replace(CharSequence target, CharSequence replacement) - Replaces all occurrences of the specified
target with the replacement

String replaceSequence = [Link]("o", "0");

[Link]("30. Replace 'o' with '0': " + replaceSequence);

// 31. subSequence(int beginIndex, int endIndex) - Returns a new character sequence that is a subsequence of
the original string

CharSequence subSequence = [Link](7, 12);

[Link]("31. Subsequence from index 7 to 12: " + subSequence);

// 32. toString() - Returns the string itself

String toStringMethod = [Link]();

[Link]("32. Result of toString() method: " + toStringMethod);

// 33. toCharArray() - Converts the string to a char array

char[] charArray = [Link]();

[Link]("33. Char array representation: " + [Link](charArray));


// 34. join(CharSequence delimiter, CharSequence... elements) - Joins the specified elements using the
specified delimiter

String joinedString = [Link](" - ", "Hello", "World");

[Link]("34. Joined string: " + joinedString);

// 35. valueOf(Object obj) - Returns the string representation of the specified object

String valueOfString = [Link](42);

[Link]("35. String representation of 42: " + valueOfString);

// 36. intern() - Returns a canonical representation of the string

String internedString2 = [Link]();

[Link]("36. Interned string: " + internedString2);

// 37. codePoints() - Returns a stream of code points from the string

IntStream codePointsStream = [Link]();

[Link]("37. Code points stream: ");

[Link](codePointValue -> [Link](codePointValue + " "));

// 38. lines() - Returns a stream of lines extracted from the string

String multilineString = "Line 1\nLine 2\nLine 3";

Stream<String> linesStream = [Link]();

[Link]("\n38. Lines stream: ");

[Link](line -> [Link](" " + line));

// 39. strip() - Returns a string with leading and trailing whitespaces removed

String stringWithWhitespace = " Strip me! ";

String strippedString = [Link]();

[Link]("39. Stripped string: '" + strippedString + "'");


// 40. repeat(int count) - Returns a new string repeating the original string the specified number of times

String repeatedString = "Repeat me! ".repeat(3);

[Link]("40. Repeated string: " + repeatedString);

// 41. formatted(Object... args) - Returns a formatted string using the specified format and arguments

String formattedString = "Name: %s, Age: %d";

String formattedResult = [Link](formattedString, "John", 25);

[Link]("41. Formatted string: " + formattedResult);

// 42. stripLeading() - Returns a string with leading whitespaces removed

String stripLeadingString = " Strip me! ";

String strippedLeadingString = [Link]();

[Link]("42. Stripped leading string: '" + strippedLeadingString + "'");

// 43. stripTrailing() - Returns a string with trailing whitespaces removed

String stripTrailingString = " Strip me! ";

String strippedTrailingString = [Link]();

[Link]("43. Stripped trailing string: '" + strippedTrailingString + "'");

// 44. repeat(int count) - Returns a new string repeating the original string the specified number of times

String repeatedString2 = "Repeat me! ".repeat(3);

[Link]("44. Repeated string: " + repeatedString2);

// 45. lines() - Returns a stream of lines extracted from the string

String multilineString2 = "Line 1\nLine 2\nLine 3";

Stream<String> linesStream2 = [Link]();

[Link]("45. Lines stream: ");

[Link](line -> [Link](" " + line));


// 46. strip() - Returns a string with leading and trailing whitespaces removed

String stringWithWhitespace2 = " Strip me! ";

String strippedString2 = [Link]();

[Link]("46. Stripped string: '" + strippedString2 + "'");

// 47. codePoints() - Returns a stream of code points from the string

IntStream codePointsStream2 = [Link]();

[Link]("47. Code points stream: ");

[Link](codePointValue -> [Link](codePointValue + " "));

// 48. transform(Function<? super Character,? extends R> f) - Applies the given function to each character of
the string

String transformedString = [Link](Character::toUpperCase);

[Link]("\n48. Transformed string (uppercase): " + transformedString);

// 49. stripIndent() - Returns a string with common leading whitespace removed

String indentedString = """

Line 1

Line 2

Line 3

""";

String strippedIndentedString = [Link]();

[Link]("49. Stripped indented string:\n" + strippedIndentedString);

// 50. indent(int n) - Returns a string with each line indented by the specified number of spaces

String indentedString2 = "Indented Line 1\nIndented Line 2\nIndented Line 3";

String indentedResult = [Link](4);

[Link]("50. Indented string (4 spaces):\n" + indentedResult);


}

String buffer.
public class StringBufferMethodsDemo {

public static void main(String[] args) {

// Creating a sample StringBuffer

StringBuffer stringBuffer = new StringBuffer("Hello, StringBuffer!");

// 1. append(Object obj) - Appends the string representation of the specified object

[Link](" Welcome");

[Link]("1. Appended string: " + stringBuffer);

// 2. insert(int offset, Object obj) - Inserts the string representation of the specified object at the
specified offset

[Link](5, " New");

[Link]("2. Inserted string at offset 5: " + stringBuffer);

// 3. replace(int start, int end, String str) - Replaces the substring from start to end with the
specified string

[Link](7, 16, "StringBuffer");

[Link]("3. Replaced substring: " + stringBuffer);


// 4. delete(int start, int end) - Deletes the substring from start to end

[Link](7, 18);

[Link]("4. Deleted substring: " + stringBuffer);

// 5. reverse() - Reverses the content of the StringBuffer

[Link]();

[Link]("5. Reversed string: " + stringBuffer);

// 6. capacity() - Returns the current capacity of the StringBuffer

int capacity = [Link]();

[Link]("6. Capacity of the StringBuffer: " + capacity);

// 7. ensureCapacity(int minCapacity) - Ensures that the capacity is at least equal to the specified
minimum capacity

[Link](50);

[Link]("7. Ensured capacity: " + [Link]());

// 8. length() - Returns the length (number of characters) of the StringBuffer

int length = [Link]();

[Link]("8. Length of the StringBuffer: " + length);

// 9. charAt(int index) - Returns the character at the specified index

char charAtIndex = [Link](2);

[Link]("9. Character at index 2: " + charAtIndex);

// 10. subSequence(int start, int end) - Returns a subsequence of the StringBuffer from start to end

CharSequence subSequence = [Link](3, 9);


[Link]("10. Subsequence from index 3 to 9: " + subSequence);

// 11. substring(int start) - Returns a substring of the StringBuffer from start to the end

String substring = [Link](6);

[Link]("11. Substring from index 6: " + substring);

// 12. substring(int start, int end) - Returns a substring of the StringBuffer from start to end

String substring2 = [Link](3, 10);

[Link]("12. Substring from index 3 to 10: " + substring2);

// 13. codePointAt(int index) - Returns the Unicode code point at the specified index

int codePoint = [Link](1);

[Link]("13. Unicode code point at index 1: " + codePoint);

// 14. codePointBefore(int index) - Returns the Unicode code point before the specified index

int codePointBefore = [Link](5);

[Link]("14. Unicode code point before index 5: " + codePointBefore);

// 15. codePointCount(int beginIndex, int endIndex) - Returns the number of Unicode code points
between the specified indices

int codePointCount = [Link](0, [Link]());

[Link]("15. Number of Unicode code points in the StringBuffer: " + codePointCount);

// 16. offsetByCodePoints(int index, int codePointOffset) - Returns the index that is offset by the
given code points

int offsetIndex = [Link](0, 2);

[Link]("16. Offset index by 2 code points: " + offsetIndex);


// 17. indexOf(String str) - Returns the index of the first occurrence of the specified substring

int indexOfSubstring = [Link]("Buffer");

[Link]("17. Index of 'Buffer': " + indexOfSubstring);

// 18. indexOf(String str, int fromIndex) - Returns the index of the first occurrence of the specified
substring after the specified index

int indexOfSubstringAfterIndex = [Link]("Buffer", 5);

[Link]("18. Index of 'Buffer' after index 5: " + indexOfSubstringAfterIndex);

// 19. lastIndexOf(String str) - Returns the index of the last occurrence of the specified substring

int lastIndexOfSubstring = [Link]("Buffer");

[Link]("19. Last index of 'Buffer': " + lastIndexOfSubstring);

// 20. lastIndexOf(String str, int fromIndex) - Returns the index of the last occurrence of the
specified substring before the specified index

int lastIndexOfSubstringBeforeIndex = [Link]("Buffer", 15);

[Link]("20. Last index of 'Buffer' before index 15: " + lastIndexOfSubstringBeforeIndex);

// 21. toString() - Returns the string representation of the StringBuffer

String toStringMethod = [Link]();

[Link]("21. Result of toString() method: " + toStringMethod);

// 22. codePoints() - Returns an IntStream of code points from the StringBuffer

IntStream codePointsStream = [Link]();

[Link]("22. Code points stream: ");

[Link](codePointValue -> [Link](codePointValue + " "));

// 23. chars() - Returns an IntStream of characters from the StringBuffer


IntStream charsStream = [Link]();

[Link]("\n23. Characters stream: ");

[Link](charValue -> [Link](charValue + " "));

// 24. subSequence(int start, int end) - Returns a subsequence of the StringBuffer from start to end

CharSequence subSequence2 = [Link](3, 8);

[Link]("\n24. Subsequence from index 3 to 8: " + subSequence2);

// 25. toString() - Returns the string representation of the StringBuffer

String toStringMethod2 = [Link]();

[Link]("25. Result of toString() method: " + toStringMethod2);

// 26. indexOf(String str) - Returns the index of the first occurrence of the specified substring

int indexOfSubstring2 = [Link]("Buffer");

[Link]("26. Index of 'Buffer': " + indexOfSubstring2);

// 27. lastIndexOf(String str) - Returns the index of the last occurrence of the specified substring

int lastIndexOfSubstring2 = [Link]("Buffer");

[Link]("27. Last index of 'Buffer': " + lastIndexOfSubstring2);

// 28. hashCode() - Returns the hash code of the StringBuffer

int hashCode = [Link]();

[Link]("28. Hash code of the StringBuffer: " + hashCode);

// 29. equals(Object obj) - Checks if the StringBuffer is equal to the specified object

boolean isEqual = [Link](new StringBuffer("Hello, StringBuffer!"));

[Link]("29. StringBuffer equals 'Hello, StringBuffer!': " + isEqual);


// 30. substring(int start) - Returns a substring of the StringBuffer from start to the end

String substring3 = [Link](6);

[Link]("30. Substring from index 6: " + substring3);

// 31. substring(int start, int end) - Returns a substring of the StringBuffer from start to end

String substring4 = [Link](3, 10);

[Link]("31. Substring from index 3 to 10: " + substring4);

// 32. deleteCharAt(int index) - Deletes the character at the specified index

[Link](5);

[Link]("32. Deleted character at index 5: " + stringBuffer);

// 33. setCharAt(int index, char ch) - Sets the character at the specified index to the specified char

[Link](6, 'X');

[Link]("33. Set character at index 6 to 'X': " + stringBuffer);

// 34. insert(int offset, CharSequence s) - Inserts the specified CharSequence at the specified
offset

[Link](5, new StringBuilder(" New"));

[Link]("34. Inserted StringBuilder at offset 5: " + stringBuffer);

// 35. insert(int dstOffset, CharSequence s, int start, int end) - Inserts a subsequence of the
specified CharSequence at the specified offset

StringBuilder subStringBuilder = new StringBuilder("Sub");

[Link](9, subStringBuilder, 0, [Link]());

[Link]("35. Inserted subsequence at offset 9: " + stringBuffer);


// 36. codePointAt(int index) - Returns the Unicode code point at the specified index

int codePoint2 = [Link](1);

[Link]("36. Unicode code point at index 1: " + codePoint2);

// 37. codePointBefore(int index) - Returns the Unicode code point before the specified index

int codePointBefore2 = [Link](5);

[Link]("37. Unicode code point before index 5: " + codePointBefore2);

// 38. codePointCount(int beginIndex, int endIndex) - Returns the number of Unicode code points
between the specified indices

int codePointCount2 = [Link](0, [Link]());

[Link]("38. Number of Unicode code points in the StringBuffer: " + codePointCount2);

// 39. offsetByCodePoints(int index, int codePointOffset) - Returns the index that is offset by the
given code points

int offsetIndex2 = [Link](0, 2);

[Link]("39. Offset index by 2 code points: " + offsetIndex2);

// 40. indexOf(String str, int fromIndex) - Returns the index of the first occurrence of the specified
substring after the specified index

int indexOfSubstringAfterIndex2 = [Link]("Buffer", 5);

[Link]("40. Index of 'Buffer' after index 5: " + indexOfSubstringAfterIndex2);

}
Maths class :
public class MathMethodsDemo {

public static void main(String[] args) {

// 1. abs(double a) - Returns the absolute value of a double value

double absoluteValue = [Link](-7.5);

[Link]("1. Absolute value: " + absoluteValue);

// 2. ceil(double a) - Returns the smallest (closest to positive infinity) double value that is greater
than or equal to the argument

double ceilValue = [Link](5.3);

[Link]("2. Ceiling value: " + ceilValue);

// 3. floor(double a) - Returns the largest (closest to negative infinity) double value that is less than
or equal to the argument

double floorValue = [Link](5.9);

[Link]("3. Floor value: " + floorValue);

// 4. max(double a, double b) - Returns the greater of two double values

double max = [Link](10.5, 8.2);

[Link]("4. Maximum value: " + max);

// 5. min(double a, double b) - Returns the smaller of two double values

double min = [Link](10.5, 8.2);

[Link]("5. Minimum value: " + min);

// 6. pow(double a, double b) - Returns the value of the first argument raised to the power of the
second argument
double power = [Link](2, 3);

[Link]("6. 2 raised to the power of 3: " + power);

// 7. sqrt(double a) - Returns the positive square root of a double value

double squareRoot = [Link](25);

[Link]("7. Square root of 25: " + squareRoot);

// 8. cbrt(double a) - Returns the cube root of a double value

double cubeRoot = [Link](27);

[Link]("8. Cube root of 27: " + cubeRoot);

// 9. exp(double a) - Returns Euler's number (e) raised to the power of a double value

double exponential = [Link](2);

[Link]("9. e raised to the power of 2: " + exponential);

// 10. log(double a) - Returns the natural logarithm (base e) of a double value

double logarithm = [Link](10);

[Link]("10. Natural logarithm of 10: " + logarithm);

// 11. log10(double a) - Returns the base 10 logarithm of a double value

double log10 = Math.log10(100);

[Link]("11. Base 10 logarithm of 100: " + log10);

// 12. sin(double a) - Returns the trigonometric sine of an angle (in radians)

double sineValue = [Link]([Link] / 2);

[Link]("12. Sine value of 90 degrees: " + sineValue);


// 13. cos(double a) - Returns the trigonometric cosine of an angle (in radians)

double cosineValue = [Link](0);

[Link]("13. Cosine value of 0 degrees: " + cosineValue);

// 14. tan(double a) - Returns the trigonometric tangent of an angle (in radians)

double tangentValue = [Link]([Link] / 4);

[Link]("14. Tangent value of 45 degrees: " + tangentValue);

// 15. asin(double a) - Returns the arc sine of a value (result in the range -π/2 through π/2)

double arcSine = [Link](0.5);

[Link]("15. Arc sine of 0.5: " + arcSine);

// 16. acos(double a) - Returns the arc cosine of a value (result in the range 0.0 through π)

double arcCosine = [Link](0.5);

[Link]("16. Arc cosine of 0.5: " + arcCosine);

// 17. atan(double a) - Returns the arc tangent of a value (result in the range -π/2 through π/2)

double arcTangent = [Link](1);

[Link]("17. Arc tangent of 1: " + arcTangent);

// 18. atan2(double y, double x) - Converts rectangular coordinates (x, y) to polar coordinates (r, θ)
and returns the theta component

double polarTheta = Math.atan2(1, 1);

[Link]("18. Polar theta for (1, 1): " + polarTheta);

// 19. toDegrees(double angrad) - Converts an angle measured in radians to degrees

double degrees = [Link]([Link] / 2);


[Link]("19. Degrees equivalent to π/2 radians: " + degrees);

// 20. toRadians(double angdeg) - Converts an angle measured in degrees to radians

double radians = [Link](180);

[Link]("20. Radians equivalent to 180 degrees: " + radians);

// 21. random() - Returns a pseudorandom double between 0.0 (inclusive) and 1.0 (exclusive)

double randomValue = [Link]();

[Link]("21. Pseudorandom value between 0.0 and 1.0: " + randomValue);

// 22. round(float a) - Returns the closest int to the argument, with ties rounding to positive infinity

int roundedValue = [Link](5.8f);

[Link]("22. Rounded value: " + roundedValue);

// 23. round(double a) - Returns the closest long to the argument, with ties rounding to positive
infinity

long roundedValueLong = [Link](5.8);

[Link]("23. Rounded value (long): " + roundedValueLong);

// 24. IEEEremainder(double f1, double f2) - Computes the remainder operation on two arguments
as prescribed by the IEEE 754 standard

double remainder = [Link](10.5, 3.2);

[Link]("24. IEEE remainder of 10.5 / 3.2: " + remainder);

// 25. max(int a, int b) - Returns the greater of two int values

int maxInt = [Link](20, 15);

[Link]("25. Maximum value (int): " + maxInt);


// 26. min(int a, int b) - Returns the smaller of two int values

int minInt = [Link](20, 15);

[Link]("26. Minimum value (int): " + minInt);

// 27. hypot(double x, double y) - Computes sqrt(x^2 + y^2) without intermediate overflow or


underflow

double hypotenuse = [Link](3, 4);

[Link]("27. Hypotenuse of a right triangle with sides 3 and 4: " + hypotenuse);

// 28. incrementExact(int a) - Returns the argument incremented by one, throwing an exception if


the result overflows an int

int incrementedExact = [Link](5);

[Link]("28. Incremented exact value: " + incrementedExact);

// 29. decrementExact(int a) - Returns the argument decremented by one, throwing an exception if


the result overflows an int

int decrementedExact = [Link](8);

[Link]("29. Decremented exact value: " + decrementedExact);

// 30. negateExact(int a) - Returns the negation of the argument, throwing an exception if the result
overflows an int

int negatedExact = [Link](10);

[Link]("30. Negated exact value: " + negatedExact);

You might also like