Question

In: Computer Science

can you teach me how to implement the ArrayStringList and LinkedStringList using the same interface? I've...

can you teach me how to implement the ArrayStringList and LinkedStringList using the same interface? I've implemented a couple of methods in my ArrayStringList but I'm not sure if I'm doing it correctly and im confused on how to do the splice, reverse, and a couple others. I'm also having trouble getting started on my LinkedStringList.

In this project, you will be providing two different implementations of a StringList interface, which defines different operations that one should be able to do with a list of strings. A list is simply an object that represents an ordered collection of elements. The list implementation can decide how the elements are stored internally so long as users are able to interact with those elements via the methods defined in the interface. In this way, a list is an example of an abstract data type (ADT). To put it another way: while the implementor needs to understand the specific details of the implementation (in order to write the code to make it happen), the user of a list does not. The users simply interact with objects of the list implementation through the methods defined in the interface.

In order to truly understand this project, you must take a step back and think about how a list object and its storage are separate things. A list uses its storage to actually store its elements. For example, the size of a list does not have to be the same as the size of its storage, although the storage is likely at least as big as the list. For example, say you have created a shopping list with 5 items on it. You would say that there are five items on your list. If the list is implemented as a class in Java, you might have some internal storage (say, an array) that can hold more than five items. From the outside perspective, the list still contains 5 elements even though the internal storage may be larger. The internal array is hidden and is of no concern to the user of the class.

Each implementation of the StringList interface will be a concrete class with specific functional and non-functional requirements. These classes need to implement StringList either directly or via a common abstract parent class.

For this project, you will NOT have access to the .java files for the interface. Instead, you will have access to the generated API documentation for the interface here. Implementors should make sure that each method functions or behaves as described by the interface's API documentation, except in cases where a functional requirement changes the behavior of the method.

Implementors are always free to implement additional methods in addition to the ones defined by the interface. However, they should not assume that users (e.g., graders) will use them (even if declared with public visibility), since they are not defined in the interface. These additional methods may help avoid redundancy and promote code reuse within an implementation.

A functional requirement is added to your point total if satisfied. There will be no partial credit for any of the requirements that simply require the presence of a method related to a particular functionality. The actual functionality is tested using test cases.

For this project, you are required to create two different classes that implement the same interface. While the specific details are listed below, the following diagram illustrates the general relationship between your classes and the interface (with instance variables and most methods omitted from the diagram for brevity):

The specific requirements for each class are presented below.

  • ArrayStringList: Create the cs1302.list.ArrayStringList class such that it properly implements the cs1302.listadt.StringList interface with additional requirements listed below.

    • You must explicitly define and document default constructor for this class. The initial size of an ArrayStringList is 0 regardless of the list's underlying storage--remember, the list's internal storage and the list itself are two different things. Here is the signature:

      public ArrayStringList();
    • You must explicitly define and document a copy constructor for this class. It should make the new list a deep copy of the other list. Therefore, the initial size and element values of the new list should be the other list. The other list can be any implementation of the StringList interface. Here is the signature:

      public ArrayStringList(StringList other);
    • Over the lifetime of an ArrayStringList object, its internal storage may change in order to accomodate more list elements. When your code increases the size of an ArrayStringList object's internal array storage, you should actively avoid: i) increasing the array size by one; and ii) doubling the size of the array. Somewhere in between is more reasonable. Furthermore, you should not set the initial array size to 0 or to the largest number that is allowed.

    • There is a requirement related to this class's storage included in the Absolute Requirements section.

    • Extra Credit (5 points): Override the iterator() method for your ArrayStringList class as described in the StringList interface. This may require you to create an additional class that implements another interface. Some web searching might recommend an anonymous inner class. Please do not do this. If you choose to do this extra credit, then you should create a regular class that properly implements the desired interface. In addition to properly overriding iterator(), to receive points for this extra credit, you must include a file called EXTRA.md in your immediate project directory and place the text [EC2] on a single line within the file. In this file, you should have one line for each extra credit that you want the grader to check.

      NOTE: You do not need to implement the iterator() method if you are not doing the extra credit.

  • LinkedStringList: Create the cs1302.list.LinkedStringList class such that it properly implements the cs1302.listadt.StringList interface with additional requirements listed below.

    • You must explicitly define and document a default constructor for this class. The initial size of a LinkedStringList is 0 regardless of the list's underlying storage--remember, the list's internal storage and the list itself are two different things. Here is the signature:

      public LinkedStringList();
    • You must explicitly define and document a copy constructor for this class. It should make the new list a deep copy of the other list. Therefore, the initial size and element values of the new list should be the other list. The other list can be any implementation of the StringList interface. Here is the signature:

      public LinkedStringList(StringList other);
    • There is a requirement related to this class's storage included in the Absolute Requirements section.

    • Extra Credit (5 points): Override the iterator() method for your LinkedStringList class as described in the StringList interface. This may require you to create an additional class that implements another interface. Some web searching might recommend an anonymous inner class. Please do not do this. If you choose to do this extra credit, then you should create a regular class that properly implements the desired interface. In addition to properly overriding iterator(), to receive points for this extra credit, you must include a file called EXTRA.md in your immediate project directory and place the text [EC2] on a single line within the file. In this file, you should have one line for each extra credit that you want the the grader to check.

    • Non-Functional Requirements

      A non-functional requirement is subtracted from your point total if not satisfied. In order to emphasize the importance of these requirements, non-compliance results in the full point amount being subtracted from your point total. That is, they are all or nothing.

    • (0 points) [RECOMMENDED] No Static Variables: Use of static variables is not appropriate for this assignment. However, static constants are perfectly fine.

    • Methods for ArrayStringList
    • Modifier and Type Method and Description
      boolean add(int index, String s)

      Inserts the specified string at the specified position in this list.

      boolean add(int index, StringList sl)

      Inserts the strings contained in the specified list at the specified position in this list, in the order in which they appear in the specified list.

      boolean add(String s)

      Appends the specified string to the end of this list.

      boolean add(StringList sl)

      Appends the strings contained in the specified list to the end of this list, in the order in which they appear in the specified list.

      void clear()

      Removes all of the strings from this list.

      boolean contains(String o)

      Returns true if this list contains the specified string.

      boolean containsIgnoreCase(String o)

      Returns true if this list contains the specified string, ignoring case.

      boolean containsSubstring(String o)

      Returns true if any string in this list contains the specified substring.

      StringList distinct()

      Builds and returns a new StringList from this list without any duplicate strings.

      String get(int index)

      Returns the string at the specified position in this list.

      int indexOf(String s)

      Returns the index of the first occurrence of the specified string in this list, or -1 if this list does not contain the string.

      int indexOfIgnoreCase(String s)

      Returns the index of the first occurrence of the specified string, ignoring case, in this list, or -1 if this list does not contain the string.

      boolean isEmpty()

      Returns true if this list contains no elements.

      default Iterator iterator()

      Returns a new iterator over the strings in this list in proper sequence.

      default String makeString()

      Returns a string representation of this list with all of strings directly concatenated in order.

      String makeString(String sep)

      Returns a string representation of this list with every string in the sequence separated by the specified separator string.

      default String makeString(String start, String sep, String end)

      Returns a string representation of this list that begins with start and ends with end, with every string in the sequence separated by sep.

      String remove(int index)

      Removes the string at the specified position in this list.

      StringList reverse()

      Builds and returns a new StringList that contains the strings from this list in reverse order.

      String set(int index, String s)

      Replaces the string at the specified position in this list with the specified element.

      int size()

      Returns the number of elements in this list.

      StringList splice(int fromIndex, int toIndex)

      Builds and returns a new StringList that contains the strings from this list between the specified fromIndex, inclusive, and toIndex, exclusive.

      String[] toArray()

      Returns a new array containing all of the strings in this list in proper sequence (from first to last element).

  • Methods for LinkedStringList
  • Constructor and Description
    Node()

    Constructs a new node with all properties unset.

    Node(String str)

    Constructs a new node with the str property set and the next property unset.

    Node(String str, StringList.Node next)

    Constructs a new node with the str and next properties set.

  • Method Summary

    Modifier and Type Method and Description
    StringList.Node getNext()

    Returns the value of the next property for this node.

    String getStr()

    Returns the value of the str property for this node.

    void setNext(StringList.Node next)

    Sets the value of the next property for this node.

    void setStr(String str)

    Sets the value of the str property for this node.

  • Uses these methods to implement the same methods as ArrayStringList belonging to the StringList interface however with the usage of node objects.

Used to download the project in UNIX that includes the interface and tester:

 git clone --depth 1 https://github.com/cs1302uga/cs1302-listadt.git

To be clear, both listadt.jar and bin are assumed to be in the your main project directory when the tester is run. If your code does not yet compile because one of the classes does not yet fully implement the StringList interface, then you can rapidly get it to compile by following the advice given here.

To see the options for the tester, run listadt-tester in your main project directory:

$ listadt-tester
Usage: listadt-tester [OPTION]...

Run public test cases for the cs1302-listadt project. This program assumes
that your code compiles correctly, the default location for compiled code
is 'bin', and 'listadt.jar' is in the current directory.

Options:
    -a | --ArrayStringList     Check and test cs1302.list.ArrayStringList
    -l | --LinkedStringList    Check and test cs1302.list.LinkedStringList
    --help                     Show this help information (ignore other options)

You can test your ArrayStringList class, LinkedStringList class, or both. For example, to just test ArrayStringList, you can run:

$ listadt-tester -a

Solutions

Expert Solution

I've implemented the program in Java-

Functional Requirements

A functional requirement is added to your point total if satisfied. There will be no partial credit for any of the requirements that simply require the presence of a method related to a particular functionality. The actual functionality is tested using test cases.

  • ArrayStringList: Create the cs1302.list.ArrayStringList class such that it properly implements the cs1302.listadt.StringList interface with additional requirements listed below.

    • You must explicitly define and document default constructor for this class. The initial size of an ArrayStringList is 0 regardless of the list's underlying storage--remember, the list's internal storage and the list itself are two different things. Here is the signature:

      public ArrayStringList();
    • You must explicitly define and document a copy constructor for this class. It should make the new list a deep copy of the other list. Therefore, the initial size and element values of the new list should be the other list. The other list can be any implementation of the StringList interface. Here is the signature:

      public ArrayStringList(StringList other);
    • There is a requirement related to this class's storage included in the Absolute Requirements section.

    • Extra Credit (5 points): Override the iterator() method for your ArrayStringList class as described in the StringList interface. This may require you to create an additional class that implements another interface. In addition to properly overriding iterator(), to receive points for this extra credit, you must include a file called EXTRA.md in your immediate project directory and place the text [EC1] on a single line within the file. In this file, you should have one line for each extra credit that you want the the grader to check.

      NOTE: You do not need to implement the iterator() method if you are not doing the extra credit.

  • LinkedStringList: Create the cs1302.list.LinkedStringList class such that it properly implements the cs1302.listadt.StringList interface with additional requirements listed below.

    • You must explicitly define and document default constructor for this class. The initial size of a LinkedStringList is 0 regardless of the list's underlying storage--remember, the list's internal storage and the list itself are two different things. Here is the signature:

      public LinkedStringList();
    • You must explicitly define and document a copy constructor for this class. It should make the new list a deep copy of the other list. Therefore, the initial size and element values of the new list should be the other list. The other list can be any implementation of the StringList interface. Here is the signature:

      public LinkedStringList(StringList other);
    • There is a requirement related to this class's storage included in the Absolute Requirements section.

    • Extra Credit (5 points): Override the iterator() method for your LinkedStringList class as described in the StringList interface. This may require you to create an additional class that implements another interface. In addition to properly overriding iterator(), to receive points for this extra credit, you must include a file called EXTRA.md in your immediate project directory and place the text [EC2] on a single line within the file. In this file, you should have one line for each extra credit that you want the the grader to check.

      NOTE: You do not need to implement the iterator() method if you are not doing the extra credit.

  • (100 points) Test Cases: The bulk of this project will be graded based on 50 JUnit test cases, each worth 2 points. This is the same as someone using the classes you wrote based purely on the interface definitions. If you implement the interface correctly, then you should pass the associated test cases.

Non-Functional Requirements

A non-functional requirement is subtracted from your point total if not satisfied. In order to emphasize the importance of these requirements, non-compliance results in the full point amount being subtracted from your point total. That is, they are all or nothing.

  • (25 points) Code Style Guidelines: You should be consistent with the style aspect of your code in order to promote readability. All of the individual code style guidelines listed below are part of a single non-functional requirement that, like the others, is all or nothing. Besides consistency, the following conventions will be enforced:

    • Reference type names are written in UpperCamelCase. Class names are
      typically nouns or noun phrases. For example, Character or ImmutableList. Interface names may also be nouns or noun phrases (for example, List), but may sometimes be adjectives or adjective phrases instead (for example, Readable).

    • Method names are written in lowerCamelCase. Method names are also typically verbs or verb phrases. For example, sendMessage or stop.

    • Braces are always used where optional. Braces should be used with if, else, for, do, and while statements, even when the body is empty or contains only a single statement.

    • Block Indentation: 4 spaces. Each time a new block or block-like construct is opened, the indent increases by four spaces. When the block ends, the indent returns to the previous indent level. The indent level applies to both code and comments throughout the block.

      If you use Emacs, you can add the following lines to your ~/.emacs file to make tabs for new files comply with this requirement:

      (setq-default indent-tabs-mode nil)
      (setq-default c-default-style "linux"
                        c-basic-offset 4)
      (setq-default tab-width 4)
      (setq indent-line-function 'insert-tab)
      
    • Column limit: 100. You should limit the number of characters, including whitespace, on any given line to 100 characters. Except as noted below, any line that would exceed this limit must be manually line-wrapped in a consistent manner. Exceptions to the column limit include:

      • Lines where obeying the column limit is not possible (for example, a long URL in Javadoc, or a long JSNI method reference).
      • In package and import statements.
      • Command line input examples in a comment that may be cut-and-pasted into a shell.

      If you use Emacs, then you can add the following lines to your ~/.emacs file to highlight characters that exceed the column limit:

      ;; check for lines that exceed some column limit
      (setq-default
       whitespace-line-column 100
       whitespace-style '(face lines-tail))
      (add-hook 'prog-mode-hook #'whitespace-mode)
      

      If you would rather have Emacs highlight entire lines that exceed the column limit, then use the following instead (not in addition to):

      ;; check for lines that exceed some column limit
      (setq-default
       whitespace-line-column 100
       whitespace-style '(face lines))
      (add-hook 'prog-mode-hook #'whitespace-mode)
      

      You can create the ~/.emacs file if it does not exist. If you have an ~/.emacs.el or ~/.emacs.d/init.el file, then you can place the lines in that file instead of ~/.emacs.

      If, after adding the configuration lines above, you still have trouble finding lines that exceed the column limit, then you can ask Emacs to mark newlines with a $ by typing M-x whitespace-newline-mode then RET (return).

    • Method height <= window height. You should limit the number of lines for a method so that the entire method can be seen on the screen at once. This includes the line(s) with the method's signature and opening curly brace, all lines in the body of the mthod (including blank lines), and the line with the method's ending curly brace. The method height does not include a method's Javadoc comment, however, it does include any comments contained within the body of the method.

      Of all the style guidelines, this is the probably the most subjective and hardest to grade because everyone might have a different window size due to different terminal emulator and physical screen size configurations. Therefore, graders will be checking for compliance with the spirit of this guideline, which is: methods that are too big and/or repetitive should be refactored to include proper looping constructs and/or broken up into smaller methods to improve readability.

      If you use Emacs, you can add the following lines to your ~/.emacs file to enable line numbers:

      ;; add line numbers
      (global-linum-mode 1)
      
      ;; display line numbers and column numbers
      (setq line-number-mode t)
      (setq column-number-mode t)
      
      ;; make sure the line numbers don't touch the text
      (setq linum-format "%d ")
      

      You can create the ~/.emacs file if it does not exist. If you have an ~/.emacs.el or ~/.emacs.d/init.el file, then you can place the lines in that file instead of ~/.emacs.

  • Javadoc Documentation (25 points): All methods and classes needs to be fully documented using Javadoc comments and appropriate Jaadoc tags. Each comment should provide a description of the method's functionality in the first sentence of the comment. This sentence needs to be a grammatically correct English sentence with proper punctuation. Further description can be provided in subsequent sentence.

    Even if documentation is inherited from an interface, you must explicitly include a Javadoc comment with either a new description (if that makes sense) or make proper use of the {@inheritDoc} tag.

    It should be noted that we do expect you to provide a Javadoc comment for each class in addition to a comment for each method within a class. The Javadoc comment for a class is placed directly above the class declaration as seen in the examples provided in the link referenced earlier.

  • In-line Documentation (25 points): Code blocks should be adequately documented using in-line comments. This is especially necessary when a block of code is not immediately understood by a reader (e.g., yourself or the grader).

Absolute Requirements

An absolute requirement is similar to a non-functional requirement, except that violating it will result in an immediate zero for the assignment. In many cases, a violation will prevent the graders from evaluating your functional requirements. No attempts will be made to modify your submission to evaluate other requirements.

  • Project Directory Structure: The location of the default package for the source code should be a direct subdirectory of cs1302-listadt called src. When the project is compiled, the -d option should be used with javac to make the default package for compiled code a direct subdirectory of cs1302-listadt called bin.

    If you follow this structure, then you would type the following to compile your code, assuming you are in the top-level project directory cs1302-listadt:

    $ javac -cp listadt.jar -d bin src/cs1302/list/ArrayStringList.java
    $ javac -cp listadt.jar -d bin src/cs1302/list/LinkedStringList.java
    

    Remember, when you compile .java files individually, there might be dependencies between the files. In such cases, the order in which you compile the code matters. Also, if more than one default package is needed (e.g., listadt.jar and some other directory like bin), then a colon : can be used to separate each path in a list of multiple paths supplied to -cp. For an example, see "Setting the Classpath" in the package tutorial.

  • Development Environment: This project must be implemented in Java 8, and it must compile and run correctly on Nike using the specific version of Java 8 that is setup according to the instructions provided by your instructor. For Spring 2019, these instructions were posted on Piazza @29.

    If you decide to introduce additional .java files into your project, then they are expected to fulfill all non-functional and absolute requirements, even if the main parts of the project do not use them. You may assume graders will compile your source code in an order that satisfies compilation dependencies. You should remove any .java files that you do not need before submission.

  • cs1302.list.ArrayStringList Storage Requirement: You must use a basic Java array for this class's storage. The initial size of the array does not have to be the same size as the initial size of the list. Whenever the size of the list is about to exceed the size of its array, the list should dynamically allocate a new array of a larger size and copy the contents over--please consider writing and documenting a private support method to do this. If you use Java's java.util.ArrayList class or something similar, then that will result in an immediate violation of this non-functional requirement, regardless of any use of a regular array elsewhere in the class. This requirement also prohibits any use of third-party implementations of list or list-like interfaces.

  • cs1302.list.LinkedStringList Storage Requirement: You must use a sequence of cs1302.listadt.StringList.Node objects for this class's storage. Unlike the array-based implementation in ArrayStringList, this type of storage is not limited to the number of elements that can fit into an array (because there is not an array). Instead, it's limited only by the available memory for the Java program using the LinkedStringList object. You may find sections 13.1 and 13.2 of the LDC textbook useful reference material for this class. If you use Java's java.util.LinkedList class or something similar, then that will result in an immediate violation of this non-functional requirement, regardless of any use of any Node objects elsewhere in the class. This requirement also prohibits any use of third-party implementations of list or list-like interfaces.

  • No Static Variables: Use of static variables is not allowed for this assignment. However, static constants are permitted.

Grading

This project will be graded using unit tests, none of which will be made available before the project deadline. You can test your implementations yourself via interface polymorphism.

ArrayStringList.java:

package cs1302.list;
import cs1302.listadt.StringList;
import java.lang.*;

/** Represents an {@code ArrayStringList} object that uses an array to store strings. */
public class ArrayStringList implements StringList {
private String[] list; //list stored as an array

/** Creates an {@code ArrayStringList} object and initializes list to be an array of size 0 */
public ArrayStringList() {
list = new String[0];
} //ArrayStringList

/**
* Creates an {@code ArrayStringList} object and copies all strings from a specified list.
* @param other the list whose strings are to be copied
*/
public ArrayStringList(StringList other) {
list = new String[other.size()];
for(int i = 0; i < other.size(); i++) {
list[i] = other.get(i);
}
} //ArrayStringList

/**
* Inserts the specified string at the specified position in this list.
* @param index index at which the specified string is to be inserted
* @param s string to be inserted
* @return true if this list changed as a result of the call; false otherwise
* @throws NullPointerException if the specified string is null
* @throws IllegalArgumentException if the specified string is empty
* @throws IndexOutOfBoundsException if the index is out of range
* (index {@literal <} 0 || index {@literal >} size())
*/
public boolean add(int index, String s) {
boolean add = false;
if (s == null) {
throw new NullPointerException("String is null");
} else if (s.equals("")) {
throw new IllegalArgumentException("String is empty");
} else if (index < 0 || index > size()) {
throw new IndexOutOfBoundsException("Index is out of range");
} else {
String[] list1 = new String[size() + 1];
int i = 0;
for(int n = 0; n < index; n++) {
list1[n] = list[n];
i++;
}
list1[i] = s;
for(int n = index + 1; n < list1.length; n++) {
list1[n] = list[n - 1];
}
list = list1;
add = true;
}
return add;
} //add
  
/**
* Inserts the strings contained in the specified list at the specified position in this list,
* in the order in which they appear in the specified list.
* @param index index at which the specified string is to be inserted
* @param sl string to be inserted
* @return true if this list changed as a result of the call; false otherwise
* @throws NullPointerException if the specified list is null
* @throws IndexOutOfBoundsException if the index is out of range
* (index {@literal <} 0 || index {@literal >} size())
*/
public boolean add(int index, StringList sl) {
boolean add = false;
if (sl == null) {
throw new NullPointerException("StringList is null");
} else if (index < 0 || index > size()) {
throw new IndexOutOfBoundsException("Index is out of range");
} else {
String[] list1 = new String[size() + sl.size()];
int i = 0;
for(int n = 0; n < index; n++) {
list1[n] = list[n];
i++;
}
for(int n = 0; n < sl.size(); n++) {
list1[i] = sl.get(n);
i++;
}
for(int n = index; n < size(); n++) {
list1[i] = list[n];
i++;
}
list = list1;
add = true;
}
return add;
} //add
  
/**
* Appends the specified string to the end of this list.
* @param s string to be appended
* @return true if this list changed as a result of the call; false otherwise
* @throws NullPointerException if the specified string is null
* @throws IllegalArgumentException if the specified string is empty
*/
public boolean add(String s) {
boolean add = false;
if (s == null) {
throw new NullPointerException("String is null");
} else if (s.equals("")) {
throw new IllegalArgumentException("String is empty");
} else {
String[] list1 = new String[size() + 1];
for(int i = 0; i < size(); i++) {
list1[i] = list[i];
}
list1[list1.length - 1] = s;
list = list1;
add = true;
}
return add;
} //add

/**
* Appends the strings contained in the specified list to the end of this list, in the order
* in which they appear in the specified list.
* @param sl list whose strings are to be appended
* @return true if this list changed as a result of the call; false otherwise
* @throws NullPointerException if the specified list is null
*/
public boolean add(StringList sl) {
boolean add = false;
if (sl == null) {
throw new NullPointerException("StringList is null");
} else {
String[] list1 = new String[this.size() + sl.size()];
int i = 0;
for(int n = 0; n < size(); n++) {
list1[n] = list[n];
i++;
}
for (int n = 0; n < sl.size(); n++) {
list1[i] = sl.get(n);
i++;
}
list = list1;
add = true;
}
return add;
} //add
  
/**
* Removes all of the stringns from this list.
* The list will be empty after this call returns.
*/
public void clear() {
String[] newList = new String[0];
list = newList;
} //clear

/**
* Returns true if this list contains the specified string.
* More formally, returns true if, and only if, this list contains at least
* one element s such that o.equals(s).
* @param o string whose presence in this list is to be tested
* @return true if this list contains the specified string
* @throws NullPointerException if the specified string is null
* @throws IllegalArgumentException if the specified string is empty
*/
public boolean contains(String o) {
boolean contains = false;
if (o == null) {
throw new NullPointerException("String is null");
} else if (o.equals("")) {
throw new IllegalArgumentException("String is empty");
} else {
for(String s : list) {
if (o.equals(s)) {
contains = true;
}
}
}
return contains;
} //contains
  
/**
* Returns true if this list contains the specified string, ignoring case.
* More formally, returns true if, and only if, this list contains at least
* one element s such that o.equalsIgnoreCase(s).
* @param o string whose presence in this list is to be tested
* @return true if this list contains the specified string
* @throws NullPointerException if the specified string is null
* @throws IllegalArgumentException if the specified string is empty
*/
public boolean containsIgnoreCase(String o) {
boolean contains = false;
if (o == null) {
throw new NullPointerException("String is null");
} else if (o.equals("")) {
throw new IllegalArgumentException("String is empty");
} else {
for(String s : list) {
if (o.equalsIgnoreCase(s)) {
contains = true;
}
}
}
return contains;
} //containsIgnoreCase

/**
* Returns true if any string in this list contains the specified substring.
* More formally, returns true if, and only if, this list contains at least
* one element s such that s.contains(o).
* @param o substring whose presence in this list is to be tested
* @return true if this list contains the specified string
* @throws NullPointerException if the specified substring is null
* @throws IllegalArgumentException if the specified substring is empty
*/
public boolean containsSubstring(String o) {
boolean contains = false;
if (o == null) {
throw new NullPointerException("String is null");
} else if (o.equals("")) {
throw new IllegalArgumentException("String is empty");
} else {
for(String s : list) {
if (s.contains(o)) {
contains = true;
}
}
}
return contains;
} //containsSubstring

/**
* Returns an array containing all of the strings in this list in proper
* sequence (from first to last element). The returned array will be "safe"
* in that no references to it are maintained by this list.
* In other words, this method must allocate a new array even if this list
* is backed by an array. The caller is thus free to modify the returned array.
* @return an array containing all of the strings in this list in proper sequence
*/
public String[] toArray() {
String[] array = new String[size()];
for(int i = 0; i < size(); i++) {
array[i] = list[i];
}
return array;
} //toArray

/**
* Returns the number of elements in this list. If this list contains more than
* Integer.MAX_VALUE elements, then this method returns Integer.MAX_VALUE.
* @return the number of elements in this list
*/
public int size() {
if(list.length > Integer.MAX_VALUE) {
return Integer.MAX_VALUE;
}
return list.length;
} //size

/**
* Returns true if this list contains no elements.
* @return true if this list contains no elements
*/
public boolean isEmpty() {
if(size() == 0) {
return true;
} else {
return false;
}
} //isEmpty

/**
* Returns the string at the specified position in this list.
* @param index index of the string to return
* @return the string at the specified position in this list
* @throws IndexOutOfBoundsException if the index is out of range
* (index {@literal <} 0 || index {@literal >}= size())
*/
public String get(int index) {
String string = "";
if (index < 0 || index >= size()) {
throw new IndexOutOfBoundsException("Index out of bounds");
} else {
string = list[index];
}
return string;
} //get

/**
* Replaces the string at the specified position in this list with the specified element.
* @param index index at which the specified string is to be inserted
* @param s string to be inserted
* @return the string previously at the specified position
* @throws NullPointerException if the specified string is null
* @throws IllegalArgumentException if the specified string is empty
* @throws IndexOutOfBoundsException if the index is out of range
* (index {@literal <} 0 || index {@literal >}= size())
*/
public String set(int index, String s) {
String string = "";
if (s == null) {
throw new NullPointerException("String is null");
} else if (s.equals("")) {
throw new IllegalArgumentException("String is empty");
} else if (index < 0 || index >= size()) {
throw new IndexOutOfBoundsException("Index out of bounds");
} else {
string = list[index];
list[index] = s;
}
return string;
} //set

/**
* Removes the string at the specified position in this list.
* Shifts any subsequent elements to the left (subtracts one from their indices).
* Returns the string that was removed from the list.
* @param index index of the string to remove
* @return the string previously at the specified position in this list
* @throws IndexOutOfBoundsException if the index is out of range
* (index {@literal <} 0 || index {@literal >}= size())
*/
public String remove(int index) {
String string = "";
if (index < 0 || index >= size()) {
throw new IndexOutOfBoundsException("Index out of bounds");
} else {
string = list[index];
String[] list1 = new String[size() - 1];
for(int i = 0; i < index; i++) {
list1[i] = list[i];
}
for (int i = index + 1; i < list.length; i++) {
list1[i-1] = list[i];
}
list = list1;
}
return string;
} //remove

/**
* Returns the index of the first occurrence of the specified string in this list, or -1 if
* this list does not contain the string. More formally, returns the lowest index i such that
* s.equals(get(i))), or -1 if there is no such index.
* @param s string to search for
* @return the index of the first occurrence of the specified string in this list, or -1 if
* this list does not contain the string
* @throws NullPointerException if the specified string is null
* @throws IllegalArgumentException if the specified string is empty
*/
public int indexOf(String s) {
if (s == null) {
throw new NullPointerException("String is null");
} else if (s.equals("")) {
throw new IllegalArgumentException("String is empty");
} else {
int index = 0;
for (String string : list) {
if(s.equals(string)) {
return index;
}
index++;
}
}
return -1;
} //indexOf

/**
* Returns the index of the first occurrence of the specified string, ignoring case, in this
* list, or -1 if this list does not contain the string. More formally, returns the lowest
* index i such that s.equalsIgnoreCase(get(i))), or -1 if there is no such index.
* @param s string to search for
* @return the index of the first occurrence of the specified string, ignoring case, in this
* list, or -1 if this list does not contain the string
* @throws NullPointerException if the specified string is null
* @throws IllegalArgumentException if the specified string is empty
*/
public int indexOfIgnoreCase(String s) {
if (s == null) {
throw new NullPointerException("String is null");
} else if (s.equals("")) {
throw new IllegalArgumentException("String is empty");
} else {
int index = 0;
for (String string : list) {
if(s.equalsIgnoreCase(string)) {
return index;
}
index++;
}
}
return -1;
} //indexOfIgnoreCase

/**
* Builds and returns a new {@code StringList} from this list without any duplicate strings.
* @return a new {@code StringList} which contains the first occurance of every string in this
* list
*/
public StringList distinct() {
StringList list1 = new ArrayStringList();
for(String string : list) {
if(list1.indexOf(string) == -1) {
list1.add(string);
}
}
return list1;
} //distinct

/**
* Builds and returns a new {@code StringList} that contains the strings from this list in
* reverse order.
* @return a new {@code StringList} with the strings from this list in reverse order
*/
public StringList reverse() {
StringList list1 = new ArrayStringList();
for(int i = size() - 1; i >= 0; i--) {
list1.add(list[i]);
}
return list1;
} //reverse

/**
* Returns a string representation of this list with every string in the sequence separated by
* the specified seprator string.
* @param sep the specified separator string
* @return string representation of this list with every string in the sequence separated by sep
*/
public String makeString(String sep) {
String string = "";
if(size() != 0) {
for(int i = 0; i < size() - 1; i++) {
string = string + list[i] + sep;
}
string += list[list.length - 1];
}
return string;
} //makeString

/**
* Builds and returns a new {@code StringList} that contains the strings from this list between
* the specified {@code fromIndex}, inclusive, and {@code toIndex}, exclusive. If
* {@code fromIndex} and {@code toIndex} are in bounds and equal, then the returned list is
* empty.
* @param fromIndex low endpoint (inclusive) of the splice
* @param toIndex high endpoint (exclusive) of the splice
* @return a new {@code StringList} with the strings from this list from the specified range
* @throws IndexOutOfBoundsException for an illegal endpoint index value
* (fromIndex {@literal <} 0 || toIndex {@literal >} size || fromIndex {@literal >} toIndex)
*/
public StringList splice(int fromIndex, int toIndex) {
StringList list1 = new ArrayStringList();
if(fromIndex < 0 || toIndex > size() || fromIndex > toIndex) {
throw new IndexOutOfBoundsException("Illegal endpoint index value");
} else {
for(int i = fromIndex; i < toIndex; i++) {
list1.add(list[i]);
}
}
return list1;
} //splice
}

LinkedStringList.java:

package cs1302.list;
import cs1302.listadt.StringList;
import cs1302.listadt.StringList.Node;

/** Represents a {@code LinkedStringList} object that uses nodes to store strings. */
public class LinkedStringList implements StringList {
StringList.Node list; //list stored as a linked list
  
/** Creates a LinkedStringList object with an empty node as its first and only node. */
public LinkedStringList() {
list = new StringList.Node();
} //LinkedStringList

/**
* Creates a {@code LinkedStringList} object with an empty node as its first node and then
* appends a copy of the specified list to the end.
* @param other the list whose strings are to be copied
*/
public LinkedStringList(StringList other) {
list = new StringList.Node();
StringList.Node current = list;
for(int i = 0; i < other.size(); i++) {
String s = other.get(i);
current.setNext(new StringList.Node(s, null));
current = current.getNext();
}
} //LinkedStringList

/**
* Returns the number of elements in this list. If this list contains more than
* Integer.MAX_VALUE elements, then this method returns Integer.MAX_VALUE.
* @return the number of elements in this list
*/
public int size() {
int size = 0;
StringList.Node current = list.getNext();
while (current != null) {
size++;
if(size > Integer.MAX_VALUE) {
return Integer.MAX_VALUE;
}
current = current.getNext();
}
return size;
} //size

/**
* {@inheritdoc}
* @return true if this list contains no elements
*/
public boolean isEmpty() {
if (size() == 0) {
return true;
} else {
return false;
}
} //isEmpty

/**
* Returns true if this list contains the specified string.
* More formally, returns true if, and only if, this list contains at least
* one element s such that o.equals(s).
* @param o string whose presence in this list is to be tested
* @return true if this list contains the specified string
* @throws NullPointerException if the specified string is null
* @throws IllegalArgumentException if the specified string is empty
*/
public boolean contains(String o) {
boolean contains = false;
if (o == null) {
throw new NullPointerException("String is null");
} else if (o.equals("")) {
throw new IllegalArgumentException("String is empty");
} else {
for (int i = 0; i < size(); i++) {
if(o.equals(get(i))) {
contains = true;
}
}
}
return contains;
} //contains

/**
* Returns true if this list contains the specified string, ignoring case.
* More formally, returns true if, and only if, this list contains at least
* one element s such that o.equalsIgnoreCase(s).
* @param o string whose presence in this list is to be tested
* @return true if this list contains the specified string
* @throws NullPointerException if the specified string is null
* @throws IllegalArgumentException if the specified string is empty
*/
public boolean containsIgnoreCase(String o) {
boolean contains = false;
if (o == null) {
throw new NullPointerException("String is null");
} else if (o.equals("")) {
throw new IllegalArgumentException("String is empty");
} else {
for (int i = 0; i < size(); i++) {
if(o.equalsIgnoreCase(get(i))) {
contains = true;
}
}
}
return contains;
} //containsIgnoreCase

/**
* Returns true if any string in this list contains the specified substring.
* More formally, returns true if, and only if, this list contains at least
* one element s such that s.contains(o).
* @param o substring whose presence in this list is to be tested
* @return true if this list contains the specified string
* @throws NullPointerException if the specified substring is null
* @throws IllegalArgumentException if the specified substring is empty
*/
public boolean containsSubstring(String o) {
boolean contains = false;
if (o == null) {
throw new NullPointerException("String is null");
} else if (o.equals("")) {
throw new IllegalArgumentException("String is empty");
} else {
for (int i = 0; i < size(); i++) {
if(o.contains(get(i))) {
contains = true;
}
}
}
return contains;
} //containsSubstring

/**
* Returns an array containing all of the strings in this list in proper
* sequence (from first to last element). The returned array will be "safe"
* in that no references to it are maintained by this list.
* In other words, this method must allocate a new array even if this list
* is backed by an array. The caller is thus free to modify the returned array.
* @return an array containing all of the strings in this list in proper sequence
*/
public String[] toArray() {
String[] array = new String[size()];
for(int i = 0; i < size(); i++) {
array[i] = get(i);
}
return array;
} //toArray

/**
* Appends the specified string to the end of this list.
* @param s string to be appended
* @return true if this list changed as a result of the call; false otherwise
* @throws NullPointerException if the specified string is null
* @throws IllegalArgumentException if the specified string is empty
*/
public boolean add(String s) {
boolean add = false;
if (s == null) {
throw new NullPointerException("String is null");
} else if (s.equals("")) {
throw new IllegalArgumentException("String is empty");
} else {
StringList.Node current = list;
while(current.getNext() != null) {
current = current.getNext();
}
current.setNext(new StringList.Node(s, null));
add = true;
}
return add;
} //add
  
  
/**
* Appends the strings contained in the specified list to the end of this list, in the order
* in which they appear in the specified list.
* @param sl list whose strings are to be appended
* @return true if this list changed as a result of the call; false otherwise
* @throws NullPointerException if the specified list is null
*/
public boolean add(StringList sl) {
boolean add = false;
if (sl == null) {
throw new NullPointerException("StringList is null");
} else {
StringList.Node current = getNode(size());
for(int i = 0; i < sl.size(); i++) {
current.setNext(new StringList.Node(sl.get(i), null));
current = current.getNext();
}
add = true;
}
return add;
} //add

/**
* Inserts the specified string at the specified position in this list.
* @param index index at which the specified string is to be inserted
* @param s string to be inserted
* @return true if this list changed as a result of the call; false otherwise
* @throws NullPointerException if the specified string is null
* @throws IllegalArgumentException if the specified string is empty
* @throws IndexOutOfBoundsException if the index is out of range
* (index {@literal <} 0 || index {@literal >} size())
*/
public boolean add(int index, String s) {
boolean add = false;
if (s == null) {
throw new NullPointerException("String is null");
} else if (s.equals("")) {
throw new IllegalArgumentException("String is empty");
} else if (index < 0 || index > size()) {
throw new IndexOutOfBoundsException("Index out of bounds");
} else {
if (index == 0) {
StringList.Node front = new StringList.Node();
StringList.Node temp = new StringList.Node(s, list.getNext());
front.setNext(temp);
list = front;
} else if (index == size()) {
add(s);
} else {
StringList.Node front = list.getNext();
for (int i = 0; i < index - 1; i++) { //sets front to the node before the index node
front = front.getNext();
}
StringList.Node back = new StringList.Node(s, front.getNext());
front.setNext(back); //merges the 2 nodes with the added string in between
}
add = true;
}
return add;
  
} //add

/**
* Inserts the strings contained in the specified list at the specified position in this list,
* in the order in which they appear in the specified list.
* @param index index at which the specified string is to be inserted
* @param sl list to be inserted
* @return true if this list changed as a result of the call; false otherwise
* @throws NullPointerException if the specified list is null
* @throws IndexOutOfBoundsException if the index is out of range
* (index {@literal <} 0 || index {@literal >} size())
*/
public boolean add(int index, StringList sl) {
boolean add = false;
if (sl == null) {
throw new NullPointerException("StringList is null");
} else if (index < 0 || index > size()) {
throw new IndexOutOfBoundsException("Index out of bounds");
} else {
if (index == size()) {
add(sl);
} else {
StringList.Node front = list.getNext();
for (int i = 0; i < index - 1; i++) { //sets front to the node before the index node
front = front.getNext();
}
StringList.Node back = front.getNext(); //sets back to the node currently at index
for (int i = 0; i < sl.size(); i++) { //adds sl to front
front.setNext(new StringList.Node(sl.get(i)));
front = front.getNext();
}
front.setNext(back); //merges the 2 lists together
add = true;
}
}
return add;
} //add

/**
* Returns a reference to the index-th node in a linked list
* @param index the index of the node
* @return a reference to the index-th node
*/
private StringList.Node getNode(int index) {
StringList.Node current;
if (size() == 0) {
current = list;
} else {
current = list.getNext();
for (int i = 0; i < index - 1; i++) {
current = current.getNext();
}
}
return current;
} //getNode

/**
* Returns the string at the specified position in this list.
* @param index index of the string to return
* @return the string at the specified position in this list
* @throws IndexOutOfBoundsException if the index is out of range
* (index {@literal <} 0 || index {@literal >}= size())
*/
public String get(int index) {
String string = "";
if (index < 0 || index >= size()) {
throw new IndexOutOfBoundsException("Index out of bounds");
} else {
StringList.Node current = list.getNext(); //Skips the first node that is always empty
for (int i = 0; i < index; i++) {
current = current.getNext();
}
string = current.getStr();
}
return string;
} //get

/**
* Replaces the string at the specified position in this list with the specified element.
* @param index index at which the specified string is to be inserted
* @param s string to be inserted
* @return the string previously at the specified position
* @throws NullPointerException if the specified string is null
* @throws IllegalArgumentException if the specified string is empty
* @throws IndexOutOfBoundsException if the index is out of range
* (index {@literal <} 0 || index {@literal >}= size())
*/
public String set(int index, String s) {
String string = "";
if (s == null) {
throw new NullPointerException("String is null");
} else if (s.equals("")) {
throw new IllegalArgumentException("String is empty");
} else if (index < 0 || index >= size()) {
throw new IndexOutOfBoundsException("Index out of bounds");
} else {
StringList.Node current = getNode(index + 1);
string = current.getStr();
current.setStr(s);
}
return string;
} //set

/**
* Removes the string at the specified position in this list.
* Shifts any subsequent elements to the left (subtracts one from their indices).
* Returns the string that was removed from the list.
* @param index index of the string to remove
* @return the string previously at the specified position in this list
* @throws IndexOutOfBoundsException if the index is out of range
* (index {@literal <} 0 || index {@literal >}= size())
*/
public String remove(int index) {
String string = "";
if (index < 0 || index >= size()) {
throw new IndexOutOfBoundsException("Index out of bounds");
} else {
StringList.Node front = list.getNext();
if(index == 0) { //if you want to remove the first element in the list
string = front.getStr();
list = front;
} else {
for (int i = 0; i < index - 1; i++) { //sets front to the node before the index node
front = front.getNext();
}
string = front.getNext().getStr();
//back equals the node after the index node
StringList.Node back = front.getNext().getNext();
front.setNext(back); //merges front and back, omitting the index node
}
}
return string;
} //remove

/**
* Returns the index of the first occurrence of the specified string in this list, or -1 if
* this list does not contain the string. More formally, returns the lowest index i such that
* s.equals(get(i))), or -1 if there is no such index.
* @param s string to search for
* @return the index of the first occurrence of the specified string in this list, or -1 if
* this list does not contain the string
* @throws NullPointerException if the specified string is null
* @throws IllegalArgumentException if the specified string is empty
*/
public int indexOf(String s) {
int index = -1;
if (s == null) {
throw new NullPointerException("String is null");
} else if (s.equals("")) {
throw new IllegalArgumentException("String is empty");
} else {
for(int i = 0; i < size(); i++) {
if(s.equals(get(i))) {
index = i;
}
}
}
return index;
} //indexOf

/**
* Returns the index of the first occurrence of the specified string, ignoring case, in this
* list, or -1 if this list does not contain the string. More formally, returns the lowest
* index i such that s.equalsIgnoreCase(get(i))), or -1 if there is no such index.
* @param s string to search for
* @return the index of the first occurrence of the specified string, ignoring case, in this
* list, or -1 if this list does not contain the string
* @throws NullPointerException if the specified string is null
* @throws IllegalArgumentException if the specified string is empty
*/
public int indexOfIgnoreCase(String s) {
int index = -1;
if (s == null) {
throw new NullPointerException("String is null");
} else if (s.equals("")) {
throw new IllegalArgumentException("String is empty");
} else {
for(int i = 0; i < size(); i++) {
if(s.equalsIgnoreCase(get(i))) {
index = i;
}
}
}
return index;
} //indexOfIgnoreCase

/**
* Removes all of the stringns from this list.
* The list will be empty after this call returns.
*/
public void clear() {
StringList.Node list1 = new StringList.Node();
list = list1;
} //clear

/**
* Builds and returns a new {@code StringList} from this list without any duplicate strings.
* @return a new {@code StringList} which contains the first occurance of every string in this
* list
*/
public StringList distinct() {
StringList list1 = new LinkedStringList();
StringList.Node current = list.getNext();
for(int i = 0; i < size(); i++) {
if(list1.indexOf(current.getStr()) == -1) {
list1.add(current.getStr());
}
current = current.getNext();
}
return list1;
} //distinct

/**
* Builds and returns a new {@code StringList} that contains the strings from this list in
* reverse order.
* @return a new {@code StringList} with the strings from this list in reverse order
*/
public StringList reverse() {
StringList list1 = new LinkedStringList();
for(int i = size() - 1; i >= 0; i--) {
list1.add(get(i));
}
return list1;
} //reverse

/**
* Returns a string representation of this list with every string in the sequence separated by
* the specified seprator string.
* @param sep the specified separator string
* @return string representation of this list with every string in the sequence separated by sep
*/
public String makeString(String sep) {
String string = "";
if(size() != 0) {
for(int i = 0; i < size() - 1; i++) {
string = string + get(i) + sep;
}
string = string + get(size() - 1);
}
return string;
} //makeString

/**
* Builds and returns a new {@code StringList} that contains the strings from this list between
* the specified {@code fromIndex}, inclusive, and {@code toIndex}, exclusive. If
* {@code fromIndex} and {@code toIndex} are in bounds and equal, then the returned list is
* empty.
* @param fromIndex low endpoint (inclusive) of the splice
* @param toIndex high endpoint (exclusive) of the splice
* @return a new {@code StringList} with the strings from this list from the specified range
* @throws IndexOutOfBoundsException for an illegal endpoint index value
* (fromIndex {@literal <} 0 || toIndex {@literal >} size() || fromIndex {@literal >} toIndex)
*/
public StringList splice(int fromIndex, int toIndex) {
StringList list1 = new LinkedStringList();
if (fromIndex < 0 || toIndex > size() || fromIndex > toIndex) {
throw new IndexOutOfBoundsException("Index out of bounds");
} else {
for(int i = fromIndex; i < toIndex; i++) {
list1.add(get(i));
}
}
return list1;   
} //splice
}

_______________________________________________________________

Please upvote so that I could answer more such questions for you :)


Related Solutions

Hi, Can you teach me how to answear product financing arrangement?
Hi, Can you teach me how to answear product financing arrangement?
Using Java, Explain how to implement a functional interface using a lambda expression. You may include...
Using Java, Explain how to implement a functional interface using a lambda expression. You may include small sections of code to illustrate your explanation.
Can you give me an examples of how the TV could teach your children different cultures.(...
Can you give me an examples of how the TV could teach your children different cultures.( I mean when they watch TV how they could learn different cultures.)
Can someone please teach me how to do these? 5. Suppose you save $19,000 per year...
Can someone please teach me how to do these? 5. Suppose you save $19,000 per year in an ordinary annuity promising you an interest rate of i=7.625% compounded once per year. How much will you have after 35 years? 6. A risk-free bond will pay you $1,000 in 1 year. The annual discount rate is i=19.69% compounded annually.  What is the bond’s present value? 7. A risk-free bond will pay you $1,000 in 2 years and nothing in between. The annual...
Implement the SimpleQueue interface with the MyQueue class. You can use either a linked list or...
Implement the SimpleQueue interface with the MyQueue class. You can use either a linked list or a dynamic array to implement the data structure. A queue is a specialised form of list in which you can only get and remove the first element in the queue. The class should be able to work with the following code: SimpleQueue queue = new MyQueue(); NB: You cannot import anything from the standard library for this task. The data structure must be of...
Hello! If possible can you please teach me in excel formulas? You have recently won the...
Hello! If possible can you please teach me in excel formulas? You have recently won the super jackpot in the Washington State Lottery. On reading the fine print, you discover that you have the following two options:    a. You will receive 30 annual payments of $270,000, with the first payment being delivered today. The income will be taxed at a rate of 30 percent. Taxes will be withheld when the checks are issued. b. You will receive $550,000 now,...
Instructions: SLLQueue (13 pts) ● Using the three properties below, implement the queue interface using the...
Instructions: SLLQueue (13 pts) ● Using the three properties below, implement the queue interface using the SLLNode class from Lab 2: ○ head_node → SLLNode object or None ○ tail_node → SLLNode object or None ○ size → int, keep track of queue size ● Implement enqueue( ), dequeue( ), front( ) ● Use SLLNode methods: get_item( ), set_item( ), get_next( ), set_next( ) ● (5 pts) In enqueue(item): ○ Add new SLLNode (with item) after tail_node ○ Update tail_node...
This is for a java program. Payroll System Using Inheritance and Polymorphism 1. Implement an interface...
This is for a java program. Payroll System Using Inheritance and Polymorphism 1. Implement an interface called EmployeeInfo with the following constant variables: FACULTY_MONTHLY_SALARY = 6000.00 STAFF_MONTHLY_HOURS_WORKED = 160 2. Implement an abstract class Employee with the following requirements: Attributes last name (String) first name (String) ID number (String) Sex - M or F Birth date - Use the Calendar Java class to create a date object Default argument constructor and argument constructors. Public methods toString - returning a string...
"How can I connect to Hadoop Hive using Python? I've tried using PyHive but always get...
"How can I connect to Hadoop Hive using Python? I've tried using PyHive but always get the error: ...could not start SASL... no mechanism available: unable to find a callback: 2"
Please can you explain to me how to do a clinical documentation using DAR Format? Using...
Please can you explain to me how to do a clinical documentation using DAR Format? Using this scenario: - You are assigned to Mrs. Jones for morning care. While assisting her with her morning bath you notice a purplish-blue bruise on her left hip. When you comment on it, she states that she fell yesterday when getting off the toilet, but didn’t tell anyone. She states the area is sore and moans when it is touched. Her mobility status stated...
ADVERTISEMENT
ADVERTISEMENT
ADVERTISEMENT