diff --git a/.DS_Store b/.DS_Store
index b3c4e49..4613776 100644
Binary files a/.DS_Store and b/.DS_Store differ
diff --git a/.gitignore b/.gitignore
index 773a8a1..42d8c76 100755
--- a/.gitignore
+++ b/.gitignore
@@ -28,3 +28,8 @@ pdf/*
 epub/*
 ZCW-JS-Prep.epub
 ZCW-JS-Prep.pdf
+.DS_Store
+reader/ReadingJava/.DS_Store
+reader/ReadingJava/Programs/.DS_Store
+reader/ReadingJava/.DS_Store
+reader/ReadingJava/Programs/.DS_Store
diff --git a/IntroAndWorkBook/JavaIntroCover.pdf b/IntroAndWorkBook/JavaIntroCover.pdf
new file mode 100644
index 0000000..2c51693
Binary files /dev/null and b/IntroAndWorkBook/JavaIntroCover.pdf differ
diff --git a/IntroAndWorkBook/JavaIntroCover.png.pdf b/IntroAndWorkBook/JavaIntroCover.png.pdf
new file mode 100644
index 0000000..2c51693
Binary files /dev/null and b/IntroAndWorkBook/JavaIntroCover.png.pdf differ
diff --git a/IntroAndWorkBook/aastartwithjshell.adoc b/IntroAndWorkBook/aastartwithjshell.adoc
index 2f0e980..dc41923 100644
--- a/IntroAndWorkBook/aastartwithjshell.adoc
+++ b/IntroAndWorkBook/aastartwithjshell.adoc
@@ -13,6 +13,10 @@ Java changed all of that in 2017 with the introduction of **jshell** - an intera
 programming environment that lets you write and test Java code instantly.
 Think of it as having a conversation with the Java language itself.
 
+Now, this section is going to mention some things you have not been introduced to yet.
+Don't let that bother you.
+`jshell` is a powerful thing, and we have to start somewhere, so just kind of move through these ideas as smoothly as you can. 
+
 === Why jshell is Revolutionary for Learning
 
 ==== Immediate Feedback
@@ -308,25 +312,14 @@ jshell> /exit
 
 === Why This Matters for Learning
 
-==== Builds Confidence
-
-When you can immediately test ideas and see them work, you build confidence in your programming abilities.
+- **Builds Confidence** When you can immediately test ideas and see them work, you build confidence in your programming abilities.
 There's no long, intimidating compilation process - just immediate results.
-
-==== Encourages Experimentation
-
-jshell makes it safe to try things.
+- **Encourages Experimentation** jshell makes it safe to try things.
 If something doesn't work, you haven't "broken" anything.
 You just try again with a different approach.
-
-==== Reinforces Learning
-
-The immediate feedback loop means concepts stick better.
+- **Reinforces Learning** The immediate feedback loop means concepts stick better.
 When you see cause and effect immediately, you understand the relationship between code and results.
-
-==== Reduces Friction
-
-By eliminating the ceremony of full programs, jshell lets you focus on learning Java concepts rather than fighting with tools and syntax.
+- **Reduces Friction** By eliminating the complexity of full java programs, jshell lets you focus on learning Java concepts rather than fighting with tools and syntax.
 
 === Practical Learning Strategy
 
diff --git a/IntroAndWorkBook/access-modifiers.adoc b/IntroAndWorkBook/access-modifiers.adoc
index 232be2f..9346fbd 100644
--- a/IntroAndWorkBook/access-modifiers.adoc
+++ b/IntroAndWorkBook/access-modifiers.adoc
@@ -178,7 +178,14 @@ public class MathUtils {
 
 ==== Real-World Example: Bank Account Class
 
-Here's a complete example showing proper use of access modifiers:
+Here's a complete example showing proper use of access modifiers.
+
+Notice how the methods are `public` but the instance variables that hold the
+key information about the account are marked `private`.
+This ensures that anyone using this class in their code can only adjust
+the _private_ variables using the _public_ methods.
+
+That is a **very** common pattern used in Java programs.
 
 [source]
 ----
diff --git a/IntroAndWorkBook/advancedoop.adoc b/IntroAndWorkBook/advancedoop.adoc
new file mode 100644
index 0000000..086152f
--- /dev/null
+++ b/IntroAndWorkBook/advancedoop.adoc
@@ -0,0 +1,530 @@
+== Advanced Object-Oriented Programming Concepts
+
+Now that you understand the basics of classes and objects, let's explore some powerful advanced concepts that make Java's object-oriented programming truly shine. These concepts help you write more organized, reusable, and maintainable code.
+
+=== Inheritance - Building on What Already Exists
+
+Inheritance is one of the core principles of object-oriented programming. It allows you to create new classes based on existing classes, inheriting their properties and methods while adding new functionality or modifying existing behavior.
+
+Think of inheritance like a family tree - children inherit traits from their parents, but they can also have their own unique characteristics.
+
+==== Basic Inheritance Example
+
+Let's start with a simple `Animal` class and create specific animal types:
+
+[source]
+----
+jshell> class Animal {
+   ...>     String name;
+   ...>     int age;
+   ...>     
+   ...>     public Animal(String name, int age) {
+   ...>         this.name = name;
+   ...>         this.age = age;
+   ...>     }
+   ...>     
+   ...>     public void eat() {
+   ...>         System.out.println(name + " is eating.");
+   ...>     }
+   ...>     
+   ...>     public void sleep() {
+   ...>         System.out.println(name + " is sleeping.");
+   ...>     }
+   ...>     
+   ...>     public void makeSound() {
+   ...>         System.out.println(name + " makes a sound.");
+   ...>     }
+   ...> }
+|  created class Animal
+
+jshell> class Dog extends Animal {
+   ...>     String breed;
+   ...>     
+   ...>     public Dog(String name, int age, String breed) {
+   ...>         super(name, age);  // Call parent constructor
+   ...>         this.breed = breed;
+   ...>     }
+   ...>     
+   ...>     public void makeSound() {
+   ...>         System.out.println(name + " barks: Woof! Woof!");
+   ...>     }
+   ...>     
+   ...>     public void wagTail() {
+   ...>         System.out.println(name + " is wagging its tail!");
+   ...>     }
+   ...> }
+|  created class Dog
+
+jshell> Dog buddy = new Dog("Buddy", 3, "Golden Retriever");
+buddy ==> Dog@...
+
+jshell> buddy.eat();        // Inherited from Animal
+Buddy is eating.
+
+jshell> buddy.makeSound();  // Overridden in Dog
+Buddy barks: Woof! Woof!
+
+jshell> buddy.wagTail();    // Specific to Dog
+Buddy is wagging its tail!
+----
+
+In this example:
+- `Dog` **extends** `Animal`, meaning Dog inherits all of Animal's properties and methods
+- `Dog` can use inherited methods like `eat()` and `sleep()`
+- `Dog` **overrides** the `makeSound()` method with its own implementation
+- `Dog` adds its own method `wagTail()` that's not in the parent class
+
+=== The 'super' Keyword
+
+The `super` keyword is used to refer to the parent class. It's particularly useful for:
+1. Calling the parent class constructor
+2. Accessing parent class methods that have been overridden
+3. Accessing parent class variables when they're hidden
+
+==== Using super in Constructors
+
+When you create a subclass constructor, you often need to initialize the parent class part of the object first:
+
+[source]
+----
+jshell> class Cat extends Animal {
+   ...>     boolean isIndoor;
+   ...>     
+   ...>     public Cat(String name, int age, boolean isIndoor) {
+   ...>         super(name, age);  // Must be first line in constructor
+   ...>         this.isIndoor = isIndoor;
+   ...>     }
+   ...>     
+   ...>     public void makeSound() {
+   ...>         System.out.println(name + " meows: Meow!");
+   ...>     }
+   ...>     
+   ...>     public void makeSound(boolean loud) {
+   ...>         if (loud) {
+   ...>             super.makeSound();  // Call parent's version
+   ...>             System.out.println("Very loudly!");
+   ...>         } else {
+   ...>             makeSound();  // Call this class's version
+   ...>         }
+   ...>     }
+   ...> }
+|  created class Cat
+
+jshell> Cat whiskers = new Cat("Whiskers", 2, true);
+whiskers ==> Cat@...
+
+jshell> whiskers.makeSound(true);
+Whiskers makes a sound.
+Very loudly!
+----
+
+=== Method Overriding vs Method Overloading
+
+These are two different concepts that beginners often confuse:
+
+==== Method Overriding
+
+**Overriding** means replacing a parent class method with a new implementation in the child class. The method signature (name, parameters) must be exactly the same.
+
+[source]
+----
+jshell> class Bird extends Animal {
+   ...>     public Bird(String name, int age) {
+   ...>         super(name, age);
+   ...>     }
+   ...>     
+   ...>     @Override  // Good practice to use this annotation
+   ...>     public void makeSound() {
+   ...>         System.out.println(name + " chirps: Tweet tweet!");
+   ...>     }
+   ...> }
+|  created class Bird
+
+jshell> Bird robin = new Bird("Robin", 1);
+robin ==> Bird@...
+
+jshell> robin.makeSound();  // Uses Bird's version, not Animal's
+Robin chirps: Tweet tweet!
+----
+
+==== Method Overloading
+
+**Overloading** means creating multiple methods with the same name but different parameters within the same class:
+
+[source]
+----
+jshell> class Calculator {
+   ...>     public int add(int a, int b) {
+   ...>         return a + b;
+   ...>     }
+   ...>     
+   ...>     public double add(double a, double b) {
+   ...>         return a + b;
+   ...>     }
+   ...>     
+   ...>     public int add(int a, int b, int c) {
+   ...>         return a + b + c;
+   ...>     }
+   ...>     
+   ...>     public String add(String a, String b) {
+   ...>         return a + b;
+   ...>     }
+   ...> }
+|  created class Calculator
+
+jshell> Calculator calc = new Calculator();
+calc ==> Calculator@...
+
+jshell> calc.add(5, 3);
+$1 ==> 8
+
+jshell> calc.add(5.5, 3.2);
+$2 ==> 8.7
+
+jshell> calc.add(1, 2, 3);
+$3 ==> 6
+
+jshell> calc.add("Hello", "World");
+$4 ==> "HelloWorld"
+----
+
+=== Abstract Classes and Methods
+
+Sometimes you want to create a class that serves as a template for other classes but should never be instantiated directly. This is where abstract classes come in.
+
+==== Abstract Classes
+
+An abstract class cannot be instantiated with `new`, but it can contain both regular methods and abstract methods that must be implemented by subclasses:
+
+[source]
+----
+jshell> abstract class Shape {
+   ...>     String color;
+   ...>     
+   ...>     public Shape(String color) {
+   ...>         this.color = color;
+   ...>     }
+   ...>     
+   ...>     // Regular method - all shapes can use this
+   ...>     public void displayColor() {
+   ...>         System.out.println("This shape is " + color);
+   ...>     }
+   ...>     
+   ...>     // Abstract method - each shape must implement this differently
+   ...>     public abstract double calculateArea();
+   ...>     public abstract void draw();
+   ...> }
+|  created class Shape
+
+jshell> class Circle extends Shape {
+   ...>     double radius;
+   ...>     
+   ...>     public Circle(String color, double radius) {
+   ...>         super(color);
+   ...>         this.radius = radius;
+   ...>     }
+   ...>     
+   ...>     @Override
+   ...>     public double calculateArea() {
+   ...>         return Math.PI * radius * radius;
+   ...>     }
+   ...>     
+   ...>     @Override
+   ...>     public void draw() {
+   ...>         System.out.println("Drawing a " + color + " circle with radius " + radius);
+   ...>     }
+   ...> }
+|  created class Circle
+
+jshell> class Rectangle extends Shape {
+   ...>     double width, height;
+   ...>     
+   ...>     public Rectangle(String color, double width, double height) {
+   ...>         super(color);
+   ...>         this.width = width;
+   ...>         this.height = height;
+   ...>     }
+   ...>     
+   ...>     @Override
+   ...>     public double calculateArea() {
+   ...>         return width * height;
+   ...>     }
+   ...>     
+   ...>     @Override
+   ...>     public void draw() {
+   ...>         System.out.println("Drawing a " + color + " rectangle " + width + "x" + height);
+   ...>     }
+   ...> }
+|  created class Rectangle
+
+jshell> Circle circle = new Circle("red", 5.0);
+circle ==> Circle@...
+
+jshell> circle.displayColor();
+This shape is red
+
+jshell> circle.calculateArea();
+$5 ==> 78.53981633974483
+
+jshell> circle.draw();
+Drawing a red circle with radius 5.0
+----
+
+=== Interfaces and Multiple Inheritance
+
+Java doesn't support multiple inheritance of classes (a class can't extend multiple classes), but it does support multiple inheritance through interfaces. An interface is like a contract that specifies what methods a class must implement.
+
+==== Basic Interface Example
+
+[source]
+----
+jshell> interface Flyable {
+   ...>     void fly();
+   ...>     void land();
+   ...> }
+|  created interface Flyable
+
+jshell> interface Swimmable {
+   ...>     void swim();
+   ...>     void dive();
+   ...> }
+|  created interface Swimmable
+
+jshell> class Duck extends Animal implements Flyable, Swimmable {
+   ...>     public Duck(String name, int age) {
+   ...>         super(name, age);
+   ...>     }
+   ...>     
+   ...>     @Override
+   ...>     public void makeSound() {
+   ...>         System.out.println(name + " quacks: Quack quack!");
+   ...>     }
+   ...>     
+   ...>     @Override
+   ...>     public void fly() {
+   ...>         System.out.println(name + " is flying through the air!");
+   ...>     }
+   ...>     
+   ...>     @Override
+   ...>     public void land() {
+   ...>         System.out.println(name + " has landed safely.");
+   ...>     }
+   ...>     
+   ...>     @Override
+   ...>     public void swim() {
+   ...>         System.out.println(name + " is swimming in the water.");
+   ...>     }
+   ...>     
+   ...>     @Override
+   ...>     public void dive() {
+   ...>         System.out.println(name + " dives underwater!");
+   ...>     }
+   ...> }
+|  created class Duck
+
+jshell> Duck donald = new Duck("Donald", 2);
+donald ==> Duck@...
+
+jshell> donald.eat();   // From Animal
+Donald is eating.
+
+jshell> donald.fly();   // From Flyable interface
+Donald is flying through the air!
+
+jshell> donald.swim();  // From Swimmable interface
+Donald is swimming in the water.
+----
+
+==== Interface Default Methods
+
+Modern Java allows interfaces to have default implementations:
+
+[source]
+----
+jshell> interface Speakable {
+   ...>     void speak();
+   ...>     
+   ...>     default void greet() {
+   ...>         System.out.println("Hello there!");
+   ...>         speak();
+   ...>     }
+   ...> }
+|  created interface Speakable
+
+jshell> class Person implements Speakable {
+   ...>     String name;
+   ...>     
+   ...>     public Person(String name) {
+   ...>         this.name = name;
+   ...>     }
+   ...>     
+   ...>     @Override
+   ...>     public void speak() {
+   ...>         System.out.println("Hi, I'm " + name);
+   ...>     }
+   ...> }
+|  created class Person
+
+jshell> Person alice = new Person("Alice");
+alice ==> Person@...
+
+jshell> alice.greet();  // Uses default implementation
+Hello there!
+Hi, I'm Alice
+----
+
+=== Polymorphism and Dynamic Binding
+
+Polymorphism is the ability for objects of different types to be treated as objects of a common base type, while still maintaining their specific behavior. This is one of the most powerful features of object-oriented programming.
+
+==== Runtime Polymorphism Example
+
+[source]
+----
+jshell> class AnimalShelter {
+   ...>     public void careForAnimal(Animal animal) {
+   ...>         System.out.println("Caring for: " + animal.name);
+   ...>         animal.eat();
+   ...>         animal.makeSound();  // This will call the specific animal's version!
+   ...>         animal.sleep();
+   ...>     }
+   ...> }
+|  created class AnimalShelter
+
+jshell> AnimalShelter shelter = new AnimalShelter();
+shelter ==> AnimalShelter@...
+
+jshell> Animal[] animals = {
+   ...>     new Dog("Rex", 4, "German Shepherd"),
+   ...>     new Cat("Mittens", 3, false),
+   ...>     new Bird("Tweety", 1)
+   ...> };
+animals ==> Animal[3] { Dog@..., Cat@..., Bird@... }
+
+jshell> for (Animal animal : animals) {
+   ...>     shelter.careForAnimal(animal);
+   ...>     System.out.println("---");
+   ...> }
+Caring for: Rex
+Rex is eating.
+Rex barks: Woof! Woof!
+Rex is sleeping.
+---
+Caring for: Mittens
+Mittens is eating.
+Mittens meows: Meow!
+Mittens is sleeping.
+---
+Caring for: Tweety
+Tweety is eating.
+Tweety chirps: Tweet tweet!
+Tweety is sleeping.
+---
+----
+
+Notice how the same method call `animal.makeSound()` produces different results depending on the actual type of the object. This is **dynamic binding** - Java determines which method to call at runtime based on the actual object type.
+
+=== Practical Example: A Shape Drawing Program
+
+Let's put it all together with a more comprehensive example:
+
+[source]
+----
+jshell> interface Drawable {
+   ...>     void draw();
+   ...>     default void describe() {
+   ...>         System.out.println("This is a drawable shape.");
+   ...>     }
+   ...> }
+|  created interface Drawable
+
+jshell> abstract class GeometricShape implements Drawable {
+   ...>     protected String color;
+   ...>     protected double x, y;  // position
+   ...>     
+   ...>     public GeometricShape(String color, double x, double y) {
+   ...>         this.color = color;
+   ...>         this.x = x;
+   ...>         this.y = y;
+   ...>     }
+   ...>     
+   ...>     public abstract double getArea();
+   ...>     public abstract double getPerimeter();
+   ...>     
+   ...>     public void move(double newX, double newY) {
+   ...>         this.x = newX;
+   ...>         this.y = newY;
+   ...>         System.out.println("Shape moved to (" + x + ", " + y + ")");
+   ...>     }
+   ...>     
+   ...>     @Override
+   ...>     public void describe() {
+   ...>         System.out.println("A " + color + " geometric shape at (" + x + ", " + y + ")");
+   ...>     }
+   ...> }
+|  created class GeometricShape
+
+jshell> class Square extends GeometricShape {
+   ...>     private double side;
+   ...>     
+   ...>     public Square(String color, double x, double y, double side) {
+   ...>         super(color, x, y);
+   ...>         this.side = side;
+   ...>     }
+   ...>     
+   ...>     @Override
+   ...>     public double getArea() {
+   ...>         return side * side;
+   ...>     }
+   ...>     
+   ...>     @Override
+   ...>     public double getPerimeter() {
+   ...>         return 4 * side;
+   ...>     }
+   ...>     
+   ...>     @Override
+   ...>     public void draw() {
+   ...>         System.out.println("Drawing a " + color + " square with side " + side);
+   ...>     }
+   ...> }
+|  created class Square
+
+jshell> class Canvas {
+   ...>     public void drawAll(Drawable[] shapes) {
+   ...>         for (Drawable shape : shapes) {
+   ...>             shape.describe();
+   ...>             shape.draw();
+   ...>             if (shape instanceof GeometricShape) {
+   ...>                 GeometricShape geoShape = (GeometricShape) shape;
+   ...>                 System.out.println("Area: " + geoShape.getArea());
+   ...>             }
+   ...>             System.out.println("---");
+   ...>         }
+   ...>     }
+   ...> }
+|  created class Canvas
+
+jshell> Square square = new Square("blue", 10, 20, 5);
+square ==> Square@...
+
+jshell> Canvas canvas = new Canvas();
+canvas ==> Canvas@...
+
+jshell> canvas.drawAll(new Drawable[]{square});
+A blue geometric shape at (10.0, 20.0)
+Drawing a blue square with side 5.0
+Area: 25.0
+---
+----
+
+=== Key Takeaways
+
+1. **Inheritance** lets you build new classes based on existing ones using `extends`
+2. **Super** keyword accesses parent class constructors, methods, and variables
+3. **Method Overriding** replaces parent methods; **Method Overloading** creates multiple versions with different parameters
+4. **Abstract classes** provide templates that cannot be instantiated directly
+5. **Interfaces** define contracts that classes must implement, enabling multiple inheritance
+6. **Polymorphism** allows different objects to be treated uniformly while maintaining their specific behavior
+7. **Dynamic binding** determines which method to call at runtime based on the actual object type
+
+These advanced OOP concepts are the foundation for building complex, maintainable Java applications. They promote code reuse, flexibility, and clean design patterns that make your programs more professional and easier to extend.
\ No newline at end of file
diff --git a/IntroAndWorkBook/appendixc.adoc b/IntroAndWorkBook/appendixc.adoc
index 32c3f85..a9711f2 100644
--- a/IntroAndWorkBook/appendixc.adoc
+++ b/IntroAndWorkBook/appendixc.adoc
@@ -11,14 +11,17 @@ First, let's see if you already have Java installed and what version it is.
 ==== Step 1: Open Your Terminal or Command Prompt
 
 *On Windows:*
+
 - Press `Windows + R`, type `cmd`, and press Enter
 - Or search for "Command Prompt" in the Start menu
 
 *On macOS:*
+
 - Press `Cmd + Space`, type `terminal`, and press Enter
 - Or go to Applications → Utilities → Terminal
 
 *On Linux:*
+
 - Press `Ctrl + Alt + T`
 - Or search for "Terminal" in your applications
 
@@ -81,18 +84,21 @@ If you need to install or update Java, here are the recommended approaches:
 OpenJDK is a free, open-source implementation of Java:
 
 *For Windows:*
+
 1. Go to https://adoptium.net/
 2. Download the latest LTS version
 3. Run the installer
 4. Make sure "Set JAVA_HOME variable" is checked during installation
 
 *For macOS with Homebrew:*
+
 [source]
 ----
 brew install openjdk
 ----
 
 *For Ubuntu/Debian Linux:*
+
 [source]
 ----
 sudo apt update
@@ -100,6 +106,7 @@ sudo apt install openjdk-17-jdk
 ----
 
 *For Red Hat/CentOS/Fedora Linux:*
+
 [source]
 ----
 sudo yum install java-17-openjdk-devel
@@ -111,6 +118,7 @@ SDKMAN is a tool for managing multiple Java versions:
 
 1. Install SDKMAN: https://sdkman.io/install
 2. Install Java:
+
 [source]
 ----
 sdk install java 17.0.2-tem
@@ -144,6 +152,7 @@ Type `/exit` to quit jshell.
 ==== "java is not recognized as an internal or external command"
 
 *On Windows:*
+
 1. The Java installer should have set the PATH automatically
 2. If not, you may need to add Java to your PATH manually:
    - Find where Java is installed (usually `C:\Program Files\Java\jdk-XX\bin`)
@@ -151,6 +160,7 @@ Type `/exit` to quit jshell.
    - Restart your command prompt
 
 *On macOS/Linux:*
+
 1. Java might be installed but not in your PATH
 2. Try: `which java` to see if it's found
 3. You may need to add Java to your PATH in your shell configuration file
@@ -162,12 +172,14 @@ If you have multiple Java versions installed:
 *On Windows:* The last installed version usually becomes the default
 
 *On macOS:* Use `java_home` to manage versions:
+
 [source]
 ----
 /usr/libexec/java_home -V
 ----
 
 *On Linux:* Use `update-alternatives`:
+
 [source]
 ----
 sudo update-alternatives --config java
@@ -176,6 +188,7 @@ sudo update-alternatives --config java
 ==== Permission Issues on macOS
 
 If you get security warnings on macOS:
+
 1. Go to System Preferences → Security & Privacy
 2. Click "Allow" for Oracle or the Java installer
 3. Try the installation again
@@ -183,11 +196,13 @@ If you get security warnings on macOS:
 === Recommended Java Versions
 
 For this book, we recommend:
+
 - **Java 21 LTS** - Latest long-term support version (recommended)
 - **Java 17 LTS** - Widely used long-term support version  
 - **Java 11 LTS** - Older but still supported LTS version
 
 Avoid:
+
 - Java 8 and earlier (no jshell support)
 - Non-LTS versions unless you have a specific need
 
@@ -198,6 +213,7 @@ Once Java is installed, you have several options for writing and running Java co
 ==== Using jshell (Recommended for This Book)
 
 jshell is perfect for learning and experimenting:
+
 - No need to create full programs
 - Immediate feedback on code snippets
 - Great for testing small pieces of code
@@ -210,15 +226,18 @@ Start jshell by typing `jshell` in your terminal.
 For larger projects, consider these tools:
 
 **Beginner-Friendly:**
+
 - **Visual Studio Code** with Java extensions - Free, lightweight
 - **IntelliJ IDEA Community Edition** - Free, powerful
 - **Eclipse** - Free, widely used
 
 **Professional:**
+
 - **IntelliJ IDEA Ultimate** - Commercial, full-featured
 - **NetBeans** - Free, Oracle-supported
 
 **Simple Text Editors:**
+
 - **Notepad++** (Windows) - Basic syntax highlighting
 - **TextEdit** (macOS) - Simple text editing
 - **Gedit** (Linux) - Basic code editing
@@ -230,16 +249,19 @@ For this book, jshell is sufficient, but having a good editor helps when you wan
 If you're still having trouble:
 
 1. **Check your Java vendor's documentation:**
+
    - Oracle: https://docs.oracle.com/en/java/
    - Adoptium: https://adoptium.net/support/
 
 2. **University/School IT Support:** Many institutions provide Java installation help
 
 3. **Online Communities:**
+
    - Stack Overflow: https://stackoverflow.com/questions/tagged/java
    - Reddit: r/learnjava
 
 4. **Verify Installation:**
+
    - Make sure you downloaded the JDK, not just the JRE
    - Ensure you downloaded the correct version for your operating system (32-bit vs 64-bit)
    - Try restarting your computer after installation
diff --git a/IntroAndWorkBook/arraylist.adoc b/IntroAndWorkBook/arraylist.adoc
new file mode 100644
index 0000000..ce7ca43
--- /dev/null
+++ b/IntroAndWorkBook/arraylist.adoc
@@ -0,0 +1,722 @@
+== ArrayList - A Better Way to Work with Lists
+
+You've learned about arrays, which are useful for storing multiple items of the 
+same type. 
+
+But arrays have some limitations that can make them frustrating to work with:
+
+- **Fixed size** - Once you create an array, you can't make it bigger or smaller
+- **No built-in methods** - You have to write your own code to search, sort, or manipulate the data
+- **Manual management** - You need to keep track of how many elements you've actually used
+
+Java provides a much better solution called **ArrayList** that solves all these problems. ArrayList is part of Java's Collections Framework and is what most professional Java programmers use instead of arrays for storing lists of items.
+
+And honestly, you just should ArrayLists, because all the Java Pros do.
+
+=== Why ArrayList is Better Than Arrays
+
+Let's see the difference with a practical example. Imagine you're building a program to keep track of student names in a class:
+
+==== The Array Way (Problematic)
+
+[source]
+----
+jshell> // With arrays - lots of manual work and limitations
+   ...> String[] studentNames = new String[10];  // Fixed size of 10
+studentNames ==> String[10] { null, null, null, null, null, ... }
+
+jshell> int studentCount = 0;  // We have to manually track how many we've added
+studentCount ==> 0
+
+jshell> // Adding students manually
+   ...> studentNames[studentCount] = "Alice";
+studentNames[0] ==> "Alice"
+
+jshell> studentCount++;
+studentCount ==> 1
+
+jshell> studentNames[studentCount] = "Bob";
+studentNames[1] ==> "Bob"
+
+jshell> studentCount++;
+studentCount ==> 2
+
+jshell> // What if we get an 11th student? We can't add them!
+   ...> // What if we want to remove a student? Complex shuffling required!
+   ...> 
+   ...> System.out.println("Current students: " + studentCount);
+Current students: 2
+
+jshell> // To print all students, we need a loop
+   ...> for (int i = 0; i < studentCount; i++) {
+   ...>     System.out.println("Student " + (i + 1) + ": " + studentNames[i]);
+   ...> }
+Student 1: Alice
+Student 2: Bob
+----
+
+==== The ArrayList Way (Much Better!)
+
+[source]
+----
+jshell> import java.util.ArrayList;
+
+jshell> // With ArrayList - dynamic and easy to use
+   ...> ArrayList<String> students = new ArrayList<>();
+students ==> []
+
+jshell> // Adding students is simple
+   ...> students.add("Alice");
+$1 ==> true
+
+jshell> students.add("Bob");
+$2 ==> true
+
+jshell> students.add("Charlie");
+$3 ==> true
+
+jshell> students.add("Diana");  // No limit! It grows automatically
+$4 ==> true
+
+jshell> // Size is automatic
+   ...> System.out.println("Number of students: " + students.size());
+Number of students: 4
+
+jshell> // Easy to print all students
+   ...> System.out.println("All students: " + students);
+All students: [Alice, Bob, Charlie, Diana]
+
+jshell> // Easy to print with a loop
+   ...> for (String student : students) {
+   ...>     System.out.println("Student: " + student);
+   ...> }
+Student: Alice
+Student: Bob
+Student: Charlie
+Student: Diana
+----
+
+See how much cleaner and easier ArrayList is to work with!
+
+=== Creating and Using ArrayList
+
+==== Basic ArrayList Creation
+
+[source]
+----
+jshell> // Creating different types of ArrayLists
+   ...> ArrayList<String> names = new ArrayList<>();        // For strings
+names ==> []
+
+jshell> ArrayList<Integer> numbers = new ArrayList<>();     // For integers
+numbers ==> []
+
+jshell> ArrayList<Double> prices = new ArrayList<>();       // For decimal numbers
+prices ==> []
+
+jshell> // You can also initialize with values
+   ...> ArrayList<String> colors = new ArrayList<>();
+colors ==> []
+
+jshell> colors.add("red");
+$5 ==> true
+
+jshell> colors.add("green");
+$6 ==> true
+
+jshell> colors.add("blue");
+$7 ==> true
+
+jshell> System.out.println("Colors: " + colors);
+Colors: [red, green, blue]
+----
+
+Note the `<String>`, `<Integer>`, etc. - these are called **generics** and they tell Java what type of objects the ArrayList will hold. This prevents you from accidentally mixing different types.
+
+==== Adding Elements
+
+[source]
+----
+jshell> ArrayList<String> fruits = new ArrayList<>();
+fruits ==> []
+
+jshell> // Add to the end
+   ...> fruits.add("apple");
+$8 ==> true
+
+jshell> fruits.add("banana");
+$9 ==> true
+
+jshell> fruits.add("cherry");
+$10 ==> true
+
+jshell> System.out.println("Fruits: " + fruits);
+Fruits: [apple, banana, cherry]
+
+jshell> // Add at a specific position
+   ...> fruits.add(1, "blueberry");  // Insert at index 1
+jshell> System.out.println("After insertion: " + fruits);
+After insertion: [apple, blueberry, banana, cherry]
+
+jshell> // Add at the beginning
+   ...> fruits.add(0, "apricot");
+jshell> System.out.println("After adding at start: " + fruits);
+After adding at start: [apricot, apple, blueberry, banana, cherry]
+----
+
+==== Accessing Elements
+
+[source]
+----
+jshell> // Get element by index (like arrays)
+   ...> String firstFruit = fruits.get(0);
+firstFruit ==> "apricot"
+
+jshell> String lastFruit = fruits.get(fruits.size() - 1);
+lastFruit ==> "cherry"
+
+jshell> System.out.println("First: " + firstFruit + ", Last: " + lastFruit);
+First: apricot, Last: cherry
+
+jshell> // Check if ArrayList contains something
+   ...> boolean hasApple = fruits.contains("apple");
+hasApple ==> true
+
+jshell> boolean hasOrange = fruits.contains("orange");
+hasOrange ==> false
+
+jshell> System.out.println("Has apple: " + hasApple + ", Has orange: " + hasOrange);
+Has apple: true, Has orange: false
+
+jshell> // Find the index of an element
+   ...> int appleIndex = fruits.indexOf("apple");
+appleIndex ==> 1
+
+jshell> System.out.println("Apple is at index: " + appleIndex);
+Apple is at index: 1
+----
+
+==== Removing Elements
+
+[source]
+----
+jshell> System.out.println("Before removal: " + fruits);
+Before removal: [apricot, apple, blueberry, banana, cherry]
+
+jshell> // Remove by value
+   ...> boolean removed = fruits.remove("banana");
+removed ==> true
+
+jshell> System.out.println("After removing banana: " + fruits);
+After removing banana: [apricot, apple, blueberry, cherry]
+
+jshell> // Remove by index
+   ...> String removedFruit = fruits.remove(2);  // Remove at index 2
+removedFruit ==> "blueberry"
+
+jshell> System.out.println("Removed: " + removedFruit);
+Removed: blueberry
+
+jshell> System.out.println("After removing by index: " + fruits);
+After removing by index: [apricot, apple, cherry]
+
+jshell> // Clear all elements
+   ...> ArrayList<String> temp = new ArrayList<>();
+temp ==> []
+
+jshell> temp.add("test1");
+$11 ==> true
+
+jshell> temp.add("test2");
+$12 ==> true
+
+jshell> System.out.println("Before clear: " + temp);
+Before clear: [test1, test2]
+
+jshell> temp.clear();
+jshell> System.out.println("After clear: " + temp);
+After clear: []
+----
+
+==== Modifying Elements
+
+[source]
+----
+jshell> System.out.println("Current fruits: " + fruits);
+Current fruits: [apricot, apple, cherry]
+
+jshell> // Change an element at a specific index
+   ...> String oldValue = fruits.set(1, "avocado");  // Replace "apple" with "avocado"
+oldValue ==> "apple"
+
+jshell> System.out.println("Replaced '" + oldValue + "' with 'avocado'");
+Replaced 'apple' with 'avocado'
+
+jshell> System.out.println("Updated fruits: " + fruits);
+Updated fruits: [apricot, avocado, cherry]
+----
+
+=== Practical Example: Grade Tracker
+
+Let's build a practical example that shows why ArrayList is so much better than arrays:
+
+[source]
+----
+jshell> class GradeTracker {
+   ...>     private ArrayList<Double> grades;
+   ...>     private String studentName;
+   ...>     
+   ...>     public GradeTracker(String name) {
+   ...>         this.studentName = name;
+   ...>         this.grades = new ArrayList<>();
+   ...>     }
+   ...>     
+   ...>     public void addGrade(double grade) {
+   ...>         if (grade >= 0 && grade <= 100) {
+   ...>             grades.add(grade);
+   ...>             System.out.println("Added grade " + grade + " for " + studentName);
+   ...>         } else {
+   ...>             System.out.println("Invalid grade: " + grade + ". Must be 0-100.");
+   ...>         }
+   ...>     }
+   ...>     
+   ...>     public void removeGrade(double grade) {
+   ...>         if (grades.remove(grade)) {  // remove() returns true if found and removed
+   ...>             System.out.println("Removed grade " + grade + " for " + studentName);
+   ...>         } else {
+   ...>             System.out.println("Grade " + grade + " not found for " + studentName);
+   ...>         }
+   ...>     }
+   ...>     
+   ...>     public double getAverage() {
+   ...>         if (grades.isEmpty()) {
+   ...>             return 0.0;
+   ...>         }
+   ...>         
+   ...>         double sum = 0.0;
+   ...>         for (double grade : grades) {
+   ...>             sum += grade;
+   ...>         }
+   ...>         return sum / grades.size();
+   ...>     }
+   ...>     
+   ...>     public void printReport() {
+   ...>         System.out.println("\n=== Grade Report for " + studentName + " ===");
+   ...>         System.out.println("All grades: " + grades);
+   ...>         System.out.println("Number of grades: " + grades.size());
+   ...>         System.out.println("Average: " + String.format("%.2f", getAverage()));
+   ...>         
+   ...>         if (!grades.isEmpty()) {
+   ...>             double highest = grades.get(0);
+   ...>             double lowest = grades.get(0);
+   ...>             
+   ...>             for (double grade : grades) {
+   ...>                 if (grade > highest) highest = grade;
+   ...>                 if (grade < lowest) lowest = grade;
+   ...>             }
+   ...>             
+   ...>             System.out.println("Highest grade: " + highest);
+   ...>             System.out.println("Lowest grade: " + lowest);
+   ...>         }
+   ...>         System.out.println("========================\n");
+   ...>     }
+   ...> }
+|  created class GradeTracker
+
+jshell> // Test the grade tracker
+   ...> GradeTracker alice = new GradeTracker("Alice");
+alice ==> GradeTracker@...
+
+jshell> alice.addGrade(85.5);
+Added grade 85.5 for Alice
+
+jshell> alice.addGrade(92.0);
+Added grade 92.0 for Alice
+
+jshell> alice.addGrade(78.5);
+Added grade 78.5 for Alice
+
+jshell> alice.addGrade(88.0);
+Added grade 88.0 for Alice
+
+jshell> alice.printReport();
+
+=== Grade Report for Alice ===
+All grades: [85.5, 92.0, 78.5, 88.0]
+Number of grades: 4
+Average: 86.00
+Highest grade: 92.0
+Lowest grade: 78.5
+========================
+
+jshell> // Easy to add more grades - no size limit!
+   ...> alice.addGrade(95.0);
+Added grade 95.0 for Alice
+
+jshell> alice.addGrade(82.5);
+Added grade 82.5 for Alice
+
+jshell> alice.printReport();
+
+=== Grade Report for Alice ===
+All grades: [85.5, 92.0, 78.5, 88.0, 95.0, 82.5]
+Number of grades: 6
+Average: 86.92
+Highest grade: 95.0
+Lowest grade: 78.5
+========================
+
+jshell> // Easy to remove a grade if there was an error
+   ...> alice.removeGrade(78.5);
+Removed grade 78.5 for Alice
+
+jshell> alice.printReport();
+
+=== Grade Report for Alice ===
+All grades: [85.5, 92.0, 88.0, 95.0, 82.5]
+Number of grades: 5
+Average: 88.60
+Highest grade: 95.0
+Lowest grade: 82.5
+========================
+----
+
+Try to imagine writing this same program with arrays - you'd need to manually resize arrays, shift elements when removing items, and keep track of how many grades you've actually stored. With ArrayList, it's all handled automatically!
+
+=== ArrayList with Different Data Types
+
+You can create ArrayLists for any type of object:
+
+==== ArrayList of Numbers
+
+[source]
+----
+jshell> ArrayList<Integer> ages = new ArrayList<>();
+ages ==> []
+
+jshell> ages.add(25);
+$13 ==> true
+
+jshell> ages.add(30);
+$14 ==> true
+
+jshell> ages.add(22);
+$15 ==> true
+
+jshell> ages.add(35);
+$16 ==> true
+
+jshell> System.out.println("Ages: " + ages);
+Ages: [25, 30, 22, 35]
+
+jshell> // Find the average age
+   ...> double totalAge = 0;
+totalAge ==> 0.0
+
+jshell> for (int age : ages) {
+   ...>     totalAge += age;
+   ...> }
+
+jshell> double averageAge = totalAge / ages.size();
+averageAge ==> 28.0
+
+jshell> System.out.println("Average age: " + averageAge);
+Average age: 28.0
+----
+
+==== ArrayList of Booleans
+
+[source]
+----
+jshell> ArrayList<Boolean> testResults = new ArrayList<>();
+testResults ==> []
+
+jshell> testResults.add(true);   // Test 1: passed
+$17 ==> true
+
+jshell> testResults.add(false);  // Test 2: failed
+$18 ==> true
+
+jshell> testResults.add(true);   // Test 3: passed
+$19 ==> true
+
+jshell> testResults.add(true);   // Test 4: passed
+$20 ==> true
+
+jshell> // Count how many tests passed
+   ...> int passedCount = 0;
+passedCount ==> 0
+
+jshell> for (boolean result : testResults) {
+   ...>     if (result) {
+   ...>         passedCount++;
+   ...>     }
+   ...> }
+
+jshell> System.out.println("Tests passed: " + passedCount + " out of " + testResults.size());
+Tests passed: 3 out of 4
+----
+
+=== Sorting and Searching ArrayList
+
+ArrayList works great with Java's built-in sorting and searching methods:
+
+[source]
+----
+jshell> import java.util.Collections;
+
+jshell> ArrayList<String> names = new ArrayList<>();
+names ==> []
+
+jshell> names.add("Charlie");
+$21 ==> true
+
+jshell> names.add("Alice");
+$22 ==> true
+
+jshell> names.add("Bob");
+$23 ==> true
+
+jshell> names.add("Diana");
+$24 ==> true
+
+jshell> System.out.println("Before sorting: " + names);
+Before sorting: [Charlie, Alice, Bob, Diana]
+
+jshell> // Sort alphabetically
+   ...> Collections.sort(names);
+jshell> System.out.println("After sorting: " + names);
+After sorting: [Alice, Bob, Charlie, Diana]
+
+jshell> // Shuffle randomly
+   ...> Collections.shuffle(names);
+jshell> System.out.println("After shuffling: " + names);
+After shuffling: [Bob, Diana, Alice, Charlie]
+
+jshell> // Sort numbers
+   ...> ArrayList<Integer> numbers = new ArrayList<>();
+numbers ==> []
+
+jshell> numbers.add(45);
+$25 ==> true
+
+jshell> numbers.add(12);
+$26 ==> true
+
+jshell> numbers.add(78);
+$27 ==> true
+
+jshell> numbers.add(23);
+$28 ==> true
+
+jshell> System.out.println("Before sorting: " + numbers);
+Before sorting: [45, 12, 78, 23]
+
+jshell> Collections.sort(numbers);
+jshell> System.out.println("After sorting: " + numbers);
+After sorting: [12, 23, 45, 78]
+----
+
+=== Converting Between Arrays and ArrayList
+
+Sometimes you might need to work with both arrays and ArrayLists in the same program:
+
+==== Array to ArrayList
+
+[source]
+----
+jshell> import java.util.Arrays;
+
+jshell> // Convert array to ArrayList
+   ...> String[] cityArray = {"New York", "Los Angeles", "Chicago", "Houston"};
+cityArray ==> String[4] { "New York", "Los Angeles", "Chicago", "Houston" }
+
+jshell> ArrayList<String> cities = new ArrayList<>(Arrays.asList(cityArray));
+cities ==> [New York, Los Angeles, Chicago, Houston]
+
+jshell> System.out.println("ArrayList from array: " + cities);
+ArrayList from array: [New York, Los Angeles, Chicago, Houston]
+
+jshell> // Now we can use ArrayList methods
+   ...> cities.add("Phoenix");
+$29 ==> true
+
+jshell> cities.remove("Chicago");
+$30 ==> true
+
+jshell> System.out.println("Modified ArrayList: " + cities);
+Modified ArrayList: [New York, Los Angeles, Houston, Phoenix]
+----
+
+==== ArrayList to Array
+
+[source]
+----
+jshell> // Convert ArrayList back to array
+   ...> String[] newCityArray = cities.toArray(new String[0]);
+newCityArray ==> String[4] { "New York", "Los Angeles", "Houston", "Phoenix" }
+
+jshell> System.out.println("Array from ArrayList: " + Arrays.toString(newCityArray));
+Array from ArrayList: [New York, Los Angeles, Houston, Phoenix]
+----
+
+=== When to Use ArrayList vs Arrays
+
+**Use ArrayList when:**
+- You don't know how many elements you'll have
+- You need to add or remove elements frequently
+- You want convenient methods like `contains()`, `indexOf()`, etc.
+- You're building most types of applications (this is the common case)
+
+**Use arrays when:**
+- You have a fixed number of elements that won't change
+- You need maximum performance for mathematical calculations
+- You're working with primitive types and need to save memory
+- You're interfacing with code that specifically requires arrays
+
+=== Common ArrayList Methods Summary
+
+Here's a quick reference of the most useful ArrayList methods:
+
+[source]
+----
+jshell> // Creating and basic operations
+   ...> ArrayList<String> list = new ArrayList<>();
+list ==> []
+
+jshell> list.add("item");           // Add to end
+$31 ==> true
+
+jshell> list.add(0, "first");       // Add at specific index
+jshell> list.get(0);                // Get element at index
+$32 ==> "first"
+
+jshell> list.set(0, "new first");   // Replace element at index
+$33 ==> "first"
+
+jshell> list.remove("item");        // Remove by value
+$34 ==> true
+
+jshell> list.remove(0);             // Remove by index
+$35 ==> "new first"
+
+jshell> // Information methods
+   ...> list.add("test");
+$36 ==> true
+
+jshell> list.size();                // Number of elements
+$37 ==> 1
+
+jshell> list.isEmpty();             // Check if empty
+$38 ==> false
+
+jshell> list.contains("test");      // Check if contains value
+$39 ==> true
+
+jshell> list.indexOf("test");       // Find index of value
+$40 ==> 0
+
+jshell> // Bulk operations
+   ...> list.clear();               // Remove all elements
+jshell> list.isEmpty();
+$41 ==> true
+----
+
+=== Practical Exercise: Shopping List Manager
+
+Try building this shopping list manager to practice using ArrayList:
+
+[source]
+----
+jshell> class ShoppingList {
+   ...>     private ArrayList<String> items;
+   ...>     
+   ...>     public ShoppingList() {
+   ...>         items = new ArrayList<>();
+   ...>     }
+   ...>     
+   ...>     public void addItem(String item) {
+   ...>         if (!items.contains(item)) {
+   ...>             items.add(item);
+   ...>             System.out.println("Added: " + item);
+   ...>         } else {
+   ...>             System.out.println(item + " is already on the list");
+   ...>         }
+   ...>     }
+   ...>     
+   ...>     public void removeItem(String item) {
+   ...>         if (items.remove(item)) {
+   ...>             System.out.println("Removed: " + item);
+   ...>         } else {
+   ...>             System.out.println(item + " was not on the list");
+   ...>         }
+   ...>     }
+   ...>     
+   ...>     public void showList() {
+   ...>         if (items.isEmpty()) {
+   ...>             System.out.println("Shopping list is empty");
+   ...>         } else {
+   ...>             System.out.println("\nShopping List:");
+   ...>             for (int i = 0; i < items.size(); i++) {
+   ...>                 System.out.println((i + 1) + ". " + items.get(i));
+   ...>             }
+   ...>             System.out.println("Total items: " + items.size() + "\n");
+   ...>         }
+   ...>     }
+   ...>     
+   ...>     public boolean hasItem(String item) {
+   ...>         return items.contains(item);
+   ...>     }
+   ...> }
+|  created class ShoppingList
+
+jshell> // Test the shopping list
+   ...> ShoppingList groceries = new ShoppingList();
+groceries ==> ShoppingList@...
+
+jshell> groceries.addItem("milk");
+Added: milk
+
+jshell> groceries.addItem("bread");
+Added: bread
+
+jshell> groceries.addItem("eggs");
+Added: eggs
+
+jshell> groceries.addItem("milk");  // Duplicate
+milk is already on the list
+
+jshell> groceries.showList();
+
+Shopping List:
+1. milk
+2. bread
+3. eggs
+Total items: 3
+
+jshell> groceries.removeItem("bread");
+Removed: bread
+
+jshell> groceries.showList();
+
+Shopping List:
+1. milk
+2. eggs
+Total items: 2
+
+jshell> System.out.println("Need milk? " + groceries.hasItem("milk"));
+Need milk? true
+----
+
+=== Key Takeaways
+
+1. **ArrayList is usually better than arrays** for most programming tasks
+2. **Dynamic size** - ArrayLists grow and shrink automatically as needed
+3. **Rich functionality** - Many built-in methods for common operations
+4. **Type safety** - Generics (`<String>`, `<Integer>`) prevent type errors
+5. **Easy to use** - Adding, removing, and accessing elements is straightforward
+6. **Integrates well** - Works seamlessly with other Java features and libraries
+
+ArrayList is one of the most commonly used classes in Java programming. Once you get comfortable with it, you'll find yourself using it constantly instead of arrays. It makes your code cleaner, safer, and much easier to maintain.
+
+Most professional Java code uses ArrayList (and other Collections) rather than basic arrays, so learning ArrayList well is essential for becoming a competent Java programmer.
\ No newline at end of file
diff --git a/IntroAndWorkBook/classes.adoc b/IntroAndWorkBook/classes.adoc
index bcef4e0..8be8580 100644
--- a/IntroAndWorkBook/classes.adoc
+++ b/IntroAndWorkBook/classes.adoc
@@ -7,12 +7,14 @@ should look like and what it can do.
 === What is a Class?
 
 Imagine you're designing a house. Before you build the actual house, you create blueprints that show:
+
 - What rooms the house will have
 - How big each room will be  
 - Where the doors and windows go
 - What the house can do (provide shelter, have electricity, etc.)
 
 A Java class works the same way. It's a blueprint that describes:
+
 - What **data** an object will store (called **instance variables** or **fields**)
 - What **actions** an object can perform (called **methods**)
 
@@ -63,7 +65,8 @@ jshell> class Person {
 
 === Creating Objects from Classes
 
-Once you have a class, you can create **objects** (also called **instances**) from it. If the class is a blueprint, the object is the actual house built from that blueprint.
+Once you have a class, you can create **objects** (also called **instances**) from it. 
+If the class is a blueprint, the object is the actual house built from that blueprint.
 
 [source]
 ----
@@ -115,6 +118,7 @@ though they're both created from the same `Person` class.
 Each object gets its own copy of these variables.
 
 In our `Person` class:
+
 - `name` stores the person's name
 - `age` stores the person's age  
 - `height` stores the person's height
@@ -124,22 +128,37 @@ other `Person` objects.
 
 === Understanding Methods
 
-**Methods** are the actions that objects can perform. They're like functions, 
+**Methods** are the actions that objects can perform. 
+In Java, methods are where the computing happens! 
+A programmer writes methods to make objects do what they need to do to accomplish some goal.
+They're like functions in other languages, 
 but they belong to a specific class and can work with that class's instance variables.
 
 In our `Person` class:
+
 - `introduce()` prints a greeting using the person's name and age
 - `celebrateBirthday()` increases the person's age by 1
 
+But there could be other things we add:
+
+- a method to change a person's name or age.
+- add other methods to track more information about a person. (Like email address, cellphone number, etc.)
+
 Methods can:
-- Access and modify instance variables
-- Take parameters
-- Return values
-- Call other methods
+
+- Access and modify instance variables (the variables inside each object)
+- Take parameters (input values)
+- Return values (the output or results of a computation)
+- Call other methods (ask other objects to do work for you)
 
 === A More Complex Example: BankAccount
 
-Let's look at a more practical example:
+Let's look at a more practical example.
+Notice how there is a little bit of computation that happens based on the state of the object.
+(Well, you should not be able take more money from an account than there is in the account!)
+
+And sometimes, you'll hear that kind of programming referred to as _business rules_.
+It's the kind of flexibility that programmers use to make the software do what it needs to do.
 
 [source]
 ----
@@ -201,19 +220,25 @@ jshell> account.withdraw(200.0);
 Invalid withdrawal amount.
 ----
 
+And consider, this a class like this you could make as many customer accounts as you might need.
+Each one will have different values, assigned to different customers, keeping all the data correct.
+
 === Constructors: Setting Up Objects
 
-Sometimes you want to set up an object with specific values when you create it. That's what **constructors** do. A constructor is a special method that runs when you create a new object.
+Sometimes you want to set up an object with specific values when you create it. 
+That's what **constructors** do. 
+A constructor is a special method that runs when you create a new object.
 
+Constructors are always named the same as the class itself. 
 [source]
 ----
-class ZipCode {
+class Location {
     String city;
     String state;
     int zipCode;
     
     // Constructor
-    ZipCode(String cityName, String stateName, int zip) {
+    Location(String cityName, String stateName, int zip) {
         city = cityName;
         state = stateName;
         zipCode = zip;
@@ -229,14 +254,14 @@ Now you can create objects with initial values:
 
 [source]
 ----
-jshell> ZipCode wilmington = new ZipCode("Wilmington", "DE", 19801);
-wilmington ==> ZipCode@...
+jshell> Location wilmington = new Location("Wilmington", "DE", 19801);
+wilmington ==> Location@...
 
 jshell> wilmington.displayLocation();
 Wilmington, DE 19801
 
-jshell> ZipCode newark = new ZipCode("Newark", "DE", 19711);
-newark ==> ZipCode@...
+jshell> Location newark = new Location("Newark", "DE", 19711);
+newark ==> Location@...
 
 jshell> newark.displayLocation();
 Newark, DE 19711
diff --git a/IntroAndWorkBook/collections.adoc b/IntroAndWorkBook/collections.adoc
new file mode 100644
index 0000000..2d01340
--- /dev/null
+++ b/IntroAndWorkBook/collections.adoc
@@ -0,0 +1,858 @@
+== Java Collections Framework
+
+So far, you've worked with arrays to store multiple items. While arrays are useful, they have limitations - they have a fixed size, and you can't easily add or remove elements. Java's **Collections Framework** provides a much more powerful and flexible way to work with groups of objects.
+
+The Collections Framework is a unified architecture for representing and manipulating collections of objects. It includes interfaces, implementations, and algorithms that make working with data much easier and more efficient.
+
+=== Why Use Collections Instead of Arrays?
+
+Let's see the difference:
+
+[source]
+----
+jshell> // Arrays - fixed size, limited functionality
+   ...> String[] arrayNames = new String[3];
+arrayNames ==> String[3] { null, null, null }
+
+jshell> arrayNames[0] = "Alice";
+arrayNames[0] ==> "Alice"
+
+jshell> arrayNames[1] = "Bob";
+arrayNames[1] ==> "Bob"
+
+jshell> // What if we want to add a 4th name? We can't!
+   ...> // arrayNames[3] = "Charlie";  // This would throw an exception
+
+jshell> // Collections - dynamic size, rich functionality
+   ...> import java.util.ArrayList;
+jshell> ArrayList<String> listNames = new ArrayList<>();
+listNames ==> []
+
+jshell> listNames.add("Alice");
+$4 ==> true
+
+jshell> listNames.add("Bob");
+$5 ==> true
+
+jshell> listNames.add("Charlie");  // No problem!
+$6 ==> true
+
+jshell> listNames.add("Diana");    // Keep adding as needed
+$7 ==> true
+
+jshell> System.out.println("List contains: " + listNames);
+List contains: [Alice, Bob, Charlie, Diana]
+
+jshell> System.out.println("Size: " + listNames.size());
+Size: 4
+----
+
+Collections are more flexible, have useful methods, and can grow or shrink as needed.
+
+=== Collection Hierarchy Overview
+
+The Collections Framework is built around several key interfaces:
+
+* **Collection** - The root interface for all collections
+* **List** - Ordered collections (like arrays, but dynamic)
+* **Set** - Collections with no duplicates
+* **Map** - Key-value pairs (like a dictionary)
+* **Queue** - Collections designed for processing elements in a specific order
+
+=== List Interface - Ordered Collections
+
+Lists maintain the order of elements and allow duplicates. The most commonly used implementations are ArrayList, LinkedList, and Vector.
+
+==== ArrayList - The Most Popular List
+
+ArrayList is like a dynamic array that can grow and shrink as needed:
+
+[source]
+----
+jshell> import java.util.ArrayList;
+jshell> import java.util.List;
+
+jshell> // Creating and adding elements
+   ...> List<String> fruits = new ArrayList<>();
+fruits ==> []
+
+jshell> fruits.add("apple");
+$8 ==> true
+
+jshell> fruits.add("banana");
+$9 ==> true
+
+jshell> fruits.add("cherry");
+$10 ==> true
+
+jshell> fruits.add("banana");  // Duplicates are allowed
+$11 ==> true
+
+jshell> System.out.println("Fruits: " + fruits);
+Fruits: [apple, banana, cherry, banana]
+
+jshell> // Accessing elements by index
+   ...> System.out.println("First fruit: " + fruits.get(0));
+First fruit: apple
+
+jshell> System.out.println("Last fruit: " + fruits.get(fruits.size() - 1));
+Last fruit: banana
+
+jshell> // Inserting at specific position
+   ...> fruits.add(1, "blueberry");
+jshell> System.out.println("After insertion: " + fruits);
+After insertion: [apple, blueberry, banana, cherry, banana]
+
+jshell> // Removing elements
+   ...> fruits.remove("banana");  // Removes first occurrence
+$12 ==> true
+
+jshell> System.out.println("After removal: " + fruits);
+After removal: [apple, blueberry, cherry, banana]
+
+jshell> // Removing by index
+   ...> String removed = fruits.remove(2);
+removed ==> "cherry"
+
+jshell> System.out.println("Removed: " + removed);
+Removed: cherry
+
+jshell> System.out.println("Final list: " + fruits);
+Final list: [apple, blueberry, banana]
+----
+
+==== LinkedList - Good for Frequent Insertions/Deletions
+
+LinkedList is better when you frequently add or remove elements from the middle of the list:
+
+[source]
+----
+jshell> import java.util.LinkedList;
+
+jshell> LinkedList<Integer> numbers = new LinkedList<>();
+numbers ==> []
+
+jshell> // Adding elements
+   ...> numbers.add(10);
+$13 ==> true
+
+jshell> numbers.add(20);
+$14 ==> true
+
+jshell> numbers.add(30);
+$15 ==> true
+
+jshell> // LinkedList has special methods for beginning and end
+   ...> numbers.addFirst(5);  // Add at beginning
+jshell> numbers.addLast(40);   // Add at end
+jshell> System.out.println("Numbers: " + numbers);
+Numbers: [5, 10, 20, 30, 40]
+
+jshell> // Special removal methods
+   ...> int first = numbers.removeFirst();
+first ==> 5
+
+jshell> int last = numbers.removeLast();
+last ==> 40
+
+jshell> System.out.println("After removing first and last: " + numbers);
+After removing first and last: [10, 20, 30]
+----
+
+==== Practical List Example: Student Grade Manager
+
+[source]
+----
+jshell> class Student {
+   ...>     String name;
+   ...>     List<Integer> grades;
+   ...>     
+   ...>     public Student(String name) {
+   ...>         this.name = name;
+   ...>         this.grades = new ArrayList<>();
+   ...>     }
+   ...>     
+   ...>     public void addGrade(int grade) {
+   ...>         if (grade >= 0 && grade <= 100) {
+   ...>             grades.add(grade);
+   ...>             System.out.println("Added grade " + grade + " for " + name);
+   ...>         } else {
+   ...>             System.out.println("Invalid grade: " + grade);
+   ...>         }
+   ...>     }
+   ...>     
+   ...>     public double getAverage() {
+   ...>         if (grades.isEmpty()) return 0.0;
+   ...>         
+   ...>         int sum = 0;
+   ...>         for (int grade : grades) {
+   ...>             sum += grade;
+   ...>         }
+   ...>         return (double) sum / grades.size();
+   ...>     }
+   ...>     
+   ...>     public void printReport() {
+   ...>         System.out.println("Student: " + name);
+   ...>         System.out.println("Grades: " + grades);
+   ...>         System.out.println("Average: " + String.format("%.2f", getAverage()));
+   ...>         System.out.println("Total grades: " + grades.size());
+   ...>     }
+   ...> }
+|  created class Student
+
+jshell> Student alice = new Student("Alice");
+alice ==> Student@...
+
+jshell> alice.addGrade(85);
+Added grade 85 for Alice
+
+jshell> alice.addGrade(92);
+Added grade 92 for Alice
+
+jshell> alice.addGrade(78);
+Added grade 78 for Alice
+
+jshell> alice.addGrade(88);
+Added grade 88 for Alice
+
+jshell> alice.printReport();
+Student: Alice
+Grades: [85, 92, 78, 88]
+Average: 85.75
+Total grades: 4
+----
+
+=== Set Interface - No Duplicates Allowed
+
+Sets are collections that don't allow duplicate elements. They're perfect when you need to ensure uniqueness.
+
+==== HashSet - Fast, No Order Guarantee
+
+[source]
+----
+jshell> import java.util.HashSet;
+jshell> import java.util.Set;
+
+jshell> Set<String> uniqueColors = new HashSet<>();
+uniqueColors ==> []
+
+jshell> uniqueColors.add("red");
+$16 ==> true
+
+jshell> uniqueColors.add("blue");
+$17 ==> true
+
+jshell> uniqueColors.add("green");
+$18 ==> true
+
+jshell> uniqueColors.add("red");  // Duplicate - won't be added
+$19 ==> false
+
+jshell> System.out.println("Unique colors: " + uniqueColors);
+Unique colors: [red, blue, green]
+
+jshell> System.out.println("Contains 'yellow': " + uniqueColors.contains("yellow"));
+Contains 'yellow': false
+
+jshell> System.out.println("Contains 'blue': " + uniqueColors.contains("blue"));
+Contains 'blue': true
+----
+
+==== TreeSet - Sorted Set
+
+TreeSet keeps elements in sorted order:
+
+[source]
+----
+jshell> import java.util.TreeSet;
+
+jshell> Set<Integer> sortedNumbers = new TreeSet<>();
+sortedNumbers ==> []
+
+jshell> sortedNumbers.add(25);
+$20 ==> true
+
+jshell> sortedNumbers.add(10);
+$21 ==> true
+
+jshell> sortedNumbers.add(35);
+$22 ==> true
+
+jshell> sortedNumbers.add(15);
+$23 ==> true
+
+jshell> sortedNumbers.add(10);  // Duplicate - won't be added
+$24 ==> false
+
+jshell> System.out.println("Sorted numbers: " + sortedNumbers);
+Sorted numbers: [10, 15, 25, 35]
+----
+
+==== LinkedHashSet - Maintains Insertion Order
+
+[source]
+----
+jshell> import java.util.LinkedHashSet;
+
+jshell> Set<String> orderedSet = new LinkedHashSet<>();
+orderedSet ==> []
+
+jshell> orderedSet.add("first");
+$25 ==> true
+
+jshell> orderedSet.add("second");
+$26 ==> true
+
+jshell> orderedSet.add("third");
+$27 ==> true
+
+jshell> orderedSet.add("first");  // Duplicate - won't be added
+$28 ==> false
+
+jshell> System.out.println("Insertion order preserved: " + orderedSet);
+Insertion order preserved: [first, second, third]
+----
+
+=== Map Interface - Key-Value Pairs
+
+Maps store key-value pairs, like a dictionary where you look up values using keys.
+
+==== HashMap - The Most Common Map
+
+[source]
+----
+jshell> import java.util.HashMap;
+jshell> import java.util.Map;
+
+jshell> Map<String, Integer> studentAges = new HashMap<>();
+studentAges ==> {}
+
+jshell> // Adding key-value pairs
+   ...> studentAges.put("Alice", 20);
+$29 ==> null
+
+jshell> studentAges.put("Bob", 22);
+$30 ==> null
+
+jshell> studentAges.put("Charlie", 19);
+$31 ==> null
+
+jshell> studentAges.put("Diana", 21);
+$32 ==> null
+
+jshell> System.out.println("Student ages: " + studentAges);
+Student ages: {Alice=20, Bob=22, Charlie=19, Diana=21}
+
+jshell> // Getting values by key
+   ...> System.out.println("Alice's age: " + studentAges.get("Alice"));
+Alice's age: 20
+
+jshell> System.out.println("Eve's age: " + studentAges.get("Eve"));  // Not found
+Eve's age: null
+
+jshell> // Check if key exists
+   ...> System.out.println("Contains Bob: " + studentAges.containsKey("Bob"));
+Contains Bob: true
+
+jshell> // Update a value
+   ...> studentAges.put("Alice", 21);  // Alice had a birthday
+$33 ==> 20
+
+jshell> System.out.println("Updated ages: " + studentAges);
+Updated ages: {Alice=21, Bob=22, Charlie=19, Diana=21}
+
+jshell> // Remove an entry
+   ...> Integer removed = studentAges.remove("Charlie");
+removed ==> 19
+
+jshell> System.out.println("After removal: " + studentAges);
+After removal: {Alice=21, Bob=22, Diana=21}
+----
+
+==== TreeMap - Sorted by Keys
+
+[source]
+----
+jshell> import java.util.TreeMap;
+
+jshell> Map<String, String> sortedMap = new TreeMap<>();
+sortedMap ==> {}
+
+jshell> sortedMap.put("zebra", "black and white");
+$34 ==> null
+
+jshell> sortedMap.put("apple", "red or green");
+$35 ==> null
+
+jshell> sortedMap.put("banana", "yellow");
+$36 ==> null
+
+jshell> System.out.println("Sorted map: " + sortedMap);
+Sorted map: {apple=red or green, banana=yellow, zebra=black and white}
+----
+
+==== Practical Map Example: Word Counter
+
+[source]
+----
+jshell> class WordCounter {
+   ...>     private Map<String, Integer> wordCounts;
+   ...>     
+   ...>     public WordCounter() {
+   ...>         wordCounts = new HashMap<>();
+   ...>     }
+   ...>     
+   ...>     public void addText(String text) {
+   ...>         String[] words = text.toLowerCase().split("\\s+");
+   ...>         
+   ...>         for (String word : words) {
+   ...>             // Remove punctuation
+   ...>             word = word.replaceAll("[^a-zA-Z]", "");
+   ...>             if (!word.isEmpty()) {
+   ...>                 wordCounts.put(word, wordCounts.getOrDefault(word, 0) + 1);
+   ...>             }
+   ...>         }
+   ...>     }
+   ...>     
+   ...>     public void printWordCounts() {
+   ...>         System.out.println("Word frequencies:");
+   ...>         for (Map.Entry<String, Integer> entry : wordCounts.entrySet()) {
+   ...>             System.out.println(entry.getKey() + ": " + entry.getValue());
+   ...>         }
+   ...>     }
+   ...>     
+   ...>     public String getMostFrequentWord() {
+   ...>         String mostFrequent = null;
+   ...>         int maxCount = 0;
+   ...>         
+   ...>         for (Map.Entry<String, Integer> entry : wordCounts.entrySet()) {
+   ...>             if (entry.getValue() > maxCount) {
+   ...>                 maxCount = entry.getValue();
+   ...>                 mostFrequent = entry.getKey();
+   ...>             }
+   ...>         }
+   ...>         
+   ...>         return mostFrequent;
+   ...>     }
+   ...> }
+|  created class WordCounter
+
+jshell> WordCounter counter = new WordCounter();
+counter ==> WordCounter@...
+
+jshell> counter.addText("The quick brown fox jumps over the lazy dog. The dog was very lazy.");
+
+jshell> counter.printWordCounts();
+Word frequencies:
+the: 3
+dog: 2
+fox: 1
+was: 1
+over: 1
+very: 1
+jumps: 1
+lazy: 2
+brown: 1
+quick: 1
+
+jshell> System.out.println("Most frequent word: " + counter.getMostFrequentWord());
+Most frequent word: the
+----
+
+=== Queue and Deque Interfaces
+
+Queues are designed for holding elements prior to processing, typically in FIFO (First-In-First-Out) order.
+
+==== LinkedList as a Queue
+
+[source]
+----
+jshell> import java.util.Queue;
+
+jshell> Queue<String> taskQueue = new LinkedList<>();
+taskQueue ==> []
+
+jshell> // Adding elements to the queue
+   ...> taskQueue.offer("Task 1");  // offer() adds to rear
+$37 ==> true
+
+jshell> taskQueue.offer("Task 2");
+$38 ==> true
+
+jshell> taskQueue.offer("Task 3");
+$39 ==> true
+
+jshell> System.out.println("Queue: " + taskQueue);
+Queue: [Task 1, Task 2, Task 3]
+
+jshell> // Processing elements from the queue
+   ...> String nextTask = taskQueue.poll();  // poll() removes from front
+nextTask ==> "Task 1"
+
+jshell> System.out.println("Processing: " + nextTask);
+Processing: Task 1
+
+jshell> System.out.println("Remaining queue: " + taskQueue);
+Remaining queue: [Task 2, Task 3]
+
+jshell> // Peek at next element without removing
+   ...> String peek = taskQueue.peek();
+peek ==> "Task 2"
+
+jshell> System.out.println("Next task (peek): " + peek);
+Next task (peek): Task 2
+
+jshell> System.out.println("Queue unchanged: " + taskQueue);
+Queue unchanged: [Task 2, Task 3]
+----
+
+==== ArrayDeque - Double-Ended Queue
+
+[source]
+----
+jshell> import java.util.ArrayDeque;
+jshell> import java.util.Deque;
+
+jshell> Deque<Integer> deque = new ArrayDeque<>();
+deque ==> []
+
+jshell> // Can add to both ends
+   ...> deque.addFirst(10);    // Add to front
+jshell> deque.addLast(20);     // Add to back
+jshell> deque.addFirst(5);     // Add to front again
+jshell> deque.addLast(30);     // Add to back again
+
+jshell> System.out.println("Deque: " + deque);
+Deque: [5, 10, 20, 30]
+
+jshell> // Can remove from both ends
+   ...> int first = deque.removeFirst();
+first ==> 5
+
+jshell> int last = deque.removeLast();
+last ==> 30
+
+jshell> System.out.println("After removing first and last: " + deque);
+After removing first and last: [10, 20]
+----
+
+=== Iterators and Enhanced For Loops
+
+There are several ways to traverse collections:
+
+==== Enhanced For Loop (For-Each)
+
+The easiest way to iterate through collections:
+
+[source]
+----
+jshell> List<String> colors = List.of("red", "green", "blue", "yellow");
+colors ==> [red, green, blue, yellow]
+
+jshell> // Enhanced for loop - clean and simple
+   ...> for (String color : colors) {
+   ...>     System.out.println("Color: " + color);
+   ...> }
+Color: red
+Color: green
+Color: blue
+Color: yellow
+
+jshell> // Works with any collection type
+   ...> Set<Integer> numbers = Set.of(10, 20, 30, 40);
+numbers ==> [40, 10, 20, 30]
+
+jshell> for (Integer number : numbers) {
+   ...>     System.out.println("Number: " + number);
+   ...> }
+Number: 40
+Number: 10
+Number: 20
+Number: 30
+----
+
+==== Iterator Interface
+
+For more control over iteration:
+
+[source]
+----
+jshell> import java.util.Iterator;
+
+jshell> List<String> animals = new ArrayList<>(List.of("cat", "dog", "bird", "fish"));
+animals ==> [cat, dog, bird, fish]
+
+jshell> Iterator<String> iter = animals.iterator();
+iter ==> java.util.ArrayList$Itr@...
+
+jshell> while (iter.hasNext()) {
+   ...>     String animal = iter.next();
+   ...>     System.out.println("Animal: " + animal);
+   ...>     
+   ...>     // Can safely remove during iteration
+   ...>     if (animal.equals("dog")) {
+   ...>         iter.remove();
+   ...>         System.out.println("Removed dog");
+   ...>     }
+   ...> }
+Animal: cat
+Animal: dog
+Removed dog
+Animal: bird
+Animal: fish
+
+jshell> System.out.println("Final list: " + animals);
+Final list: [cat, bird, fish]
+----
+
+==== Iterating Over Maps
+
+Maps require special handling since they contain key-value pairs:
+
+[source]
+----
+jshell> Map<String, Integer> scores = new HashMap<>();
+scores ==> {}
+
+jshell> scores.put("Alice", 95);
+$40 ==> null
+
+jshell> scores.put("Bob", 87);
+$41 ==> null
+
+jshell> scores.put("Charlie", 92);
+$42 ==> null
+
+jshell> // Iterate over entries (key-value pairs)
+   ...> for (Map.Entry<String, Integer> entry : scores.entrySet()) {
+   ...>     System.out.println(entry.getKey() + " scored " + entry.getValue());
+   ...> }
+Alice scored 95
+Bob scored 87
+Charlie scored 92
+
+jshell> // Iterate over just keys
+   ...> for (String name : scores.keySet()) {
+   ...>     System.out.println("Student: " + name);
+   ...> }
+Student: Alice
+Student: Bob
+Student: Charlie
+
+jshell> // Iterate over just values
+   ...> for (Integer score : scores.values()) {
+   ...>     System.out.println("Score: " + score);
+   ...> }
+Score: 95
+Score: 87
+Score: 92
+----
+
+=== Collections Utility Class
+
+The `Collections` class provides useful static methods for working with collections:
+
+[source]
+----
+jshell> import java.util.Collections;
+
+jshell> List<String> names = new ArrayList<>(List.of("Charlie", "Alice", "Bob", "Diana"));
+names ==> [Charlie, Alice, Bob, Diana]
+
+jshell> // Sorting
+   ...> Collections.sort(names);
+jshell> System.out.println("Sorted: " + names);
+Sorted: [Alice, Bob, Charlie, Diana]
+
+jshell> // Shuffling
+   ...> Collections.shuffle(names);
+jshell> System.out.println("Shuffled: " + names);
+Shuffled: [Diana, Alice, Charlie, Bob]
+
+jshell> // Reversing
+   ...> Collections.reverse(names);
+jshell> System.out.println("Reversed: " + names);
+Reversed: [Bob, Charlie, Alice, Diana]
+
+jshell> // Finding min and max
+   ...> String min = Collections.min(names);
+min ==> "Alice"
+
+jshell> String max = Collections.max(names);
+max ==> "Diana"
+
+jshell> System.out.println("Min: " + min + ", Max: " + max);
+Min: Alice, Max: Diana
+
+jshell> // Frequency counting
+   ...> List<String> letters = List.of("a", "b", "a", "c", "b", "a");
+letters ==> [a, b, a, c, b, a]
+
+jshell> int frequency = Collections.frequency(letters, "a");
+frequency ==> 3
+
+jshell> System.out.println("'a' appears " + frequency + " times");
+'a' appears 3 times
+
+jshell> // Creating unmodifiable collections
+   ...> List<String> readOnlyList = Collections.unmodifiableList(names);
+readOnlyList ==> [Bob, Charlie, Alice, Diana]
+
+jshell> // readOnlyList.add("Eve");  // This would throw an exception
+----
+
+=== Practical Example: Library Management System
+
+Let's put everything together with a comprehensive example:
+
+[source]
+----
+jshell> class Book {
+   ...>     String title;
+   ...>     String author;
+   ...>     String isbn;
+   ...>     boolean isAvailable;
+   ...>     
+   ...>     public Book(String title, String author, String isbn) {
+   ...>         this.title = title;
+   ...>         this.author = author;
+   ...>         this.isbn = isbn;
+   ...>         this.isAvailable = true;
+   ...>     }
+   ...>     
+   ...>     public String toString() {
+   ...>         return title + " by " + author + " (ISBN: " + isbn + ") - " + 
+   ...>                (isAvailable ? "Available" : "Checked out");
+   ...>     }
+   ...> }
+|  created class Book
+
+jshell> class Library {
+   ...>     private List<Book> books;
+   ...>     private Map<String, Book> booksByIsbn;
+   ...>     private Map<String, Set<Book>> booksByAuthor;
+   ...>     private Queue<String> waitingList;
+   ...>     
+   ...>     public Library() {
+   ...>         books = new ArrayList<>();
+   ...>         booksByIsbn = new HashMap<>();
+   ...>         booksByAuthor = new HashMap<>();
+   ...>         waitingList = new LinkedList<>();
+   ...>     }
+   ...>     
+   ...>     public void addBook(String title, String author, String isbn) {
+   ...>         Book book = new Book(title, author, isbn);
+   ...>         books.add(book);
+   ...>         booksByIsbn.put(isbn, book);
+   ...>         
+   ...>         // Add to author's collection
+   ...>         booksByAuthor.computeIfAbsent(author, k -> new HashSet<>()).add(book);
+   ...>         
+   ...>         System.out.println("Added: " + book);
+   ...>     }
+   ...>     
+   ...>     public Book findBookByIsbn(String isbn) {
+   ...>         return booksByIsbn.get(isbn);
+   ...>     }
+   ...>     
+   ...>     public Set<Book> findBooksByAuthor(String author) {
+   ...>         return booksByAuthor.getOrDefault(author, new HashSet<>());
+   ...>     }
+   ...>     
+   ...>     public void checkOutBook(String isbn) {
+   ...>         Book book = findBookByIsbn(isbn);
+   ...>         if (book != null && book.isAvailable) {
+   ...>             book.isAvailable = false;
+   ...>             System.out.println("Checked out: " + book.title);
+   ...>         } else if (book != null) {
+   ...>             System.out.println("Book not available: " + book.title);
+   ...>         } else {
+   ...>             System.out.println("Book not found with ISBN: " + isbn);
+   ...>         }
+   ...>     }
+   ...>     
+   ...>     public void returnBook(String isbn) {
+   ...>         Book book = findBookByIsbn(isbn);
+   ...>         if (book != null && !book.isAvailable) {
+   ...>             book.isAvailable = true;
+   ...>             System.out.println("Returned: " + book.title);
+   ...>         } else if (book != null) {
+   ...>             System.out.println("Book was not checked out: " + book.title);
+   ...>         } else {
+   ...>             System.out.println("Book not found with ISBN: " + isbn);
+   ...>         }
+   ...>     }
+   ...>     
+   ...>     public void printAllBooks() {
+   ...>         System.out.println("Library Collection:");
+   ...>         for (Book book : books) {
+   ...>             System.out.println("  " + book);
+   ...>         }
+   ...>     }
+   ...>     
+   ...>     public void printBooksByAuthor(String author) {
+   ...>         Set<Book> authorBooks = findBooksByAuthor(author);
+   ...>         if (authorBooks.isEmpty()) {
+   ...>             System.out.println("No books found by " + author);
+   ...>         } else {
+   ...>             System.out.println("Books by " + author + ":");
+   ...>             for (Book book : authorBooks) {
+   ...>                 System.out.println("  " + book);
+   ...>             }
+   ...>         }
+   ...>     }
+   ...> }
+|  created class Library
+
+jshell> // Test the library system
+   ...> Library library = new Library();
+library ==> Library@...
+
+jshell> library.addBook("1984", "George Orwell", "978-0451524935");
+Added: 1984 by George Orwell (ISBN: 978-0451524935) - Available
+
+jshell> library.addBook("Animal Farm", "George Orwell", "978-0451526342");
+Added: Animal Farm by George Orwell (ISBN: 978-0451526342) - Available
+
+jshell> library.addBook("To Kill a Mockingbird", "Harper Lee", "978-0061120084");
+Added: To Kill a Mockingbird by Harper Lee (ISBN: 978-0061120084) - Available
+
+jshell> library.printAllBooks();
+Library Collection:
+  1984 by George Orwell (ISBN: 978-0451524935) - Available
+  Animal Farm by George Orwell (ISBN: 978-0451526342) - Available
+  To Kill a Mockingbird by Harper Lee (ISBN: 978-0061120084) - Available
+
+jshell> library.printBooksByAuthor("George Orwell");
+Books by George Orwell:
+  1984 by George Orwell (ISBN: 978-0451524935) - Available
+  Animal Farm by George Orwell (ISBN: 978-0451526342) - Available
+
+jshell> library.checkOutBook("978-0451524935");
+Checked out: 1984
+
+jshell> library.checkOutBook("978-0451524935");  // Try to check out again
+Book not available: 1984
+
+jshell> library.returnBook("978-0451524935");
+Returned: 1984
+
+jshell> library.printAllBooks();
+Library Collection:
+  1984 by George Orwell (ISBN: 978-0451524935) - Available
+  Animal Farm by George Orwell (ISBN: 978-0451526342) - Available
+  To Kill a Mockingbird by Harper Lee (ISBN: 978-0061120084) - Available
+----
+
+=== Key Takeaways
+
+1. **Collections Framework** provides flexible, dynamic data structures that are superior to arrays for most use cases
+2. **List** (ArrayList, LinkedList) - ordered collections that allow duplicates
+3. **Set** (HashSet, TreeSet, LinkedHashSet) - collections that don't allow duplicates
+4. **Map** (HashMap, TreeMap, LinkedHashMap) - key-value pair collections
+5. **Queue/Deque** - collections designed for processing elements in specific orders
+6. **Enhanced for loops** provide clean, simple iteration over collections
+7. **Iterators** give more control over collection traversal and modification
+8. **Collections utility class** provides helpful static methods for common operations
+
+The Collections Framework is essential for professional Java development. It provides the building blocks for managing data efficiently and makes your code more maintainable and powerful. Understanding when to use each collection type and how to iterate through them effectively will make you a much more capable Java programmer.
\ No newline at end of file
diff --git a/IntroAndWorkBook/consolelog.adoc b/IntroAndWorkBook/consolelog.adoc
index 1acc8d0..c396f09 100644
--- a/IntroAndWorkBook/consolelog.adoc
+++ b/IntroAndWorkBook/consolelog.adoc
@@ -44,8 +44,8 @@ You'll see a prompt like this:
 
 jshell>
 ```
-__(And if you get something like **jshell: command not found**, see the appendix at the back of the book
-on how to install what you need.) - (and if the number up there is 9 or 11 or 21... well it really doesn't matter)
+__(And if you get something like **jshell: command not found**, see the **appendix** at the back of the book
+on how to install the java software you need.) - (and if the number up there is Version 9 or 11 or 21... well it really doesn't matter)
  - (I'll wait. Go ahead, come back here when it's installed.)__
 
 Now you can type simple Java statements directly! For example:
@@ -359,7 +359,7 @@ In this book, you may see that the code used in examples is longer than can fit
 [source]
 ----
 k = h * kph - (rest / 60);
-
+// OR
 kilometersCycled = numberOfHoursPedalled * kilometersPerHour - (totalMinutesOfRest / 60);
 ----
 
@@ -382,7 +382,7 @@ if (magePower > 120.0) {
 
 See those curly-braces? They start and stop the _block_, and contain the statements within. You can also see how the code is indented, but the real key are those braces. You'll see lots of blocks when you're looking at Java code.
 
-And, it's a bad idea, but this code:
+And, while this is a bad idea, this code:
 
 [source]
 ----
@@ -400,6 +400,7 @@ if (wizardStrength > 120.0) {
 }
 ----
 
-But the SECOND example is formatted much cleaner, making it more readable and therefore easier to understand.
-So I encourage you to your code easy to read by keeping it tidy.
+But the **SECOND example is formatted much cleaner**, making it more **readable** and therefore easier to understand.
+So I encourage you to make your code easy to read by keeping it tidy.
+Why? Well, if no other reason than that it is what the professionals do.
 
diff --git a/IntroAndWorkBook/exceptions.adoc b/IntroAndWorkBook/exceptions.adoc
new file mode 100644
index 0000000..1d12d5d
--- /dev/null
+++ b/IntroAndWorkBook/exceptions.adoc
@@ -0,0 +1,575 @@
+== Exception Handling in Java
+
+When you write programs, things don't always go as planned. Files might not exist, users might enter invalid data, network connections might fail, or you might try to divide by zero. Java provides a robust system called **exception handling** to deal with these unexpected situations gracefully.
+
+=== Understanding Exceptions and Error Handling
+
+An **exception** is an event that occurs during program execution that disrupts the normal flow of instructions. Instead of letting your program crash, Java allows you to "catch" these exceptions and handle them appropriately.
+
+Think of exceptions like unexpected events in real life - if you're driving and encounter a roadblock, you don't just stop your car forever. You find an alternate route or wait for the roadblock to clear.
+
+==== What Causes Exceptions?
+
+Here are some common situations that cause exceptions:
+
+[source]
+----
+jshell> int result = 10 / 0;  // ArithmeticException
+|  Exception java.lang.ArithmeticException: / by zero
+|        at (#1:1)
+
+jshell> String text = null;
+text ==> null
+
+jshell> int length = text.length();  // NullPointerException
+|  Exception java.lang.NullPointerException
+|        at (#3:1)
+
+jshell> int[] numbers = {1, 2, 3};
+numbers ==> int[3] { 1, 2, 3 }
+
+jshell> int value = numbers[5];  // ArrayIndexOutOfBoundsException
+|  Exception java.lang.ArrayIndexOutOfBoundsException: Index 5 out of bounds for length 3
+|        at (#5:1)
+----
+
+Without exception handling, these errors would terminate your program. But with proper exception handling, you can make your program continue running even when these situations occur.
+
+=== Try-Catch-Finally Blocks
+
+The primary mechanism for handling exceptions in Java is the **try-catch-finally** statement. Here's how it works:
+
+==== Basic Try-Catch
+
+[source]
+----
+jshell> public static void safeDivision(int a, int b) {
+   ...>     try {
+   ...>         int result = a / b;
+   ...>         System.out.println(a + " / " + b + " = " + result);
+   ...>     } catch (ArithmeticException e) {
+   ...>         System.out.println("Error: Cannot divide by zero!");
+   ...>         System.out.println("Exception message: " + e.getMessage());
+   ...>     }
+   ...>     System.out.println("Program continues...");
+   ...> }
+|  created method safeDivision(int,int)
+
+jshell> safeDivision(10, 2);
+10 / 2 = 5
+Program continues...
+
+jshell> safeDivision(10, 0);
+Error: Cannot divide by zero!
+Exception message: / by zero
+Program continues...
+----
+
+==== Multiple Catch Blocks
+
+You can handle different types of exceptions differently:
+
+[source]
+----
+jshell> public static void processArray(int[] array, int index) {
+   ...>     try {
+   ...>         System.out.println("Accessing element at index " + index);
+   ...>         int value = array[index];
+   ...>         int result = 100 / value;
+   ...>         System.out.println("Result: " + result);
+   ...>     } catch (ArrayIndexOutOfBoundsException e) {
+   ...>         System.out.println("Error: Index " + index + " is out of bounds!");
+   ...>     } catch (ArithmeticException e) {
+   ...>         System.out.println("Error: Cannot divide by zero!");
+   ...>     } catch (NullPointerException e) {
+   ...>         System.out.println("Error: Array is null!");
+   ...>     }
+   ...>     System.out.println("Method finished.");
+   ...> }
+|  created method processArray(int[],int)
+
+jshell> int[] numbers = {1, 0, 5, 10};
+numbers ==> int[4] { 1, 0, 5, 10 }
+
+jshell> processArray(numbers, 2);
+Accessing element at index 2
+Result: 20
+
+jshell> processArray(numbers, 10);  // Index out of bounds
+Error: Index 10 is out of bounds!
+Method finished.
+
+jshell> processArray(numbers, 1);   // Division by zero
+Accessing element at index 1
+Error: Cannot divide by zero!
+Method finished.
+
+jshell> processArray(null, 0);      // Null pointer
+Error: Array is null!
+Method finished.
+----
+
+==== The Finally Block
+
+The **finally** block always executes, whether an exception occurs or not. It's perfect for cleanup code:
+
+[source]
+----
+jshell> import java.io.*;
+jshell> public static void readFile(String filename) {
+   ...>     BufferedReader reader = null;
+   ...>     try {
+   ...>         reader = new BufferedReader(new FileReader(filename));
+   ...>         String line = reader.readLine();
+   ...>         System.out.println("First line: " + line);
+   ...>     } catch (FileNotFoundException e) {
+   ...>         System.out.println("Error: File '" + filename + "' not found!");
+   ...>     } catch (IOException e) {
+   ...>         System.out.println("Error reading file: " + e.getMessage());
+   ...>     } finally {
+   ...>         System.out.println("Cleanup: Closing file reader...");
+   ...>         if (reader != null) {
+   ...>             try {
+   ...>                 reader.close();
+   ...>             } catch (IOException e) {
+   ...>                 System.out.println("Error closing file: " + e.getMessage());
+   ...>             }
+   ...>         }
+   ...>     }
+   ...>     System.out.println("Method completed.");
+   ...> }
+|  created method readFile(String)
+
+jshell> readFile("nonexistent.txt");
+Error: File 'nonexistent.txt' not found!
+Cleanup: Closing file reader...
+Method completed.
+----
+
+==== Try-with-Resources (Modern Approach)
+
+Java 7 introduced a cleaner way to handle resources that need to be closed:
+
+[source]
+----
+jshell> public static void readFileModern(String filename) {
+   ...>     try (BufferedReader reader = new BufferedReader(new FileReader(filename))) {
+   ...>         String line = reader.readLine();
+   ...>         System.out.println("First line: " + line);
+   ...>     } catch (FileNotFoundException e) {
+   ...>         System.out.println("Error: File '" + filename + "' not found!");
+   ...>     } catch (IOException e) {
+   ...>         System.out.println("Error reading file: " + e.getMessage());
+   ...>     }
+   ...>     System.out.println("Method completed (reader auto-closed).");
+   ...> }
+|  created method readFileModern(String)
+----
+
+The resource (BufferedReader) is automatically closed when the try block finishes, even if an exception occurs.
+
+=== Checked vs Unchecked Exceptions
+
+Java has two main categories of exceptions:
+
+==== Unchecked Exceptions (Runtime Exceptions)
+
+These are exceptions that can occur during normal program execution and don't need to be explicitly caught or declared. They usually indicate programming errors:
+
+[source]
+----
+jshell> public static void demonstrateUncheckedExceptions() {
+   ...>     // These can happen but don't need to be caught
+   ...>     
+   ...>     // NullPointerException
+   ...>     String text = null;
+   ...>     // text.length();  // Would throw NPE
+   ...>     
+   ...>     // ArrayIndexOutOfBoundsException  
+   ...>     int[] array = new int[3];
+   ...>     // array[10] = 5;  // Would throw AIOOBE
+   ...>     
+   ...>     // ArithmeticException
+   ...>     // int result = 5 / 0;  // Would throw ArithmeticException
+   ...>     
+   ...>     System.out.println("No exceptions thrown this time!");
+   ...> }
+|  created method demonstrateUncheckedExceptions()
+
+jshell> demonstrateUncheckedExceptions();
+No exceptions thrown this time!
+----
+
+==== Checked Exceptions
+
+These are exceptions that must be either caught or declared in the method signature. They represent recoverable conditions:
+
+[source]
+----
+jshell> import java.io.IOException;
+jshell> import java.io.FileReader;
+
+jshell> // This method MUST handle or declare the IOException
+   ...> public static void mustHandleCheckedException() throws IOException {
+   ...>     FileReader file = new FileReader("somefile.txt");  // Checked exception!
+   ...>     // Must either catch IOException or declare it with 'throws'
+   ...> }
+|  created method mustHandleCheckedException()
+
+jshell> // Better approach - handle the exception
+   ...> public static void handleCheckedException() {
+   ...>     try {
+   ...>         FileReader file = new FileReader("somefile.txt");
+   ...>         System.out.println("File opened successfully!");
+   ...>         file.close();
+   ...>     } catch (IOException e) {
+   ...>         System.out.println("Could not open file: " + e.getMessage());
+   ...>     }
+   ...> }
+|  created method handleCheckedException()
+
+jshell> handleCheckedException();
+Could not open file: somefile.txt (No such file or directory)
+----
+
+=== Creating Custom Exceptions
+
+Sometimes the built-in exceptions don't fit your specific needs. You can create your own exceptions:
+
+==== Custom Unchecked Exception
+
+[source]
+----
+jshell> class InvalidAgeException extends RuntimeException {
+   ...>     public InvalidAgeException(String message) {
+   ...>         super(message);
+   ...>     }
+   ...>     
+   ...>     public InvalidAgeException(String message, int age) {
+   ...>         super(message + " Age provided: " + age);
+   ...>     }
+   ...> }
+|  created class InvalidAgeException
+
+jshell> class Person {
+   ...>     private String name;
+   ...>     private int age;
+   ...>     
+   ...>     public Person(String name, int age) {
+   ...>         if (age < 0 || age > 150) {
+   ...>             throw new InvalidAgeException("Age must be between 0 and 150.", age);
+   ...>         }
+   ...>         this.name = name;
+   ...>         this.age = age;
+   ...>     }
+   ...>     
+   ...>     public void setAge(int age) {
+   ...>         if (age < 0 || age > 150) {
+   ...>             throw new InvalidAgeException("Invalid age provided", age);
+   ...>         }
+   ...>         this.age = age;
+   ...>     }
+   ...>     
+   ...>     public String toString() {
+   ...>         return name + " (age " + age + ")";
+   ...>     }
+   ...> }
+|  created class Person
+
+jshell> try {
+   ...>     Person person1 = new Person("Alice", 25);
+   ...>     System.out.println("Created: " + person1);
+   ...>     
+   ...>     Person person2 = new Person("Bob", -5);  // This will throw exception
+   ...> } catch (InvalidAgeException e) {
+   ...>     System.out.println("Exception caught: " + e.getMessage());
+   ...> }
+Created: Alice (age 25)
+Exception caught: Age must be between 0 and 150. Age provided: -5
+----
+
+==== Custom Checked Exception
+
+[source]
+----
+jshell> class InsufficientFundsException extends Exception {
+   ...>     private double balance;
+   ...>     private double amount;
+   ...>     
+   ...>     public InsufficientFundsException(double balance, double amount) {
+   ...>         super("Insufficient funds. Balance: $" + balance + ", Requested: $" + amount);
+   ...>         this.balance = balance;
+   ...>         this.amount = amount;
+   ...>     }
+   ...>     
+   ...>     public double getBalance() { return balance; }
+   ...>     public double getAmount() { return amount; }
+   ...> }
+|  created class InsufficientFundsException
+
+jshell> class BankAccount {
+   ...>     private double balance;
+   ...>     private String accountNumber;
+   ...>     
+   ...>     public BankAccount(String accountNumber, double initialBalance) {
+   ...>         this.accountNumber = accountNumber;
+   ...>         this.balance = initialBalance;
+   ...>     }
+   ...>     
+   ...>     public void withdraw(double amount) throws InsufficientFundsException {
+   ...>         if (amount > balance) {
+   ...>             throw new InsufficientFundsException(balance, amount);
+   ...>         }
+   ...>         balance -= amount;
+   ...>         System.out.println("Withdrew $" + amount + ". New balance: $" + balance);
+   ...>     }
+   ...>     
+   ...>     public double getBalance() { return balance; }
+   ...> }
+|  created class BankAccount
+
+jshell> BankAccount account = new BankAccount("12345", 100.0);
+account ==> BankAccount@...
+
+jshell> try {
+   ...>     account.withdraw(50.0);   // This should work
+   ...>     account.withdraw(75.0);   // This should fail
+   ...> } catch (InsufficientFundsException e) {
+   ...>     System.out.println("Transaction failed: " + e.getMessage());
+   ...>     System.out.println("Current balance: $" + e.getBalance());
+   ...> }
+Withdrew $50.0. New balance: $50.0
+Transaction failed: Insufficient funds. Balance: $50.0, Requested: $75.0
+Current balance: $50.0
+----
+
+=== Best Practices for Exception Handling
+
+==== 1. Be Specific with Exception Types
+
+Don't catch generic `Exception` unless you really need to:
+
+[source]
+----
+jshell> // Bad - too generic
+   ...> public static void badExample() {
+   ...>     try {
+   ...>         int[] array = {1, 2, 3};
+   ...>         int value = array[10];
+   ...>     } catch (Exception e) {  // Too broad!
+   ...>         System.out.println("Something went wrong");
+   ...>     }
+   ...> }
+|  created method badExample()
+
+jshell> // Good - specific exception handling
+   ...> public static void goodExample() {
+   ...>     try {
+   ...>         int[] array = {1, 2, 3};
+   ...>         int value = array[10];
+   ...>     } catch (ArrayIndexOutOfBoundsException e) {  // Specific!
+   ...>         System.out.println("Array index out of bounds: " + e.getMessage());
+   ...>     }
+   ...> }
+|  created method goodExample()
+----
+
+==== 2. Don't Swallow Exceptions
+
+Always do something meaningful in catch blocks:
+
+[source]
+----
+jshell> // Bad - silent failure
+   ...> public static void badLogging() {
+   ...>     try {
+   ...>         int result = 10 / 0;
+   ...>     } catch (ArithmeticException e) {
+   ...>         // Silent failure - very bad!
+   ...>     }
+   ...> }
+|  created method badLogging()
+
+jshell> // Good - proper logging/handling
+   ...> public static void goodLogging() {
+   ...>     try {
+   ...>         int result = 10 / 0;
+   ...>     } catch (ArithmeticException e) {
+   ...>         System.err.println("Mathematical error occurred: " + e.getMessage());
+   ...>         // Log the exception or take appropriate action
+   ...>     }
+   ...> }
+|  created method goodLogging()
+
+jshell> goodLogging();
+Mathematical error occurred: / by zero
+----
+
+==== 3. Use Exception Chaining
+
+When catching an exception and throwing a new one, preserve the original exception:
+
+[source]
+----
+jshell> class DataProcessingException extends Exception {
+   ...>     public DataProcessingException(String message, Throwable cause) {
+   ...>         super(message, cause);
+   ...>     }
+   ...> }
+|  created class DataProcessingException
+
+jshell> public static void processData(int[] data) throws DataProcessingException {
+   ...>     try {
+   ...>         // Simulate some processing that might fail
+   ...>         int result = data[0] / data[1];
+   ...>         System.out.println("Processing result: " + result);
+   ...>     } catch (ArithmeticException | ArrayIndexOutOfBoundsException e) {
+   ...>         // Chain the original exception
+   ...>         throw new DataProcessingException("Failed to process data", e);
+   ...>     }
+   ...> }
+|  created method processData(int[])
+
+jshell> try {
+   ...>     processData(new int[]{10, 0});  // Will cause ArithmeticException
+   ...> } catch (DataProcessingException e) {
+   ...>     System.out.println("Application error: " + e.getMessage());
+   ...>     System.out.println("Root cause: " + e.getCause().getClass().getSimpleName());
+   ...> }
+Application error: Failed to process data
+Root cause: ArithmeticException
+----
+
+==== 4. Validate Input Early
+
+Prevent exceptions by validating input parameters:
+
+[source]
+----
+jshell> public static double calculateCircleArea(double radius) {
+   ...>     // Validate input early
+   ...>     if (radius < 0) {
+   ...>         throw new IllegalArgumentException("Radius cannot be negative: " + radius);
+   ...>     }
+   ...>     
+   ...>     return Math.PI * radius * radius;
+   ...> }
+|  created method calculateCircleArea(double)
+
+jshell> System.out.println("Area: " + calculateCircleArea(5.0));
+Area: 78.53981633974483
+
+jshell> try {
+   ...>     calculateCircleArea(-3.0);
+   ...> } catch (IllegalArgumentException e) {
+   ...>     System.out.println("Invalid input: " + e.getMessage());
+   ...> }
+Invalid input: Radius cannot be negative: -3.0
+----
+
+=== Practical Example: A Robust File Processor
+
+Let's put it all together with a comprehensive example:
+
+[source]
+----
+jshell> import java.io.*;
+jshell> import java.util.ArrayList;
+jshell> import java.util.List;
+
+jshell> class FileProcessingException extends Exception {
+   ...>     public FileProcessingException(String message) {
+   ...>         super(message);
+   ...>     }
+   ...>     
+   ...>     public FileProcessingException(String message, Throwable cause) {
+   ...>         super(message, cause);
+   ...>     }
+   ...> }
+|  created class FileProcessingException
+
+jshell> class NumberFileProcessor {
+   ...>     public List<Integer> processNumberFile(String filename) throws FileProcessingException {
+   ...>         if (filename == null || filename.trim().isEmpty()) {
+   ...>             throw new IllegalArgumentException("Filename cannot be null or empty");
+   ...>         }
+   ...>         
+   ...>         List<Integer> numbers = new ArrayList<>();
+   ...>         
+   ...>         try (BufferedReader reader = new BufferedReader(new FileReader(filename))) {
+   ...>             String line;
+   ...>             int lineNumber = 0;
+   ...>             
+   ...>             while ((line = reader.readLine()) != null) {
+   ...>                 lineNumber++;
+   ...>                 try {
+   ...>                     line = line.trim();
+   ...>                     if (!line.isEmpty()) {
+   ...>                         int number = Integer.parseInt(line);
+   ...>                         numbers.add(number);
+   ...>                     }
+   ...>                 } catch (NumberFormatException e) {
+   ...>                     System.err.println("Warning: Invalid number on line " + lineNumber + ": '" + line + "'");
+   ...>                     // Continue processing other lines
+   ...>                 }
+   ...>             }
+   ...>             
+   ...>         } catch (FileNotFoundException e) {
+   ...>             throw new FileProcessingException("File not found: " + filename, e);
+   ...>         } catch (IOException e) {
+   ...>             throw new FileProcessingException("Error reading file: " + filename, e);
+   ...>         }
+   ...>         
+   ...>         if (numbers.isEmpty()) {
+   ...>             throw new FileProcessingException("No valid numbers found in file: " + filename);
+   ...>         }
+   ...>         
+   ...>         return numbers;
+   ...>     }
+   ...>     
+   ...>     public double calculateAverage(List<Integer> numbers) {
+   ...>         if (numbers == null || numbers.isEmpty()) {
+   ...>             throw new IllegalArgumentException("Number list cannot be null or empty");
+   ...>         }
+   ...>         
+   ...>         long sum = 0;
+   ...>         for (Integer number : numbers) {
+   ...>             sum += number;
+   ...>         }
+   ...>         
+   ...>         return (double) sum / numbers.size();
+   ...>     }
+   ...> }
+|  created class NumberFileProcessor
+
+jshell> // Simulate processing a file
+   ...> NumberFileProcessor processor = new NumberFileProcessor();
+processor ==> NumberFileProcessor@...
+
+jshell> try {
+   ...>     // This would normally read from a real file
+   ...>     List<Integer> numbers = List.of(10, 20, 30, 40, 50);  // Simulated data
+   ...>     double average = processor.calculateAverage(numbers);
+   ...>     System.out.println("Numbers processed: " + numbers);
+   ...>     System.out.println("Average: " + average);
+   ...> } catch (IllegalArgumentException e) {
+   ...>     System.err.println("Input validation error: " + e.getMessage());
+   ...> } catch (Exception e) {
+   ...>     System.err.println("Unexpected error: " + e.getMessage());
+   ...>     e.printStackTrace();
+   ...> }
+Numbers processed: [10, 20, 30, 40, 50]
+Average: 30.0
+----
+
+=== Key Takeaways
+
+1. **Exceptions** are unexpected events that can disrupt program flow
+2. **Try-catch-finally** blocks let you handle exceptions gracefully
+3. **Checked exceptions** must be caught or declared; **unchecked exceptions** don't require explicit handling
+4. **Custom exceptions** can represent specific error conditions in your domain
+5. **Finally blocks** always execute and are perfect for cleanup code
+6. **Try-with-resources** automatically manages resource cleanup
+7. **Best practices**: Be specific with exception types, don't swallow exceptions, use exception chaining, and validate input early
+
+Exception handling is crucial for writing robust, professional Java applications. It allows your programs to gracefully handle unexpected situations and provide meaningful feedback to users rather than crashing unexpectedly.
\ No newline at end of file
diff --git a/IntroAndWorkBook/file-io.adoc b/IntroAndWorkBook/file-io.adoc
index ef07bd1..0ab36b1 100644
--- a/IntroAndWorkBook/file-io.adoc
+++ b/IntroAndWorkBook/file-io.adoc
@@ -6,6 +6,7 @@ This is essential for creating programs that can save and load information, proc
 ==== Why File I/O?
 
 Most real-world programs need to:
+
 - Save user data between program runs
 - Read configuration settings
 - Process data from spreadsheets or databases
@@ -152,7 +153,8 @@ public class ZipCode {
 
 ==== Exception Handling with Files
 
-File operations can fail for many reasons (file doesn't exist, no permission, disk full, etc.), so we must handle exceptions:
+File operations can fail for many reasons (file doesn't exist, 
+no permission, disk full, etc.), so we must handle exceptions:
 
 ===== Try-Catch Blocks
 
@@ -189,7 +191,8 @@ public class ZipCode {
 
 ===== Try-with-Resources (Automatic Cleanup)
 
-Java provides a cleaner way to handle file resources that automatically closes them:
+Java provides a cleaner way to handle file resources that 
+automatically closes them:
 
 [source]
 ----
@@ -219,7 +222,8 @@ public class ZipCode {
 
 ==== Complete Example: Student Grade Manager
 
-Here's a practical example that reads student data from a file, processes it, and writes a report:
+Here's a practical example that reads student data from a file, 
+processes it, and writes a report:
 
 [source]
 ----
diff --git a/IntroAndWorkBook/index.adoc b/IntroAndWorkBook/index.adoc
index 6f6e73f..4efa704 100644
--- a/IntroAndWorkBook/index.adoc
+++ b/IntroAndWorkBook/index.adoc
@@ -1,8 +1,8 @@
 :doctype: book
 :title-page:
-= Zip Code Wilmington's Programming in Java
+= Zip Code Wilmington's Introduction to Java Programming
 Kristofer Younger <kris@zipcodewilmington.com>
-v2.2, 2025-06-17
+v2.4, 2025-07-24
 :imagesdir: images
 :pdf-theme: indextheme.yml
 :source-highlighter: rouge
@@ -12,13 +12,13 @@ v2.2, 2025-06-17
 :homepage: https://zipcodewilmington.com/javabook
 //:pdf-page-size:  [5.5in, 8.5in]
 :pdf-page-size:  [6.75in, 9.1875in]
-//:front-cover-image: ZCW_JS-Book-FNL.png
+:front-cover-image: JavaIntroCover.pdf
 :toc:
 
 [colophon]
 == Colophon
 
-Zip Code Wilmington's Programming in Java
+Zip Code Wilmington's Introduction to Java Programming
 by Kristofer Younger
 
 Copyright (C) 2020-2025 by Zip Code Wilmington. All Rights Reserved.
@@ -152,6 +152,8 @@ include::arrays.adoc[]
 
 include::multidimensional-arrays.adoc[]
 
+include::arraylist.adoc[]
+
 include::controlflow.adoc[]
 
 include::if.adoc[]
@@ -181,12 +183,30 @@ include::access-modifiers.adoc[]
 
 == Input/Output Operations
 
+Getting things in and out of the programs you write, well, this is pretty important.
+Here's a few things to use.
+
 include::scanner-input.adoc[]
 
 include::file-io.adoc[]
 
 include::output-formatting.adoc[]
 
+== Advanced Java Concepts
+
+These are things that are lightly covered here.
+These deserve a much deeper examination, as they are pretty important,
+but if you're just starting to learn Java, they are not crucial.
+
+Be sure to take a look at other Java resourses, if you need more information
+about them!
+
+include::advancedoop.adoc[]
+
+include::exceptions.adoc[]
+
+include::collections.adoc[]
+
 include::appendixa.adoc[]
 
 include::appendixb.adoc[]
diff --git a/IntroAndWorkBook/jvm-ecosystem.adoc b/IntroAndWorkBook/jvm-ecosystem.adoc
index 4a67290..d0b9664 100644
--- a/IntroAndWorkBook/jvm-ecosystem.adoc
+++ b/IntroAndWorkBook/jvm-ecosystem.adoc
@@ -71,40 +71,47 @@ When you run this code:
 
 === The Java Ecosystem
 
+The ecosystem is vast for Java.
+There are many things which make Java very useful to many people an dlots of kinds of applications.
+
 ==== Core Components
 
+There are several kinds of Java. The language is the same, but how it's packaged
+is different. 
 **Java SE (Standard Edition)**
+
 - Basic Java platform for desktop and server applications
 - Includes core libraries, JVM, and development tools
 - What we use in this book
 
-**Java EE (Enterprise Edition)**
+**Jakarta EE(Enterprise Edition)**
+
 - Extended platform for large-scale enterprise applications
 - Includes web services, database connectivity, security features
 - Used for building complex business applications
 
-**Java ME (Micro Edition)**
-- Lightweight platform for mobile and embedded devices
-- Smaller footprint, optimized for resource-constrained environments
-
 ==== Popular Java Frameworks and Libraries
 
 **Web Development:**
+
 - **Spring** - Most popular Java web framework
 - **Spring Boot** - Simplified Spring for rapid development
 - **Struts** - Web application framework
 
 **Data and Databases:**
+
 - **Hibernate** - Object-relational mapping (ORM)
 - **JDBC** - Database connectivity API
 - **JPA** - Java Persistence API
 
 **Testing:**
+
 - **JUnit** - Unit testing framework
 - **TestNG** - Testing framework with advanced features
 - **Mockito** - Mocking framework for testing
 
 **Build Tools:**
+
 - **Maven** - Project management and build automation
 - **Gradle** - Modern build automation tool
 - **Ant** - XML-based build tool
diff --git a/IntroAndWorkBook/method-overloading.adoc b/IntroAndWorkBook/method-overloading.adoc
index 5cc5b97..8642dd9 100644
--- a/IntroAndWorkBook/method-overloading.adoc
+++ b/IntroAndWorkBook/method-overloading.adoc
@@ -8,11 +8,13 @@ Each version is still saying hello, but with different information.
 
 ==== What is Method Overloading?
 
-Method overloading means having multiple methods with:
+Method overloading means having multiple methods in the same class with:
+
 - The **same name**
-- **Different parameters** (different number, types, or order)
+- But **different parameters** (different number, types, or order)
 
-Java determines which method to call based on the arguments you provide when calling the method.
+Java determines which method to call based on the arguments you 
+provide when calling the method.
 
 ==== Basic Example
 
@@ -20,7 +22,7 @@ Here's a simple example using addition:
 
 [source]
 ----
-public class ZipCode {
+public class SimpleOverload {
 
   void compute() {
     // Test all our add methods
@@ -44,7 +46,7 @@ public class ZipCode {
     return a + b + c;
   }
 
-  public static void main(String[] args) { new ZipCode().compute(); }
+  public static void main(String[] args) { new SimpleOverload().compute(); }
 }
 ----
 
@@ -105,7 +107,7 @@ Here's a practical example showing different ways to greet users:
 
 [source]
 ----
-public class ZipCode {
+public class GreetMagic {
 
   void compute() {
     greet("Alice");                    // Simple greeting
@@ -130,7 +132,7 @@ public class ZipCode {
     }
   }
 
-  public static void main(String[] args) { new ZipCode().compute(); }
+  public static void main(String[] args) { new GreetMagic().compute(); }
 }
 ----
 
@@ -146,6 +148,8 @@ public class ZipCode {
 
 ==== What DOES Work (Valid Overloading)
 
+These examples are okay.
+
 [source]
 ----
 public static int process(int x) { return x * 2; }
@@ -156,12 +160,15 @@ public static int process(String x) { return x.length(); }       // Different ty
 
 ==== What DOES NOT Work (Invalid Overloading)
 
+These examples don't work!
+
 [source]
 ----
 public static int process(int x) { return x * 2; }
 public static double process(int x) { return x * 2.0; }  // ERROR! Only return type differs
 ----
 
+Again, it's because the _return_ types are different, but the _parameters_ are the same type (both are `int` type).
 ==== Constructor Overloading
 
 You can also overload constructors (we'll learn more about these later):
diff --git a/IntroAndWorkBook/methods.adoc b/IntroAndWorkBook/methods.adoc
index 291a072..5ba69af 100644
--- a/IntroAndWorkBook/methods.adoc
+++ b/IntroAndWorkBook/methods.adoc
@@ -7,11 +7,13 @@ Now that you understand classes and objects, let's dive deeper into **methods**
 A method is a block of code that performs a specific task. Think of methods as the "verbs" of your program - they represent actions that can be performed.
 
 Just like in real life:
+
 - A `Person` can `walk()`, `talk()`, or `sleep()`
 - A `Car` can `start()`, `accelerate()`, or `brake()`
 - A `Calculator` can `add()`, `subtract()`, or `divide()`
 
 Methods help you:
+
 1. **Organize code** into logical chunks
 2. **Reuse code** instead of writing the same thing multiple times
 3. **Break down complex problems** into smaller, manageable pieces
@@ -30,6 +32,7 @@ public static returnType methodName(parameters) {
 ----
 
 Let's break this down:
+
 - `public static` - We'll explain these keywords later, but for now, always include them
 - `returnType` - What type of data the method gives back (or `void` if it gives back nothing)  
 - `methodName` - What you want to call your method
@@ -42,6 +45,13 @@ Let's start with some basic methods you can try in jshell:
 
 ==== Methods that Don't Return Anything (void methods)
 
+A void method in Java is a method that does not return any 
+value at the end of the computation. 
+The keyword void is used in the method declaration to 
+indicate this. Instead of sending data back, a void method 
+typically performs an action, 
+such as printing output or modifying an object.
+
 [source]
 ----
 jshell> public static void sayHello() {
@@ -192,6 +202,11 @@ Methods can take different types and numbers of parameters:
 
 ==== Single Parameter
 
+The simplest way to pass information to a method is through a 
+single parameter. This allows you to create flexible methods 
+that can work with different values each time they're called, 
+making your code more reusable and powerful.
+
 [source]
 ----
 jshell> public static int square(int number) {
@@ -205,6 +220,12 @@ $1 ==> 16
 
 ==== Multiple Parameters
 
+When your method needs more than one piece of information to do 
+its job, you can pass multiple parameters separated by commas. 
+This is essential for methods that perform calculations or 
+operations involving several values, like mathematical functions 
+or data processing.
+
 [source]
 ----
 jshell> public static int multiply(int a, int b) {
@@ -218,6 +239,12 @@ $2 ==> 42
 
 ==== Different Parameter Types
 
+Methods can accept parameters of different data types in the 
+same parameter list. This flexibility allows you to create 
+methods that work with various kinds of data simultaneously, 
+such as combining text, numbers, and boolean values to perform 
+complex operations.
+
 [source]
 ----
 jshell> public static void introduce(String name, int age, double height) {
@@ -235,7 +262,15 @@ Height: 5.8 feet
 
 === Return Values Explained
 
-When a method returns a value, you can:
+One way to think about programming is to think about how the data of
+program moves around.
+A programmer controls, and manipulates, the data that is input into 
+the program, and passes it around as various computations are done.
+
+Having methods handle certain computations, and then produce results, well, you need a way to 
+_return_ those results.
+
+When a method returns a resulting value, you can:
 
 **Store it in a variable**:
 
@@ -274,6 +309,11 @@ ageInMonths ==> 300
 
 === Methods with Conditional Logic
 
+Making decisions based on data is a central point of programming.
+You need to do different things based on different data, so it is very
+common to have If statements in methods that use conditions to perform
+computations.
+
 Methods can make decisions using if statements:
 
 [source]
@@ -305,7 +345,8 @@ $5 ==> "F"
 
 === Practical Example: A Complete Class with Methods
 
-Let's create a `Student` class that demonstrates various types of methods:
+Let's create a `Student` class that demonstrates various 
+types of methods:
 
 [source]
 ----
@@ -386,6 +427,7 @@ Letter grade: B
 Choose clear, descriptive names for your methods:
 
 **Good method names:**
+
 - `calculateArea()`
 - `getUserInput()`
 - `validateEmail()`
@@ -393,6 +435,7 @@ Choose clear, descriptive names for your methods:
 - `isEven()`
 
 **Poor method names:**
+
 - `doStuff()`
 - `method1()`
 - `calc()`
@@ -402,7 +445,11 @@ Choose clear, descriptive names for your methods:
 
 ==== Validation Methods
 
-Methods that check if something is valid often return boolean values:
+Validation methods are essential for ensuring data integrity 
+and making logical decisions in your programs. 
+These methods typically return boolean values (true or false) 
+and are used to check conditions, validate input, or determine 
+program flow. They're commonly used in if statements and loops.
 
 [source]
 ----
@@ -420,7 +467,11 @@ $7 ==> false
 
 ==== Utility Methods
 
-Methods that perform common calculations:
+Utility methods are general-purpose functions that perform 
+common operations you might need throughout your program. 
+These methods encapsulate frequently-used calculations or 
+conversions, making your code more organized and eliminating 
+the need to write the same logic multiple times.
 
 [source]
 ----
@@ -441,6 +492,7 @@ $9 ==> 212.0
 Try creating these methods in jshell:
 
 **Exercise 1: Basic Math Methods**
+
 [source]
 ----
 // Create these methods:
@@ -458,6 +510,7 @@ public static boolean isPositive(int number) {
 ----
 
 **Exercise 2: String Methods**
+
 [source]
 ----
 // Create these methods:
@@ -472,7 +525,9 @@ public static int countVowels(String text) {
 ----
 
 **Exercise 3: ZipCoder Challenge**
+
 Create a method that follows these rules:
+
 - If a number is divisible by both 3 and 5, print "ZipCoder"
 - If divisible by only 3, print "Zip"  
 - If divisible by only 5, print "Coder"
diff --git a/IntroAndWorkBook/objectsmethods.adoc b/IntroAndWorkBook/objectsmethods.adoc
index 9a9686f..0ab47fa 100644
--- a/IntroAndWorkBook/objectsmethods.adoc
+++ b/IntroAndWorkBook/objectsmethods.adoc
@@ -11,21 +11,20 @@ In the winter, of course, if you're in the northern hemisphere, you tend to choo
 
 If the thermostat is rather old fashion, it might have a ring you rotate to set the temperature, say 68 degrees.
 
-A Java programmer writes code which in _classes_ and then, when a java program runs, _objects_ are created 
-All but one of them are called “primitive” data types, because their values contain only a single thing (be it a string or a number or whatever).
+A Java programmer writes code which in _classes_ and then, when a java program 
+runs, _objects_ are created. 
 
-In contrast, *objects* are used to store *keyed* collections of various data and more complex entities. 
-_Objects_ add tremendous power to Java and penetrate almost every aspect of the language. 
-Here are a few different objects, all these are actually objects in Java, which makes the language rather elegant:
+*Objects* are instances of classes that encapsulate data (instance variables) and behavior (methods) together. 
+_Objects_ add tremendous power to Java and are fundamental to the language's object-oriented design. 
+In Java, everything except primitive types (int, double, boolean, etc.) are objects, including:
 
-* arrays
-* functions
-* regular expressions 
-* objects 
+* String objects
+* Collection objects (ArrayList, HashMap, etc.)
+* Custom class objects you create
 
-Objects are used to collect and organize data - and that data can be variable values, functions and other things. 
-Objects can also contain other objects(!), in kind of a "nesting" way. 
-This allows for large data structures to be built using a very simple and elegant mechanism.
+Objects are used to model real-world entities and organize related data and methods together. 
+Objects can contain other objects as instance variables, creating complex data structures and relationships. 
+This composition allows for building sophisticated applications using well-organized, reusable components.
 
 
 [source]
@@ -43,6 +42,23 @@ class Person {
         this.homedistrict = homedistrict;
         this.skills = skills;
     }
+    
+    // Getter methods
+    public String getFirstname() {
+        return firstname;
+    }
+    
+    public String getLastname() {
+        return lastname;
+    }
+    
+    public int getHomedistrict() {
+        return homedistrict;
+    }
+    
+    public String[] getSkills() {
+        return skills;
+    }
 }
 
 Person katniss = new Person("Katniss", "Everdene", 12, 
@@ -85,7 +101,7 @@ class Player {
         this.species = species;
         this.superPower = superPower;
         this.lives = lives;
-        this.weapons = weapons;
+        this.weapon = weapons;
     }
 }
 
@@ -106,7 +122,7 @@ This approach follows the principle of **encapsulation**, which helps protect th
 
 Suppose you have a `Player` class with a `name` field:
 
-````java
+```java
 public class Player {
     private String name; // instance variable
 
@@ -120,18 +136,18 @@ public class Player {
         name = newName;
     }
 }
-````
+```
 
 - **Getter** (`getName()`): Returns the value of `name`.
 - **Setter** (`setName(String newName)`): Updates the value of `name`.
 
 ### Usage
 
-````java
+```java
 Player player1 = new Player();
 player1.setName("Rocco");              // Set the name using the setter
 System.out.println(player1.getName()); // Get the name using the getter
-````
+```
 
 **Gotcha:**  
 Directly accessing fields (e.g., `player1.name = "Rocco";`) is only possible if the field is `public`. 
@@ -141,6 +157,36 @@ Using getters and setters is safer and more flexible, especially if you want to
 
 This next little bit will stretch your mind a bit. 
 
+A Java object reference is like a label or pointer that tracks for your program 
+where to find an object in memory. (So you don't have to)
+When you create an object using `new`, Java stores it somewhere in memory, 
+and the variable you assign it to holds a reference 
+(not the actual object itself).
+
+Example:
+
+```
+Airplane plane1 = new Airplane("Boeing", 900, 200, 0);
+```
+
+Here, plane1 is an object reference. 
+It doesn't contain the Airplane object itself, but it knows where to find 
+it in memory. If you assign 
+
+```
+Airplane plane2 = plane1;
+```
+ 
+both references point to the same object and changing the object 
+through one reference affects the other.
+
+Key points:
+
+Object references store the location of objects, not the objects themselves.
+Multiple references can point to the same object.
+Changing the object through one reference is visible through all references to that object.
+This is different from primitive types (like int or double), which store actual values, not references.
+
 If we have an object:
 
 [source]
@@ -160,7 +206,31 @@ class Airplane {
         this.passengersOnboard = passengersOnboard;
     }
 
-    // assume we have all the setters and getters we need.
+    // Getter methods
+    public String getDestination() {
+        return destination;
+    }
+    
+    public String getOrigin() {
+        return origin;
+    }
+    
+    public int getPassengersOnboard() {
+        return passengersOnboard;
+    }
+    
+    // Setter methods
+    public void setDestination(String destination) {
+        this.destination = destination;
+    }
+    
+    public void setOrigin(String origin) {
+        this.origin = origin;
+    }
+    
+    public void setPassengersOnboard(int passengersOnboard) {
+        this.passengersOnboard = passengersOnboard;
+    }
 }
 
 Airplane airplane512 = new Airplane("airbusA330", 0.86, 253, 0);
@@ -177,8 +247,8 @@ flight77.setOrigin("Seattle");
 // now watch carefully...
 flight77.setPassengersOnboard(120);
 
-// and if I print out some of the properties...
-System.out.println(airplane512.passengersOnboard);  // 120
+// and if I print out some of the instance variables...
+System.out.println(airplane512.getPassengersOnboard());  // 120
 System.out.println(flight77.type); // airbusA330
 System.out.println(airplane512.type); // airbusA330
 ----
@@ -188,9 +258,12 @@ so when you make changes through the flight77 name, the properties in the object
 you can get and/or set properties through the airplane512 name as well. 
 This proves very powerful in many cases.
 
+Is is also the source of confusion, if you happen to make a mistake and that's NOT what you hadd in mind,
+you may have to untangle it a bit.
+
 === Instance Methods
 
-Now to make things even more powerful, Java objects can have _methods_ attached to them.
+As we have said, to make things even more powerful, Java objects can have _methods_ attached to them.
 Let's build a special counter object, something we might use in a program or app somewhere.
 
 As you may be aware, in American football there are four common changes to a team's score during a game:
diff --git a/IntroAndWorkBook/pdf/index.pdf b/IntroAndWorkBook/pdf/JavaIntro2-4.pdf
similarity index 61%
rename from IntroAndWorkBook/pdf/index.pdf
rename to IntroAndWorkBook/pdf/JavaIntro2-4.pdf
index d35bb36..cd23bfc 100644
Binary files a/IntroAndWorkBook/pdf/index.pdf and b/IntroAndWorkBook/pdf/JavaIntro2-4.pdf differ
diff --git a/IntroAndWorkBook/topics2.md b/IntroAndWorkBook/topics2.md
index 4e07cac..ce7939c 100644
--- a/IntroAndWorkBook/topics2.md
+++ b/IntroAndWorkBook/topics2.md
@@ -48,19 +48,19 @@ Reading user input (Scanner class)
 Basic file I/O operations
 Formatting output
 Java Advanced Syllabus
-Module 1: Advanced OOP Concepts
+Chapter: Advanced OOP Concepts
 Inheritance and the 'super' keyword
 Method overriding vs overloading
 Abstract classes and methods
 Interfaces and multiple inheritance
 Polymorphism and dynamic binding
-Module 2: Exception Handling
+Chapter: Exception Handling
 Understanding exceptions and error handling
 Try-catch-finally blocks
 Checked vs unchecked exceptions
 Creating custom exceptions
 Best practices for exception handling
-Module 3: Collections Framework
+Chapter: Collections Framework
 List interface (ArrayList, LinkedList, Vector)
 Set interface (HashSet, TreeSet, LinkedHashSet)
 Map interface (HashMap, TreeMap, LinkedHashMap)
diff --git a/IntroAndWorkBook/type-casting.adoc b/IntroAndWorkBook/type-casting.adoc
index c1c9be7..edecd9f 100644
--- a/IntroAndWorkBook/type-casting.adoc
+++ b/IntroAndWorkBook/type-casting.adoc
@@ -331,13 +331,20 @@ public class ZipCode {
 5. **Be explicit** about your intentions with casting
 6. **Understand precision loss** when casting floats/doubles to integers
 
+But wait, what is _parsing_ ?
+**Parsing** user input means converting text (like what a user types) into a specific data type your program can use, 
+such as turning the string "123" into the integer 123. This lets your code work with numbers, dates, or other types instead of just plain text.
+
 ==== Common Casting Scenarios
 
+And while _most_ of the time Java is pretty salty about changing the type of things, 
+there are some common situations where casting is okay, and very possibly, essential.
+
 ===== Rounding vs. Truncating
 
 [source]
 ----
-public class ZipCode {
+public class CastingAbout {
 
   void compute() {
     double value = 4.7;
@@ -356,18 +363,25 @@ public class ZipCode {
     System.out.println("Price rounded: $" + dollars);  // $20
   }
 
-  public static void main(String[] args) { new ZipCode().compute(); }
+  public static void main(String[] args) { new CastingAbout().compute(); }
 }
 ----
 
 ===== Safe Range Checking
 
+Sometimes, BEFORE you make a cast from one type to another, you need to _check that the number will fit_.
+Well, perhaps you have a really big number, say something in the trillions.
+A number like is probably not fit in a java Integer.
+So you compare the number against the smallest and largest integers, and if it in or out of that range,
+you do or do not make the cast.
+
 [source]
 ----
-public class ZipCode {
+public class WonkyCast {
 
   void compute() {
     long bigNumber = 50000L;
+    long numberTrillion = 1_000_000_000_001L; // 1 trillion and 1.
     
     // Check if it fits in an int before casting
     if (bigNumber >= Integer.MIN_VALUE && bigNumber <= Integer.MAX_VALUE) {
@@ -376,10 +390,25 @@ public class ZipCode {
     } else {
         System.out.println("Number too large for int!");
     }
+    // Check if it fits in an int before casting
+    if (numberTrillion >= Integer.MIN_VALUE && numberTrillion <= Integer.MAX_VALUE) {
+        int safeInt = (int) numberTrillion;
+        System.out.println("Safe conversion: " + numberTrillion);
+    } else {
+        System.out.println("Number"+ numberTrillion + " too large for int!");
+    }
   }
 
-  public static void main(String[] args) { new ZipCode().compute(); }
+  public static void main(String[] args) { new WonkyCast().compute(); }
 }
 ----
 
-Type casting is a fundamental skill in Java programming. Understanding when conversions happen automatically and when you need to be explicit will help you write more reliable and predictable code!
\ No newline at end of file
+when I run this, I'd get output of:
+
+```
+Safe conversion: 50000
+Number 1000000000001 too large for int!
+```
+
+Type casting is a fundamental skill in Java programming. 
+Understanding when conversions happen automatically and when you need to be explicit will help you write more reliable and predictable code!
\ No newline at end of file
diff --git a/reader/ReadingJava/.DS_Store b/reader/ReadingJava/.DS_Store
index 9d709ba..2d4e5b6 100644
Binary files a/reader/ReadingJava/.DS_Store and b/reader/ReadingJava/.DS_Store differ
diff --git a/reader/ReadingJava/Programs/.DS_Store b/reader/ReadingJava/Programs/.DS_Store
index ca43696..0e7d5d7 100644
Binary files a/reader/ReadingJava/Programs/.DS_Store and b/reader/ReadingJava/Programs/.DS_Store differ
