Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 21 additions & 0 deletions Lab-Exercises/Solutions/lab1_smart_survey.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# Lab 1: The Smart Survey Onboarding Engine

# 1. Capture inputs from user (Name, Age, Developer Status)
name = input("Enter your name: ")
age = int(input("Enter your age: ")) # Cast to int for numeric comparison
is_developer = input("Are you a developer? (yes/no): ").strip().lower() == "yes"

# 2. Evaluate conditional logic to determine the clearance tier
if age < 18:
tier = "Tier 3: Guest"
elif is_developer:
tier = "Tier 1: Admin Infrastructure Access"
else:
tier = "Tier 2: Standard Executive Access"

# 3. Print out the final profile card using an f-string
print(f"\n--- Profile Configuration Summary ---")
print(f"Name: {name}")
print(f"Age: {age}")
print(f"Developer: {'Yes' if is_developer else 'No'}")
print(f"Clearance: {tier}")
28 changes: 28 additions & 0 deletions Lab-Exercises/Solutions/lab1_solution.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# Lab 1 Solution Logic: The Smart Survey Onboarding Engine

## Goal
Interview a user, capture their profile, and assign a clearance tier based on age
and developer status.

## Step-by-step Logic

1. **Capture inputs** — `input()` always returns a string.
- `name` stays a string.
- `age` is cast with `int()` so it can be compared numerically.
- The developer answer is normalized with `.strip().lower()` and compared to
`"yes"`, producing a clean boolean (`is_developer`).

2. **Tier decision (`if-elif-else`)** — order matters here:
- Check `age < 18` **first**. If true, the user is a Guest regardless of
developer status.
- Only if they are 18+ do we look at `is_developer`:
- Developer → `Tier 1: Admin Infrastructure Access`.
- Not a developer → `Tier 2: Standard Executive Access`.
- Because each branch is mutually exclusive, exactly one tier is assigned.

3. **Output** — an f-string builds a readable profile card. A nested
`{'Yes' if is_developer else 'No'}` converts the boolean back to friendly text.

## Why this works
The age gate is evaluated before the developer check, which matches the rule that
under-18 users can never reach Tier 1, even if they are developers.
27 changes: 27 additions & 0 deletions Lab-Exercises/Solutions/lab2_ip_audit.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# Lab 2: The Multi-Cluster IP Audit Tool

cluster_config = {
"cluster_name": "dhaka-prod-east",
"total_max_slots": 8,
"active_nodes": ["10.0.1.15", "10.0.1.16", "10.0.1.17", "10.0.1.18", "10.0.1.19"]
}

def calculate_capacity(config):
# Count how many items are in the active_nodes list using a loop
active_count = 0
for _node in config["active_nodes"]:
active_count += 1

total_slots = config["total_max_slots"]

# Run the mathematical formula to find utilization percentage
utilization = (active_count / total_slots) * 100

# Print the status statement
print(f"--- Capacity Audit: {config['cluster_name']} ---")
print(f"Active Nodes : {active_count}")
print(f"Total Slots : {total_slots}")
print(f"Utilization : {utilization:.1f}%")

# Execute the audit tool
calculate_capacity(cluster_config)
28 changes: 28 additions & 0 deletions Lab-Exercises/Solutions/lab2_solution.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# Lab 2 Solution Logic: The Multi-Cluster IP Audit Tool

## Goal
Parse a nested cluster config, count the active nodes with a loop, and report
the cluster utilization percentage.

## Step-by-step Logic

1. **Access nested data** — `cluster_config` is a dictionary. We read values by
key: `config["active_nodes"]` (a list) and `config["total_max_slots"]` (an int).

2. **Count with a loop** — the task explicitly asks for a `for` loop, so instead of
`len()` we iterate over `active_nodes` and increment `active_count` once per
element. The loop variable is named `_node` because we only care about the
count, not the value.

3. **Utilization formula**
```
Utilization % = (Active Nodes / Total Max Slots) * 100
```
With 5 active nodes and 8 slots: `(5 / 8) * 100 = 62.5%`.

4. **Report** — an f-string prints a clean summary. `{utilization:.1f}` formats the
percentage to one decimal place so the output stays tidy.

## Why this works
Dictionary key lookups give direct access to the structured config, and the manual
counter demonstrates loop-based aggregation that the lab is practicing.
17 changes: 17 additions & 0 deletions Lab-Exercises/Solutions/lab3_budget_optimizer.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# Lab 3: The Deployment Budget Optimizer

def estimate_deployment_cost(instance_count, hourly_rate, budget_cap):
# Calculate total monthly cost (30 days * 24 hours = 720 hours of uptime)
HOURS_PER_MONTH = 720
total_cost = instance_count * hourly_rate * HOURS_PER_MONTH

# Compare against the budget cap and return the appropriate message
if total_cost > budget_cap:
overage = total_cost - budget_cap
return f"REJECTED: Budget Exceeded by ${overage:.2f}!"
else:
return f"APPROVED: Total Estimated Cost is ${total_cost:.2f}."

# Test Cases to verify your execution:
print(estimate_deployment_cost(instance_count=5, hourly_rate=0.45, budget_cap=1500.00))
print(estimate_deployment_cost(instance_count=12, hourly_rate=0.85, budget_cap=5000.00))
32 changes: 32 additions & 0 deletions Lab-Exercises/Solutions/lab3_solution.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# Lab 3 Solution Logic: The Deployment Budget Optimizer

## Goal
Estimate the monthly cost of a server group and approve or reject it against a
budget cap.

## Step-by-step Logic

1. **Function signature** — `estimate_deployment_cost(instance_count, hourly_rate,
budget_cap)` accepts the three required inputs and **returns** a string (rather
than printing), so callers can reuse the result.

2. **Cost formula** — a standard billing month is fixed at
`30 days * 24 hours = 720 hours`:
```
total_cost = instance_count * hourly_rate * 720
```

3. **Budget check (`if/else`)**
- If `total_cost > budget_cap`: compute the overage (`total_cost - budget_cap`)
and return a `REJECTED` message.
- Otherwise: return an `APPROVED` message with the total cost.

4. **Clean number injection** — `{value:.2f}` formats dollars to two decimal places.

## Worked test cases
- `5 * 0.45 * 720 = 1620.00` vs cap `1500.00` → exceeds by `120.00` → **REJECTED**.
- `12 * 0.85 * 720 = 7344.00` vs cap `5000.00` → exceeds by `2344.00` → **REJECTED**.

## Why this works
Pulling the 720-hour constant into a named variable keeps the formula readable, and
returning strings keeps the function pure and testable.
25 changes: 25 additions & 0 deletions Lab-Exercises/Solutions/lab4_solution.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# Lab 4 Solution Logic: The Profile Text Normalization Pipeline

## Goal
Clean a list of messy survey strings into a normalized list ready for production.

## Step-by-step Logic

1. **Iterate** — loop over each `record` in `raw_survey_inputs`.

2. **Chain string methods** — for every record:
- `.strip()` removes leading/trailing whitespace (the erratic outer spaces).
- `.lower()` forces consistent lowercase casing.
- Chaining (`record.strip().lower()`) applies both in one expression because each
method returns a new string.

3. **Build a new list** — `sanitized_records.append(cleaned)` stores each result.
The original `raw_survey_inputs` is left untouched (strings are immutable, and we
never reassign into it), so we can print a before/after comparison.

4. **Verify** — print both lists to visually confirm the transformation.

## Note
`.strip()` only trims the *outer* whitespace; spaces inside an item (e.g.
`"alice smith"`) and characters like commas/underscores are preserved on purpose,
since those are part of the actual content.
12 changes: 12 additions & 0 deletions Lab-Exercises/Solutions/lab4_text_normalization.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# Lab 4: The Profile Text Normalization Pipeline

raw_survey_inputs = [" ALICE SMITH ", " dhaka, BANGLADESH ", " mLOpS_ENGineer ", " LIAM,MAYA "]
sanitized_records = []

# Clean each string: strip surrounding whitespace, then force lowercase
for record in raw_survey_inputs:
cleaned = record.strip().lower()
sanitized_records.append(cleaned)

print(f"Raw Input: {raw_survey_inputs}")
print(f"Sanitized Production Input: {sanitized_records}")
15 changes: 15 additions & 0 deletions Lab-Exercises/Solutions/lab5_alert_evaluator.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# Lab 5: System Alert Flag Evaluator

# Change these values to verify different execution paths!
is_active = True
cpu_percent = 94.5
is_production = True

# Build the compound logical matching condition statement.
# Alert if the server is down, OR if CPU is critically high in production.
should_alert = (not is_active) or (cpu_percent > 90.0 and is_production)

if should_alert:
print("[ALERT] Urgent dispatch! System needs manual intervention.")
else:
print("[OK] System operating within safe margin bounds.")
35 changes: 35 additions & 0 deletions Lab-Exercises/Solutions/lab5_solution.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
# Lab 5 Solution Logic: System Alert Flag Evaluator

## Goal
Combine three telemetry flags into one boolean that decides whether to page an
engineer.

## Step-by-step Logic

The alert rule is the **OR** of two independent failure conditions:

1. **Server down** — `not is_active`. If the server is not active, alert
immediately, no matter the CPU.

2. **Overloaded production** — `cpu_percent > 90.0 and is_production`. High CPU is
only urgent when it happens in a production environment. Both parts must be true
(`and`).

Combined:
```python
should_alert = (not is_active) or (cpu_percent > 90.0 and is_production)
```

## Operator precedence
Python evaluates `not` first, then `and`, then `or`, so the parentheses are not
strictly required — but they make the two failure conditions explicit and readable.

## Trace of the sample values
`is_active=True`, `cpu_percent=94.5`, `is_production=True`:
- `not is_active` → `False`
- `94.5 > 90.0 and True` → `True`
- `False or True` → **`True`** → prints the `[ALERT]` line.

## Why this works
Grouping the CPU + production check together ensures a high CPU on a non-production
box won't wake anyone up, while a downed server always will.